MacGLide/MacGLide/OpenGLide/Glide.cpp

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.13";
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
// 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 );
}