I've been "hacking" one of my favorite games from when I was younger, and I've managed to be able to intercept OpenGL calls and inject C++ code using an opengl32.dll wrapper. I've been able to come up with a number of cool uses for this, but my current goal is to implement post processing glsl shaders into this old game to make it look a bit more modern. The game was originally released in the late 90's, so its usage of OpenGL and its rendering code is limited/primitive/outdated.
I have been able to successfully produce vertex and fragment shaders by injecting code to initialize and use glsl shader programs, but my problem lies in producing a framebuffer / rendering my scene to a texture to send to my fragment shader as a sampler. As far as I can tell, the texture I produce is usually all black.
It's hard to find resources that are relevant to what I am doing and examining the raw opengl calls (I have been trying to determine where to insert the code by reading an opengl trace of a single frame of gameplay), so I haven't been able to wrap my head around what I'm doing wrong.
I've tried putting the code in many places, but currently, I'm binding the framebuffer after the game calls wglSwapBuffers()
and I'm unbinding it immediately before the next glFlush()
call is made, but I'm not sure if the multiple viewports setup, or matrix operations, or whatever else created between these times is somehow messing with the framebuffer.
This is the code to initialize the framebuffer:
void initFB()
{
/* Texture */
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &fbo_texture);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1920, 1080, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
/* Depth buffer */
glGenRenderbuffers(1, &fbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1920, 1080);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
/* Framebuffer to link everything together */
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_depth);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "glCheckFramebufferStatus: error %p", status);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
This is the code called after wglSwapBuffers
:
GLenum fboBuff[] = { GL_COLOR_ATTACHMENT0 };
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glDrawBuffers(1, fboBuff);
glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT);
This is the code called before glFlush()
:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glPopAttrib(); // Restore our glEnable and glViewport states
... Draw an Overlay containing with fbo texture binded ...
Here is the gl trace of a single frame.
It's nearly 800 lines but a trained opengl eye should be able to see what calls are getting made when. I removed several hundred lines of drawing calls that I atleast understand.