476 lines
15 KiB
C++
476 lines
15 KiB
C++
//**************************************************************
|
|
//* OpenGLide - Glide to OpenGL Wrapper
|
|
//* http://openglide.sourceforge.net
|
|
//*
|
|
//* Utility File
|
|
//*
|
|
//* OpenGLide is OpenSource under LGPL license
|
|
//* Originaly made by Fabio Barros
|
|
//* Modified by Paul for Glidos (http://www.glidos.net)
|
|
//* Mac version and additional features by Jens-Olaf Hemprich
|
|
//**************************************************************
|
|
|
|
#include "Glide.h"
|
|
#include "GlideDisplay.h"
|
|
#include "GlideSettings.h"
|
|
#include "GLExtensions.h"
|
|
#include "GLUtil.h"
|
|
#include "PGTexture.h"
|
|
|
|
|
|
OSStatus aglReportWarning(void)
|
|
{
|
|
GLenum err = aglGetError();
|
|
if (AGL_NO_ERROR != err)
|
|
{
|
|
GlideMsg("AGL-Error: %s\n", reinterpret_cast<const char *>(aglErrorString(err)));
|
|
}
|
|
// ensure we are returning an OSStatus noErr if no error condition
|
|
if (err == AGL_NO_ERROR)
|
|
return noErr;
|
|
else
|
|
return (OSStatus) err;
|
|
}
|
|
|
|
// Gobals for initialising the display
|
|
WindowPtr pGLWindow = NULL;
|
|
structWindowInfoPtr pWindowInfo = NULL;
|
|
|
|
short SetAGLAttributes(GLint* aglAttributes, short index)
|
|
{
|
|
// The maximun depth buffer size will be requested
|
|
// by choosing AGL_MAXIMUM_POLICY
|
|
if (UserConfig.DepthBufferBits < 0) UserConfig.DepthBufferBits = 0;
|
|
if (UserConfig.DepthBufferBits > 32) UserConfig.DepthBufferBits = 32;
|
|
GLint depthbufferbits = UserConfig.DepthBufferBits;
|
|
// 0 triggers the maximun number of available depth
|
|
// buffer bits to be used but at least 16
|
|
if (depthbufferbits == 0)
|
|
{
|
|
depthbufferbits = 16;
|
|
}
|
|
aglAttributes[index++] = AGL_RGBA;
|
|
aglAttributes[index++] = AGL_ALPHA_SIZE;
|
|
aglAttributes[index++] = 0; // Alpha not supported on Glide Cards with depth buffering
|
|
aglAttributes[index++] = AGL_DOUBLEBUFFER;
|
|
// ARB_multisample doesn't seem to work in Classic,
|
|
// but maybe someone wants to port this to Carbon...
|
|
/*
|
|
if (UserConfig.FullSceneAntiAliasing > 0)
|
|
{
|
|
aglAttributes[index++] = AGL_SAMPLE_BUFFERS_ARB;
|
|
aglAttributes[index++] = 1;
|
|
aglAttributes[index++] = AGL_SAMPLES_ARB;
|
|
aglAttributes[index++] = UserConfig.FullSceneAntiAliasing > 0;
|
|
}
|
|
*/
|
|
aglAttributes[index++] = AGL_NO_RECOVERY;
|
|
if (UserConfig.DepthBufferBits == 0) aglAttributes[index++] = AGL_MAXIMUM_POLICY;
|
|
aglAttributes[index++] = AGL_DEPTH_SIZE;
|
|
aglAttributes[index++] = depthbufferbits;
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_aglSetFullScreen)
|
|
{
|
|
aglAttributes[index++] = AGL_FULLSCREEN;
|
|
}
|
|
if (UserConfig.GapFix & OpenGLideGapFixFlag_Enabled)
|
|
{
|
|
aglAttributes[index++] = AGL_STENCIL_SIZE;
|
|
aglAttributes[index++] = AGL_2_BIT;
|
|
}
|
|
aglAttributes[index] = AGL_NONE;
|
|
return index;
|
|
}
|
|
|
|
// This function can only use settings from UserConfig,
|
|
// as it's called before InternalConfig
|
|
bool InitialiseOpenGLWindow(FxU32 hwnd, int x, int y, FxU32 width, FxU32 height )
|
|
{
|
|
glReportErrors("InitialiseOpenGLWindow");
|
|
// Adjust the origin if the selected display resolution
|
|
// is greater than the OpenGL resolution
|
|
unsigned long display_width = 0;
|
|
unsigned long display_height = 0;
|
|
OpenGL.OriginX = 0;
|
|
OpenGL.OriginY = 0;
|
|
Rect rectWin = {y, x , height, width};
|
|
// Change the screen resolution?
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_DisplayManager ||
|
|
UserConfig.DisplayMode == OpenGLideDisplayMode_aglSetFullScreen)
|
|
{
|
|
OSErr err = DisplayManager_RememberPassthroughDisplay();
|
|
if (err == noErr)
|
|
{
|
|
// Avoid flicker during screen resolution switching
|
|
#ifndef OGL_DEBUG
|
|
DisplayManager_SetPassthroughDisplayGammaBlack();
|
|
#endif
|
|
long freq = UserConfig.MonitorRefreshRate;
|
|
// sort out illegal values
|
|
if (freq < 60) freq = 0;
|
|
// check whether to use the refresh rate requested by the Glide application
|
|
if (freq == 0) freq = OpenGL.Refresh;
|
|
// Allows to play Falcon 4.0 in True Color and to play Tomb Raider Gold 1+2 with movies enabled.
|
|
// However, Tomb Raider II < 1.03 has problems displaying Lara and other in-game objects.
|
|
err = DisplayManager_SetGlideDisplay(width, height, freq);
|
|
if (err != noErr)
|
|
{
|
|
if (width < 640)
|
|
{
|
|
// Not all displays support all Glide resolutions,
|
|
// for instance the LCD-iMacs don't support 512x384
|
|
GlideMsg("Error: Resolution %dx%d@%dHz not found. Trying double resolution %dx%d@%dHz.\n", width, height, freq, width << 1, height << 1, freq);
|
|
// Restore gamma first
|
|
err = DisplayManager_SetGlideDisplay(width << 1, height << 1, freq);
|
|
if (err == noErr)
|
|
{
|
|
width = width << 1;
|
|
height = height << 1;
|
|
OpenGL.WindowWidth = width;
|
|
OpenGL.WindowHeight = height;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (err != noErr)
|
|
{
|
|
// If changing the screensize failed (for instance
|
|
// when the calling app checks for available resolutions)
|
|
// the gamma correction table must be restored or
|
|
// we may end up with a black screen
|
|
DisplayManager_RestorePassthroughDisplayGamma();
|
|
return false;
|
|
}
|
|
if (DisplayManager_GetGlideDisplayResolution(display_width, display_height))
|
|
{
|
|
// Position the viewport in the middle of the screen
|
|
OpenGL.OriginX = (display_width - width) / 2;
|
|
OpenGL.OriginY = (display_height - height) / 2;
|
|
rectWin.right = display_width;
|
|
rectWin.bottom = display_height;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (DisplayManager_GetDesktopDisplayResolution(display_width, display_height))
|
|
{
|
|
// Position the window in the middle of the screen
|
|
rectWin.left = (display_width - width) / 2;
|
|
rectWin.top = (display_height - height) / 2;
|
|
}
|
|
else
|
|
{
|
|
rectWin.left = 40;
|
|
rectWin.top = 60;
|
|
}
|
|
rectWin.right = rectWin.left + width;
|
|
rectWin.bottom = rectWin.top + height;
|
|
}
|
|
// build window
|
|
pWindowInfo = (structWindowInfoPtr) NewPtrSysClear (sizeof (structWindowInfo));
|
|
OSStatus err = CreateNewWindow(kDocumentWindowClass, kWindowNoAttributes, &rectWin, &pGLWindow);
|
|
if (pGLWindow)
|
|
{
|
|
ShowWindow (pGLWindow);
|
|
SetPortWindowPort (pGLWindow);
|
|
pWindowInfo->glInfo.fDraggable = false;
|
|
pWindowInfo->glInfo.fmt = 0;
|
|
pWindowInfo->glInfo.fAcceleratedMust = true;
|
|
pWindowInfo->glInfo.VRAM = 0;
|
|
pWindowInfo->glInfo.textureRAM = 0;
|
|
SetAGLAttributes(pWindowInfo->glInfo.aglAttributes, 0);
|
|
BuildGLFromWindow(pGLWindow, &pWindowInfo->aglContext, &pWindowInfo->glInfo, NULL);
|
|
if (pWindowInfo->aglContext)
|
|
{
|
|
// This does not work reliably
|
|
/*
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_aglSetFullScreen)
|
|
{
|
|
long freq = UserConfig.MonitorRefreshRate;
|
|
// sort out illegal values
|
|
if (freq < 60) freq = 0;
|
|
// check whether to use the refresh rate requested by the Glide application
|
|
if (freq == 0) freq = OpenGL.Refresh;
|
|
// aglSetDrawable(pWindowInfo->aglContext, (AGLDrawable) NULL);
|
|
if (aglSetFullScreen(pWindowInfo->aglContext, width, height, freq, 0))
|
|
{
|
|
if (aglSetCurrentContext(pWindowInfo->aglContext))
|
|
{
|
|
aglUpdateContext(pWindowInfo->aglContext);
|
|
}
|
|
else
|
|
{
|
|
aglReportWarning();
|
|
GlideError("aglSetCurrentContext() after aglSetFullScreen() failed\n");
|
|
// shutdown full screen
|
|
aglSetCurrentContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
aglSetDrawable(pWindowInfo->aglContext, (AGLDrawable) GetWindowPort(pGLWindow));
|
|
aglReportError();
|
|
aglUpdateContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aglReportWarning();
|
|
GlideError("aglSetFullScreen() failed\n");
|
|
// shutdown full screen
|
|
aglSetCurrentContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
aglSetDrawable(pWindowInfo->aglContext, (AGLDrawable) GetWindowPort(pGLWindow));
|
|
aglReportError();
|
|
aglUpdateContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (aglSetCurrentContext(pWindowInfo->aglContext))
|
|
{
|
|
aglUpdateContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
}
|
|
else
|
|
{
|
|
aglReportWarning();
|
|
GlideError("aglSetCurrentContext() failed\n");
|
|
}
|
|
}
|
|
*/
|
|
// Keep renderers in memory
|
|
aglConfigure(AGL_RETAIN_RENDERERS, GL_TRUE);
|
|
aglReportWarning();
|
|
// And minimise cache size
|
|
aglConfigure(AGL_FORMAT_CACHE_SIZE, 1);
|
|
aglReportWarning();
|
|
// Don't render ahead
|
|
bool runningInClassic = strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)), "GL_EXT_fog_coord") != NULL;
|
|
if (runningInClassic)
|
|
{
|
|
aglEnable(pWindowInfo->aglContext, AGL_SWAP_LIMIT);
|
|
aglReportWarning();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aglReportWarning();
|
|
DestroyGLFromWindow(&pWindowInfo->aglContext, &pWindowInfo->glInfo);
|
|
GlideError("couldn't create agl context");
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GlideError("Couldn't create window");
|
|
}
|
|
// clear color buffer to black to minimmise white screen flash on resolution change
|
|
// and white top/bottoms when displaying widescreen movies on 4/3 screens
|
|
glDrawBuffer(GL_BACK);
|
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
GLint swap = 0;
|
|
aglSetInteger(pWindowInfo->aglContext, AGL_SWAP_INTERVAL, &swap);
|
|
aglSwapBuffers(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
|
|
if (UserConfig.GapFix & OpenGLideGapFixFlag_Enabled)
|
|
{
|
|
glEnable(GL_STENCIL_TEST);
|
|
glStencilMask(0x03);
|
|
glClearStencil(0x00);
|
|
glStencilFunc(GL_ALWAYS, 0x02, 0x03);
|
|
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
|
glReportError();
|
|
}
|
|
|
|
// The gamma correction value is restored in grSstWinOpen()
|
|
// so we don't have to do anything here
|
|
return true;
|
|
}
|
|
|
|
void FinaliseOpenGLWindow(void)
|
|
{
|
|
s_Framebuffer.Cleanup();
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_DisplayManager ||
|
|
UserConfig.DisplayMode == OpenGLideDisplayMode_aglSetFullScreen)
|
|
{
|
|
#ifndef OGL_DEBUG
|
|
DisplayManager_SetGlideDisplayGammaBlack();
|
|
#endif
|
|
}
|
|
if (pWindowInfo)
|
|
{
|
|
// DeleteFontGL (pWindowInfo->fontList);
|
|
// must clean up failure to do so will result in an Unmapped Memory Exception
|
|
DestroyGLFromWindow(&pWindowInfo->aglContext, &pWindowInfo->glInfo);
|
|
DisposePtr ((Ptr) pWindowInfo);
|
|
pWindowInfo = NULL;
|
|
}
|
|
if (pGLWindow)
|
|
{
|
|
DisposeWindow (pGLWindow);
|
|
pGLWindow = NULL;
|
|
}
|
|
// Cleanup display manager?
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_DisplayManager ||
|
|
UserConfig.DisplayMode == OpenGLideDisplayMode_aglSetFullScreen)
|
|
{
|
|
DisplayManager_RestorePassthroughDisplay();
|
|
}
|
|
}
|
|
|
|
void HideOpenGLWindow()
|
|
{
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_DisplayManager ||
|
|
UserConfig.DisplayMode == OpenGLideDisplayMode_aglSetFullScreen)
|
|
{
|
|
#ifndef OGL_DEBUG
|
|
DisplayManager_SetGlideDisplayGammaBlack();
|
|
#endif
|
|
}
|
|
// Hide window by moving it offscreen, allowing some extra offset to hide the bar
|
|
MoveWindow(pGLWindow, OpenGL.WindowWidth + 64, OpenGL.WindowHeight + 64, FALSE);
|
|
// Actually HideWIndow() should be working, but it blacks out
|
|
// the Movies in Tomb Raider Gold
|
|
// HideWindow(pGLWindow);
|
|
aglUpdateContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_DisplayManager ||
|
|
UserConfig.DisplayMode == OpenGLideDisplayMode_aglSetFullScreen)
|
|
{
|
|
DisplayManager_RestorePassthroughDisplay();
|
|
aglUpdateContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
}
|
|
}
|
|
|
|
void RestoreOpenGLWindow()
|
|
{
|
|
// Change the screen resolution?
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_DisplayManager ||
|
|
UserConfig.DisplayMode == OpenGLideDisplayMode_aglSetFullScreen)
|
|
{
|
|
OSErr err = DisplayManager_RememberPassthroughDisplay();
|
|
if (err == noErr)
|
|
{
|
|
// Avoid flicker during screen resolution switching
|
|
#ifndef OGL_DEBUG
|
|
DisplayManager_SetPassthroughDisplayGammaBlack();
|
|
#endif
|
|
}
|
|
}
|
|
DisplayManager_RestoreGlideDisplay();
|
|
// 0,0 is only correct in fullscreen modes where the OpenGL window matches the
|
|
// Glide screen resolution.
|
|
MoveWindow(pGLWindow, 0, 0, FALSE);
|
|
// Actually HideWIndow() should be working, but it blacks out the
|
|
// Movies in Tomb Raider Gold
|
|
// ShowWindow(pGLWindow);
|
|
aglUpdateContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
SelectWindow(pGLWindow);
|
|
aglUpdateContext(pWindowInfo->aglContext);
|
|
aglReportError();
|
|
// @todo: Sometimes textures in Descent look wierd
|
|
// Clearing the textues shouldn't be necessary,
|
|
// so updating the context might not be enough.
|
|
// to restore the textures (they look wierd after showing he window)
|
|
// Textures->Clear();
|
|
DisplayManager_SetGlideDisplayGamma(Glide.State.Gamma);
|
|
|
|
}
|
|
|
|
void ConvertColorB( GrColor_t GlideColor, FxU8 &R, FxU8 &G, FxU8 &B, FxU8 &A )
|
|
{
|
|
switch ( Glide.State.ColorFormat )
|
|
{
|
|
case GR_COLORFORMAT_ARGB: //0xAARRGGBB
|
|
A = (FxU8)( ( GlideColor & 0xFF000000 ) >> 24 );
|
|
R = (FxU8)( ( GlideColor & 0x00FF0000 ) >> 16 );
|
|
G = (FxU8)( ( GlideColor & 0x0000FF00 ) >> 8 );
|
|
B = (FxU8)( ( GlideColor & 0x000000FF ) );
|
|
break;
|
|
|
|
case GR_COLORFORMAT_ABGR: //0xAABBGGRR
|
|
A = (FxU8)( ( GlideColor & 0xFF000000 ) >> 24 );
|
|
B = (FxU8)( ( GlideColor & 0x00FF0000 ) >> 16 );
|
|
G = (FxU8)( ( GlideColor & 0x0000FF00 ) >> 8 );
|
|
R = (FxU8)( ( GlideColor & 0x000000FF ) );
|
|
break;
|
|
|
|
case GR_COLORFORMAT_RGBA: //0xRRGGBBAA
|
|
R = (FxU8)( ( GlideColor & 0xFF000000 ) >> 24 );
|
|
G = (FxU8)( ( GlideColor & 0x00FF0000 ) >> 16 );
|
|
B = (FxU8)( ( GlideColor & 0x0000FF00 ) >> 8 );
|
|
A = (FxU8)( ( GlideColor & 0x000000FF ) );
|
|
break;
|
|
|
|
case GR_COLORFORMAT_BGRA: //0xBBGGRRAA
|
|
B = (FxU8)( ( GlideColor & 0xFF000000 ) >> 24 );
|
|
G = (FxU8)( ( GlideColor & 0x00FF0000 ) >> 16 );
|
|
R = (FxU8)( ( GlideColor & 0x0000FF00 ) >> 8 );
|
|
A = (FxU8)( ( GlideColor & 0x000000FF ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
GrColor_t ConvertConstantColor( float R, float G, float B, float A )
|
|
{
|
|
GrColor_t r = (GrColor_t) R;
|
|
GrColor_t g = (GrColor_t) G;
|
|
GrColor_t b = (GrColor_t) B;
|
|
GrColor_t a = (GrColor_t) A;
|
|
|
|
switch ( Glide.State.ColorFormat )
|
|
{
|
|
case GR_COLORFORMAT_ARGB: //0xAARRGGBB
|
|
return ( a << 24 ) | ( r << 16 ) | ( g << 8 ) | b;
|
|
|
|
case GR_COLORFORMAT_ABGR: //0xAABBGGRR
|
|
return ( a << 24 ) | ( b << 16 ) | ( g << 8 ) | r;
|
|
|
|
case GR_COLORFORMAT_RGBA: //0xRRGGBBAA
|
|
return ( r << 24 ) | ( g << 16 ) | ( b << 8 ) | a;
|
|
|
|
case GR_COLORFORMAT_BGRA: //0xBBGGRRAA
|
|
return ( b << 24 ) | ( g << 16 ) | ( r << 8 ) | a;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ConvertColorF( GrColor_t GlideColor, float &R, float &G, float &B, float &A )
|
|
{
|
|
switch ( Glide.State.ColorFormat )
|
|
{
|
|
case GR_COLORFORMAT_ARGB: //0xAARRGGBB
|
|
A = (float)( ( GlideColor & 0xFF000000 ) >> 24 ) * D1OVER255;
|
|
R = (float)( ( GlideColor & 0x00FF0000 ) >> 16 ) * D1OVER255;
|
|
G = (float)( ( GlideColor & 0x0000FF00 ) >> 8 ) * D1OVER255;
|
|
B = (float)( ( GlideColor & 0x000000FF ) ) * D1OVER255;
|
|
break;
|
|
|
|
case GR_COLORFORMAT_ABGR: //0xAABBGGRR
|
|
A = (float)( ( GlideColor & 0xFF000000 ) >> 24 ) * D1OVER255;
|
|
B = (float)( ( GlideColor & 0x00FF0000 ) >> 16 ) * D1OVER255;
|
|
G = (float)( ( GlideColor & 0x0000FF00 ) >> 8 ) * D1OVER255;
|
|
R = (float)( ( GlideColor & 0x000000FF ) ) * D1OVER255;
|
|
break;
|
|
|
|
case GR_COLORFORMAT_RGBA: //0xRRGGBBAA
|
|
R = (float)( ( GlideColor & 0xFF000000 ) >> 24 ) * D1OVER255;
|
|
G = (float)( ( GlideColor & 0x00FF0000 ) >> 16 ) * D1OVER255;
|
|
B = (float)( ( GlideColor & 0x0000FF00 ) >> 8 ) * D1OVER255;
|
|
A = (float)( ( GlideColor & 0x000000FF ) ) * D1OVER255;
|
|
break;
|
|
|
|
case GR_COLORFORMAT_BGRA: //0xBBGGRRAA
|
|
B = (float)( ( GlideColor & 0xFF000000 ) >> 24 ) * D1OVER255;
|
|
G = (float)( ( GlideColor & 0x00FF0000 ) >> 16 ) * D1OVER255;
|
|
R = (float)( ( GlideColor & 0x0000FF00 ) >> 8 ) * D1OVER255;
|
|
A = (float)( ( GlideColor & 0x000000FF ) ) * D1OVER255;
|
|
break;
|
|
}
|
|
}
|
|
|