Fixed incorrect initialization of certain OpenGL function pointers.

Basically, the OpenGL class can use functions from several different
versions of OpenGL (1.3 and 2.0+), and all sections of code need to
be wrapped in IF statements to make sure we don't use a function
pointer that is NULL.  Basically, this means that all GLSL/2.0+
stuff needs to be wrapped in 'if(myTvFiltersEnabled) ...'.

This actually lays the groundwork for the next feature I'll be
adding (frame buffer objects), since those require yet another
level of OpenGL functions that may not be available everywhere.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1816 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2009-06-24 11:28:07 +00:00
parent 1275c25681
commit 79fdcb3480
1 changed files with 183 additions and 155 deletions

View File

@ -59,6 +59,7 @@ OGL_DECLARE(void,glPixelStorei,(GLenum, GLint));
OGL_DECLARE(void,glTexEnvf,(GLenum, GLenum, GLfloat)); OGL_DECLARE(void,glTexEnvf,(GLenum, GLenum, GLfloat));
OGL_DECLARE(void,glGenTextures,(GLsizei, GLuint*)); OGL_DECLARE(void,glGenTextures,(GLsizei, GLuint*));
OGL_DECLARE(void,glDeleteTextures,(GLsizei, const GLuint*)); OGL_DECLARE(void,glDeleteTextures,(GLsizei, const GLuint*));
OGL_DECLARE(void,glActiveTexture,(GLenum));
OGL_DECLARE(void,glBindTexture,(GLenum, GLuint)); OGL_DECLARE(void,glBindTexture,(GLenum, GLuint));
OGL_DECLARE(void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)); OGL_DECLARE(void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*));
OGL_DECLARE(void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)); OGL_DECLARE(void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*));
@ -77,7 +78,6 @@ OGL_DECLARE(void,glUniform1i,(GLint, GLint));
OGL_DECLARE(void,glUniform1f,(GLint, GLfloat)); OGL_DECLARE(void,glUniform1f,(GLint, GLfloat));
OGL_DECLARE(void,glCopyTexImage2D,(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)); OGL_DECLARE(void,glCopyTexImage2D,(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint));
OGL_DECLARE(void,glCopyTexSubImage2D,(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)); OGL_DECLARE(void,glCopyTexSubImage2D,(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei));
OGL_DECLARE(void,glActiveTexture,(GLenum));
OGL_DECLARE(void,glGetIntegerv,(GLenum, GLint*)); OGL_DECLARE(void,glGetIntegerv,(GLenum, GLint*));
OGL_DECLARE(void,glTexEnvi,(GLenum, GLenum, GLint)); OGL_DECLARE(void,glTexEnvi,(GLenum, GLenum, GLint));
OGL_DECLARE(void,glMultiTexCoord2f,(GLenum, GLfloat, GLfloat)); OGL_DECLARE(void,glMultiTexCoord2f,(GLenum, GLfloat, GLfloat));
@ -163,6 +163,7 @@ bool FrameBufferGL::loadFuncs(GLFunctionality functionality)
OGL_INIT(void,glTexEnvf,(GLenum, GLenum, GLfloat)); OGL_INIT(void,glTexEnvf,(GLenum, GLenum, GLfloat));
OGL_INIT(void,glGenTextures,(GLsizei, GLuint*)); OGL_INIT(void,glGenTextures,(GLsizei, GLuint*));
OGL_INIT(void,glDeleteTextures,(GLsizei, const GLuint*)); OGL_INIT(void,glDeleteTextures,(GLsizei, const GLuint*));
OGL_INIT(void,glActiveTexture,(GLenum));
OGL_INIT(void,glBindTexture,(GLenum, GLuint)); OGL_INIT(void,glBindTexture,(GLenum, GLuint));
OGL_INIT(void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)); OGL_INIT(void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*));
OGL_INIT(void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)); OGL_INIT(void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*));
@ -184,7 +185,6 @@ bool FrameBufferGL::loadFuncs(GLFunctionality functionality)
OGL_INIT(void,glUniform1f,(GLint, GLfloat)); OGL_INIT(void,glUniform1f,(GLint, GLfloat));
OGL_INIT(void,glCopyTexImage2D,(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint)); OGL_INIT(void,glCopyTexImage2D,(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint));
OGL_INIT(void,glCopyTexSubImage2D,(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei)); OGL_INIT(void,glCopyTexSubImage2D,(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei));
OGL_INIT(void,glActiveTexture,(GLenum));
OGL_INIT(void,glGetIntegerv,(GLenum, GLint*)); OGL_INIT(void,glGetIntegerv,(GLenum, GLint*));
OGL_INIT(void,glTexEnvi,(GLenum, GLenum, GLint)); OGL_INIT(void,glTexEnvi,(GLenum, GLenum, GLint));
OGL_INIT(void,glMultiTexCoord2f,(GLenum, GLfloat, GLfloat)); OGL_INIT(void,glMultiTexCoord2f,(GLenum, GLfloat, GLfloat));
@ -359,7 +359,7 @@ bool FrameBufferGL::setVidMode(VideoMode& mode)
myGLVersion = atof(version.substr(0, 3).c_str()); myGLVersion = atof(version.substr(0, 3).c_str());
// TV effects depend on the GLSL functions being available // TV effects depend on the GLSL functions being available
myGLSLAvailable = myGLVersion >= 2.0 && loadFuncs(kGL_SHADER); myGLSLAvailable = loadFuncs(kGL_SHADER);
} }
else else
return false; return false;
@ -429,7 +429,12 @@ cerr << "dimensions: " << (fullScreen() ? "(full)" : "") << endl
// and other UI surfaces are no longer tied together // and other UI surfaces are no longer tied together
// Note that this may change in the future, when we add more // Note that this may change in the future, when we add more
// complex filters/scalers, but for now it's fine // complex filters/scalers, but for now it's fine
//
// Also note that TV filtering is only available with OpenGL 2.0+ // Also note that TV filtering is only available with OpenGL 2.0+
// The hint we provide here is only that GLSL is available and
// TV effects *can* be applied to this surface
// The specific TV effect settings still determine whether any
// filtering *will* be applied in such a case
myTiaSurface = new FBSurfaceGL(*this, baseWidth>>1, baseHeight, myTiaSurface = new FBSurfaceGL(*this, baseWidth>>1, baseHeight,
mode.image_w, mode.image_h, mode.image_w, mode.image_h,
myGLSLAvailable); myGLSLAvailable);
@ -587,7 +592,7 @@ FBSurfaceGL::FBSurfaceGL(FrameBufferGL& buffer,
myPhosphorProgram(0), myPhosphorProgram(0),
myTextureNoiseProgram(0), myTextureNoiseProgram(0),
myNoiseNum(0), myNoiseNum(0),
myTvFiltersEnabled(allowFiltering) myTvFiltersEnabled(false)
{ {
// Fill buffer struct with valid data // Fill buffer struct with valid data
// This changes depending on the texturing used // This changes depending on the texturing used
@ -620,6 +625,19 @@ FBSurfaceGL::FBSurfaceGL(FrameBufferGL& buffer,
0x00007c00, 0x000003e0, 0x0000001f, 0x00000000); 0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
myPitch = myTexture->pitch >> 1; myPitch = myTexture->pitch >> 1;
// The 'allowFiltering' boolean is only a hint that filtering is allowed
// on this surface
// We still need to check if the functionality exists to do it
if(allowFiltering)
{
// It's only enabled if we use one of the filters *AND* GLSL is available
myTvFiltersEnabled = myFB.myGLSLAvailable &&
(myFB.myUseTexture || myFB.myUseNoise ||
myFB.myUseBleed || myFB.myUseGLPhosphor);
}
else
myTvFiltersEnabled = false;
// Only do this if TV filters enabled, otherwise it won't be used anyway // Only do this if TV filters enabled, otherwise it won't be used anyway
if(myTvFiltersEnabled) if(myTvFiltersEnabled)
{ {
@ -643,175 +661,182 @@ FBSurfaceGL::FBSurfaceGL(FrameBufferGL& buffer,
myFilterTexCoord[2] = (GLfloat) scaleWidth / myFilterTexWidth; myFilterTexCoord[2] = (GLfloat) scaleWidth / myFilterTexWidth;
myFilterTexCoord[1] = (GLfloat) scaleHeight / myFilterTexHeight; myFilterTexCoord[1] = (GLfloat) scaleHeight / myFilterTexHeight;
} }
}
// Only do this if TV and color bleed filters are enabled // Only do this if TV and color bleed filters are enabled
// This filer applies a color averaging of surrounding pixels for each pixel // This filer applies a color averaging of surrounding pixels for each pixel
if(myTvFiltersEnabled && myFB.myUseBleed) if(myFB.myUseBleed)
{
// Load shader programs. If it fails, don't use this filter.
myBleedProgram = genShader(SHADER_BLEED);
if(myBleedProgram == 0)
{ {
myFB.myUseBleed = false; // Load shader programs. If it fails, don't use this filter.
cout << "ERROR: Failed to make bleed programs" << endl; myBleedProgram = genShader(SHADER_BLEED);
} if(myBleedProgram == 0)
}
// If the texture and noise filters are enabled together, we can use a single shader
// Make sure we can use three textures at once first
GLint texUnits;
p_glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texUnits);
if(myTvFiltersEnabled && texUnits >= 3 && myFB.myUseTexture && myFB.myUseNoise)
{
// Load shader program. If it fails, don't use this shader.
myTextureNoiseProgram = genShader(SHADER_TEXNOISE);
if(myTextureNoiseProgram == 0)
{
cout << "ERROR: Failed to make texture/noise program" << endl;
// Load shader program. If it fails, don't use this filter.
myTextureProgram = genShader(SHADER_TEX);
if(myTextureProgram == 0)
{ {
myFB.myUseTexture = false; myFB.myUseBleed = false;
cout << "ERROR: Failed to make texture program" << endl; cout << "ERROR: Failed to make bleed programs" << endl;
}
// Load shader program. If it fails, don't use this filter.
myNoiseProgram = genShader(SHADER_NOISE);
if(myNoiseProgram == 0)
{
myFB.myUseNoise = false;
cout << "ERROR: Failed to make noise program" << endl;
} }
} }
}
// Else, detect individual settings // If the texture and noise filters are enabled together, we can use a single shader
else if(myTvFiltersEnabled) // Make sure we can use three textures at once first
{ GLint texUnits;
p_glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texUnits);
if(texUnits >= 3 && myFB.myUseTexture && myFB.myUseNoise)
{
// Load shader program. If it fails, don't use this shader.
myTextureNoiseProgram = genShader(SHADER_TEXNOISE);
if(myTextureNoiseProgram == 0)
{
cout << "ERROR: Failed to make texture/noise program" << endl;
// Load shader program. If it fails, don't use this filter.
myTextureProgram = genShader(SHADER_TEX);
if(myTextureProgram == 0)
{
myFB.myUseTexture = false;
cout << "ERROR: Failed to make texture program" << endl;
}
// Load shader program. If it fails, don't use this filter.
myNoiseProgram = genShader(SHADER_NOISE);
if(myNoiseProgram == 0)
{
myFB.myUseNoise = false;
cout << "ERROR: Failed to make noise program" << endl;
}
}
}
// Else, detect individual settings
else
{
if(myFB.myUseTexture)
{
// Load shader program. If it fails, don't use this filter.
myTextureProgram = genShader(SHADER_TEX);
if(myTextureProgram == 0)
{
myFB.myUseTexture = false;
cout << "ERROR: Failed to make texture program" << endl;
}
}
if(myFB.myUseNoise)
{
// Load shader program. If it fails, don't use this filter.
myNoiseProgram = genShader(SHADER_NOISE);
if(myNoiseProgram == 0)
{
myFB.myUseNoise = false;
cout << "ERROR: Failed to make noise program" << endl;
}
}
}
// Only do this if TV and color texture filters are enabled
// This filter applies an RGB color pixel mask as well as a blackspace mask
if(myFB.myUseTexture) if(myFB.myUseTexture)
{ {
// Load shader program. If it fails, don't use this filter. // Prepare subpixel texture
myTextureProgram = genShader(SHADER_TEX); mySubpixelTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
if(myTextureProgram == 0) myFilterTexWidth, myFilterTexHeight, 16,
{ 0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
myFB.myUseTexture = false;
cout << "ERROR: Failed to make texture program" << endl;
}
}
if(myFB.myUseNoise)
{
// Load shader program. If it fails, don't use this filter.
myNoiseProgram = genShader(SHADER_NOISE);
if(myNoiseProgram == 0)
{
myFB.myUseNoise = false;
cout << "ERROR: Failed to make noise program" << endl;
}
}
}
// Only do this if TV and color texture filters are enabled
// This filer applies an RGB color pixel mask as well as a blackspace mask
if(myTvFiltersEnabled && myFB.myUseTexture)
{
// Prepare subpixel texture
mySubpixelTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
myFilterTexWidth, myFilterTexHeight, 16,
0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
uInt32 pCounter = 0;
for (uInt32 y = 0; y < (uInt32)myFilterTexHeight; y++)
{
for (uInt32 x = 0; x < (uInt32)myFilterTexWidth; x++)
{
// Cause vertical offset for every other black row if enabled
uInt32 offsetY;
if (!myFB.myTextureStag || x % 6 < 3)
offsetY = y;
else
offsetY = y + 2;
// Make a row of black for the mask every so often
if (offsetY % 4 == 0)
{
((uInt16*)mySubpixelTexture->pixels)[pCounter] = 0x0000;
}
// Apply the coorect color mask
else
{
((uInt16*)mySubpixelTexture->pixels)[pCounter] = 0x7c00 >> ((x % 3) * 5);
}
pCounter++;
}
}
}
// Only do this if TV and noise filters are enabled
// This filter applies a texture filled with gray pixel of random intensities
if(myTvFiltersEnabled && myFB.myUseNoise)
{
// Get the current number of nose textures to use
myNoiseNum = myFB.myNoiseQuality;
// Allocate space for noise textures
myNoiseTexture = new SDL_Surface*[myNoiseNum];
myNoiseMaskTexID = new GLuint[myNoiseNum];
// Prepare noise textures
for(int i = 0; i < myNoiseNum; i++)
{
myNoiseTexture[i] = SDL_CreateRGBSurface(SDL_SWSURFACE,
myFilterTexWidth, myFilterTexHeight, 16,
0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
}
uInt32 pCounter = 0;
for(int i = 0; i < myNoiseNum; i++)
{
pCounter = 0;
// Attempt to make the numbers as random as possible
int temp = (unsigned)time(0) + rand()/4;
srand(temp);
uInt32 pCounter = 0;
for (uInt32 y = 0; y < (uInt32)myFilterTexHeight; y++) for (uInt32 y = 0; y < (uInt32)myFilterTexHeight; y++)
{ {
for (uInt32 x = 0; x < (uInt32)myFilterTexWidth; x++) for (uInt32 x = 0; x < (uInt32)myFilterTexWidth; x++)
{ {
// choose random 0 - 2 // Cause vertical offset for every other black row if enabled
// 0 = 0x0000 uInt32 offsetY;
// 1 = 0x0421 if (!myFB.myTextureStag || x % 6 < 3)
// 2 = 0x0842 offsetY = y;
int num = rand() % 3; else
if (num == 0) offsetY = y + 2;
((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0000;
else if (num == 1)
((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0421;
else if (num == 2)
((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0842;
// Make a row of black for the mask every so often
if (offsetY % 4 == 0)
{
((uInt16*)mySubpixelTexture->pixels)[pCounter] = 0x0000;
}
// Apply the coorect color mask
else
{
((uInt16*)mySubpixelTexture->pixels)[pCounter] = 0x7c00 >> ((x % 3) * 5);
}
pCounter++; pCounter++;
} }
} }
} }
}
// Only do this if TV and phosphor filters are enabled // Only do this if TV and noise filters are enabled
// This filter merges the past screen with the current one, to give a phosphor burn-off effect // This filter applies a texture filled with gray pixel of random intensities
if(myTvFiltersEnabled && myFB.myUseGLPhosphor) if(myFB.myUseNoise)
{
// Load shader program. If it fails, don't use this filter.
myPhosphorProgram = genShader(SHADER_PHOS);
if(myPhosphorProgram == 0)
{ {
myFB.myUseGLPhosphor = false; // Get the current number of nose textures to use
cout << "ERROR: Failed to make phosphor program" << endl; myNoiseNum = myFB.myNoiseQuality;
// Allocate space for noise textures
myNoiseTexture = new SDL_Surface*[myNoiseNum];
myNoiseMaskTexID = new GLuint[myNoiseNum];
// Prepare noise textures
for(int i = 0; i < myNoiseNum; i++)
{
myNoiseTexture[i] = SDL_CreateRGBSurface(SDL_SWSURFACE,
myFilterTexWidth, myFilterTexHeight, 16,
0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
}
uInt32 pCounter = 0;
for(int i = 0; i < myNoiseNum; i++)
{
pCounter = 0;
// Attempt to make the numbers as random as possible
int temp = (unsigned)time(0) + rand()/4;
srand(temp);
for (uInt32 y = 0; y < (uInt32)myFilterTexHeight; y++)
{
for (uInt32 x = 0; x < (uInt32)myFilterTexWidth; x++)
{
// choose random 0 - 2
// 0 = 0x0000
// 1 = 0x0421
// 2 = 0x0842
int num = rand() % 3;
if (num == 0)
((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0000;
else if (num == 1)
((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0421;
else if (num == 2)
((uInt16*)myNoiseTexture[i]->pixels)[pCounter] = 0x0842;
pCounter++;
}
}
}
}
// Only do this if TV and phosphor filters are enabled
// This filter merges the past screen with the current one, to give a phosphor burn-off effect
if(myFB.myUseGLPhosphor)
{
// Load shader program. If it fails, don't use this filter.
myPhosphorProgram = genShader(SHADER_PHOS);
if(myPhosphorProgram == 0)
{
myFB.myUseGLPhosphor = false;
cout << "ERROR: Failed to make phosphor program" << endl;
}
} }
} }
// Check to see if filters should still be used
// Filtering must have been previously enabled, and GLSL must still be
// available
myTvFiltersEnabled = myTvFiltersEnabled && myFB.myGLSLAvailable &&
(myFB.myUseTexture || myFB.myUseNoise ||
myFB.myUseBleed || myFB.myUseGLPhosphor);
// Associate the SDL surface with a GL texture object // Associate the SDL surface with a GL texture object
reload(); reload();
} }
@ -1025,11 +1050,8 @@ void FBSurfaceGL::update()
bool firstRender = true; bool firstRender = true;
// Render as usual if no filters are used // Render as usual if no filters are used
if(!myTvFiltersEnabled || if(!myTvFiltersEnabled)
(!myFB.myUseTexture && !myFB.myUseNoise && !myFB.myUseBleed && !myFB.myUseGLPhosphor))
{ {
p_glUseProgram(0);
// Texturemap complete texture to surface so we have free scaling // Texturemap complete texture to surface so we have free scaling
// and antialiasing // and antialiasing
p_glActiveTexture(GL_TEXTURE0); p_glActiveTexture(GL_TEXTURE0);
@ -1054,6 +1076,7 @@ void FBSurfaceGL::update()
} }
// If TV filters are enabled // If TV filters are enabled
// TODO - check if this IF is necessary, or can it be chained by else to above
if(myTvFiltersEnabled) if(myTvFiltersEnabled)
{ {
// If combined texture/noise program exists, // If combined texture/noise program exists,
@ -1205,6 +1228,11 @@ void FBSurfaceGL::update()
// We have rendered, set firstRender to false // We have rendered, set firstRender to false
firstRender = false; firstRender = false;
} }
// Disable all shader programs for the next rendering pass
// This is placed here since it's a GLSL 2.0-specific function, and
// doesn't exist (and isn't required) for base OpenGL functionality
p_glUseProgram(0);
} }
mySurfaceIsDirty = false; mySurfaceIsDirty = false;