mirror of
https://github.com/jenshemprich/MacGLide.git
synced 2025-03-13 05:29:21 +00:00
510 lines
16 KiB
C++
510 lines
16 KiB
C++
//**************************************************************
|
|
//* OpenGLide - Glide to OpenGL Wrapper
|
|
//* http://openglide.sourceforge.net
|
|
//*
|
|
//* Main 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 "GlideApplication.h"
|
|
#include "GlideDisplay.h"
|
|
#include "GlideFramebuffer.h"
|
|
#include "GlideSettings.h"
|
|
#include "GLextensions.h"
|
|
#include "GLUtil.h"
|
|
#include "PGTexture.h"
|
|
#include "PGUTexture.h"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////// Version numbers ///////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const char* OpenGLideVersion = "0.13rc1";
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Structs
|
|
GlideStruct Glide;
|
|
OpenGLStruct OpenGL;
|
|
GlideSettingsImpl UserConfig;
|
|
GlideSettingsImpl InternalConfig;
|
|
PGTexture* Textures = NULL;
|
|
PGUTexture UTextures;
|
|
GlideFramebuffer s_Framebuffer;
|
|
|
|
// Number of Errors
|
|
unsigned long NumberOfErrors;
|
|
|
|
OSErr InitMainVariables(void)
|
|
{
|
|
OpenGL.WinOpen = false;
|
|
OpenGL.GlideInit = false;
|
|
NumberOfErrors = 0;
|
|
OSErr err = UserConfig.load();
|
|
if (err == noErr)
|
|
{
|
|
// The following values must be updated right away, because the client application
|
|
// might call grSstQueryHardware() before opening a window
|
|
if ((UserConfig.TextureMemorySize >= OGL_MIN_TEXTURE_BUFFER) &&
|
|
(UserConfig.TextureMemorySize <= OGL_MAX_TEXTURE_BUFFER))
|
|
{
|
|
UserConfig.TextureMemorySize = UserConfig.TextureMemorySize;
|
|
}
|
|
|
|
if ((UserConfig.FrameBufferMemorySize >= OGL_MIN_FRAME_BUFFER) &&
|
|
(UserConfig.FrameBufferMemorySize <= OGL_MAX_FRAME_BUFFER))
|
|
{
|
|
UserConfig.FrameBufferMemorySize = UserConfig.FrameBufferMemorySize;
|
|
}
|
|
|
|
if (UserConfig.BoardType < OpenGLideBoardType_Voodoo)
|
|
{
|
|
UserConfig.BoardType = OpenGLideBoardType_Voodoo;
|
|
}
|
|
else if (UserConfig.BoardType > OpenGLideBoardType_Voodoo2)
|
|
{
|
|
UserConfig.BoardType = OpenGLideBoardType_Voodoo2;
|
|
}
|
|
|
|
if (UserConfig.GlideTextureUnits < 1)
|
|
{
|
|
UserConfig.GlideTextureUnits = 1;
|
|
}
|
|
else if (UserConfig.GlideTextureUnits > 3)
|
|
{
|
|
UserConfig.GlideTextureUnits = 3;
|
|
}
|
|
// Detect vector unit (Altivec, SSE, etc.)
|
|
UserConfig.VectorUnitType = GetVectorUnitType();
|
|
if (UserConfig.VectorUnitType > OpenGLideVectorUnitType_None)
|
|
{
|
|
GlideMsg("Using %s vector unit\n", OpenGLideVectorUnitNames[UserConfig.VectorUnitType - 1]);
|
|
}
|
|
// Apply mandatory application dependent settings/patches
|
|
GlideApplication::Type application = s_GlideApplication.GetType();
|
|
switch (application)
|
|
{
|
|
case GlideApplication::Quake:
|
|
{
|
|
// Quake would not display anything without fixing the memory
|
|
unsigned int megabytes = 4;
|
|
if (UserConfig.FrameBufferMemorySize > megabytes)
|
|
{
|
|
UserConfig.FrameBufferMemorySize = megabytes;
|
|
GlideMsg("Decreased frmaebuffer memory size to %d megabytes to make Quake 3Dfx happy\n");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Apply optional game specific settings
|
|
if (UserConfig.AutoEnableGameSpecificSettings)
|
|
{
|
|
bool texturesmoothing = false;
|
|
bool subtextures = false;
|
|
bool gapfix = false;
|
|
switch(application)
|
|
{
|
|
case GlideApplication::Carmageddon:
|
|
texturesmoothing = true;
|
|
break;
|
|
case GlideApplication::MythTFL:
|
|
texturesmoothing = true;
|
|
break;
|
|
case GlideApplication::Falcon40:
|
|
texturesmoothing = true;
|
|
break;
|
|
case GlideApplication::TombRaiderI:
|
|
texturesmoothing = true;
|
|
subtextures = true;
|
|
gapfix = true;
|
|
break;
|
|
case GlideApplication::TombRaiderII:
|
|
// subtextures = true; // works but slow
|
|
gapfix = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (texturesmoothing || subtextures || gapfix)
|
|
{
|
|
GlideMsg("Auto-enabling game specific settings for %s:\n", s_GlideApplication.GetName());
|
|
}
|
|
// Suppress artefacts in main menu
|
|
if (texturesmoothing)
|
|
{
|
|
UserConfig.TextureSmoothing = true;
|
|
GlideMsg("- TextureSmoothing\n");
|
|
}
|
|
if (subtextures)
|
|
{
|
|
UserConfig.GenerateSubTextures = 8; // Good for TR1 and TR2
|
|
GlideMsg("- Subtexture generation\n");
|
|
}
|
|
if (gapfix)
|
|
{
|
|
UserConfig.GapFix = static_cast<OpenGLideGapFixFlags>(UserConfig.GapFix | (OpenGLideGapFixFlag_Enabled));
|
|
GlideMsg("- GapFix\n");
|
|
}
|
|
}
|
|
}
|
|
if (err != noErr) GlideError("Failed to load user config file: Error code %d", err);
|
|
return err;
|
|
}
|
|
|
|
bool InitWindow(FxU32 hwnd)
|
|
{
|
|
if (InitialiseOpenGLWindow(hwnd, 0, 0, OpenGL.WindowWidth, OpenGL.WindowHeight) == false)
|
|
{
|
|
return FXFALSE;
|
|
}
|
|
// Initialise some basic OpenGL() settings
|
|
InitOpenGL();
|
|
// Continue initialising OpenGL with processing
|
|
// the user config and setup OpenGL extensions
|
|
ValidateUserConfig();
|
|
|
|
GlideMsg( OGL_LOG_SEPARATE );
|
|
GlideMsg( "3Dfx/Glide Configuration:\n");
|
|
GlideMsg( OGL_LOG_SEPARATE );
|
|
char sEnabled[] = "enabled";
|
|
char sDisabled[] = "disabled";
|
|
const char* boardnames[4] = {"Voodoo", "Voodoo Rush", "AT3D", "Voodoo 2"};
|
|
GlideMsg( "Board type = %s\n", boardnames[InternalConfig.BoardType]);
|
|
GlideMsg( "Number of emulated 3Dfx/Glide Texture Units = %d\n", InternalConfig.GlideTextureUnits );
|
|
GlideMsg( "Texture Memory Size = %d Mb\n", InternalConfig.TextureMemorySize );
|
|
GlideMsg( "Frame Buffer Memory Size = %d Mb\n", InternalConfig.FrameBufferMemorySize );
|
|
GlideMsg( "Display method = %d\n", InternalConfig.DisplayMode);
|
|
// display resolution
|
|
GlideMsg("Display resolution = %dx%d\n", OpenGL.WindowWidth, OpenGL.WindowHeight);
|
|
if (InternalConfig.MonitorRefreshRate > 0)
|
|
{
|
|
GlideMsg( "Monitor Refresh Rate = %d\n", InternalConfig.MonitorRefreshRate );
|
|
}
|
|
GlideMsg("Mipmapping %s\n", InternalConfig.Mipmapping ? sEnabled : sDisabled );
|
|
if (InternalConfig.AnisotropylLevel >= 2 && InternalConfig.EXT_texture_filter_anisotropic)
|
|
{
|
|
GlideMsg("Selected level of anisotropy = %d\n", InternalConfig.AnisotropylLevel);
|
|
}
|
|
else
|
|
{
|
|
GlideMsg("Anisotropic texture filtering disabled\n");
|
|
}
|
|
if (InternalConfig.FullSceneAntiAliasing == 0)
|
|
{
|
|
GlideMsg("FullSceneAntiAliasing disabled\n");
|
|
}
|
|
else
|
|
{
|
|
GlideMsg("FullSceneAntiAliasing enabled, using %d samples\n", InternalConfig.FullSceneAntiAliasing);
|
|
}
|
|
GlideMsg("TextureSmoothing = %s\n", InternalConfig.TextureSmoothing ? sEnabled : sDisabled );
|
|
GlideMsg("Precision Fix = %s\n", InternalConfig.PrecisionFix ? sEnabled : sDisabled );
|
|
bool gapfix_enabled = InternalConfig.GapFix & OpenGLideGapFixFlag_Enabled;
|
|
GlideMsg("GapFix = %s\n", gapfix_enabled ? sEnabled : sDisabled);
|
|
if (gapfix_enabled)
|
|
{
|
|
GlideMsg(" Debug = %s\n", InternalConfig.GapFix & OpenGLideGapFixFlag_Debug ? sEnabled : sDisabled);
|
|
GlideMsg(" IncircleFilterOr = %s\n", InternalConfig.GapFix & OpenGLideGapFixFlag_IncircleOr ? sEnabled : sDisabled);
|
|
GlideMsg(" IncircleFilterAnd = %s\n", InternalConfig.GapFix & OpenGLideGapFixFlag_IncircleAnd ? sEnabled : sDisabled);
|
|
GlideMsg(" IncircleFilterSecondRadius = %s\n", InternalConfig.GapFix & OpenGLideGapFixFlag_IncircleSecondRadius ? sEnabled : sDisabled);
|
|
GlideMsg("VertexLengthFilterSecondRadius = %s\n", InternalConfig.GapFix & OpenGLideGapFixFlag_VertexLengthSecondRadius ? sEnabled : sDisabled);
|
|
GlideMsg(" 1st radius = %g\n", InternalConfig.GapFixParam1);
|
|
if (InternalConfig.GapFix & OpenGLideGapFixFlag_VertexLengthSecondRadius)
|
|
{
|
|
GlideMsg(" Vertex Length = %g\n", InternalConfig.GapFixParam2);
|
|
}
|
|
else
|
|
{
|
|
GlideMsg(" triangle isoscelesness= %g\n", InternalConfig.GapFixParam2);
|
|
}
|
|
if ((InternalConfig.GapFix & OpenGLideGapFixFlag_IncircleSecondRadius) || (InternalConfig.GapFix & OpenGLideGapFixFlag_VertexLengthSecondRadius))
|
|
{
|
|
GlideMsg(" 2nd radius = %g\n", InternalConfig.GapFixParam3);
|
|
}
|
|
if (InternalConfig.GapFix & OpenGLideGapFixFlag_DepthFactor)
|
|
{
|
|
GlideMsg(" Depth Factor = %g\n", InternalConfig.GapFixDepthFactor);
|
|
}
|
|
}
|
|
GlideMsg("Generate subtextures = %s", InternalConfig.GenerateSubTextures ? sEnabled : sDisabled );
|
|
if (InternalConfig.GenerateSubTextures) GlideMsg(" (gridsize = %d)", InternalConfig.GenerateSubTextures);
|
|
GlideMsg("\n");
|
|
GlideMsg("Framebuffer overlays = %s\n", InternalConfig.EnableFrameBufferOverlays ? sEnabled : sDisabled );
|
|
GlideMsg("Framebuffer underlays = %s\n", InternalConfig.EnableFrameBufferUnderlays ? sEnabled : sDisabled );
|
|
if (InternalConfig.FramebufferIgnoreUnlock) GlideMsg( "Ignore buffer unlocks = %s\n", InternalConfig.FramebufferIgnoreUnlock ? sEnabled : sDisabled);
|
|
if (InternalConfig.PedanticFrameBufferEmulation) GlideMsg( "Pedantic Framebuffer emulation = %s\n", InternalConfig.PedanticFrameBufferEmulation ? sEnabled : sDisabled);
|
|
GlideMsg(OGL_LOG_SEPARATE);
|
|
|
|
#ifdef OGL_DEBUG
|
|
GlideMsg("GlideState size = %d\n", sizeof(GlideState));
|
|
GlideMsg("GrState size = %d\n", sizeof(GrState));
|
|
GlideMsg(OGL_LOG_SEPARATE);
|
|
#endif
|
|
GlideMsg("** Glide Calls **\n" );
|
|
GlideMsg(OGL_LOG_SEPARATE);
|
|
|
|
return true;
|
|
}
|
|
|
|
void* AllocFrameBuffer(long buffersize, long buffertypesize)
|
|
{
|
|
void* buffer = AllocSysPtr16ByteAligned(buffersize * buffertypesize);
|
|
if (buffer == NULL)
|
|
{
|
|
GlideError("Could NOT allocate sufficient memory for framebuffer... Sorry.");
|
|
exit( -1 );
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
void FreeFrameBuffer(void* buffer)
|
|
{
|
|
Free16ByteAligned(buffer);
|
|
}
|
|
|
|
void* AllocBuffer(long buffersize, long buffertypesize)
|
|
{
|
|
void* buffer = AllocSysPtr16ByteAligned(buffersize * buffertypesize);
|
|
if (buffer == NULL)
|
|
{
|
|
GlideError("Could NOT allocate sufficient memory for buffer... Sorry.");
|
|
exit( -1 );
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
void FreeBuffer(void* buffer)
|
|
{
|
|
Free16ByteAligned(buffer);
|
|
}
|
|
|
|
|
|
void* AllocObject(long buffersize)
|
|
{
|
|
// Causes classic to crash
|
|
void* buffer = AllocSysPtr16ByteAligned(buffersize);
|
|
if (buffer == NULL)
|
|
{
|
|
GlideError("Could NOT allocate sufficient memory for object... Sorry.");
|
|
exit( -1 );
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
void FreeObject(void* buffer)
|
|
{
|
|
Free16ByteAligned(buffer);
|
|
}
|
|
|
|
// error handling
|
|
#ifdef OPENGL_DEBUG
|
|
OSStatus glReportError_impl (const char* __glide_functionname)
|
|
{
|
|
char* errortext = NULL;
|
|
GLenum err = glGetError();
|
|
switch (err)
|
|
{
|
|
case GL_NO_ERROR:
|
|
break;
|
|
case GL_INVALID_ENUM:
|
|
errortext = "Invalid enumeration";
|
|
break;
|
|
case GL_INVALID_VALUE:
|
|
errortext ="Invalid value";
|
|
break;
|
|
case GL_INVALID_OPERATION:
|
|
errortext = "Invalid operation";
|
|
break;
|
|
case GL_STACK_OVERFLOW:
|
|
errortext = "Stack overflow";
|
|
break;
|
|
case GL_STACK_UNDERFLOW:
|
|
errortext = "Stack underflow";
|
|
break;
|
|
case GL_OUT_OF_MEMORY:
|
|
errortext = "Out of memory";
|
|
break;
|
|
default:
|
|
errortext = "Unknown error code";
|
|
break;
|
|
}
|
|
if (errortext)
|
|
{
|
|
GlideMsg ("Function %s, GL Error: %s\n", __glide_functionname, errortext);
|
|
}
|
|
// ensure we are returning an OSStatus noErr if no error condition
|
|
if (err == GL_NO_ERROR)
|
|
return noErr;
|
|
else
|
|
return (OSStatus) err;
|
|
}
|
|
#endif
|
|
|
|
#if defined(OPTIMISE_OPENGL_STATE_CHANGES) || defined(OGL_DEBUG) || defined(OPENGL_DEBUG)
|
|
bool VerifyActiveTextureUnit_impl(GLint x, const char* functionname)
|
|
{
|
|
glReportErrors("VerifyActiveTextureUnit_impl");
|
|
GLint y;
|
|
glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &y);
|
|
glReportError();
|
|
bool bVerified = x == y;
|
|
if (!bVerified)
|
|
{
|
|
GlideMsg("Warning: %s() active texture unit is GL_TEXTURE%d_ARB, but should be GL_TEXTURE%d_ARB\n", functionname, y - GL_TEXTURE0_ARB, x - GL_TEXTURE0_ARB);
|
|
}
|
|
glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE_ARB, &y);
|
|
glReportError();
|
|
bVerified = x == y;
|
|
if (!bVerified)
|
|
{
|
|
GlideMsg("Warning: %s() client active texture unit is GL_TEXTURE%d_ARB, but should be GL_TEXTURE%d_ARB\n", functionname, y - GL_TEXTURE0_ARB, x - GL_TEXTURE0_ARB);
|
|
}
|
|
return bVerified;
|
|
}
|
|
#endif
|
|
|
|
#if defined(OPTIMISE_OPENGL_STATE_CHANGES) || defined(OGL_DEBUG) || defined(OPENGL_DEBUG)
|
|
bool VerifyTextureEnabledState_impl(const char* functionname)
|
|
{
|
|
glReportErrors("VerifyActiveTextureUnit_impl");
|
|
|
|
// remember state
|
|
GLint activeTexture;
|
|
glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture);
|
|
GLint activeClientTexture;
|
|
if (InternalConfig.EXT_compiled_vertex_array)
|
|
{
|
|
glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE_ARB, &activeClientTexture);
|
|
}
|
|
glReportError();
|
|
bool bVerified = true;
|
|
if (OpenGL.ColorAlphaUnit2)
|
|
{
|
|
for(long unit_index = 1; unit_index >= 0; unit_index--)
|
|
{
|
|
glActiveTextureARB(OpenGL.ColorAlphaUnit1 + unit_index);
|
|
bool bState = glIsEnabled(GL_TEXTURE_2D);
|
|
if (bState != (OpenGL.ColorAlphaUnitColorEnabledState[unit_index] ||
|
|
OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]))
|
|
{
|
|
GlideMsg("Warning: texture unit GL_TEXTURE%d_ARB is %s in %s()\n", OpenGL.ColorAlphaUnit1 + unit_index - GL_TEXTURE0_ARB, bState ? "enabled" : "disabled", functionname);
|
|
bVerified = false;
|
|
}
|
|
if (InternalConfig.EXT_compiled_vertex_array)
|
|
{
|
|
glClientActiveTextureARB(OpenGL.ColorAlphaUnit1 + unit_index);
|
|
bState = glIsEnabled(GL_TEXTURE_COORD_ARRAY);
|
|
if (bState != (OpenGL.ColorAlphaUnitColorEnabledState[unit_index] ||
|
|
OpenGL.ColorAlphaUnitAlphaEnabledState[unit_index]))
|
|
{
|
|
GlideMsg("Warning: texcoord array for unit GL_TEXTURE%d_ARB is %s in %s()\n", OpenGL.ColorAlphaUnit1 + unit_index - GL_TEXTURE0_ARB, bState ? "enabled" : "disabled", functionname);
|
|
bVerified = false;
|
|
}
|
|
}
|
|
glReportError();
|
|
}
|
|
}
|
|
// Restore previous state
|
|
glActiveTextureARB(activeTexture);
|
|
if (InternalConfig.EXT_compiled_vertex_array)
|
|
{
|
|
glClientActiveTextureARB(activeClientTexture);
|
|
}
|
|
glReportError();
|
|
return bVerified;
|
|
}
|
|
#endif
|
|
|
|
//*************************************************
|
|
//* Initializes OpenGL
|
|
//*************************************************
|
|
void InitOpenGL( void )
|
|
{
|
|
OpenGL.ZNear = ZBUFFERNEAR;
|
|
OpenGL.ZFar = ZBUFFERFAR;
|
|
OpenGL.ClipMinX = 0;
|
|
OpenGL.ClipMinY = 0;
|
|
OpenGL.ClipMaxX = OpenGL.WindowWidth;
|
|
OpenGL.ClipMaxY = OpenGL.WindowHeight;
|
|
// Glide texture data is aligned at 8 byte boundaries
|
|
int alignment = 8;
|
|
glPixelStorei( GL_PACK_ALIGNMENT, alignment);
|
|
glPixelStorei( GL_UNPACK_ALIGNMENT, alignment);
|
|
}
|
|
|
|
void GlideMsg(const char* message, ... )
|
|
{
|
|
va_list(args);
|
|
va_start(args, message);
|
|
|
|
char buffer[StringBufferSize];
|
|
|
|
vsnprintf(buffer, StringBufferSize, message, args);
|
|
UserConfig.write_log(buffer);
|
|
va_end(args);
|
|
}
|
|
|
|
void GlideError(const char *message, ... )
|
|
{
|
|
va_list(args);
|
|
va_start(args, message);
|
|
|
|
char buffer[StringBufferSize];
|
|
|
|
NumberOfErrors++;
|
|
vsnprintf(buffer, StringBufferSize, message, args);
|
|
GlideMsg(buffer);
|
|
|
|
va_end(args);
|
|
|
|
grGlideShutdown();
|
|
if (UserConfig.DisplayMode == OpenGLideDisplayMode_DisplayManager)
|
|
{
|
|
DisplayManager_RestoreDesktopDisplay();
|
|
}
|
|
FatalErrorMessageBox(buffer);
|
|
exit(0);
|
|
}
|
|
|
|
|
|
bool ClearAndGenerateLogFile( void )
|
|
{
|
|
UserConfig.create_log();
|
|
char buffer[32];
|
|
GlideMsg(OGL_LOG_SEPARATE );
|
|
GlideMsg("%s Log File\n", OpenGLideProductName);
|
|
GlideMsg(OGL_LOG_SEPARATE );
|
|
GlideMsg("***** %s %s *****\n", OpenGLideProductName, OpenGLideVersion);
|
|
GlideMsg(OGL_LOG_SEPARATE );
|
|
_strdate(buffer);
|
|
GlideMsg("Date: %s\n", buffer);
|
|
_strtime(buffer);
|
|
GlideMsg("Time: %s\n", buffer);
|
|
GlideMsg("Application: %s\n", s_GlideApplication.GetName());
|
|
return true;
|
|
}
|
|
|
|
void CloseLogFile( void )
|
|
{
|
|
char tmpbuf[ 128 ];
|
|
GlideMsg( OGL_LOG_SEPARATE );
|
|
_strtime( tmpbuf );
|
|
GlideMsg( "Time: %s\n", tmpbuf );
|
|
GlideMsg( OGL_LOG_SEPARATE );
|
|
}
|
|
|