提问人:samas69420 提问时间:10/22/2023 最后编辑:Mark Rotteveelsamas69420 更新时间:10/23/2023 访问量:150
尝试在使用 win32 API 创建的子窗口中使用 OpenGL 时调整大小问题
Resizing issues while trying to use OpenGL in a child window made with win32 API
问:
我想在带有自定义标题栏的窗口中使用 OpenGL,只使用 Windows API,但我在调整大小时遇到了奇怪的行为。
这是我现在的情况:我有一个用 win32 API 制作的窗口。在这个窗口中有一个较小的窗口,另一个线程在其中使用 OpenGL 绘制图像。我删除了默认框架(按照微软的本指南),然后绘制了父窗口的可见部分,将其用作自定义标题栏。一切看起来都不错,但是当我尝试调整窗口大小时,它会在一小段时间内开始出现故障,同时它一直在较小的窗口中呈现内容。我该如何解决这个问题?
也许知道如果我停止 OpenGL 线程的循环,窗口就会停止给我这个错误,但它也会被完全重绘,子 OpenGL 窗口会被覆盖。
这是我使用的代码的一个小版本,这给了我问题。要重现它,您只需复制粘贴并编译即可。我希望 ~600 行对于这里的问题来说不是太多。
#include<windows.h>
#include<dwmapi.h>
#include<pthread.h>
#include<stdio.h>
#include<GL/gl.h>
#include<GL/glext.h>
#include<GL/wglext.h>
#define TITLEBARHEIGHT 25
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
HGLRC glcontext = {0};
HGLRC dummy_glcontext = {0};
void** newglfun = {0};
GLuint buffer = 0;
GLuint ibuffer = 0;
GLuint vao = 0;
unsigned int program = 0;
int u_location = 0;
float r = 0;
float increment = 0.05;
HANDLE handle_to_this_module = {0};
HWND handle_to_window = {0};
HWND parent = {0};
HWND child = {0};
HDC device_context = {0};
void (*glGenBuffers)(GLsizei, GLuint*)={0};
void (*glBindBuffer)(GLenum, GLuint)={0};
void (*glBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum)={0};
void (*glVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*)={0};
void (*glEnableVertexAttribArray)(GLuint)={0};
GLuint (*glCreateProgram)(void)={0};
GLuint (*glCreateShader)(GLenum)={0};
void (*glShaderSource)(GLuint, GLsizei,const GLchar**, const GLint*)={0};
void (*glCompileShader)(GLuint)={0};
void (*glAttachShader)(GLuint, GLuint)={0};
void (*glLinkProgram)(GLuint)={0};
void (*glValidateProgram)(GLuint)={0};
void (*glDeleteShader)(GLuint)={0};
void (*glGetShaderiv)(GLuint,GLenum, GLint*)={0};
void (*glUseProgram)(GLuint)={0};
void (*glDeleteProgram)(GLuint)={0};
GLint (*glGetUniformLocation)(GLuint, const GLchar*)={0};
void (*glUniform4f)(GLint,GLfloat,GLfloat,GLfloat,GLfloat)={0};
const GLubyte* (*glGetStringi)(GLenum, GLuint)={0};
void (*glGenVertexArrays)(GLsizei, GLuint*)={0};
void (*glBindVertexArray)(GLuint)={0};
void (*wglSwapIntervalEXT)(int)={0};
const char* (*wglGetExtensionsStringARB)(HDC)={0};
BOOL (*wglChoosePixelFormatARB)(HDC, const int*,const FLOAT*,UINT,int*,UINT*)={0};
HGLRC (*wglCreateContextAttribsARB)(HDC,HGLRC, const int*)={0};
int loadModernGLFunctions()
{
char* newglfuncnames[] = {"glGenBuffers","glBindBuffer","glBufferData",
"glVertexAttribPointer","glEnableVertexAttribArray",
"glCreateProgram", "glCreateShader",
"glShaderSource","glCompileShader",
"glAttachShader","glLinkProgram","glValidateProgram",
"glDeleteShader", "glGetShaderiv","glUseProgram",
"glDeleteProgram","glUniform4f","glGetUniformLocation",
"wglSwapIntervalEXT","glGetStringi","wglGetExtensionsStringARB",
"wglChoosePixelFormatARB","wglCreateContextAttribsARB",
"glGenVertexArrays","glBindVertexArray"};
int n_functions = sizeof(newglfuncnames)/8;
newglfun = malloc(sizeof(newglfuncnames));
for(int i = 0; i<n_functions; i++){
newglfun[i] = (void*) wglGetProcAddress(newglfuncnames[i]);
}
glGenBuffers = newglfun[0];
glBindBuffer = newglfun[1];
glBufferData = newglfun[2];
glVertexAttribPointer = newglfun[3];
glEnableVertexAttribArray = newglfun[4];
glCreateProgram = newglfun[5];
glCreateShader = newglfun[6];
glShaderSource = newglfun[7];
glCompileShader = newglfun[8];
glAttachShader = newglfun[9];
glLinkProgram = newglfun[10];
glValidateProgram = newglfun[11];
glDeleteShader = newglfun[12];
glGetShaderiv = newglfun[13];
glUseProgram = newglfun[14];
glDeleteProgram = newglfun[15];
glUniform4f = newglfun[16];
glGetUniformLocation = newglfun[17];
wglSwapIntervalEXT = newglfun[18];
glGetStringi = newglfun[19];
wglGetExtensionsStringARB = newglfun[20];
wglChoosePixelFormatARB = newglfun[21];
wglCreateContextAttribsARB = newglfun[22];
glGenVertexArrays = newglfun[23];
glBindVertexArray = newglfun[24];
return TRUE;
}
void end_opengl(void)
{
glDeleteProgram(program);
}
int make_shaders(void)
{
int compileresult;
program = (unsigned int) glCreateProgram();
unsigned int id_vert = (unsigned int) glCreateShader(GL_VERTEX_SHADER);
const char* vert_shader_source = "\n\
#version 330 core \n\
layout(location = 0) in vec4 position;\n\
void main()\n\
{\n\
gl_Position = position;\n\
}\n\
";
glShaderSource(id_vert, 1, &vert_shader_source, NULL);
glCompileShader(id_vert);
glGetShaderiv(id_vert, GL_COMPILE_STATUS, &compileresult);
if(!compileresult){
printf("error shader vert\n");
return 0;
}
unsigned int vs = id_vert;
unsigned int id_frag = (unsigned int) glCreateShader(GL_FRAGMENT_SHADER);
const char* frag_shader_source = "\n\
#version 330 core \n\
layout(location = 0) out vec4 color;\n\
uniform vec4 u_Color;\n\
void main()\n\
{\n\
color = u_Color;\n\
}\n\
";
glShaderSource(id_frag, 1, &frag_shader_source, NULL);
glCompileShader(id_frag);
glGetShaderiv(id_frag, GL_COMPILE_STATUS, &compileresult);
if(!compileresult){
printf("error shader frag\n");
return 0;
}
unsigned int fs = id_frag;
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glValidateProgram(program);
glUseProgram(program);
glDeleteShader(vs);
glDeleteShader(fs);
u_location = glGetUniformLocation(program, "u_Color");
glUniform4f(u_location, 0.3254f, 0.098f, 0.9843f, 1.0f);
return TRUE;
}
int init_opengl(void)
{
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24,
8,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int dummyiPixelFormat = ChoosePixelFormat(device_context, &pfd);
SetPixelFormat(device_context, dummyiPixelFormat, &pfd);
if(!(dummy_glcontext = wglCreateContext(device_context)))
printf("errcode %d\n", GetLastError());
if(!wglMakeCurrent(device_context, dummy_glcontext))
return 1;
if(!loadModernGLFunctions())
return 0;
int iPixelFormat;
UINT numFormats;
const int PixAttribList[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0,
};
if(!wglChoosePixelFormatARB(device_context, PixAttribList, NULL, 1, &iPixelFormat, &numFormats))
{
return 0;
}
const int CtxAttribList[] =
{
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
0,
};
if(!(glcontext = wglCreateContextAttribsARB(device_context, NULL, CtxAttribList)))
return 0;
if(!wglMakeCurrent(device_context, glcontext))
return 0;
glClearColor(0.1f,0.1f,0.1f,0.1f);
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
wglSwapIntervalEXT(0);
float positions[8] = {
-0.5, -0.5,
-0.5f, 0.5f,
0.5f, 0.5f,
0.5f, -0.5f
};
unsigned int indices[] = {
0, 1, 2,
2, 3, 0
};
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 8*sizeof(float),positions,GL_STATIC_DRAW);
glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,sizeof(float)*2, 0);
glEnableVertexAttribArray(0);
glGenBuffers(1, &ibuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*sizeof(unsigned int),indices,GL_STATIC_DRAW);
if(!make_shaders())
return 0;
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if(!wglMakeCurrent(device_context, NULL))
return 0;
return TRUE;
}
void opengl_draw(void)
{
if (r>1.0f)
increment = -0.05f;
else if (r< 0.0f)
increment = 0.05f;
r+=increment;
RECT rcCli;
GetClientRect(WindowFromDC(device_context), &rcCli);
int nWidth = rcCli.right-rcCli.left;
int nHeight = rcCli.bottom-rcCli.top;
glViewport(rcCli.left,rcCli.top,nWidth,nHeight);
glUseProgram(program);
glBindVertexArray(vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuffer);
glClear(GL_COLOR_BUFFER_BIT);
glUniform4f(u_location, r, 0.098f, 0.9843f, 1.0f);
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,NULL);
SwapBuffers(device_context);
}
void OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
int parentWidth = LOWORD(lParam);
int parentHeight = HIWORD(lParam);
RECT parentRect;
GetClientRect(hwnd, &parentRect);
RECT childRect;
GetWindowRect(child, &childRect);
int childWidth = parentRect.right - parentRect.left;
int childHeight = parentRect.bottom - parentRect.top - 25;
int childX = parentRect.left;
int childY = parentRect.top + 25;
SetWindowPos(child,
NULL,
childX, childY,
childWidth, childHeight,
SWP_NOZORDER | SWP_NOACTIVATE);
}
LRESULT HitTestNCA(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
POINT ptMouse = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
RECT rcWindow;
GetWindowRect(hWnd, &rcWindow);
RECT rcFrame = { 0 };
rcFrame.top = rcWindow.top + 5;
rcFrame.bottom = rcWindow.bottom - 5;
rcFrame.left = rcWindow.left + 5;
rcFrame.right = rcWindow.right - 5;
USHORT uRow = 1;
USHORT uCol = 1;
BOOL fOnResizeBorder = FALSE;
if (ptMouse.y >= rcWindow.top && ptMouse.y < rcWindow.top + 25){
fOnResizeBorder = (ptMouse.y < rcFrame.top);
uRow = 0;
}
else if (ptMouse.y < rcWindow.bottom && ptMouse.y >= rcWindow.bottom - 20){
uRow = 2;
}
if (ptMouse.x >= rcWindow.left && ptMouse.x < rcWindow.left + 8){
uCol = 0;
}
else if (ptMouse.x < rcWindow.right && ptMouse.x >= rcWindow.right - 8){
uCol = 2;
}
BOOL titlebar = (ptMouse.x > rcWindow.left && ptMouse.x < rcWindow.right-25) &&
(ptMouse.y > rcWindow.top && ptMouse.y < rcWindow.top+25) ? 1 : 0;
if(titlebar)
return HTCAPTION;
BOOL client = (ptMouse.x > rcWindow.left+5 && ptMouse.x < rcWindow.right-5) &&
(ptMouse.y > rcWindow.top+5 && ptMouse.y < rcWindow.bottom-5) ? 1 : 0;
if(client){
return HTCLIENT;
}
LRESULT hitTests[3][3] =
{
{ HTTOPLEFT, fOnResizeBorder ? HTTOP : HTCAPTION, HTTOPRIGHT },
{ HTLEFT, HTNOWHERE, HTRIGHT },
{ HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT },
};
return hitTests[uRow][uCol];
}
LRESULT CALLBACK childProc(HWND chwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_NCHITTEST:
return HTTRANSPARENT;
default:
return DefWindowProc(chwnd, uMsg, wParam, lParam);
}
}
LRESULT CALLBACK myProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SETCURSOR:
{
int ht_result = LOWORD(lParam);
if(ht_result == HTCLIENT){
SetCursor(LoadCursor(NULL, IDC_ARROW));
return TRUE;
}
else
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_SIZING:
{
RECT rect;
GetClientRect(hwnd, &rect);
InvalidateRect(hwnd, &rect, TRUE);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
case WM_SIZE:
{
OnSize(hwnd, wParam, lParam);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
case WM_LBUTTONDOWN:
{
POINT ptMouse = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
RECT rc;
GetClientRect(hwnd, &rc);
BOOL close = (ptMouse.x >= rc.right-25 && ptMouse.x < rc.right) &&
(ptMouse.y > rc.top && ptMouse.y < rc.top+25) ? 1 : 0;
if(close)
DestroyWindow(hwnd);
InvalidateRect(hwnd, NULL, TRUE);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
case WM_PAINT:
{
RECT rect;
GetClientRect(hwnd, &rect);
RECT titlebar;
RECT closebutton;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
titlebar.top = 0;
titlebar.bottom = 25;
titlebar.left = 0;
titlebar.right = rect.right - rect.left;
closebutton.top = 0;
closebutton.bottom = 25;
closebutton.left = rect.right - 25;
closebutton.right = rect.right;
HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &titlebar, hBrush);
DeleteObject(hBrush);
HBRUSH hBrush3 = CreateSolidBrush(RGB(10, 10, 10));
FillRect(hdc, &closebutton, hBrush3);
DeleteObject(hBrush3);
HBRUSH hBrush2 = CreateSolidBrush(RGB(100, 100, 100));
RECT main;
main.top = 25;
main.bottom = rect.bottom;
main.left = 0;
main.right = titlebar.right;
FillRect(hdc, &main, hBrush2);
DeleteObject(hBrush2);
EndPaint(hwnd, &ps);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
case WM_NCHITTEST:
{
return HitTestNCA(hwnd, wParam, lParam);
}
case WM_ACTIVATE:
{
MARGINS margins;
margins.cxLeftWidth = 0;
margins.cxRightWidth = 0;
margins.cyBottomHeight = 0;
margins.cyTopHeight = 0;
HRESULT hr = DwmExtendFrameIntoClientArea(hwnd, &margins);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
case WM_CREATE:
{
SetWindowPos(hwnd,
NULL,
0, 0,
0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
case WM_NCCALCSIZE:
{
if(wParam == TRUE) return 0;
else return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int init_win32(void)
{
handle_to_this_module = GetModuleHandle(NULL);
if(!handle_to_this_module)
return 0;
WNDCLASS class = {0};
class.lpfnWndProc = myProc;
class.hInstance = handle_to_this_module;
class.lpszClassName = (LPCSTR) L"mainclass";
class.hbrBackground = NULL;
RegisterClass(&class);
handle_to_window = CreateWindowExA(
0,
(LPCSTR) L"mainclass",
"mainwin",
WS_OVERLAPPEDWINDOW |
WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
420,
420,
(HWND) NULL,
(HMENU) NULL,
handle_to_this_module,
NULL
);
if(!handle_to_window)
return 0;
parent = handle_to_window;
WNDCLASS childclass = {0};
childclass.lpfnWndProc = childProc;
childclass.hInstance = handle_to_this_module;
childclass.lpszClassName = (LPCSTR) L"childclass";
childclass.hCursor = class.hCursor;
childclass.hbrBackground = NULL;
RegisterClass(&childclass);
child = CreateWindowExA(
0,
(LPCSTR) L"childclass",
"childwin",
WS_CHILD | WS_VISIBLE,
0, TITLEBARHEIGHT,
420, 420-TITLEBARHEIGHT,
parent,
0,
handle_to_this_module,
NULL);
UpdateWindow(handle_to_window);
device_context = GetDC(child);
return TRUE;
}
void init(void)
{
if(!init_win32())
exit(1);
if(!init_opengl())
exit(2);
}
void run(void)
{
MSG msg = {0};
while(msg.message != WM_QUIT){
if(PeekMessageW(&msg, NULL, 0x0,0x0, PM_REMOVE))
DispatchMessage(&msg);
}
}
void* drawing_loop(void* arg)
{
if(!wglMakeCurrent(device_context, glcontext))
return 0;
while(1){
opengl_draw();
}
}
void start_drawing_thread(void)
{
pthread_t rendering_thread;
pthread_create(&rendering_thread, NULL, drawing_loop, NULL);
}
void quit(void)
{
end_opengl();
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
init();
start_drawing_thread();
run();
quit();
}
// > gcc .\file.c -lgdi32 -ldwmapi -lopengl32 -o file
答: 暂无答案
评论