Multiple OpenGL Window Rendering

Discuss programming topics that involve the OpenGL API.
Post Reply
sniperz227
Posts: 112
Joined: Sat Apr 09, 2011 3:19 am

Multiple OpenGL Window Rendering

Post by sniperz227 »

Hey Sniperz227 here, I've recently been building a map editor using Win32 and OpenGL and well it's been a great learning experience. I have one question in my level editor i have 4 windows and i want to render different things in each one(ones perspective,top,side,front) and well after several attempts i haven't been successful getting opengl working on my second window. I was wondering if someone could tell me what i did wrong and how to fix it so i can render multiple windows. Thanks, here's my source, btw ill comment the lines i added in to try and get the second window working with a this line comment. Also my other question im pretty sure the answers yes but i just want to be 100% sure, i have a Render function where i setup my renders for my first window and for my other windows would i have to do the same for the second window like make a different Render function so it would render opengl stuff?

Anyways here's the code:

Opengl initialization code in a header(GEMOGL.h):

Code: Select all

#include <gl.h>
#include <glu.h>
#include <Windows.h>
#include <iostream>

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



class GEMOGL
{
public:

HDC hDC;
HDC hDCa;//this line
HGLRC glrca;//this line
HGLRC glrc;
HWND RenderWindow;


bool Init(HWND hwnd, unsigned char color_bits=24,
unsigned char depth_bits=32);

bool Release(HWND hWnd);

int raster();
};

bool GEMOGL::Init(HWND hWnd, unsigned char color_bits, unsigned char depth_bits)
{

PIXELFORMATDESCRIPTOR pfd;
int PixelFormat;
hDC = GetDC(hWnd);
if (hDC == NULL)
{
MessageBox(hWnd, "Error: Can't Get Device Context for Window", "ERROR",MB_OK | MB_ICONERROR);
return (false);
}

hDCa=GetDC(hWnd);//this statement
if (hDCa == NULL)
{
MessageBox(hWnd, "Error: Can't Get Device Context for Window", "ERROR",MB_OK | MB_ICONERROR);
return (false);
}

/* Original Method
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = color_bits;
pfd.cRedBits = 0;
pfd.cRedShift = 0;
pfd.cGreenBits = 0;
pfd.cGreenShift = 0;
pfd.cBlueBits = 0;
pfd.cBlueShift = 0;
pfd.cAlphaBits = 0;
pfd.cAlphaShift = 0;
pfd.cAccumBits = 0;
pfd.cAccumRedBits = 0;
pfd.cAccumGreenBits = 0;
pfd.cAccumBlueBits = 0;
pfd.cAccumAlphaBits = 0;
pfd.cDepthBits = depth_bits;
pfd.cStencilBits = 0;
pfd.cAuxBuffers = 0;
pfd.iLayerType = 0;
pfd.bReserved = 0;
pfd.dwLayerMask = 0;
pfd.dwVisibleMask = 0;
pfd.dwDamageMask = 0;
*/
memset (&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.cColorBits = color_bits;
pfd.cDepthBits = depth_bits;

PixelFormat = ChoosePixelFormat(hDC, &pfd);
if (PixelFormat == 0)
{
MessageBox(hWnd, "Error: Can't Choose Pixel Format", "ERROR", MB_OK |
MB_ICONERROR);
ReleaseDC (hWnd, hDC);
hDC = NULL;
return (false);
}

PixelFormat = ChoosePixelFormat(hDCa, &pfd);//this statement
if (PixelFormat == 0)
{
MessageBox(hWnd, "Error: Can't Choose Pixel Format", "ERROR", MB_OK |MB_ICONERROR);
ReleaseDC (hWnd, hDCa);
hDCa = NULL;
return (false);
}

if (SetPixelFormat(hDC, PixelFormat, &pfd) == 0)
{
MessageBox(hWnd, "Error: Can't Set The Pixel Format", "ERROR", MB_OK |MB_ICONERROR);
ReleaseDC (hWnd, hDC);
hDC = NULL;
return (false);
}

if (SetPixelFormat(hDCa, PixelFormat, &pfd) == 0)//this statement
{
MessageBox(hWnd, "Error: Can't Set The Pixel Format", "ERROR", MB_OK |MB_ICONERROR);
ReleaseDC (hWnd, hDCa);
hDCa = NULL;
return (false);
}


glrc = wglCreateContext(hDC);
if (glrc == NULL)
{
MessageBox(hWnd, "Error: Can't Create GL Context", "ERROR", MB_OK |MB_ICONERROR);
ReleaseDC (hWnd, hDC);
hDC = NULL;
return (false);
}

glrca = wglCreateContext(hDCa);//this statement
if (glrca == NULL)
{
MessageBox(hWnd, "Error: Can't Create GL Context", "ERROR", MB_OK |MB_ICONERROR);
ReleaseDC (hWnd, hDCa);
hDCa = NULL;
return (false);
}

if (!wglMakeCurrent(hDC, glrc))
{
MessageBox(hWnd, "Error: Can't Make Current GL Context", "ERROR", MB_OK |MB_ICONERROR);
wglDeleteContext(glrc);
ReleaseDC (hWnd, hDC);
glrc = NULL;
hDC = NULL;
return (false);
}

if (!wglMakeCurrent(hDCa, glrca))//this statement
{
MessageBox(hWnd, "Error: Can't Make Current GL Context", "ERROR", MB_OK |MB_ICONERROR);
wglDeleteContext(glrca);
ReleaseDC (hWnd, hDCa);
glrca = NULL;
hDCa = NULL;
return (false);
}
return (true);
}

bool GEMOGL::Release(HWND hWnd)
{	
if (hDC == NULL || glrc == NULL||hDCa==NULL||glrca==NULL) return (false);//the extra 2 or statement were added

if (wglMakeCurrent(NULL, NULL) == false)
{
MessageBox(hWnd, "Error: Release Of DC And RC Failed.", "Release Error",
MB_OK | MB_ICONERROR);
return (false);
}
if (wglDeleteContext(glrc) == false)
{
MessageBox(hWnd, "Error: Release Rendering Context Failed.", "Release Error", MB_OK | MB_ICONERROR);
return (false);
}
glrc = NULL;
if (wglDeleteContext(glrca) == false)//this statement
{
MessageBox(hWnd, "Error: Release Rendering Context Failed.", "Release Error", MB_OK | MB_ICONERROR);
return (false);
}
glrca=NULL; // this line

if (ReleaseDC(hWnd, hDC) == false)
{
MessageBox(hWnd, "Error: Release Device Context Failed.", "Release Error",
MB_OK | MB_ICONERROR);
return (false);
}
hDC = NULL;

if (ReleaseDC(hWnd, hDCa) == false)//this statement
{
MessageBox(hWnd, "Error: Release Device Context Failed.", "Release Error",MB_OK | MB_ICONERROR);
return (false);
}
hDCa = NULL;//this line

return (true);

while (1)
{
	MSG msg;
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage (&msg);
}
}

}
Main.cpp

Code: Select all

#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include "resource.h"
#include "gemogl.h"

#define DEFAULT_BUTTON_WIDTH 100
#define DEFAULT_BUTTON_HEIGHT 20

HINSTANCE GlobalInstance;
HMENU Menu;
HMENU PopupMenu;
HWND Window;
HWND RenderWindowTL;
HWND RenderWindowBL;
HWND RenderWindowTR;
HWND RenderWindowBR;
HWND bCreateWall;
GEMOGL gemogl;



void ResizeGLWindow(long width, long height)
{
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-200,200, -200,-200, -2000,2000);
glMatrixMode(GL_MODELVIEW);
}

void SetGLDefaults()
{
glEnable (GL_DEPTH_TEST);
glDisable (GL_CULL_FACE);
}

void Render()
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
glLoadIdentity();
glPushMatrix();
glTranslatef (0.0f, 0.0f, 0.0f);

glBegin (GL_TRIANGLES);
glVertex3f (0.0f, 0.0f, 0.0f);
glVertex3f (0.0f, 1.0f, 0.0f);
glVertex3f (1.0f, 1.0f, 0.0f);
glEnd();

glPopMatrix();
SwapBuffers (gemogl.hDC);

}

void Rendera()//this function
{
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
glLoadIdentity();
glPushMatrix();
glTranslatef (0.0f, 0.0f, 0.0f);

glBegin (GL_TRIANGLES);
glVertex3f (0.0f, 0.0f, 0.0f);
glVertex3f (0.0f, 1.0f, 0.0f);
glVertex3f (1.0f, 1.0f, 0.0f);
glEnd();

glPopMatrix();

SwapBuffers (gemogl.hDCa);//this line
}

LRESULT CALLBACK MapDetailsDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
SetDlgItemText (hWnd, IDC_MAP_DETAILS_NAME, "Map Name");
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_RULES, LB_ADDSTRING,
0, (LPARAM)"Erase Me");
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_RULES, LB_RESETCONTENT,
0, 0);
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_RULES, LB_ADDSTRING,
0, (LPARAM)"Exit");
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_RULES, LB_ADDSTRING,
0, (LPARAM)"Get Fragged");
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_RULES, LB_SETCURSEL,
0, 1);
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_TYPE, CB_ADDSTRING,
0, (LPARAM)"Erase Me");
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_TYPE, CB_RESETCONTENT,
0, 0);
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_TYPE, CB_ADDSTRING,
0, (LPARAM)"Single Player");
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_TYPE, CB_ADDSTRING,
0, (LPARAM)"Multi Player");
SendDlgItemMessage (hWnd, IDC_MAP_DETAILS_LEVEL_TYPE, CB_SETCURSEL,
0, 1);
} break;
case WM_COMMAND:
{
if (wParam == IDOK)
{
long level_rule = SendDlgItemMessage (hWnd,
IDC_MAP_DETAILS_LEVEL_RULES, LB_GETCURSEL, 0, 0);
long level_type = SendDlgItemMessage (hWnd,
IDC_MAP_DETAILS_LEVEL_TYPE, CB_GETCURSEL, 0, 0);
char temp[500];
sprintf (temp, "Level Type: %i\r\nLevel Rule: %i\r\nOK Button!",
level_type, level_rule);
MessageBox (hWnd, temp, "OK", MB_OK);
EndDialog (hWnd, 0);
}
else if (wParam == IDCANCEL)
{
MessageBox (hWnd, "Cancel Button!", "Cancel", MB_OK);
EndDialog (hWnd, 0);
}
} break;
}
return (0);
}

void WMCommand(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (lParam == (LPARAM)bCreateWall) MessageBox (Window, "You Pressed bCreateWall", "Congrats!", MB_OK);
else if (wParam == ID_FILE_EXIT) PostQuitMessage(0);
else if (wParam == ID_DRAWING_WIREFRAME)
{
CheckMenuItem (Menu, ID_DRAWING_WIREFRAME, MF_CHECKED);
CheckMenuItem (Menu, ID_DRAWING_SOLID, MF_UNCHECKED);
}
else if (wParam == ID_DRAWING_SOLID)
{
CheckMenuItem (Menu, ID_DRAWING_SOLID, MF_CHECKED);
CheckMenuItem (Menu, ID_DRAWING_WIREFRAME, MF_UNCHECKED);
}
else if (wParam == ID_MAP_DETAILS) DialogBox (GlobalInstance,
MAKEINTRESOURCE(IDD_MAP_DETAILS), NULL, (DLGPROC)MapDetailsDlgProc);
// Pop-up Menu Items
else if (wParam == ID_MOVE) MessageBox (Window, "Move", "Click", MB_OK);
else if (wParam == ID_DELETE) MessageBox (Window, "Delete", "Click",MB_OK);
else if (wParam == ID_TEXTURE) MessageBox (Window, "Texture", "Click",MB_OK);
else if (wParam == ID_DUPLICATE) MessageBox (Window, "Duplicate","Click", MB_OK);
}

void DisplayPopupMenu(long x, long y)
{
HMENU temp = GetSubMenu(PopupMenu, 0);
TrackPopupMenu(temp, TPM_LEFTALIGN|TPM_RIGHTBUTTON, x, y, 0, Window, NULL);
}

void WMSize(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
RECT rect;
GetClientRect (Window, &rect);
MoveWindow (RenderWindowTL, DEFAULT_BUTTON_WIDTH, 30,500,354, true);
GetClientRect (RenderWindowTL, &rect);
MoveWindow (RenderWindowTR, 600, 30,500,354, true);
GetClientRect (RenderWindowTR, &rect);
ResizeGLWindow (rect.right-rect.left, rect.bottom-rect.top);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY: PostQuitMessage(0); break;
case WM_COMMAND: WMCommand (hWnd, msg, wParam, lParam); break;
case WM_SIZE: WMSize (hWnd, msg, wParam, lParam); break;
case WM_RBUTTONUP: DisplayPopupMenu(LOWORD(lParam), HIWORD(lParam)); break;
}
return (DefWindowProc(hWnd, msg, wParam, lParam));
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevious, LPSTR lpCmdString,
int CmdShow)
{
WNDCLASS wc;
MSG msg;
RECT rect;
GlobalInstance = hInstance;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = "ME";
wc.lpszMenuName = NULL;
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
if (!RegisterClass(&wc))
{
MessageBox (NULL,"Error: Cannot Register Class","ERROR!",MB_OK);
return (0);
}
Window = CreateWindow("ME", "Map Editor", WS_OVERLAPPEDWINDOW | WS_VISIBLE,0, 0, 640, 480, NULL, NULL, hInstance, NULL);
if (Window == NULL)
{
MessageBox (NULL,"Error: Failed to Create Window","ERROR!",MB_OK);
return (0);
}
GetClientRect (Window, &rect);
bCreateWall = CreateWindow("BUTTON", "Create Wall", WS_CHILD | WS_VISIBLE,0, 100, DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT, Window,NULL, hInstance, NULL);

RenderWindowTL = CreateWindow("STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,DEFAULT_BUTTON_WIDTH, 30,500,354, Window, NULL, hInstance, NULL);

RenderWindowTR = CreateWindow("STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,650, 30,550,354, Window, NULL, hInstance, NULL);//second window

Menu = LoadMenu (hInstance, MAKEINTRESOURCE(IDR_MENU));
SetMenu (Window, Menu);
PopupMenu = LoadMenu (hInstance, MAKEINTRESOURCE(IDR_POPUP_MENU));

if (!gemogl.Init(RenderWindowTL)) return (0);
GetClientRect (RenderWindowTL, &rect);
ResizeGLWindow (rect.right-rect.left, rect.bottom-rect.top);
SetGLDefaults();
while (1)
{
Render();
Rendera();
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage (&msg);
}
}
gemogl.Release(RenderWindowTL);

return(1);
}


again thanks !
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Multiple OpenGL Window Rendering

Post by Spike »

4 windows, 4 contexts, 4 sets of textures...
you need to use wglMakeCurrent to select which gl context you are using every time you start rendering to a different context upon the same thread.

Be warned that wglGetProcAddress must be called separately for each context. Function pointers returned by wglMakeCurrent are private to the context from which they were obtained, and crashes can legitimately occur if you call a function from a context which is not current. Of course, most drivers will use the same pointer for every context, and most machines will only have one driver, so it might be hard to test this.

Regarding textures, use wglShareLists to share lists+textures+etc between multiple contexts, then you don't need 4 separate sets of textures. Make sure you call it before creating any such objects.


so stick a wglMakeCurrent call at the top of your Render functions. Also, why oh why oh why do you have two separate copies of the same function? Use a context index or something, so much cleaner and less copypasta.
sniperz227
Posts: 112
Joined: Sat Apr 09, 2011 3:19 am

Re: Multiple OpenGL Window Rendering

Post by sniperz227 »

Spike wrote:4 windows, 4 contexts, 4 sets of textures...
you need to use wglMakeCurrent to select which gl context you are using every time you start rendering to a different context upon the same thread.

Be warned that wglGetProcAddress must be called separately for each context. Function pointers returned by wglMakeCurrent are private to the context from which they were obtained, and crashes can legitimately occur if you call a function from a context which is not current. Of course, most drivers will use the same pointer for every context, and most machines will only have one driver, so it might be hard to test this.

Regarding textures, use wglShareLists to share lists+textures+etc between multiple contexts, then you don't need 4 separate sets of textures. Make sure you call it before creating any such objects.


so stick a wglMakeCurrent call at the top of your Render functions. Also, why oh why oh why do you have two separate copies of the same function? Use a context index or something, so much cleaner and less copypasta.
yes i know i need 4 but im trying it out with 2 first so i can see how it works then do the other 4 i'm asking what i did wrong here because it isn't initializing the 2nd window only stuff on the first one and i already made another wglMakeCurrent in my header, my real question is how do i assign an hDC to a window because i tested both them out using SwapBuffers and when i put both them in they both render to the first screen so i need to set one of them to the second screen
sniperz227
Posts: 112
Joined: Sat Apr 09, 2011 3:19 am

Re: Multiple OpenGL Window Rendering

Post by sniperz227 »

nvm i got it i just changed my handlers and created them in them class and then set them using the GetDC function :)
Post Reply