// CWGL.cpp - implementation of CWGL -
// MS Windows OpenGL rendering interface class.
//
// (c) W.Weyna
//
#include "stdafx.h"
//#include "resource.h"
#include "OGLT.h"
#include "CWGL.h"
LRESULT CALLBACK CWGL_FullScreen_WndProc(HWND, UINT, WPARAM, LPARAM);
//******************************************************
//
// CWGL()
//
//******************************************************
CWGL::CWGL()
{
m_pDC = NULL;
m_pBitmapDC = NULL;
m_pWnd = NULL;
m_hWnd = NULL;
m_hWndRC = NULL;
m_hFSWndRC = NULL;
m_hBmpRC = NULL;
m_bNewRCCreated = false;
m_bWeCreatedDC = false;
m_dwRenderingTime = 1;
m_dwStartRenderingTime = 0;
m_hPrevDC = NULL;
m_hPrevRC = NULL;
// Remember current RC (needed for CWGL nesting)
m_hPrevRC = wglGetCurrentContext();
m_hPrevDC = wglGetCurrentDC();
//
// Create a default font
//
memset(&m_defaultLogfont, 0, sizeof m_defaultLogfont);
m_defaultLogfont.lfHeight = 14;
m_defaultLogfont.lfWeight = 1;
strcpy(m_defaultLogfont.lfFaceName, "Courier New");
m_defaultLogfont.lfCharSet = ANSI_CHARSET;
m_defaultLogfont.lfOutPrecision = OUT_TT_PRECIS;
m_defaultLogfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
m_defaultLogfont.lfQuality = PROOF_QUALITY;
m_defaultLogfont.lfPitchAndFamily = FF_SWISS | VARIABLE_PITCH;
m_defaultFont.CreateFontIndirect(&m_defaultLogfont);
m_pFont = &m_defaultFont;
//
// Register FULL SCREEN window class
//
m_hFSWnd = NULL;
m_hViewWnd = NULL;
m_pView = NULL;
m_bFullScreen = false;
m_nMode = 0;
m_windowRect = CRect(0, 0, 640, 480);
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)CWGL_FullScreen_WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = AfxGetInstanceHandle();
wc.hIcon = LoadIcon(AfxGetInstanceHandle(), "IDR_MAINFRAME");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "SIWinFS";
RegisterClass(&wc);
}
//******************************************************
//
// ~CWGL()
//
//******************************************************
CWGL::~CWGL()
{
TRACE("--- CWGL Destroying all\n");
wglMakeCurrent(NULL, NULL);
if(m_hFSWndRC)
wglDeleteContext(m_hFSWndRC);
if(m_hFSWnd)
{
// If we created a full screen window for a view,
// unsubclass now and reattach view's window.
if(m_pView)
{
ASSERT(m_hViewWnd);
m_pView->UnsubclassWindow();
m_pView->Attach(m_hViewWnd);
}
::DestroyWindow(m_hFSWnd);
}
if(m_hWndRC)
wglDeleteContext(m_hWndRC);
if(m_hBmpRC)
wglDeleteContext(m_hBmpRC);
// If nested RC's reactivate previous one
if(m_hPrevRC)
wglMakeCurrent(m_hPrevDC, m_hPrevRC);
TRACE("--- CWGL Destroying done\n");
}
bool CWGL::Begin(CDC* pDC /* = NULL */)
{
// If NULL is passed instead of a valid DC,
// it is a request to create a DC for last used window.
// Pass NULL if you want to make last used window RC current again.
m_bWeCreatedDC = false;
if(pDC == NULL)
{
ASSERT(!m_bFullScreen);
if(m_pWnd == NULL || !IsWindow(m_hWnd))
{
// You must call Begin(windowDC) at least once
// before Begin(NULL) calls are allowed.
ASSERT(0);
return false;
}
pDC = new CClientDC(m_pWnd);
m_bWeCreatedDC = true;
}
if(!m_hPrevRC)
{
// Synchronize access to surface
// ( on Win95 may be remove to increased performance)
GdiFlush();
}
// Make sure that previous RC is inactivated.
wglMakeCurrent(NULL, NULL);
m_bNewRCCreated = false;
// m_pDC is for SwapBuffers() to work,
// and will be NULL if rendered to bitmap.
m_pDC = NULL;
if(pDC->IsPrinting())
{
// Printing not supported.
// Render on a DIB section and print the DIB section.
ASSERT(0);
return false;
}
//
// Rendering in a window (in a window's backbuffer)
//
if(pDC->GetWindow())
{
if(m_bFullScreen)
{
if(m_hFSWndRC == NULL)
{
if(!SetPixelFormat(pDC))
return false;
if((m_hFSWndRC = wglCreateContext(pDC->m_hDC))==NULL)
return false;
m_bNewRCCreated = true;
}
ASSERT(m_hFSWndRC);
// Associate OpenGL rendering context with this window
if(!wglMakeCurrent(pDC->m_hDC, m_hFSWndRC))
return false;
}
else
{
if(m_pWnd && m_pWnd != pDC->GetWindow())
{
// one CWGL object may be used to render only in one window
ASSERT(0);
return false;
}
// If rendering in a window for the first time,
// set the pixelformat for this window and create RC.
// The pixelformat may be set only once for the windows life time.
// The created RC will exist and will be used for subsequent
// renderings until the window will be destroyed.
if(m_pWnd == NULL)
{
m_pWnd = pDC->GetWindow();
m_hWnd = m_pWnd->m_hWnd;
if(!SetPixelFormat(pDC))
return false;
if((m_hWndRC = wglCreateContext(pDC->m_hDC))==NULL)
return false;
m_bNewRCCreated = true;
}
ASSERT(m_hWndRC);
// Associate OpenGL rendering context with this window
if(!wglMakeCurrent(pDC->m_hDC, m_hWndRC))
return false;
}
m_pDC = pDC; // save pDC so we can do SwapBuffers() in End()
if(m_bNewRCCreated)
CompileFonts();
m_dwStartRenderingTime = GetTickCount();
return true;
}
HGDIOBJ hGDIObject = GetCurrentObject(pDC->m_hDC, OBJ_BITMAP);
if(hGDIObject == NULL)
{
// Dont know how to render on this DC
ASSERT(0);
return false;
}
//
// Rendering on a DIB section GDI object or bitmap.
// For each new DC we must call SetPixelFormat()
// and we must create new RC.
//
// Delete previously used RC.
if(m_hBmpRC && pDC != m_pBitmapDC)
{
wglDeleteContext(m_hBmpRC);
m_hBmpRC = NULL;
m_pBitmapDC = NULL;
}
// Create new RC for new bitmap DC
if(m_hBmpRC == NULL)
{
// Set the pixelformat for the bitmap selected into pDC.
CBitmap* pBitmap = pDC->GetCurrentBitmap();
BITMAP bmInfo;
pBitmap->GetObject(sizeof(BITMAP), &bmInfo);
ASSERT(bmInfo.bmPlanes == 1);
ASSERT(bmInfo.bmBitsPixel == 8 || bmInfo.bmBitsPixel == 16 || bmInfo.bmBitsPixel == 24 || bmInfo.bmBitsPixel == 32);
if(!SetPixelFormat(pDC, PFD_DRAW_TO_BITMAP, bmInfo.bmBitsPixel))
return false;
// Create new RC for the bitmap selected into pDC
if((m_hBmpRC = wglCreateContext(pDC->m_hDC)) == NULL)
return false;
m_bNewRCCreated = true;
m_pBitmapDC = pDC;
}
if(!wglMakeCurrent(pDC->m_hDC, m_hBmpRC))
return false;
CompileFonts();
m_dwStartRenderingTime = GetTickCount();
return true;
}
void CWGL::End(bool m_bDontSwapBuffers /* = false*/)
{
// Synchronize access to surface
// ( on Win95 may be remove to increased performance)
glFinish();
// if(m_pDC) means 'if not rendered to bitmap'
if(m_pDC && !m_bDontSwapBuffers)
{
// If rendered to the window's backbuffer, show the image.
// If rendered directly to the window,
// this call will have no effect.
SwapBuffers(m_pDC->m_hDC);
GdiFlush(); // ( on Win95 may be remove to increased performance)
}
// Free currently selected OpenGL RC,
// so the other window belonging to
// this thread may also do the OpenGL rendering.
wglMakeCurrent(NULL, NULL);
if(m_bWeCreatedDC)
{
ASSERT(m_pDC);
delete m_pDC;
}
m_dwRenderingTime = GetTimeDif(m_dwStartRenderingTime);
if(m_dwRenderingTime == 0)
m_dwRenderingTime = 10;
}
bool CWGL::SetPixelFormat(CDC* pDC, DWORD dwFlags /* = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER */, int nBitsPerPixel /* = 24 */)
{
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_SUPPORT_OPENGL | dwFlags,
PFD_TYPE_RGBA, // RGBA type
nBitsPerPixel, // color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
16, // 16-bit z-buffer
8, // require stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pixelformat;
if(!(pixelformat = ChoosePixelFormat(pDC->m_hDC, &pfd)))
return false;
if(!::SetPixelFormat(pDC->m_hDC, pixelformat, &pfd))
return false;
return true;
}
DWORD CWGL::GetTimeDif(DWORD dwStartTime)
{
DWORD dwTickCount = GetTickCount();
if(dwTickCount < dwStartTime)
return dwTickCount + 0xFFFFFFFF - dwStartTime;
return dwTickCount - dwStartTime;
}
void CWGL::CompileFonts()
{
HDC hDC = wglGetCurrentDC();
if(hDC == NULL)
{
// CompileFonts() called without RC active
ASSERT(0);
return;
}
SelectObject(hDC, m_pFont->m_hObject);
wglUseFontBitmaps(hDC, 0, 255, WGL_FONTS_LISTBASE);
}
void CWGL::TextOut(const CString& str)
{
glListBase(WGL_FONTS_LISTBASE);
glCallLists(str.GetLength(), GL_UNSIGNED_BYTE, LPCTSTR(str));
glListBase(0);
}
bool CWGL::FullScreen(int nMode /* = -1*/, CView* pView /* = NULL */)
{
if(m_bFullScreen)
{
//
// Restore windowed mode
//
ASSERT(m_hFSWnd);
m_bFullScreen = false;
if(m_hFSWndRC)
{
// In CWGL, for full screen mode,
// a window is always created when going
// into the full screen mode and
// destroyed when going back to windowed mode.
// So, RC has to be also created and destroyed.
wglDeleteContext(m_hFSWndRC);
m_hFSWndRC = NULL;
}
// If we created a full screen window for a view,
// unsubclass now and reattach view's window.
if(m_pView)
{
ASSERT(m_hViewWnd);
m_pView->UnsubclassWindow();
m_pView->Attach(m_hViewWnd);
}
::DestroyWindow(m_hFSWnd);
m_hFSWnd = NULL;
if(m_nMode != -1)
ChangeDisplaySettings(NULL, NULL);
return true;
}
m_bFullScreen = false;
m_hFSWnd = NULL;
m_nMode = nMode;
switch(m_nMode)
{
case -1:
{
// use current display settings
CClientDC dc(NULL);
m_windowRect.right = dc.GetDeviceCaps(HORZRES);
m_windowRect.bottom = dc.GetDeviceCaps(VERTRES);
}
break;
//
// use some fixed display settings
//
case 0:
m_windowRect = CRect(0, 0, 640, 480);
break;
case 1:
m_windowRect = CRect(0, 0, 800, 600);
break;
case 2:
m_windowRect = CRect(0, 0, 1024, 768);
break;
case 3:
m_windowRect = CRect(0, 0, 1152, 864);
break;
default:
m_windowRect = CRect(0, 0, 1280, 1024);
break;
}
//
// Try to change to full screen display mode.
//
if(m_nMode != -1)
{
DEVMODE dmScreenSettings;
ZeroMemory(&dmScreenSettings, sizeof dmScreenSettings);
dmScreenSettings.dmSize = sizeof dmScreenSettings;
dmScreenSettings.dmPelsWidth = m_windowRect.Width(); // Selected Screen Width
dmScreenSettings.dmPelsHeight = m_windowRect.Height(); // Selected Screen Height
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// CDS_FULLSCREEN option means - 'the mode will be temporary'.
if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
dmScreenSettings.dmBitsPerPel = 24;
if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
dmScreenSettings.dmBitsPerPel = 16;
if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
return false;
}
}
}
//
// Create the full screen window
//
if (!(m_hFSWnd = CreateWindowEx(NULL,
"SIWinFS",
"SIWinFS",
WS_POPUP |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN |
WS_VISIBLE,
0, 0,
m_windowRect.Width(),
m_windowRect.Height(),
NULL,
NULL,
AfxGetInstanceHandle(),
NULL)))
{
return false;
}
m_hViewWnd = NULL;
m_pView = NULL;
// If we create a full screen window for a CView view,
// subclass the window.
if(pView)
{
m_pView = pView;
m_hViewWnd = m_pView->m_hWnd;
m_pView->SubclassWindow(m_hFSWnd);
}
m_bFullScreen = true;
return true;
}
//*********************************************************************
//
// CWGL_FullScreen_WndProc()
//
//*********************************************************************
LRESULT CALLBACK CWGL_FullScreen_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_ACTIVATE:
return 0;
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0;
}
break;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
//////////////////////////////////////////////////////////////////////