我使用WinAPI创建了一个子窗口,现在我试图在那里绘制一个三角形。它已绘制,但其比例不正确。
我认为这是因为我没有正确安装正交系统。它是在init()函数中设置的,当在WM_CREATE消息中创建子窗口时会调用它,但它仍被触发,但是正交投影仍未设置为所需的大小。所以我只看到三角形的底部。

#include <Windows.h>
#include <GL/GL.h>
#include <GL/GLU.h>

#pragma comment(lib, "OpenGL32.lib")
#pragma comment(lib, "glu32.lib")

//opengl values
int windowWidth = 600, windowHeight = 800, windowDepth = 600;
void init();

HWND childOpenGLWindowHWND = NULL;

HWND CreateOpenGLChildWindow(wchar_t* title, int x, int y, int width, int height,
  BYTE type, DWORD flags, HWND hWndParent, HINSTANCE hInstance, WNDPROC wndProc)
{
  int         pf;
  HDC         hDC;
  HWND        hWnd;
  PIXELFORMATDESCRIPTOR pfd;

  WNDCLASS wc;
  wc.style = CS_OWNDC;
  wc.lpfnWndProc = wndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = NULL;
  wc.lpszMenuName = NULL;
  wc.lpszClassName = L"OpenGL";

  if (!RegisterClass(&wc)) {
    MessageBox(NULL, L"RegisterClass() failed:  "
      L"Cannot register window class.", L"Error", MB_OK);
    return NULL;
  }

  hWnd = CreateWindow(
    L"OpenGL",
    title,
    WS_CHILD,
    x,
    y,
    width,
    height,
    hWndParent,
    NULL,
    NULL,
    NULL
  );

  if (!hWnd) {
    MessageBox(NULL, L"CreateWindow() failed:  Cannot create a window.",
      L"Error", MB_OK);
    return NULL;
  }

  hDC = GetDC(hWnd);

  /* there is no guarantee that the contents of the stack that become
      the pfd are zeroed, therefore _make sure_ to clear these bits. */
  memset(&pfd, 0, sizeof(pfd));
  pfd.nSize = sizeof(pfd);
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_TYPE_RGBA | flags;
  pfd.iPixelType = type;
  pfd.cColorBits = 32;

  pf = ChoosePixelFormat(hDC, &pfd);
  if (pf == 0) {
    MessageBox(NULL, L"ChoosePixelFormat() failed:  "
      "Cannot find a suitable pixel format.", L"Error", MB_OK);
    return 0;
  }

  if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
    MessageBox(NULL, L"SetPixelFormat() failed:  "
      "Cannot set format specified.", L"Error", MB_OK);
    return 0;
  }

  DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

  ReleaseDC(hWnd, hDC);

  return hWnd;

}

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
wchar_t WinName[] = L"MainFrame";

int WINAPI WinMain(
  HINSTANCE This,
  HINSTANCE Prev,
  LPSTR cmd,
  int mode
)
{
  HDC hDC;              /* device context */
  HGLRC hRC;                /* opengl context */

  HWND hWnd;
  MSG msg;
  WNDCLASS wc;
  wc.hInstance = This;
  wc.lpszClassName = WinName;
  wc.lpfnWndProc = WndProc;
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.lpszMenuName = NULL;
  wc.cbClsExtra = NULL;
  wc.cbWndExtra = NULL;
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  if (!RegisterClass(&wc)) return NULL;
  int windowWidth = 800;
  int windowHeight = 800;
  int screenWidth = GetSystemMetrics(SM_CXSCREEN);
  int screenHeight = GetSystemMetrics(SM_CYSCREEN);
  hWnd = CreateWindow(
    WinName,
    L"Title",
    WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX,
    (screenWidth - windowWidth) / 2,
    (screenHeight - windowHeight) / 2,
    windowWidth,
    windowHeight,
    HWND_DESKTOP,
    NULL,
    This,
    NULL
  );

  if (!hWnd)
  {
    MessageBox(NULL, L"MAIN HWND ERROR!!!",
      L"Error", MB_OK);
    exit(1);
  }

  childOpenGLWindowHWND = CreateOpenGLChildWindow(
    WinName,
    0,
    0,
    600,
    800,
    NULL,
    NULL,
    hWnd,
    This,
    WndProc
  );

  if (!childOpenGLWindowHWND)
  {
    MessageBox(NULL, L"Child window init error", L"Error", MB_OK);
    return 0;
  }



  hDC = GetDC(childOpenGLWindowHWND);
  hRC = wglCreateContext(hDC);
  wglMakeCurrent(hDC, hRC);

  SendMessage(hWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS), NULL);
  ShowWindow(hWnd, mode);
  ShowWindow(childOpenGLWindowHWND, mode);
  while (GetMessage(&msg, NULL, NULL, NULL))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  wglMakeCurrent(NULL, NULL);
  ReleaseDC(childOpenGLWindowHWND, hDC);
  wglDeleteContext(hRC);
  DestroyWindow(childOpenGLWindowHWND);

  return msg.wParam;

  //return NULL;
}

void init()
{
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2);
}

void display()
{
  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_TRIANGLES);
  glColor3f(0, 1, 0);
  glVertex3f(-50, 0, 0);
  glVertex3f(50, 0, 0);
  glVertex3f(0, 50, 0);
  glEnd();
  glFlush();
}

LRESULT CALLBACK WndProc(
  HWND hWnd,
  UINT message,
  WPARAM wParam,
  LPARAM lParam
)
{

  PAINTSTRUCT ps;

  switch (message)
  {
  case WM_CREATE:
    init();
  case WM_PAINT:
    display();
    BeginPaint(hWnd, &ps);
    EndPaint(hWnd, &ps);
    return NULL;
  case WM_SIZE:
    glViewport(0, 0, LOWORD(lParam), HIWORD(lParam));
    PostMessage(hWnd, WM_PAINT, 0, 0);
    return NULL;
  case WM_CHAR:
    switch (wParam) {
    case 27:
      PostQuitMessage(0);
      break;
    }
    return 0;
  case WM_DESTROY:
    PostQuitMessage(NULL);
    break;
  default: return DefWindowProc(hWnd, message, wParam, lParam);
  }
  return NULL;
}

最佳答案

WM_CREATE 消息由 CreateWindow 触发。这是在OpenGL Context创建 wglCreateContext 并由 wglMakeCurrent 设置为最新版本之前。
因此,目前还没有任何OpenGL指令生效。

我建议改为实现 WM_SHOWWINDOW 消息:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;

    HDC hDC;
    switch (message)
    {
    // [...]

    case WM_SHOWWINDOW:
        BeginPaint(hWnd, &ps);
        init();
        EndPaint(hWnd, &ps);
        return NULL;

    case WM_PAINT:
        BeginPaint(hWnd, &ps);
        display();
        EndPaint(hWnd, &ps);
        return NULL;

    // [...]
    }
    return NULL;
}

10-06 06:02