page transparency

57 views
Skip to first unread message

Jarrett Chisholm

unread,
Nov 20, 2012, 4:59:50 PM11/20/12
to berk...@googlegroups.com
Hi all,

I'm trying to get transparency working (want to use the rendered page as a HUD for a game), but I'm not having much luck.


My code to render looks like this:

glDisable(GL_LIGHTING);
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
   
    //Glfloat global_ambient[] = { 1.0f, 1.0f, 1.0f, 1.0f };
    //glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
   
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable( GL_TEXTURE_2D );
    glBindTexture(GL_TEXTURE_2D, web_texture);
   
    // display   
    glBegin(GL_QUADS);
        glTexCoord2f(0.f, 1.f); glVertex3f(-1.f, -1.f, 0.f);
        glTexCoord2f(0.f, 0.f); glVertex3f(-1.f,  1.f, 0.f);
        glTexCoord2f(1.f, 0.f); glVertex3f( 1.f,  1.f, 0.f);
        glTexCoord2f(1.f, 1.f); glVertex3f( 1.f, -1.f, 0.f);
    glEnd();
   
    // wait a bit before calling Berkelium::update() again
    if (testint > 30) {
        BOOST_LOG_TRIVIAL(debug) << "calling update";
        Berkelium::update();
        testint = -1;
    }
   
    testint++;
   
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    glEnable(GL_LIGHTING);


My berkelium onPaint looksl ike this:
void GUI::onPaint(Berkelium::Window* wini,
    const unsigned char *bitmap_in, const Berkelium::Rect &bitmap_rect,
    size_t num_copy_rects, const Berkelium::Rect* copy_rects,
    int dx, int dy, const Berkelium::Rect& scroll_rect) {        
        
        bool updated = mapOnPaintToTexture(
            wini, bitmap_in, bitmap_rect, num_copy_rects, copy_rects,
            dx, dy, scroll_rect,
            web_texture, width, height, needs_full_refresh, scroll_buffer
        );
        
        
        if (updated) {
            needs_full_refresh = false;
            //glutPostRedisplay();
        }
}

Here's my  mapOnPaintToTexture:
bool GUI::mapOnPaintToTexture(
    Berkelium::Window *wini,
    const unsigned char* bitmap_in, const Berkelium::Rect& bitmap_rect,
    size_t num_copy_rects, const Berkelium::Rect *copy_rects,
    int dx, int dy,
    const Berkelium::Rect& scroll_rect,
    unsigned int dest_texture,
    unsigned int dest_texture_width,
    unsigned int dest_texture_height,
    bool ignore_partial,
    char* scroll_buffer) {
   
    BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: " << dest_texture_width << "x" << dest_texture_width << " dest_texture: " << dest_texture;

    glBindTexture(GL_TEXTURE_2D, dest_texture);

    const int kBytesPerPixel = 4;
   
   
    // TESTING BEGIN
    //int length = strlen((char*)bitmap_in);
    int theMax = bitmap_rect.right() * bitmap_rect.bottom();
    int length = theMax*kBytesPerPixel;
    unsigned char* bitmap_in_copy = new unsigned char[length]();
    //strncpy((char*)bitmap_in_copy, (char*)bitmap_in, length);
   
    BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: theMax: " << theMax << " (" << length << ")";
    for(int j= 0; j < theMax; j++) {
        bitmap_in_copy[j*4+0] = bitmap_in[j*4+0];
        bitmap_in_copy[j*4+1] = bitmap_in[j*4+1];
        bitmap_in_copy[j*4+2] = bitmap_in[j*4+2];
        bitmap_in_copy[j*4+3] = 0;
        //std::cout<<j<<": "<<bitmap_in[j*4+0]<<"**"<<bitmap_in[j*4+1]<<"**"<<bitmap_in[j*4+2]<<"**"<<bitmap_in[j*4+3]<<std::endl;
    }
    // TESTING END

    // If we've reloaded the page and need a full update, ignore updates
    // until a full one comes in.  This handles out of date updates due to
    // delays in event processing.
    if (ignore_partial) {
        if (bitmap_rect.left() != 0 ||
            bitmap_rect.top() != 0 ||
            bitmap_rect.right() != dest_texture_width ||
            bitmap_rect.bottom() != dest_texture_height) {
            return false;
        }

        BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 0a";
        glTexImage2D(GL_TEXTURE_2D, 0, kBytesPerPixel, dest_texture_width, dest_texture_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, bitmap_in_copy);
        ignore_partial = false;
        BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 0b";
        return true;
    }
   
    BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 1";


    // Now, we first handle scrolling. We need to do this first since it
    // requires shifting existing data, some of which will be overwritten by
    // the regular dirty rect update.
    if (dx != 0 || dy != 0) {
        // scroll_rect contains the Rect we need to move
        // First we figure out where the the data is moved to by translating it
        Berkelium::Rect scrolled_rect = scroll_rect.translate(-dx, -dy);
        // Next we figure out where they intersect, giving the scrolled
        // region
        Berkelium::Rect scrolled_shared_rect = scroll_rect.intersect(scrolled_rect);
        // Only do scrolling if they have non-zero intersection
        if (scrolled_shared_rect.width() > 0 && scrolled_shared_rect.height() > 0) {
            // And the scroll is performed by moving shared_rect by (dx,dy)
            Berkelium::Rect shared_rect = scrolled_shared_rect.translate(dx, dy);

            int wid = scrolled_shared_rect.width();
            int hig = scrolled_shared_rect.height();
           
            if (DEBUG_PAINT) {
              std::cout << "Scroll rect: w=" << wid << ", h=" << hig << ", ("
                        << scrolled_shared_rect.left() << "," << scrolled_shared_rect.top()
                        << ") by (" << dx << "," << dy << ")" << std::endl;
            }
           
            int inc = 1;
            char *outputBuffer = scroll_buffer;
            // source data is offset by 1 line to prevent memcpy aliasing
            // In this case, it can happen if dy==0 and dx!=0.
            char *inputBuffer = scroll_buffer+(dest_texture_width*1*kBytesPerPixel);
            int jj = 0;
            if (dy > 0) {
                // Here, we need to shift the buffer around so that we start in the
                // extra row at the end, and then copy in reverse so that we
                // don't clobber source data before copying it.
                outputBuffer = scroll_buffer+(
                    (scrolled_shared_rect.top()+hig+1)*dest_texture_width
                    - hig*wid)*kBytesPerPixel;
                inputBuffer = scroll_buffer;
                inc = -1;
                jj = hig-1;
            }

            // Copy the data out of the texture
            glGetTexImage(
                GL_TEXTURE_2D, 0,
                GL_BGRA, GL_UNSIGNED_BYTE,
                inputBuffer
            );

            // Annoyingly, OpenGL doesn't provide convenient primitives, so
            // we manually copy out the region to the beginning of the
            // buffer
            for(; jj < hig && jj >= 0; jj+=inc) {
                memcpy(
                    outputBuffer + (jj*wid) * kBytesPerPixel,
//scroll_buffer + (jj*wid * kBytesPerPixel),
                    inputBuffer + (
                        (scrolled_shared_rect.top()+jj)*dest_texture_width
                        + scrolled_shared_rect.left()) * kBytesPerPixel,
                    wid*kBytesPerPixel
                );
            }

            // And finally, we push it back into the texture in the right
            // location
            glTexSubImage2D(GL_TEXTURE_2D, 0,
                shared_rect.left(), shared_rect.top(),
                shared_rect.width(), shared_rect.height(),
                GL_BGRA, GL_UNSIGNED_BYTE, outputBuffer
            );
        }
    }

    BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 2";
    if (DEBUG_PAINT) {
      std::cout << (void*)wini << " Bitmap rect: w="
                << bitmap_rect.width()<<", h="<<bitmap_rect.height()
                <<", ("<<bitmap_rect.top()<<","<<bitmap_rect.left()
                <<") tex size "<<dest_texture_width<<"x"<<dest_texture_height
                <<std::endl;
    }
   
    BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 3";
    for (size_t i = 0; i < num_copy_rects; i++) {
        int wid = copy_rects[i].width();
        int hig = copy_rects[i].height();
        int top = copy_rects[i].top() - bitmap_rect.top();
        int left = copy_rects[i].left() - bitmap_rect.left();
        BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 4";
       
        if (DEBUG_PAINT) {
            std::cout << (void*)wini << " Copy rect: w=" << wid << ", h=" << hig << ", ("
                      << top << "," << left << ")" << std::endl;
        }
        BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 5";
        for(int jj = 0; jj < hig; jj++) {
            memcpy(
                scroll_buffer + jj*wid*kBytesPerPixel,
                bitmap_in_copy + (left + (jj+top)*bitmap_rect.width())*kBytesPerPixel,
                wid*kBytesPerPixel
                );
        }
        BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 6";
        // Finally, we perform the main update, just copying the rect that is
        // marked as dirty but not from scrolled data.
        glTexSubImage2D(GL_TEXTURE_2D, 0,
                        copy_rects[i].left(), copy_rects[i].top(),
                        wid, hig,
                        GL_BGRA, GL_UNSIGNED_BYTE, scroll_buffer
            );
        BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 7";
    }

    glBindTexture(GL_TEXTURE_2D, 0);
   
    BOOST_LOG_TRIVIAL(debug) << "mapOnPaintToTexture: here 8";

    return true;
}


What I was trying with the 'bitmap_in_copy' variable is to copy the 'bitmap_in' variable, but then make all the alpha channels to be '0' (on i think?).  My hope is that this would set the texture to have alpha on, and I could see through it...Doesn't quite seem to be working though.  (Also, i called setTransparency(true) on the window).

I can see my model kind of flickering in the background, but mostly the screen just looks black.

Anyone have any ideas what I might be doing wrong?

Ewen Cheslack-Postava

unread,
Nov 20, 2012, 6:30:39 PM11/20/12
to berk...@googlegroups.com
Calling window->setTransparent(true) should work, ensuring the alpha channel is properly saved instead of overwritten with full opacity.

But the way you are setting the alpha values to 0 just destroys that information. The code in the demo already saves the alpha channel into the texture (note the GL_BGRA flag).

The demos actually already works with transparency just using the default settings. For example, set the clear color to something very obvious like this purple:

glClearColor( 1.0, .3, 1.0, 1 );

and then load a page like this one: https://gist.github.com/4121955 Very simple, just don't specify a background color (or if you do, specify opacity) and it should use a transparent background by default. When you render this (e.g. glut_input "file:///home/ewencp/berkelium.git/trans.html"), it should show the text over purple.

For your specific case, you should probably try to get something working loading a known pattern into a texture (e.g. 2x2 pixels that you specify manually to ensure you have different levels of transparency) and make sure you can get that rendering with just that simple texture. Then, transition over to the Berkelium texture. Then you'll be able to narrow it down to either the code dealing with berkelium or your rendering code.

-Ewen

Jarrett Chisholm

unread,
Nov 20, 2012, 10:23:44 PM11/20/12
to berk...@googlegroups.com
Ahhh yes, you're right.  Sorry, I'm still getting my head around opengl/textures (as well as berkelium).

Another problem I had was that the page loaded wasn't showing any models in the background, but that was because of my 'render' code (I didn't disable the blending in opengl).

On a side note, Berkelium is AWESOME - I'm quite pumped about it!  Keep up the good work ;)  And thanks for the help!

Cheers

Jarrett
Reply all
Reply to author
Forward
0 new messages