openclonk/src/platform/StdGLCtx.cpp

441 lines
10 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2005-2006 Sven Eberhardt
* Copyright (c) 2005-2007 Günther Brammer
* Copyright (c) 2006 Julian Raschke
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
/* OpenGL implementation of NewGfx, the context */
#include "C4Include.h"
#include <Standard.h>
#include <StdGL.h>
#include <StdSurface2.h>
#include <StdWindow.h>
#ifdef USE_GL
void CStdGLCtx::SelectCommon()
{
pGL->pCurrCtx = this;
// update size
UpdateSize();
// assign size
pGL->lpPrimary->Wdt=cx; pGL->lpPrimary->Hgt=cy;
// set some default states
glDisable(GL_DEPTH_TEST);
glShadeModel(GL_FLAT);
glDisable(GL_ALPHA_TEST);
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
//glEnable(GL_LINE_SMOOTH);
//glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
//glEnable(GL_POINT_SMOOTH);
}
#ifdef _WIN32
CStdGLCtx::CStdGLCtx(): hrc(0), pWindow(0), hDC(0), cx(0), cy(0) { }
void CStdGLCtx::Clear()
{
if (hrc)
{
Deselect();
wglDeleteContext(hrc); hrc=0;
}
if (hDC)
{
ReleaseDC(pWindow ? pWindow->hWindow : hWindow, hDC);
hDC=0;
}
pWindow = 0; cx = cy = 0; hWindow = NULL;
}
bool CStdGLCtx::Init(CStdWindow * pWindow, CStdApp *pApp, HWND hWindow)
{
// safety
if (!pGL) return false;
// store window
this->pWindow = pWindow;
// default HWND
if (pWindow) hWindow = pWindow->hWindow; else this->hWindow = hWindow;
// get DC
hDC=GetDC(hWindow);
if (!hDC) return !!pGL->Error(" gl: Error getting DC");
PIXELFORMATDESCRIPTOR &rPfd = pApp->GetPFD();
if (!pGL->iPixelFormat)
{
// pixel format
memset(&rPfd, 0, sizeof(PIXELFORMATDESCRIPTOR)) ;
rPfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
rPfd.nVersion = 1 ;
rPfd.dwFlags = PFD_DOUBLEBUFFER | /*(pGL->fFullscreen ? PFD_SWAP_EXCHANGE : 0) |*/
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW ;
rPfd.iPixelType = PFD_TYPE_RGBA;
rPfd.cColorBits = pGL->iClrDpt;
rPfd.cDepthBits = 0;
rPfd.iLayerType = PFD_MAIN_PLANE;
pGL->iPixelFormat = ChoosePixelFormat(hDC, &rPfd);
if (!pGL->iPixelFormat) return !!pGL->Error(" gl: Error getting pixel format");
}
if (!SetPixelFormat (hDC, pGL->iPixelFormat, &rPfd)) pGL->Error(" gl: Error setting pixel format");
// create context
hrc = wglCreateContext(hDC); if (!hrc) return !!pGL->Error(" gl: Error creating gl context");
//if (this != &pGL->MainCtx) wglCopyContext(pGL->MainCtx.hrc, hrc, GL_ALL_ATTRIB_BITS);
// share textures
wglMakeCurrent(NULL, NULL); pGL->pCurrCtx=NULL;
if (this != &pGL->MainCtx)
{
if (!wglShareLists(pGL->MainCtx.hrc, hrc)) pGL->Error(" gl: Textures for secondary context not available");
return true;
}
// select
if (!Select()) return !!pGL->Error(" gl: Unable to select context");
// init extensions
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
}
// success
return true;
}
bool CStdGLCtx::Select(bool verbose)
{
// safety
if (!pGL || !hrc) return false; if (!pGL->lpPrimary) return false;
// make context current
if (!wglMakeCurrent (hDC, hrc)) return false;
SelectCommon();
// update clipper - might have been done by UpdateSize
// however, the wrong size might have been assumed
if (!pGL->UpdateClipper()) return false;
// success
return true;
}
void CStdGLCtx::Deselect()
{
if (pGL && pGL->pCurrCtx == this)
{
wglMakeCurrent(NULL, NULL);
pGL->pCurrCtx=NULL;
}
}
bool CStdGLCtx::UpdateSize()
{
// safety
if (!pWindow && !hWindow) return false;
// get size
RECT rt; if (!GetClientRect(pWindow ? pWindow->hWindow : hWindow, &rt)) return false;
int cx2=rt.right-rt.left, cy2=rt.bottom-rt.top;
// assign if different
if (cx!=cx2 || cy!=cy2)
{
cx=cx2; cy=cy2;
if (pGL) pGL->UpdateClipper();
}
// success
return true;
}
bool CStdGLCtx::PageFlip()
{
// flush GL buffer
glFlush();
SwapBuffers(hDC);
return true;
}
bool CStdGL::SaveDefaultGammaRamp(CStdWindow * pWindow)
{
HDC hDC = GetDC(pWindow->hWindow);
if (hDC)
{
if (!GetDeviceGammaRamp(hDC, &DefRamp))
{
DefRamp.Default();
Log(" Error getting default gamma ramp; using standard");
}
ReleaseDC(pWindow->hWindow, hDC);
return true;
}
return false;
}
bool CStdGL::ApplyGammaRamp(D3DGAMMARAMP &ramp, bool fForce)
{
if (!MainCtx.hDC || (!Active && !fForce)) return false;
if (!SetDeviceGammaRamp(MainCtx.hDC, &ramp))
{
int i=::GetLastError();
//Beep(i,i);
}
return true;
}
#elif defined(USE_X11)
// Xmd.h typedefs bool to CARD8, whereas microsoft windows and Clonk use int
#define bool _BOOL
#include <X11/Xmd.h>
#include <GL/glx.h>
#include <X11/extensions/xf86vmode.h>
#undef bool
CStdGLCtx::CStdGLCtx(): pWindow(0), ctx(0), cx(0), cy(0) { }
void CStdGLCtx::Clear()
{
Deselect();
if (ctx)
{
glXDestroyContext(pWindow->dpy, (GLXContext)ctx);
ctx = 0;
}
pWindow = 0;
cx = cy = 0;
}
bool CStdGLCtx::Init(CStdWindow * pWindow, CStdApp *)
{
// safety
if (!pGL) return false;
// store window
this->pWindow = pWindow;
// Create Context with sharing (if this is the main context, our ctx will be 0, so no sharing)
// try direct rendering first
if (!DDrawCfg.NoAcceleration)
ctx = glXCreateContext(pWindow->dpy, (XVisualInfo*)pWindow->Info, (GLXContext)pGL->MainCtx.ctx, True);
// without, rendering will be unacceptable slow, but that's better than nothing at all
if (!ctx)
ctx = glXCreateContext(pWindow->dpy, (XVisualInfo*)pWindow->Info, (GLXContext)pGL->MainCtx.ctx, False);
// No luck at all?
if (!ctx) return pGL->Error(" gl: Unable to create context");
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
// init extensions
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
}
return true;
}
bool CStdGLCtx::Select(bool verbose)
{
// safety
if (!pGL || !ctx)
{
if (verbose) pGL->Error(" gl: pGL is zero");
return false;
}
if (!pGL->lpPrimary)
{
if (verbose) pGL->Error(" gl: lpPrimary is zero");
return false;
}
// make context current
if (!pWindow->renderwnd || !glXMakeCurrent(pWindow->dpy, pWindow->renderwnd, (GLXContext)ctx))
{
if (verbose) pGL->Error(" gl: glXMakeCurrent failed");
return false;
}
SelectCommon();
// update clipper - might have been done by UpdateSize
// however, the wrong size might have been assumed
if (!pGL->UpdateClipper())
{
if (verbose) pGL->Error(" gl: UpdateClipper failed");
return false;
}
// success
return true;
}
void CStdGLCtx::Deselect()
{
if (pGL && pGL->pCurrCtx == this)
{
glXMakeCurrent(pWindow->dpy, None, NULL);
pGL->pCurrCtx = 0;
}
}
bool CStdGLCtx::UpdateSize()
{
// safety
if (!pWindow) return false;
// get size
Window winDummy;
unsigned int borderDummy;
int x, y;
unsigned int width, height;
unsigned int depth;
XGetGeometry(pWindow->dpy, pWindow->renderwnd, &winDummy, &x, &y,
&width, &height, &borderDummy, &depth);
// assign if different
if (cx!=width || cy!=height)
{
cx=width; cy=height;
if (pGL) pGL->UpdateClipper();
}
// success
return true;
}
bool CStdGLCtx::PageFlip()
{
// flush GL buffer
glFlush();
if (!pWindow || !pWindow->renderwnd) return false;
glXSwapBuffers(pWindow->dpy, pWindow->renderwnd);
return true;
}
bool CStdGL::ApplyGammaRamp(_D3DGAMMARAMP& ramp, bool fForce) {
if (!DeviceReady() || (!Active && !fForce)) return false;
if (pApp->xf86vmode_major_version < 2) return false;
if (gammasize != 256) return false;
return XF86VidModeSetGammaRamp(pApp->dpy, DefaultScreen(pApp->dpy), 256,
ramp.red, ramp.green, ramp.blue);
}
bool CStdGL::SaveDefaultGammaRamp(CStdWindow * pWindow)
{
if (pApp->xf86vmode_major_version < 2) return false;
// Get the Display
Display * const dpy = pWindow->dpy;
XF86VidModeGetGammaRampSize(dpy, DefaultScreen(dpy), &gammasize);
if (gammasize != 256)
{
LogF(" Size of GammaRamp is %d, not 256", gammasize);
}
else
{
// store default gamma
if (!XF86VidModeGetGammaRamp(pWindow->dpy, DefaultScreen(pWindow->dpy), 256,
DefRamp.ramp.red, DefRamp.ramp.green, DefRamp.ramp.blue))
{
DefRamp.Default();
Log(" Error getting default gamma ramp; using standard");
}
}
return true;
}
#elif defined(USE_SDL_MAINLOOP)
CStdGLCtx::CStdGLCtx(): pWindow(0), cx(0), cy(0) { }
void CStdGLCtx::Clear()
{
pWindow = 0;
cx = cy = 0;
}
bool CStdGLCtx::Init(CStdWindow * pWindow, CStdApp *)
{
// safety
if (!pGL) return false;
// store window
this->pWindow = pWindow;
assert(!DDrawCfg.NoAcceleration);
// No luck at all?
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
// init extensions
GLenum err = glewInit();
if (GLEW_OK != err)
{
// Problem: glewInit failed, something is seriously wrong.
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
}
return true;
}
bool CStdGLCtx::Select(bool verbose)
{
SelectCommon();
// update clipper - might have been done by UpdateSize
// however, the wrong size might have been assumed
if (!pGL->UpdateClipper())
{
if (verbose) pGL->Error(" gl: UpdateClipper failed");
return false;
}
// success
return true;
}
void CStdGLCtx::Deselect()
{
if (pGL && pGL->pCurrCtx == this)
{
pGL->pCurrCtx = 0;
}
}
bool CStdGLCtx::UpdateSize()
{
// safety
if (!pWindow) return false;
// get size
RECT rc;
pWindow->GetSize(&rc);
int width = rc.right - rc.left, height = rc.bottom - rc.top;
// assign if different
if (cx!=width || cy!=height)
{
cx=width; cy=height;
if (pGL) pGL->UpdateClipper();
}
// success
return true;
}
bool CStdGLCtx::PageFlip()
{
// flush GL buffer
glFlush();
if (!pWindow) return false;
SDL_GL_SwapBuffers();
return true;
}
bool CStdGL::ApplyGammaRamp(_D3DGAMMARAMP& ramp, bool fForce) {
return SDL_SetGammaRamp(ramp.red, ramp.green, ramp.blue) != -1;
}
bool CStdGL::SaveDefaultGammaRamp(CStdWindow * pWindow) {
return SDL_GetGammaRamp(DefRamp.ramp.red, DefRamp.ramp.green, DefRamp.ramp.blue) != -1;
}
#endif //USE_X11/USE_SDL_MAINLOOP
#endif // USE_GL