3

I've successfully got some triangles to show up on screen together with some textures and a couple of event listeners. However, my texture is not rendering properly, it seems like pixels between 0 and 255 in brightness gets disorted while completely black/white pixels are rendering as they should. <- This might not be the best description but I will provide an example below.

This is the texture I'm trying to map onto my two triangles at the moment:

My texture

Here is the result after compiling and running the program:

enter image description here

What I think is that it may have something to do with the shaders, at the moment I do not have any shaders activated, neither vertex nor fragment shaders. I don't know if this is the problem but it might be a clue to it all.

Below is my main.cpp:


#include <iostream>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysymdef.h>

#include <GL/glx.h>
#include <GL/gl.h>
// #include <GL/glut.h> 
// #include <GL/glu.h>

#include <sys/time.h>
#include <unistd.h>

#define GLX_CONTEXT_MAJOR_VERSION_ARB       0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB       0x2092
typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display*, GLXFBConfig, GLXContext, Bool, const int*);


#define WINDOW_WIDTH    800
#define WINDOW_HEIGHT   800
#define FPS 30

uint8_t shutdown = 0;

#define SKIP_TICKS ( 1000 / FPS )

// macros
void Render( void );
void HandleEvents( XEvent ev );
void Resize( int w, int h );
void Shutdown( void );
void fill_triangle_buffer( void );

struct triangle { 
    float color[ 3 ];
    float p1[ 3 ];
    float p2[ 3 ];
    float p3[ 3 ];
}; 

struct triangle triangles[ 12 ];

static double GetMilliseconds() {
    static timeval s_tTimeVal;
    gettimeofday(&s_tTimeVal, NULL);
    double time = s_tTimeVal.tv_sec * 1000.0; // sec to ms
    time += s_tTimeVal.tv_usec / 1000.0; // us to ms
    return time;
}


GLuint loadBMP_custom( const char * imagepath ) {
    // Data read from the header of the BMP file
    unsigned char header[54]; // Each BMP file begins by a 54-bytes header
    unsigned int dataPos;     // Position in the file where the actual data begins
    unsigned int width, height;
    unsigned int imageSize;   // = width*height*3
    // Actual RGB data
    unsigned char * data;
    
    // Open the file
    FILE * file = fopen(imagepath,"rb");
    if (!file) {
        printf("Image could not be opened\n");
        return 0;
    }

    if ( fread(header, 1, 54, file)!=54 ){ // If not 54 bytes read : problem
        printf("Not a correct BMP file\n");
        return false;
    }

    if ( header[0]!='B' || header[1]!='M' ){
        printf("Not a correct BMP file\n");
        return 0;
    }
    
    // Read ints from the byte array
    dataPos    = *(int*)&(header[0x0A]);
    imageSize  = *(int*)&(header[0x22]);
    width      = *(int*)&(header[0x12]);
    height     = *(int*)&(header[0x16]);

    // Some BMP files are misformatted, guess missing information
    if (imageSize==0)
        imageSize=width*height*3; // 3 : one byte for each Red, Green and Blue component
    if (dataPos==0)
        dataPos=54; // The BMP header is done that way

    // Create a buffer
    data = new unsigned char [imageSize];

    // Read the actual data from the file into the buffer
    fread(data,1,imageSize,file);

    //Everything is in memory now, the file can be closed
    fclose(file);

    // Create one OpenGL texture
    GLuint textureID;
    glGenTextures(1, &textureID);

    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, textureID);

    // Give the image to OpenGL
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    // return GLuint
    return textureID;
}


int main (int argc, char ** argv){
    Display *dpy = XOpenDisplay(0);
    Window win;
    XEvent ev;

    int nelements;
    GLXFBConfig *fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), 0, &nelements);

    static int attributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None };
    XVisualInfo *vi = glXChooseVisual(dpy, DefaultScreen(dpy),attributeList);
    
    // Set Window attributes
    XSetWindowAttributes swa;
    swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone);
    swa.border_pixel = 0;
    swa.event_mask = StructureNotifyMask;
    win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa);

    // Select window inputs to be triggered in the eventlistener
    XSelectInput( dpy, win, PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask );
    
    XMapWindow (dpy, win);

    //oldstyle context:
    //  GLXContext ctx = glXCreateContext(dpy, vi, 0, GL_TRUE);

    std::cout << "glXCreateContextAttribsARB " << (void*) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB") << std::endl;
    GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");

    int attribs[] = {
        GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
        GLX_CONTEXT_MINOR_VERSION_ARB, 0,
        0};

    
    // Redirect Close
    Atom atomWmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(dpy, win, &atomWmDeleteWindow, 1);

    // Create GLX OpenGL context

    GLXContext ctx = glXCreateContextAttribsARB(dpy, *fbc, 0, true, attribs);

    glXMakeCurrent( dpy, win, ctx );
    glMatrixMode( GL_PROJECTION );
    glEnable( GL_CULL_FACE ); 
    glCullFace( GL_FRONT );
        glFrustum( -1, 1, 1, -1, -1, 1 );
    
        glClearColor (0, 0.5, 1, 1);
        glClear (GL_COLOR_BUFFER_BIT);
        glXSwapBuffers (dpy, win);

    
    fill_triangle_buffer();

    // Load and bind texture
    glEnable(GL_TEXTURE_2D);
    loadBMP_custom("textures/texture.bmp");


    // prepare gameloop
    
    double prevTime = GetMilliseconds();
    double currentTime = GetMilliseconds();
    double deltaTime = 0.0;

    timeval time;
    long sleepTime = 0;
    gettimeofday(&time, NULL);
    long nextGameTick = (time.tv_sec * 1000) + (time.tv_usec / 1000);   

    while ( shutdown != 1 ) {
        // Get events if there is any
        if (XPending(dpy) > 0) {
            XNextEvent(dpy, &ev);
            if (ev.type == Expose) {
                XWindowAttributes attribs;
                XGetWindowAttributes(dpy, win, &attribs);
                Resize(attribs.width, attribs.height);
            }
            if (ev.type == ClientMessage) {
                if (ev.xclient.data.l[0] == atomWmDeleteWindow) {
                    break;
                }
            }
            else if (ev.type == DestroyNotify) { 
                break;
            }
        }
        
        // Framelimit calculations, before heavy load
        currentTime = GetMilliseconds();
        deltaTime = double( currentTime - prevTime ) * 0.001;
        prevTime = currentTime;
        
        // Do work
        HandleEvents( ev );
        //Render();
        
glClear( GL_COLOR_BUFFER_BIT ); 
glBegin(GL_TRIANGLES);
    glColor3f( 255, 255, 255 );
/*
glTexCoord2f( 0.0f, 1.0f );
    glVertex3f( -0.5f,  0.5f, 0.0f );
glTexCoord2f( 1.0f, 1.0f );
    glVertex3f(  0.5f,  0.5f, 0.0f );
glTexCoord2f( 0.0f, 0.0f );
    glVertex3f( -0.5f, -0.5f, 0.0f );
        
    glVertex3f(  0.5f,  0.5f, 0.0f );
glTexCoord2f( 1.0f, 0.0f );
    glVertex3f(  0.5f, -0.5f, 0.0f );
    glVertex3f( -0.5f, -0.5f, 0.0f );
*/

     // first triangle, bottom left half
    glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -0.5f, -0.5f, 0 );
    glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -0.5f,  0.5f, 0 );
    glTexCoord2f( 1.0f, 0.0f ); glVertex3f(  0.5f, -0.5f, 0 );

    // second triangle, top right half
    glTexCoord2f( 1.0f, 0.0f ); glVertex3f(  0.5f, -0.5f, 0 );
    glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -0.5f,  0.5f, 0 );
    glTexCoord2f( 1.0f, 1.0f ); glVertex3f(  0.5f,  0.5f, 0 );

glEnd();
glFlush();
        glXSwapBuffers( dpy, win );
        
        // Limit Framerate
        gettimeofday( &time, NULL );
        nextGameTick += SKIP_TICKS;
        sleepTime = nextGameTick - ( (time.tv_sec * 1000) + (time.tv_usec / 1000) );
        usleep((unsigned int)(sleepTime/1000));
    }

    ctx = glXGetCurrentContext(); 
    glXDestroyContext(dpy, ctx); 
}

void fill_triangle_buffer( void ){
    triangles[ 0 ] = {   
                {  1.0f,  0.0f,  0.0f },
                { -0.5f, -0.5f, -0.5f },
                {  0.5f,  0.5f, -0.5f },
                {  0.5f, -0.5f, -0.5f }  };
    triangles[ 1 ] = {   
                {  0.0f,  0.0f,  1.0f },
                { -0.5f, -0.5f, -0.5f },
                { -0.5f,  0.5f, -0.5f },
                {  0.5f,  0.5f, -0.5f } };
    triangles[ 2 ] = {   
                {  0.0f,  0.0f,  1.0f },
                {  0.5f,  0.5f, -0.5f },
                {  0.5f, -0.5f,  0.5f },
                {  0.5f, -0.5f, -0.5f }  };
    triangles[ 3 ] = {   
                {  1.0f,  1.0f,  0.0f },
                {  0.5f,  0.5f, -0.5f },
                {  0.5f,  0.5f,  0.5f },
                {  0.5f, -0.5f,  0.5f } };
    triangles[ 4 ] = {   
                {  1.0f,  0.0f,  0.0f },
                { -0.5f, -0.5f,  0.5f },
                {  0.5f, -0.5f,  0.5f },
                { -0.5f,  0.5f,  0.5f }  };
    triangles[ 5 ] = {   
                {  0.0f,  0.0f,  1.0f },
                {  0.5f, -0.5f,  0.5f },
                {  0.5f,  0.5f,  0.5f },
                { -0.5f,  0.5f,  0.5f } };
    triangles[ 6 ] = {   
                {  0.0f,  0.0f,  1.0f },
                { -0.5f,  0.5f, -0.5f },
                { -0.5f, -0.5f,  0.5f },
                { -0.5f,  0.5f,  0.5f }  };
    triangles[ 7 ] = {   
                {  1.0f,  1.0f,  0.0f },
                { -0.5f,  0.5f, -0.5f },
                { -0.5f, -0.5f, -0.5f },
                { -0.5f, -0.5f,  0.5f } };
    triangles[ 8 ] = {   
                {  1.0f,  0.0f,  0.0f },
                { -0.5f,  0.5f, -0.5f },
                { -0.5f,  0.5f,  0.5f },
                {  0.5f,  0.5f,  0.5f }  };
    triangles[ 9 ] = {   
                {  0.0f,  0.0f,  1.0f },
                { -0.5f,  0.5f, -0.5f },
                {  0.5f,  0.5f,  0.5f },
                {  0.5f,  0.5f, -0.5f } };
    triangles[ 10 ] = {   
                {  0.0f,  0.0f,  1.0f },
                {  0.5f, -0.5f, -0.5f },
                {  0.5f, -0.5f,  0.5f },
                { -0.5f, -0.5f,  0.5f }  };
    triangles[ 11 ] = {   
                {  1.0f,  1.0f,  0.0f },
                {  0.5f, -0.5f, -0.5f },
                { -0.5f, -0.5f,  0.5f },
                { -0.5f, -0.5f, -0.5f } };
}

void Resize(int w, int h) {
    glViewport(0, 0, w, h);
}

void Shutdown() {
    shutdown = 1;   
}


void Render( void ) {
    glClearColor ( 1.0f, 1.0f, 1.0f, 1 );
    glClear( GL_COLOR_BUFFER_BIT ); 
    glBegin(GL_TRIANGLES);
        /*glColor3f( 0.0f, 1.0f, 0.0f );
        glVertex3f( test_cnt, 0.0f, 1.0f );
        glVertex3f( 1.0f, 0.0f, 1.0f );
        glVertex3f( 0.0f, -1.0f, 1.0f );
        */

    int numTriangles = sizeof(triangles)/sizeof(triangles[0]);
    for ( int i = 0; i < numTriangles; i++ ) {
    glClear( GL_COLOR_BUFFER_BIT ); 
    glBegin(GL_TRIANGLES);
        struct triangle tr = triangles[ i ];
        glColor3f( tr.color[ 0 ], tr.color[ 1 ], tr.color[ 2 ] );
        glVertex3f( tr.p1[ 0 ], tr.p1[ 1 ], tr.p1[ 2 ] );
        glVertex3f( tr.p2[ 0 ], tr.p2[ 1 ], tr.p2[ 2 ] );
        glVertex3f( tr.p3[ 0 ], tr.p3[ 1 ], tr.p3[ 2 ] );
    }


    glEnd();
    glFlush();

}

float dx, dy;
float prevx, prevy;
uint8_t prev_defined = 0;
uint8_t key_down = 0;

void HandleEvents( XEvent ev ) {
    int x, y;

    switch ( ev.type ) {
        case ButtonPress:
            if ( ev.xbutton.button == 1 ) {
                std::cout << "Left mouse down \n";
                    // glRotatef( 0.01, 0.0, 0.0, 1.0 );
                if ( key_down == 0 )
                    prev_defined = 0;
                key_down = 1;
            }
            break;
        case ButtonRelease:
            if ( ev.xbutton.button == 1 ) {
                std::cout << "Left mouse up \n";
                key_down = 0;
            }
            break;
        case KeyPress:
            if ( ev.xkey.keycode == 9 ) { // ESC
                Shutdown();
            }
            break;
        case MotionNotify:
            x = ev.xmotion.x;
            y = ev.xmotion.y;
            if ( key_down == 0 )
                break;
            if ( !prev_defined ) {
                prevx = x;
                prevy = y;
                prev_defined = 1;
                break;
            }
            
            dx = x - prevx;
            dy = y - prevy;

            prevx = x;
            prevy = y;

            glRotatef( -dy/10, 1.0f, 0.0f, 0.0f );
            glRotatef( -dx/10, 0.0f, 1.0f, 0.0f );
            
            //std::cout << "Mouse X:" << x << ", Y: " << y << "\n";
            break;  
    }
}


I compile with:

g++ -g -Wall -o _build/main main.cpp -I/opt/x11/include  -L/usr/x11/lib -lglfw -lGLEW -lGL -lX11

OS:

Linux kali 5.9.0-kali4-amd64 #1 SMP Debian 5.9.11-1kali1 (2020-12-01) x86_64 GNU/Linux

Do anyone know how to resolve this issue in order to completely show above texture on my triangles?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Snakehater
  • 145
  • 1
  • 9
  • I don't know what you did, but that's actually pretty cool. Are you sure the pixel format matches the bitmap? – Neil Oct 31 '21 at 17:12
  • @Neil Thank you I pieced togher a whole lotta code. I tried to change to GL_RGB if that is what you meant but there were no difference :/ – Snakehater Oct 31 '21 at 17:44
  • I think bmps are in some weird pixel format, but it shouldn't matter with greyscale. I had a lot of troubles getting this right, but now prefer [lodepng](http://lodev.org/lodepng/) and [nanojpeg](http://keyj.emphy.de/nanojpeg/) for compression. It may have something to do with your shader. If the texture is generated procedurally, does it do the same thing? – Neil Oct 31 '21 at 18:07
  • @Neil I can try with loedpng, the thing with my shader is that I have not included any shaders into my program. And I don't know how a texture could be generated procedurally, or how it even is generated atm. – Snakehater Oct 31 '21 at 18:19
  • 2
    @Snakehater Likely the texture has an alpha channel. Do not skip the alpha channel and enable [blending](https://www.khronos.org/opengl/wiki/Blending). – Rabbid76 Oct 31 '21 at 18:27
  • In your call to `glTexImage2D`, try replacing `data` with a simple procedurally generated block of pixel data in the right form, (`for(x = 0; x < width; x++)...`)? – Neil Oct 31 '21 at 18:31
  • 1
    @Neil the exact same thing happened to me when trying to implement lodepng. so still the same problem remains. – Snakehater Oct 31 '21 at 21:55
  • @Rabbid76 this made it even worse, when using GL_BGRA instead of GL_BGR. And yes I tried other combinations as well. – Snakehater Oct 31 '21 at 21:56
  • When trying a picture where a line without fading has been drawn, this line displays just fine. – Snakehater Oct 31 '21 at 21:59
  • It looks fine on my computer with the following: I exported it as R8G8B8 bmp; I couldn't compile the `fill_triangle_buffer` so I just made them `static const`; got gid of the `-lglfw`, since it's not used, (this may be the problem, but I actually don't have `glfw` on my machine at the time, so couldn't tell.) – Neil Nov 01 '21 at 23:53
  • @Neil I tried to also remove -lglfw, my bmp file is 256 x 256 x 24 according to the cmd "file" and according to "identify" it is an 8-bit sRGB BMP file. I really don't know what is going on since it works for you. 32 bit bmp didn't work either :/ – Snakehater Nov 02 '21 at 21:31
  • Are you sure I shouldn't add a shader of some sort? – Snakehater Nov 02 '21 at 21:38
  • I guess my computer may fall back on the fixed-function pipeline whereas yours may require a compatibility setting. It's worth a shot using explicit shaders? Here is the [bare minimum](https://gist.github.com/sortofsleepy/9821640) which you must pass to the _glsl_ compiler as a string. – Neil Nov 03 '21 at 01:52
  • @Neil I have now installed both fragment and vertex shaders, but it still doesn't work – Snakehater Nov 08 '21 at 20:05
  • Your code works fine on MacOSX; maybe it's an X11 issue? I don't know X11, but I'd suspect `XCreateColormap`? – Neil Nov 08 '21 at 20:21
  • Any update on this issue? Is it resolved. I am also facing similar issue with texture display on X11 (Ubuntu 20.04). In my case texture becomes completely transparent if I use swizzle mask (.r) and completely black rectangles if I don't use anything. If I use (.w) for swizzle then I get white rectangles instead of black rectangles. Let me know if I should put any more info here or a new question should be raised. – Vicky Dec 06 '22 at 01:15
  • @Vicky No the issue has not been resolved. – Snakehater Dec 06 '22 at 07:07
  • @Snakehater, in my case, when I used .png image instead of .bmp and GL_RGBA format, it solved the issue and gave me better texture. I am yet to modify it with blend equation but it seems to work better now. But, now I am facing another issue, the same of settings are still giving me black texture when I am integrating my code with other scene rendered by different engine. Again trapped in same loop. Any help in this regard? – Vicky Dec 07 '22 at 08:44
  • I am sorry to flood this discussion. Just to close my own topic: My issue was that I was not activating texture using glActiveTexture after integration so it wasn't taking right texture unit. – Vicky Dec 07 '22 at 13:08

0 Answers0