I do like Ryanâs suggestion to do the palette conversion in OpenGL,
For those that are curious, hereâs the code for thatâŚ
// call prepareOpenGLShaders() after setting up your GL context.
struct OpenGLVertexAttribs
{
GLfloat x;
GLfloat y;
GLfloat u;
GLfloat v;
};
static bool prepareOpenGLShaders(const int w, const int h)
{
static const char *glslVertexShader =
â#version 110\nâ
âattribute vec2 pos;â
âattribute vec2 tex;â
âvoid main() {â
âgl_Position = vec4(pos.xy, 0.0, 1.0);â
âgl_TexCoord[0].xy = tex;â
â}â
;
static const char *glslFragmentShader2D =
"#version 110\n"
"uniform sampler2D image;"
"uniform sampler2D palette;"
"void main() {"
"gl_FragColor = texture2D(palette, vec2(texture2D(image,
gl_TexCoord[0].xy).x, 0.0));"
â}â
;
static const char *glslFragmentShaderRect =
"#version 110\n"
"#extension GL_ARB_texture_rectangle : enable\n"
"uniform sampler2DRect image;"
"uniform sampler2DRect palette;"
"void main() {"
"gl_FragColor = texture2DRect(palette,
vec2(texture2DRect(image, gl_TexCoord[0].xy).x * 255.0, 0.0));"
â}â
;
GLuint vertex = 0;
GLuint fragment = 0;
GLuint program = 0;
GLint ok = 0;
GLint shaderlen = 0;
ok = 0;
shaderlen = (GLint) strlen(glslVertexShader);
vertex = pglCreateShader(GL_VERTEX_SHADER);
pglShaderSource(vertex, 1, (const GLchar **) &glslVertexShader,
&shaderlen);
pglCompileShader(vertex);
pglGetShaderiv(vertex, GL_COMPILE_STATUS, &ok);
if (!ok)
{
char errbuf[256];
GLsizei len = 0;
pglGetShaderInfoLog(vertex, sizeof (errbuf), &len, (GLchar *)
errbuf);
printf(âPOSTAL1 vertex shader compile error:\n%s\n\nâ, errbuf);
pglDeleteShader(vertex);
return false;
} // if
const bool isTextureRect = (OpenGLTextureTarget ==
GL_TEXTURE_RECTANGLE_ARB);
const char *glslFragmentShader = isTextureRect ?
glslFragmentShaderRect : glslFragmentShader2D;
ok = 0;
shaderlen = (GLint) strlen(glslFragmentShader);
fragment = pglCreateShader(GL_FRAGMENT_SHADER);
pglShaderSource(fragment, 1, (const GLchar **) &glslFragmentShader,
&shaderlen);
pglCompileShader(fragment);
pglGetShaderiv(fragment, GL_COMPILE_STATUS, &ok);
if (!ok)
{
char errbuf[256];
GLsizei len = 0;
pglGetShaderInfoLog(fragment, sizeof (errbuf), &len, (GLchar *)
errbuf);
printf(âPOSTAL1 fragment shader compile error:\n%s\n\nâ, errbuf);
pglDeleteShader(vertex);
pglDeleteShader(fragment);
return false;
} // if
ok = 0;
OpenGLProgram = pglCreateProgram();
pglAttachShader(OpenGLProgram, vertex);
pglAttachShader(OpenGLProgram, fragment);
pglBindAttribLocation(OpenGLProgram, 0, "pos");
pglBindAttribLocation(OpenGLProgram, 1, "tex");
pglLinkProgram(OpenGLProgram);
pglDeleteShader(vertex);
pglDeleteShader(fragment);
pglGetProgramiv(OpenGLProgram, GL_LINK_STATUS, &ok);
if (!ok)
{
pglDeleteProgram(OpenGLProgram);
OpenGLProgram = 0;
return false;
} // if
pglUseProgram(OpenGLProgram);
pglUniform1i(pglGetUniformLocation(OpenGLProgram, "image"), 0);
pglUniform1i(pglGetUniformLocation(OpenGLProgram, "palette"), 1);
const float left = -1.0f;
const float right = 1.0f;
const float top = 1.0f;
const float bottom = -1.0f;
OpenGLVertexAttribs verts[4] = {
{ left, top, 0.0f, 0.0f },
{ right, top, 1.0f, 0.0f },
{ left, bottom, 0.0f, 1.0f },
{ right, bottom, 1.0f, 1.0f }
};
if (isTextureRect)
{
for (int i = 0; i < (sizeof (verts) / sizeof (verts[0])); i++)
{
verts[i].u *= (GLfloat) w;
verts[i].v *= (GLfloat) h;
}
}
pglGenBuffers(1, &OpenGLVBO);
pglBindBuffer(GL_ARRAY_BUFFER, OpenGLVBO);
pglBufferData(GL_ARRAY_BUFFER, sizeof (verts), verts, GL_STATIC_DRAW);
const OpenGLVertexAttribs *ptr = NULL; // it's a bound VBO.
pglVertexAttribPointer(0, 2, GL_FLOAT, 0, sizeof (verts[0]), &ptr->x);
pglEnableVertexAttribArray(0);
pglVertexAttribPointer(1, 2, GL_FLOAT, 0, sizeof (verts[0]), &ptr->u);
pglEnableVertexAttribArray(1);
return true;
}
// Make sure your image texture and palette texture are on texunits 0
// and 1. Everything else is all set up in here, so other than making
// sure the textures are set up, hereâs how you get it to the screen:
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
SDL_GL_SwapBuffers(); // this is SDL_GL_SwapWindow() in SDL2.
The FBOs to stretch-blit add another dozen or two lines of code, but
thatâs the gist otherwise.
however, I will still need the pure software fallback where OpenGL is
not available. When working on a game like Wolfenstein 3D, youâre kind
of expected to support old hardware.
Id Softwareâs original build is still available for people still running
DOS. 
âryan.