Search code examples
c++opengltexturesc++buildersharing

Access violation on wglBindTexImageARB ; due to WGL_FRONT_LEFT_ARB not defined allthoug wglext.h included?


I have an Access violation on this line :

if (RTT.wgl.wglBindTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB) == FALSE)
    ShowMessage(AnsiString().sprintf("wglBindTexImageARB returned %i", GetLastError()));

The exception is thrown before the getlasterror() call : so getlasterror can't tell anything.

When I try to evaluate the expression with Borland Builder's debugger, it says impossible to evaluate : due to WGL_FRONT_LEFT_ARB not defined.

So I added wglext.h in the includes : no success, same debugger message.

But perhaps is it a C++ syntax problem or Borland logic not respected ?

Here are extracts of my code :

UnitGLForm.h :

#include <GL/gl.h>
#include "glext.h"
#include "wglext.h"
class TGLForm : public TForm
{
__published:    // Composants gérés par l'EDI
    void __fastcall FormCreate(TObject *Sender);
private:    // Déclarations de l'utilisateur
    HDC   ghDC;
    bool bSetupPixelFormat(HDC hdc,HDC hdc2);
public:     // Déclarations de l'utilisateur
    __fastcall TGLForm(TComponent* Owner, class CPreviewCallback *delegatePreview, HDC hDC);
    virtual void DrawScene();
};

struct GLRenderToTexture
{
    struct
    {
        HDC          hdc;
        HGLRC        hGlRc;
        HPBUFFERARB  hBuffer;
        PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
        PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
        PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
        PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
        PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB;
        PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
        PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
        PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB;
        PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB;
    } wgl;
    unsigned int  uintTexture;  // the texture we're going to render to
};
GLRenderToTexture  RTT;

HDC   ghDC2;
HGLRC ghRC;

So it seems for me logic that I can access to RTT, ghDC2, ghRC from any other .h or .cpp file. Follows here the implementation :

UniGLForm.cpp :

__fastcall TGLForm::TGLForm(TComponent* Owner, class CPreviewCallback *delegatePreview, HDC hDC)
:TForm(Owner)
{
    ghDC2 = hDC;
    this->DoubleBuffered = true;
}
//---------------------------------------------------------------------------
bool TGLForm::bSetupPixelFormat(HDC hdc,HDC hdc2)
{
    PIXELFORMATDESCRIPTOR pfd, *ppfd;
    int pixelformat;
    ppfd = &pfd;
    ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
    ppfd->nVersion = 1;
    ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA;
    ppfd->dwLayerMask = PFD_MAIN_PLANE;
    ppfd->iPixelType = PFD_TYPE_COLORINDEX;
    ppfd->cColorBits = 8;
    ppfd->cDepthBits = 16;

    ppfd->cAccumBits = 0;
    ppfd->cStencilBits = 0;

    if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 )
    {
    MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
    return false;
    }

    if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
    {
    MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
    return false;
    }


    if ( (pixelformat = ChoosePixelFormat(hdc2, ppfd)) == 0 )
    {
    MessageBox(NULL, "ChoosePixelFormat 2 failed", "Error", MB_OK);
    return false;
    }

    if (SetPixelFormat(hdc2, pixelformat, ppfd) == FALSE)
    {
    MessageBox(NULL, "SetPixelFormat 2 failed", "Error", MB_OK);
    return false;
    }

    return true;
}
//---------------------------------------------------------------------------
void __fastcall TGLForm::FormCreate(TObject *Sender)
{
    ghDC = GetDC(Handle);
    if (!bSetupPixelFormat(ghDC, ghDC2)) Close();
    ghRC = wglCreateContext(ghDC);

wglMakeCurrent(ghDC, ghRC);
    InitializeGL();

    // pixel buffer
    RTT.wgl.wglChoosePixelFormatARB= (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
    RTT.wgl.wglGetExtensionsStringARB= (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
    RTT.wgl.wglChoosePixelFormatARB= (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
    RTT.wgl.wglCreatePbufferARB= (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
    RTT.wgl.wglGetPbufferDCARB= (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
    RTT.wgl.wglQueryPbufferARB= (PFNWGLQUERYPBUFFERARBPROC)wglGetProcAddress("wglQueryPbufferARB");
    RTT.wgl.wglDestroyPbufferARB= (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
    RTT.wgl.wglReleasePbufferDCARB= (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
    RTT.wgl.wglBindTexImageARB= (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
    RTT.wgl.wglReleaseTexImageARB= (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");

    int     pixelFormats;
    int     intAttrs[32] ={WGL_RED_BITS_ARB,8,
                               WGL_GREEN_BITS_ARB,8,
                               WGL_BLUE_BITS_ARB,8,
                               WGL_ALPHA_BITS_ARB,8,
                               WGL_DRAW_TO_PBUFFER_ARB, GL_TRUE,
                               WGL_BIND_TO_TEXTURE_RGBA_ARB, GL_TRUE,
                               WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
                               WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
                               WGL_DOUBLE_BUFFER_ARB,GL_FALSE,
                               0}; // 0 terminate the list
    unsigned int numFormats = 0;
    // get an acceptable pixel format to create the PBuffer with
    if (RTT.wgl.wglChoosePixelFormatARB(ghDC, intAttrs, NULL, 1, &pixelFormats, &numFormats)==FALSE)
        ShowMessage(AnsiString().sprintf("wglChoosePixelFormatARB returned %i", GetLastError())); // GetLastError will tell us why it failed

    //Set some p-buffer attributes so that we can use this p-buffer as a 2d texture target
    const int attributes[]= {WGL_TEXTURE_FORMAT_ARB,  WGL_TEXTURE_RGBA_ARB, // p-buffer will have RBA texture format
                        WGL_TEXTURE_TARGET_ARB, WGL_TEXTURE_2D_ARB, 0}; // Of texture target will be GL_TEXTURE_2D
    // the size of the PBuffer must be the same size as the texture
    RTT.wgl.hBuffer= RTT.wgl.wglCreatePbufferARB(ghDC, pixelFormats, ClientWidth, ClientHeight, attributes);
    RTT.wgl.hdc= RTT.wgl.wglGetPbufferDCARB(RTT.wgl.hBuffer);
    RTT.wgl.hGlRc= wglCreateContext(RTT.wgl.hdc);

    // so that we can share textures between contexts
wglMakeCurrent(NULL, NULL);
    if (wglShareLists(ghRC,RTT.wgl.hGlRc) == FALSE)
        SCmsgError(AnsiString().sprintf("wglShareLists returned %i", GetLastError())); // GetLastError will tell us why it failed
}
//---------------------------------------------------------------------------
void TGLForm::DrawScene()
{
wglMakeCurrent(ghDC, ghRC);
    ClientWidth = 1920;
    ClientHeight = 1080;

    // create a texture to use as the backbuffer
    glGenTextures(1, &RTT.uintTexture);
    glBindTexture(GL_TEXTURE_2D, RTT.uintTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    // make sure this is the same color format as the screen
    glTexImage2D(GL_TEXTURE_2D, 0, 4,  ClientWidth, ClientHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    // switch to the texture context
wglMakeCurrent(RTT.wgl.hdc, RTT.wgl.hGlRc);     
    glEnable(GL_TEXTURE_2D);              // Enable Texture Mapping
    TGLBlend::SetBlendMode(0);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE); //ARC
    glClear(GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT);

    glDisable(GL_TEXTURE_2D);

    // switch back to the screen context
wglMakeCurrent(ghDC, ghRC);
    TGLBlend::SetBlendMode(0);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE); //ARC
    glClear(GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, ClientWidth, ClientHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

wglMakeCurrent(RTT.wgl.hdc, RTT.wgl.hGlRc);
    glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, RTT.uintTexture);
        PaintGL();
    glDisable(GL_TEXTURE_2D);

wglMakeCurrent(ghDC, ghRC);
    glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, RTT.uintTexture);
        RTT.wgl.wglBindTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB);
        // set up some vertices to render a texture to a model; example:
        glBegin(GL_QUADS);
            glColor4ub(255,255,255,255);
            glTexCoord2f (0.0, 0.0); glVertex2f (-1.0, -1.0);
            glTexCoord2f (1.0, 0.0); glVertex2f (1.0, -1.0);
            glTexCoord2f (1.0, 1.0); glVertex2f (1.0, 1.0);
            glTexCoord2f (0.0, 1.0); glVertex2f (-1.0, 1.0);
        glEnd();
        RTT.wgl.wglReleaseTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB);
    glDisable(GL_TEXTURE_2D);

    glFlush();
    SwapBuffers(ghDC);
}

=> this copy of PaintGL to the texture and then textured to a quad works perfectly.

The problem is when I want to use this texture in another window :

UnitGLForm2.h :

class TGLForm2 : public TForm
{
__published:    // Composants gérés par l'EDI
    void __fastcall FormCreate(TObject *Sender);
public:     // Déclarations de l'utilisateur
    __fastcall TGLForm2(TComponent* Owner, class CPreviewCallback *delegatePreview);
    virtual void DrawScene();
};

UnitGLForm2.cpp :

__fastcall TGLForm2::TGLForm2(TComponent* Owner, class CPreviewCallback *delegatePreview)//, HDC hDC)
:TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TGLForm2::FormCreate(TObject *Sender)
{
wglMakeCurrent(ghDC2, ghRC);
    InitializeGL();
}
//---------------------------------------------------------------------------
void TGLForm2::DrawScene()
{
        ClientWidth = 1920;
        ClientHeight = 1080;
wglMakeCurrent(ghDC2, ghRC);
    TGLBlend::SetBlendMode(0);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE); //ARC
    glClear(GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, ClientWidth, ClientHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_TEXTURE_2D);
        RTT.wgl.wglBindTexImageARB= (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
        RTT.wgl.wglReleaseTexImageARB= (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");

        glBindTexture(GL_TEXTURE_2D, RTT.uintTexture);
        if (RTT.wgl.wglBindTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB) == FALSE)
            SCmsgError(AnsiString().sprintf("wglBindTexImageARB returned %i", GetLastError())); // GetLastError will tell us why it failed      
        glBegin(GL_QUADS);
            glColor4ub(255,200,200,200);
            glTexCoord2f (0.0, 0.0); glVertex2f (-1.0, -1.0);
            glTexCoord2f (1.0, 0.0); glVertex2f (1.0, -1.0);
            glTexCoord2f (1.0, 1.0); glVertex2f (1.0, 1.0);
            glTexCoord2f (0.0, 1.0); glVertex2f (-1.0, 1.0);
        glEnd();
        RTT.wgl.wglReleaseTexImageARB(RTT.wgl.hBuffer, WGL_FRONT_LEFT_ARB);
    glDisable(GL_TEXTURE_2D);
    glFlush();
    SwapBuffers(ghDC2);

wglMakeCurrent(NULL,NULL);
}

Solution

  • Including a header is not enough. You also have actually load the extension. Everything related to PBuffers is a extension and thus must be loaded in a special way. Google for "OpenGL extension loading"