Reputation: 151
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
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