Hello Folks,
I'm writing a plugin for a simulator called 'X-Plane 11'. My plugin essentially calls on a DLL (Which I've written) that makes OpenGL calls to draw graphics onto the active draw target (it does no OpenGL initialization). I want this external DLL to represent the logic behind a computer screen, but not be directly coupled with the OpenGL context that it is being drawn to. In this current instance for example, I am drawing it to the screen in X-Plane, however, I may at some point want to draw it to the screen of a different game engine, or perhaps even just a windows program.
The way I am trying to achieve this:
- Generate a frame buffer and texture
- Initialize texture and add it to the framebuffer
- On the drawcall...
- Bind to the frame buffer
- Call the dll's draw method
- Un-bind the frame buffer
- Bind to the host applications framebuffer
- Bind to the associated texture
- Draw a quad in the corner of the screen with appropriate texture coordinates
- Un-bind the texture
I have the problem though that the output is always just a black square...(See attached image)
The code goes a little like this (Only showing the relevant bits):
#include <Windows.h>
#include <string>
#include "PluginHeader.h"
#include <GL\glew.h>
#include <gl\GL.h>
#include <gl\GLU.h>
#include "MFDSim.h"
HINSTANCE g_MfdSimLibHandle = 0;
XPLMWindowID g_MfdWindowID = 0;
GLuint g_FrameBufferID = 0;
GLuint g_fbTex = 0;
GLuint g_rbo = 0;
unsigned int g_MfdScreenWidth = 0;
unsigned int g_MfdScreenHeight = 0;
/////////////////////////////////////////////////////
// Standard plugin functions ------------------------
PLUGIN_API int XPluginStart(
char* outName,
char* outSig,
char* outDesc)
{
strcpy(outName,"MFD Sim");
strcpy(outSig, "mfd");
strcpy(outDesc, ");
int retVal = TRUE;
glewInit();
HINSTANCE g_MfdSimLibHandle = LoadLibrary("./Resources/plugins/MFD_Sim_Plugin/win_x64/MFDSim.dll");
if (g_MfdSimLibHandle != nullptr)
{
try
{
MFD::mfdInit("./Resources/plugins/MFD_Sim_Plugin/config/layout.xml");
MFD::mfdGetWidthHeight(g_MfdScreenWidth, g_MfdScreenHeight);
}
catch (const std::exception& ex)
{
retVal = FALSE;
}
}
else
{
retVal = FALSE;
}
return retVal;
}
PLUGIN_API void XPluginStop()
{
FreeLibrary(g_MfdSimLibHandle);
}
PLUGIN_API int XPluginEnable()
{
// We need to revert back to the appropriate frame buffer after we're done
GLint currentReadFB = 0;
GLint currentDrawFB = 0;
glGetIntegerv(GL_READ_FRAMEBUFFER, ¤tReadFB);
glGetIntegerv(GL_DRAW_FRAMEBUFFER, ¤tDrawFB);
XPLMRegisterDrawCallback(OnDrawCall, xplm_Phase_LastCockpit, TRUE, nullptr);
// Generate OPENGL stuff we need
glGenFramebuffers(1, &g_FrameBufferID);
glBindFramebuffer(GL_FRAMEBUFFER, g_FrameBufferID);
glGenTextures(1, &g_fbTex);
glBindTexture(GL_TEXTURE_2D, g_fbTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, g_MfdScreenWidth, g_MfdScreenHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, g_fbTex, 0);
glGenRenderbuffers(1, &g_rbo);
glBindRenderbuffer(GL_RENDERBUFFER, g_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, g_MfdScreenWidth, g_MfdScreenHeight);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, g_rbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, currentReadFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentDrawFB);
return TRUE;
}
PLUGIN_API void XPluginDisable()
{
XPLMUnregisterDrawCallback(OnDrawCall, xplm_Phase_LastCockpit, TRUE, nullptr);
glDeleteFramebuffers(1, &g_FrameBufferID);
glDeleteTextures(1, &g_fbTex);
}
PLUGIN_API void XPluginReceiveMessage(
XPLMPluginID inFrom,
int inMsg,
void* inParam)
{
}
// Boilerplate DLL stuff
BOOL WINAPI DLLMain(
_In_ HINSTANCE hInstance,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved)
{
return TRUE;
}
/////////////////////////////////////////////////////
// MFD functions -----------------------------------
void HandleWindowKeyEvent(XPLMWindowID inWindowID, char inKey, XPLMKeyFlags inFlags, char inVirtualKey, void * inRefcon, int losingFocus)
{
if (inWindowID == g_MfdWindowID)
{
}
}
int OnDrawCall(XPLMDrawingPhase inPhase, int inIsBefore, void * refCon)
{
// We need to revert back to the appropriate frame buffer after we're done
GLint currentReadFB = 0;
GLint currentDrawFB = 0;
glGetIntegerv(GL_READ_FRAMEBUFFER, ¤tReadFB);
glGetIntegerv(GL_DRAW_FRAMEBUFFER, ¤tDrawFB);
// Bind to our own frame buffer and draw our MFD
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_FrameBufferID);
glBindFramebuffer(GL_READ_FRAMEBUFFER, g_FrameBufferID);
glBindTexture(GL_TEXTURE_2D, g_fbTex);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_TEXTURE_2D);
if (!MFD::mfdDraw(1.0f))
{
// TODO: Handle failure to draw
}
glBegin(GL_LINES);
glColor4f(1.0f, 0.1f, 0.1f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(100.0f, 100.0f);
glEnd();
glBindFramebuffer(GL_READ_FRAMEBUFFER, currentReadFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentDrawFB);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glVertex2f(0, 0); glTexCoord2f(0.0f, 0.0f);
glVertex2f(0, g_MfdScreenHeight); glTexCoord2f(0.0f, 1.0f);
glVertex2f(g_MfdScreenWidth, g_MfdScreenHeight); glTexCoord2f(1.0f, 1.0f);
glVertex2f(g_MfdScreenWidth, 0); glTexCoord2f(1.0f, 0.0f);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
return 0;
}