sporingGT
sporingGT

Reputation: 151

glviewport and win32 api

EDIT AT BOTTOM I HAVE ADDED THE SOURCE FILES

My program which simply renders a triangle works correctly, however when i use glviewport function to set it to the createwindow dimensions of x and y i.e 640 and 640 and run the same program on two different computers(my laptop and my desktop)

it causes the triangle to be off the screen by some percentage on my desktop computer while it renders correctly on my laptop , i am not getting the full triangle on the screen anymore but a triangle that is larger then the screen size so a portion of it is mising(a bit on the top and a bit on the right)

I know this has somethign to do with device units while opengl uses pixels

so how do i go about correcting this?

when i remove the glviewport function out of the program then it renders correctly

so what needs to be done so that this is corrected?


from edit to question

as you can see that when i request glViewport to be same size and width as the screen of create window in the header file(you can try it by un-commenting it out) that it gives a result where the triangle is missing a portion , but when it is commented out and left to run without the glViewport function requesting the same width and height as the createWindow dimensions that it works it gives correct result , my question to reiterate is why is this happening and how to fix it

source files below :

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;
}

compile with:

gcc mainWin.c -lopengl32 -lglew32 -lgdi32

Upvotes: 0

Views: 970

Answers (1)

Yakov Galka
Yakov Galka

Reputation: 72449

Presumably you created the window with a caption and a border. But the size CreateWindow uses is for the entire window, including the borders. To overcome this you must use the size of the client-area (that is the area of the window excluding borders) as arguments to the glViewport call. To get the client-area of the window use the GetClientRect function. That will give you a viewport smaller than the size you specified in CreateWindow. If you really want to set the size of the window based on a specific client-area size, then you shall adjust the size using the AdjustWindowRect function.

Upvotes: 3

Related Questions