glviewport和win32 api

时间:2017-01-16 18:53:13

标签: c winapi opengl

在底部编辑我添加了源文件

我只是渲染三角形的程序可以正常工作,但是当我使用glviewport函数将其设置为x和y的创建窗口尺寸(即640和640)并在两台不同的计算机上运行相同的程序时(我的笔记本电脑)和我的桌面)

它导致我的桌面计算机上的三角形在屏幕上移动了一定百分比,而它在我的笔记本电脑上正确呈现,我不再在屏幕上显示完整的三角形,而是一个比屏幕大小更大的三角形所以a它的一部分是mising(有点在顶部,有点在右边)

我知道这与设备单元有一些关系,而opengl使用像素

所以我该如何纠正这个?

当我从程序中删除glviewport函数时,它会正确呈现

那么需要做些什么来纠正这个问题呢?

从编辑到问题

正如你所看到的那样,当我请求glViewport与头文件中创建窗口的屏幕大小和宽度相同时(你可以通过取消注释来尝试它),它会给出三角形缺失的结果一部分,但是当它被注释掉并且没有glViewport函数请求与它工作的createWindow维度相同的宽度和高度时,它会给出正确的结果,我要重申的问题是为什么会发生这种情况以及如何解决它< / p>

以下源文件:

mainWin.c

#include "mainWin.h"

//main function, point of entry for windows application 
//must be present in a windows application

//pass argument hInstance to delcare an instnace of application created

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
               LPSTR lpCmdLine, int nCmdShow)
{
   MSG        Msg;  //variable for storing messages retrieved from operating system by using GetMessage
   WNDCLASS   WndCls;

   //initialize window class must be initialized no default class 
   initWinClass(&WndCls, hInstance);
   //Register the application must register application to make it available to other controls 
   RegisterClass(&WndCls);

   //setup dummy context and initialize glew to get function pointers
   setupDummyContext(hInstance);

   //initialize our real window and setup some context state settings i.e glViewport
   initGL(hInstance);

   //same basic data(triangle) loading to server side(graphics memory)
   loadTri();

   //creating shaders and uploading to server side i.e grahics card
   createShaders();

   //setting context settings
   glUseProgram(program);
   glClearColor(0.0f, 1.0f, 0.0f, 0.0f);

   while (true)
   { 
      while (PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE) > 0) //Or use an if statement
      {
          TranslateMessage (&Msg);
          DispatchMessage (&Msg);
      }

      if(Msg.message == WM_QUIT){
         break;
      }


     //Here is were all the "animation that isn't used when the user does something" code will go.

      glClear(GL_COLOR_BUFFER_BIT);
      glDrawArrays(GL_TRIANGLES, 0, 3); // Starting from vertex 0; 3 vertices total -> 1 triangle
      SwapBuffers(hDC);

   }
   //if quit correctly i.e PostQuitMessage(wParam) this value should be wparam = 0
   return Msg.wParam;
}

mainWin.h

#define true 1
#define false 0
#define WIDTH 128
#define HEIGHT 128

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/wglew.h>
#include <GL/gl.h>

GLuint vertex_shader;
GLuint fragment_shader;
GLuint program;

//string concatenation occurs and becomes all one string
char const * vertShad = 
//[VERTEX SHADER]
"#version 330 core\n"
"layout(location = 0)in vec3 pos;\n"
"void main()\n"
"{\n"
"  gl_Position = vec4(pos, 1.0);\n"
"}\n";

char const * fragShad =
//[FRAGMENT SHADER]
"#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"  FragColor = vec4(1.0, 0.0, 0.0, 0.7);\n"
"}\n"
;


LPCTSTR ClsName = "OpenGL App";
LPCTSTR WndName = "My Game";

//global variables
HDC hDC;
HGLRC hRC;
HWND hWndMain;

void createShaders();
void loadTri();
void setupPixelFormat(HDC hDC);
void initGlew();
void setupPixelFormatARB();

LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

void setupDummyContext(HINSTANCE hInstance){

   HWND hWndF = CreateWindow(ClsName, "FAKE" ,WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
                       0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

   //printf("in setup dummy context %x\n", hWndF);
   //create a dummy context
   HDC hDC = GetDC(hWndF);  
   //get the device context for window
   //An application can only set the pixel format of a window one time. 
   //note that the pixel format can be set only once for a window, 
   //so if you decide to change it, you must destroy and re-create the window using createWindow function
   //Once a window's pixel format is set, it cannot be changed
   setupPixelFormat(hDC); //call our pixel format setup function

   //in order to use ARB context creation you create a dummy rendering context
   HGLRC tempContext = wglCreateContext(hDC);
   wglMakeCurrent(hDC, tempContext);

   //only once a dummy context has been created can you load function pointers
   initGlew();

   wglMakeCurrent(NULL,NULL);
   wglDeleteContext(tempContext);
   DestroyWindow(hWndF);

}

void initGL(HINSTANCE hInstance){

   //adjust the screen to the required size accounting for including borders/styles 
   RECT r = {0,0,WIDTH,HEIGHT};
   DWORD dwstyle = WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
   AdjustWindowRect(&r, dwstyle, false );

   printf("width needed for %d client area is %ld ,height needed for %d client area is %ld\n",WIDTH, r.right-r.left, HEIGHT,r.bottom-r.top );

   //to create windowless and borderless set style (third option) to WS_BORDER and then use SetWindowLong(hWndMain, GWL_STYLE, 0); //remove all window styles, check MSDN for details
   hWndMain = CreateWindow(ClsName, WndName ,dwstyle/*(WS_BORDER )*/,
                       0, 0, r.right-r.left, r.bottom-r.top, NULL, NULL, hInstance, NULL);

   //SetWindowLong(hWndMain, GWL_STYLE, 0); //remove all window styles, check MSDN for details                    

   //printf("in initGL now %x\n", hWndMain);                    
   // Display the window to the user
   ShowWindow(hWndMain, SW_SHOW);
   //??? not sure yet its use not compulsory
   UpdateWindow(hWndMain);

   hDC = GetDC(hWndMain);

   setupPixelFormatARB();

   // If everything went OK
   if(hRC) wglMakeCurrent(hDC, hRC);

   //printf("client size of window is width %ld and height %ld\n",r.right - r.left, r.bottom - r.top);

   printf("OpenGL version string is %s\n", glGetString(GL_VERSION));

   GLint OpenGLVersion[3];

   glGetIntegerv(GL_MAJOR_VERSION, &OpenGLVersion[0]);
   glGetIntegerv(GL_MINOR_VERSION, &OpenGLVersion[1]);


   printf("GL Major version %d\nGL Minor Version %d\n", OpenGLVersion[0], OpenGLVersion[1]);
   printf("GLSL version is %s \nVendor of OpenGL is %s \nRenderer version is %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION), 
                                                                                    glGetString(GL_VENDOR) ,glGetString(GL_RENDERER));
   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   glViewport(0,0,WIDTH,HEIGHT);                                                                                                                                                   
}

void initGlew(){

   //set experimental value to true so that all functions can be used
   glewExperimental = GL_TRUE;

   //initialize glew and get result , check result is not a failure 
   GLenum err = glewInit();
       if(err!=GLEW_OK){
          printf("glew failed!!!....");     
       }

   printf("Glew version is %s\n", glewGetString(GLEW_VERSION));  



   //glClearColor(0,0,0,0); default

}


void initWinClass(PWNDCLASS WndCls, HINSTANCE hInstance){

   // Create the application window
   //WndCls.cbSize        = sizeof(WNDCLASSEX); wndclassex
   WndCls->style         = CS_HREDRAW | CS_VREDRAW |CS_OWNDC;  
   //the style member variable specifies the primary operations applied on the window class
   //if user moves or changes its size, you would need the window redrawn to get its characteristics 
   //CS_HREDRAW CS_VREDRAW draw the window vertically and horizontally  
   WndCls->lpfnWndProc   = WndProcedure;
   WndCls->cbClsExtra    = 0;
   WndCls->cbWndExtra    = 0;
   WndCls->hIcon         = LoadIcon(NULL, IDI_APPLICATION);
   WndCls->hCursor       = LoadCursor(NULL, IDC_ARROW);
   WndCls->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //cast to HBRUSH 
   WndCls->lpszMenuName  = NULL;
   WndCls->lpszClassName = ClsName;
   WndCls->hInstance     = hInstance;
   //WndCls.hIconSm       = LoadIcon(NULL, IDI_APPLICATION); wndclassex

}

void setupPixelFormat(HDC hDC){

   PIXELFORMATDESCRIPTOR pfd;

   memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); 
   pfd.nSize= sizeof(PIXELFORMATDESCRIPTOR); 
   pfd.nVersion   = 1; 
   pfd.dwFlags    = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; 
   pfd.iPixelType = PFD_TYPE_RGBA; 
   pfd.cColorBits = 32; 
   pfd.cDepthBits = 32; 
   pfd.iLayerType = PFD_MAIN_PLANE;

   int nPixelFormat;

   /*      Choose best matching format*/
   nPixelFormat = ChoosePixelFormat(hDC, &pfd);

   if (nPixelFormat == 0) printf("Error in choose pixel format\n");

   /*      Set the pixel format to the device context of the window which cannot be changed afterwards*/
   BOOL bResult = SetPixelFormat(hDC, nPixelFormat, &pfd);

   if (!bResult) printf("Error in set pixel format\n");


}

//uses extension function which require a opengl context to be present either default or dummy
void setupPixelFormatARB(){

   PIXELFORMATDESCRIPTOR pfd;

   //framebuffer pixel format attribs
   const int attribList[] =
   {
     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,        //End
   };

   //context attribs
   int attribs[] =
   {
     WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
     WGL_CONTEXT_MINOR_VERSION_ARB, 3,
     WGL_CONTEXT_PROFILE_MASK_ARB,
     WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
     //WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
     0
   };

   int pixelFormat;
   UINT numFormats;

   wglChoosePixelFormatARB(hDC, attribList, NULL, 1, &pixelFormat, &numFormats);
   SetPixelFormat(hDC, pixelFormat, &pfd); //pfd is redundant here not used but must be present in function 

   hRC = wglCreateContextAttribsARB(hDC, 0, attribs); 
}




void loadTri(){

   // An array of 3 vectors which represents 3 vertices
   static const GLfloat verticies[] = {
     -1.0f, -1.0f, 0.0f,
      1.0f, -1.0f, 0.0f,
      0.0f,  1.0f, 0.0f,
   };

   GLuint vao;
   glGenVertexArrays(1, &vao);
   glBindVertexArray(vao);

   // This will identify our vertex buffer
   GLuint vbo;
   // Generate 1 buffer, put the resulting identifier in vertexbuffer
   glGenBuffers(1, &vbo);
   // The following commands will talk about our 'vertexbuffer' buffer
   glBindBuffer(GL_ARRAY_BUFFER, vbo);
   // Give our vertices to OpenGL.
   glBufferData(GL_ARRAY_BUFFER, sizeof(verticies), verticies, GL_STATIC_DRAW);

   // 1st attribute buffer : vertices
   glEnableVertexAttribArray(0);
   glBindBuffer(GL_ARRAY_BUFFER, vbo);
   glVertexAttribPointer(
      0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
      3,                  // size
      GL_FLOAT,           // type
      GL_FALSE,           // normalized?
      0,                  // stride
      (void*)0            // array buffer offset
   );

   //glDisableVertexAttribArray(0);

}
void createShaders(){

   vertex_shader = glCreateShader(GL_VERTEX_SHADER);
   fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);

   glShaderSource(vertex_shader, 1, &vertShad, NULL);
   glShaderSource(fragment_shader, 1, &fragShad, NULL);

   glCompileShader(vertex_shader);

   //get compilation results

   GLint success = -1;
   GLint maxLength = 0;

   glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);

   if(success==GL_FALSE){
      printf("error in vertex shader\n");
      maxLength = 0;
      glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &maxLength);
      char infoLog[maxLength]; 
      glGetShaderInfoLog(vertex_shader, maxLength, &maxLength, &infoLog[0]);
      printf("%s", infoLog);
   }

   success = -1;
   glCompileShader(fragment_shader);

   glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);

   if(success==GL_FALSE){
      printf("error in fragment shader\n");
      maxLength = 0;
      glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &maxLength);
      char infoLog2[maxLength];
      glGetShaderInfoLog(fragment_shader, maxLength, &maxLength, &infoLog2[0]);
      printf("%s", infoLog2);
   }

   //if(glGetShaderiv(fragment_shader,GL_COMPILE_STATUS)!=GL_TRUE)
   //   printf("error in fragment shader");

   //get compilation results with glGetShaderiv(GL_COMPILE_STATUS) if GL_TRUE returned then successfull compilation
   //If the compilation
   //failed, you can determine what the error was by retrieving the compilation
   //log. glGetShaderInfoLog() will return an implementation-specific set of
   //messages describing the compilation errors. The current size of the error
   //log can be queried by calling glGetShaderiv() with an argument of
   //GL_INFO_LOG_LENGTH

   program = glCreateProgram();

   glAttachShader(program, vertex_shader);
   glAttachShader(program, fragment_shader);
   glLinkProgram(program);

   GLint isLinked = 0;
   glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
   if(isLinked == GL_FALSE){
      printf("did not link\n");   
   }
}

LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
   //printf("the message %d memory address is %x\n", Msg, hWnd);   
   //printf("in wnd procedure function\n");

   switch(Msg)
   {
    //this is the favourite message you can use to perform any early processing that you want to make 
    //sure happens before most things show up you can use this message to initialize anything in your application
    //The window procedure of the new window receives this message after the window is created, 
    //but before the window becomes visible.
    //will only run once on creation
    case WM_CREATE:

    break;

    //minimum application needs to deal with: 
    //wm_destroy message to close window and default case for non registered default messaging processing
    //otherwise hanging or not reaching event queue  

    case WM_DESTROY: //Sent when a window is being destroyed. 
    //It is sent to the window procedure of the window being destroyed after the window is removed from the screen.
    //you can use this message to deconstruct the window once the user requests to destroy the window


       //printf("in wnd prcd %x\n", hWnd);
       //condition set here make sure which window sent the close message
       //make it terminate the main loop by closing of the correct window 
       //or make it terminate main loop by being any window other then the 
       //dummy window by keeping a copy of its pointer
       if(hWndMain==hWnd){
          wglMakeCurrent(hDC,NULL); //deselect rendering context
          wglDeleteContext(hRC);        //delete rendering context
          PostQuitMessage(0);
       }
             //The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately
       //send wm_quit message

       //Indicates a request to terminate an application, and is generated when the application calls the PostQuitMessage function. 
       //This message causes the GetMessage function to return zero.
       //printf("Window destroyed goodbye...bye\n");
    break;

    //this must exist to process left over messages or the application will hang or will not go forward through the 
    //event queue and the while loop will 
       default:
       // Process the left-over messages and messages that are not dealt with
          return DefWindowProc(hWnd, Msg, wParam, lParam);
       break;
    }
    // If something was not done, let it go
   return 0;
}

编译:

gcc mainWin.c -lopengl32 -lglew32 -lgdi32

1 个答案:

答案 0 :(得分:1)

据推测,您创建了带有标题和边框的窗口。但CreateWindow的大小用于整个窗口,包括边框。要解决此问题,您必须使用客户区的大小(即除边框之外的窗口区域)作为glViewport调用的参数。要获取窗口的客户区,请使用GetClientRect函数。这将为您提供一个小于的视口您在CreateWindow中指定的大小。如果您真的想根据特定的客户区大小设置窗口的大小,那么您应该使用AdjustWindowRect函数调整大小。