I'm going to use this thread for documenting stuff and it might even result in a mini-project of making a FitzQuake 0.85 combo renderer tomorrow morning.
I've spend a lot of time over the last year using MH's wrapper hands-on and after thinking about FTEQW's switchable renderer and thinking about multiplatform stuffs (DarkPlaces and AGL on OS X come to mind).
Here are some rough thoughts/notes:
In an idea world, MH's wrapper would be turned into a .dll. This would help both the engine code size (not really an issue, my engine grew from 760KB to 934KB with a combo renderer build -- not a big deal), but more to allow dynamic linking to each.Notes wrote:1. I have the initial version of a switchable renderer version of my engine done. It was kind of anti-climatic starting it up.
2. My approach was to link to both the opengl library and use MH's wrapper natively. I notice that FTEQW (and DarkPlaces?) appears to dynamically link with opengl32.dll, which is technically a superior way. A weakness of the way I did it, you get dependencies of both OpenGL and Direct3D 8.1 which isn't actually "better" as you've increased the chances of the engine encountering a machine that the engine won't run on.
3. To fine-tune my stuff, I'm going to have to build OpenGL only and Direct3D only #ifdefs to ensure I have everything properly separated.
Render restarting stuff: I haven't implemented this yet, but the gist of the idea is that you'll have to check extensions and check the hardware stuffs (max TMUs, etc.). MH's wrapper doesn't support vsync inherently, but MH gave me some instructions to make it support vsync if you know in advance (like a command line param) and with renderer restart, it shouldn't be a problem.
Other notes:
I like the idea of an engine structure that keeps track of everything, but also want modular design so that components don't require headers they shouldn't require and are transportable from project to project. And although this isn't exactly rocket science, I shifted the Renderer initialization procedure to return a pointer with the idea that eventually all the initialization functions in Host_Init will return pointers (where it is a good fit).
Code: Select all
engine.renderer = Renderer_Init (RENDERER_OPENGL);Code: Select all
// renderer.h -- Renderer neutral modular component
#ifndef RENDERER_H
#define RENDERER_H
#define RENDERER_OPENGL 1
#define RENDERER_DIRECT3D 2
typedef struct
{
char RendererText[20];
int graphics_api; //1 = OpenGL, 2 = Direct3D, 0 = Uninitialized
qbool initialized;
} renderer_def_t;
renderer_def_t myRenderer;
#endifCode: Select all
// renderer.c -- Renderer neutral modular component
#include "quakedef.h"
#include "gl_local.h" // Baker: Needed
void Renderer_D3D (void)
{
eglAlphaFunc = d3dmh_glAlphaFunc;
eglBegin = d3dmh_glBegin;
eglBindTexture = d3dmh_glBindTexture;
eglBlendFunc = d3dmh_glBlendFunc;
eglClear = d3dmh_glClear;
eglClearColor = d3dmh_glClearColor;
eglClearStencil = d3dmh_glClearStencil;
eglColor3f = d3dmh_glColor3f;
eglColor3fv = d3dmh_glColor3fv;
eglColor3ubv = d3dmh_glColor3ubv;
eglColor4f = d3dmh_glColor4f;
eglColor4fv = d3dmh_glColor4fv;
eglColor4ub = d3dmh_glColor4ub;
eglColor4ubv = d3dmh_glColor4ubv;
eglColorMask = d3dmh_glColorMask;
eglCullFace = d3dmh_glCullFace;
eglDeleteTextures = d3dmh_glDeleteTextures;
eglDepthFunc = d3dmh_glDepthFunc;
eglDepthMask = d3dmh_glDepthMask;
eglDepthRange = d3dmh_glDepthRange;
eglDisable = d3dmh_glDisable;
eglDrawBuffer = d3dmh_glDrawBuffer;
eglEnable = d3dmh_glEnable;
eglEnd = d3dmh_glEnd;
eglFinish = d3dmh_glFinish;
eglFogf = d3dmh_glFogf;
eglFogfv = d3dmh_glFogfv;
eglFogi = d3dmh_glFogi;
eglFogiv = d3dmh_glFogiv;
eglFrontFace = d3dmh_glFrontFace;
eglFrustum = d3dmh_glFrustum;
eglGenTextures = d3dmh_glGenTextures;
eglGetFloatv = d3dmh_glGetFloatv;
eglGetIntegerv = d3dmh_glGetIntegerv;
eglGetString = d3dmh_glGetString;
eglGetTexImage = d3dmh_glGetTexImage;
eglGetTexParameterfv = d3dmh_glGetTexParameterfv;
eglHint = d3dmh_glHint;
eglLoadIdentity = d3dmh_glLoadIdentity;
eglLoadMatrixf = d3dmh_glLoadMatrixf;
eglMatrixMode = d3dmh_glMatrixMode;
eglMultMatrixf = d3dmh_glMultMatrixf;
eglNormal3f = d3dmh_glNormal3f;
eglOrtho = d3dmh_glOrtho;
eglPolygonMode = d3dmh_glPolygonMode;
eglPolygonOffset = d3dmh_glPolygonOffset;
eglPopMatrix = d3dmh_glPopMatrix;
eglPushMatrix = d3dmh_glPushMatrix;
eglReadBuffer = d3dmh_glReadBuffer;
eglReadPixels = d3dmh_glReadPixels;
eglRotatef = d3dmh_glRotatef;
eglScalef = d3dmh_glScalef;
eglScissor = d3dmh_glScissor;
eglShadeModel = d3dmh_glShadeModel;
eglStencilFunc = d3dmh_glStencilFunc;
eglStencilOp = d3dmh_glStencilOp;
eglTexCoord2f = d3dmh_glTexCoord2f;
eglTexCoord2fv = d3dmh_glTexCoord2fv;
eglTexEnvf = d3dmh_glTexEnvf;
eglTexEnvi = d3dmh_glTexEnvi;
eglTexImage2D = d3dmh_glTexImage2D;
eglTexParameterf = d3dmh_glTexParameterf;
eglTexParameteri = d3dmh_glTexParameteri;
eglTexSubImage2D = d3dmh_glTexSubImage2D;
eglTranslatef = d3dmh_glTranslatef;
eglVertex2f = d3dmh_glVertex2f;
eglVertex2fv = d3dmh_glVertex2fv;
eglVertex3f = d3dmh_glVertex3f;
eglVertex3fv = d3dmh_glVertex3fv;
eglViewport = d3dmh_glViewport;
ewglCreateContext = d3dmh_wglCreateContext;
ewglDeleteContext = d3dmh_wglDeleteContext;
ewglGetCurrentContext = d3dmh_wglGetCurrentContext;
ewglGetCurrentDC = d3dmh_wglGetCurrentDC;
ewglMakeCurrent = d3dmh_wglMakeCurrent;
ewglGetProcAddress = d3dmh_wglGetProcAddress;
eSetPixelFormat = d3dmh_SetPixelFormat;
eChangeDisplaySettings = ChangeDisplaySettings_FakeGL;
myRenderer.graphics_api = RENDERER_DIRECT3D;
strcpy (myRenderer.RendererText, "DX8");
}
void Renderer_OpenGL (void)
{
eglAlphaFunc = glAlphaFunc;
eglBegin = glBegin;
eglBindTexture = glBindTexture;
eglBlendFunc = glBlendFunc;
eglClear = glClear;
eglClearColor = glClearColor;
eglClearStencil = glClearStencil;
eglColor3f = glColor3f;
eglColor3fv = glColor3fv;
eglColor3ubv = glColor3ubv;
eglColor4f = glColor4f;
eglColor4fv = glColor4fv;
eglColor4ub = glColor4ub;
eglColor4ubv = glColor4ubv;
eglColorMask = glColorMask;
eglCullFace = glCullFace;
eglDeleteTextures = glDeleteTextures;
eglDepthFunc = glDepthFunc;
eglDepthMask = glDepthMask;
eglDepthRange = glDepthRange;
eglDisable = glDisable;
eglDrawBuffer = glDrawBuffer;
eglEnable = glEnable;
eglEnd = glEnd;
eglFinish = glFinish;
eglFogf = glFogf;
eglFogfv = glFogfv;
eglFogi = glFogi;
eglFogiv = glFogiv;
eglFrontFace = glFrontFace;
eglFrustum = glFrustum;
eglGenTextures = glGenTextures;
eglGetFloatv = glGetFloatv;
eglGetIntegerv = glGetIntegerv;
eglGetString = glGetString;
eglGetTexImage = glGetTexImage;
eglGetTexParameterfv = glGetTexParameterfv;
eglHint = glHint;
eglLoadIdentity = glLoadIdentity;
eglLoadMatrixf = glLoadMatrixf;
eglMatrixMode = glMatrixMode;
eglMultMatrixf = glMultMatrixf;
eglNormal3f = glNormal3f;
eglOrtho = glOrtho;
eglPolygonMode = glPolygonMode;
eglPolygonOffset = glPolygonOffset;
eglPopMatrix = glPopMatrix;
eglPushMatrix = glPushMatrix;
eglReadBuffer = glReadBuffer;
eglReadPixels = glReadPixels;
eglRotatef = glRotatef;
eglScalef = glScalef;
eglScissor = glScissor;
eglShadeModel = glShadeModel;
eglStencilFunc = glStencilFunc;
eglStencilOp = glStencilOp;
eglTexCoord2f = glTexCoord2f;
eglTexCoord2fv = glTexCoord2fv;
eglTexEnvf = glTexEnvf;
eglTexEnvi = glTexEnvi;
eglTexImage2D = glTexImage2D;
eglTexParameterf = glTexParameterf;
eglTexParameteri = glTexParameteri;
eglTexSubImage2D = glTexSubImage2D;
eglTranslatef = glTranslatef;
eglVertex2f = glVertex2f;
eglVertex2fv = glVertex2fv;
eglVertex3f = glVertex3f;
eglVertex3fv = glVertex3fv;
eglViewport = glViewport;
ewglCreateContext = wglCreateContext;
ewglDeleteContext = wglDeleteContext;
ewglGetCurrentContext = wglGetCurrentContext;
ewglGetCurrentDC = wglGetCurrentDC;
ewglMakeCurrent = wglMakeCurrent;
ewglGetProcAddress = wglGetProcAddress;
eSetPixelFormat = SetPixelFormat;
eChangeDisplaySettings = ChangeDisplaySettings;
myRenderer.graphics_api = RENDERER_OPENGL;
strcpy (myRenderer.RendererText, "GL");
}
renderer_def_t *Renderer_Init (int RendererType)
{
if (RendererType == RENDERER_OPENGL)
Renderer_OpenGL ();
else
Renderer_D3D ();
myRenderer.initialized = true;
return &myRenderer;
}Code: Select all
...
void (APIENTRY *eglPolygonMode) (GLenum face, GLenum mode);
void (APIENTRY *eglPolygonOffset) (GLfloat factor, GLfloat units);
void (APIENTRY *eglPolygonStipple) (const GLubyte *mask);
void (APIENTRY *eglPopAttrib) (void);
void (APIENTRY *eglPopClientAttrib) (void);
void (APIENTRY *eglPopMatrix) (void);
...