Hi Michael,

On Thu, 2005-09-15 at 09:30 +0200, Michael Ortega wrote:
> 
> And in the Display Func of the client :
> 
> //lines to change ImageLeft and ImageRight (static 640*480 images)
> void display(void)
> {
>                 .................
> 
>          beginEditCP(IXGauche);
>               IXGauche->setData(ImageLeft);
>               TXGauche->imageContentChanged(0,640,0,480);
>           endEditCP(IXGauche);

Do you get a new pointer to the image data or does the data just change
in place? If the latter, you shouldn't do the setData. But it shouldn't
have that big an influence on the performance.

One thing that might be the problem is the texture filter. If you don't
set it defaults to mipmapping, creation of which can take a long time.
Try to set the min and mag filter to GL_LINEAR and see if that helps.

Have you checked out the videotexturebackground example that we have?
That seems to work fine (and fast ;) for a 640x480 changing image. I
attached it again for reference. Can you try that and see how it
performs on your system?

Yours

        Dirk

// OpenSG Tutorial Example: Show an animated texture in hte background
//
// This example shows how to use the TextureBackground to show animated
// pictures behind the 3D graphics, and how to do it as efficiently as 
// possible
//
// Based on 02move.cpp

// Headers
#include <OpenSG/OSGGLUT.h>
#include <OpenSG/OSGConfig.h>
#include <OpenSG/OSGSimpleGeometry.h>
#include <OpenSG/OSGGLUTWindow.h>
#include <OpenSG/OSGSimpleSceneManager.h>
#include <OpenSG/OSGBaseFunctions.h>
#include <OpenSG/OSGTransform.h>

// new headers: 

// For the access to OpenGL extensions
#include <OpenSG/OSGGLEXT.h>

// For the image(s) to display
#include <OpenSG/OSGImage.h>

// For textures
#include <OpenSG/OSGTextureChunk.h>

// To put a texture into the background
#include <OpenSG/OSGTextureBackground.h>


// Activate the OpenSG namespace
OSG_USING_NAMESPACE

// The pointer to the transformation
TransformPtr trans;

// The pointer to the dynamic image and the texture
ImagePtr        image;
TextureChunkPtr tex;

// Some helper flags for different code pathes

// flag to indicate whether the images are power-of-two (POT) in size or not
bool  isPOT = false;

// flag to indicate whether rectangular textures are available
bool  hasRectTex = false;


// flag to indicate that only a small part of the image should be changed
// per frame. The random image geenration can get slow for large
// images.
bool  changeOnlyPart = false;

// The SimpleSceneManager to manage simple applications
SimpleSceneManager *mgr;

// forward declaration so we can have the interesting stuff upfront
int setupGLUT( int *argc, char *argv[] );


// Grab/update the image
// This just update the image's data and tells the texture that it changed.
// For a video this would grab the next frame
void grabImage(ImagePtr img)
{
    beginEditCP(img, Image::PixelFieldMask);
    
    UInt8* data = img->getData();
    
    // for this example, just fill it with random junk    
    if(changeOnlyPart)
    {
        // Just change a small rectangular area
        UInt32 x = rand() % (img->getWidth() - 100);
        UInt32 y = rand() % (img->getHeight() - 100);
        UInt32 w = rand() % 100;
        UInt32 h = rand() % 100;
       
        UInt32 bpp = img->getBpp();
        UInt32 bpl = img->getWidth() * bpp;
        UInt32 bytes = w * bpp;
        
        data += y * bpl + x * bpp;
        
        UInt8 val = (rand() & 0x7f + 0x80);
        
        for(UInt32 i = h; i > 0; --i, data += bpl)
        {
            UInt8 *d = data;
            
            for(UInt32 j = bytes; j > 0; --j)
                *d++ = val;
        }
        
        // If only a part of the image changed, only that part needs to 
        // be updated. The speed of the update operation is pretty
        // directly dependent on the amount of data changed.
        tex->imageContentChanged(x, x + w, y, y + h);
    }
    else
    {       
        // Fill the whole picture
        for(UInt32 i = img->getHeight(); i > 0; --i)
        {
            UInt8 val = (rand() & 0x3f + 0x80);
            
            for(UInt32 j = img->getWidth() * img->getBpp(); j > 0; --j)
                *data++ = val;
        }
        
        // Everything changed
        tex->imageContentChanged();
    }
        
    endEditCP(img, Image::PixelFieldMask);
}


// redraw the window
void display( void )
{
    // update the geometry
    Matrix m;
    Real32 t = glutGet(GLUT_ELAPSED_TIME );
    
    m.setTransform(Vec3f(      osgsin(t / 1000.f), 
                               osgcos(t / 1000.f), 
                               osgsin(t / 1000.f)),
                   Quaternion( Vec3f(0,1,0), 
                               t / 1000.f));

    beginEditCP(trans, Transform::MatrixFieldMask);
    {
        trans->setMatrix(m);
    }   
    endEditCP  (trans, Transform::MatrixFieldMask);
    
    // update the image
    grabImage(image);
    
    // redraw the screen
    mgr->redraw();
}

// Initialize GLUT & OpenSG and set up the scene
int main(int argc, char **argv)
{
    // OSG init
    osgInit(argc,argv);

    // GLUT init
    int winid = setupGLUT(&argc, argv);

    // the connection between GLUT and OpenSG
    GLUTWindowPtr gwin= GLUTWindow::create();
    gwin->setId(winid);
    gwin->init();

    // create the scene

    NodePtr torus = makeTorus( .5, 2, 16, 32 );
    NodePtr scene = Node::create();
    trans = Transform::create();
    beginEditCP(scene, Node::CoreFieldMask | Node::ChildrenFieldMask);
    {
        scene->setCore(trans);
        scene->addChild(torus);
    }
    endEditCP  (scene, Node::CoreFieldMask | Node::ChildrenFieldMask);
    
    // Create the parts needed for the video background
    
    UInt32 width = 640;
    UInt32 height = 480;
    
    // get the desired size from the command line
    if(argc >= 3)
    {
        width = atoi(argv[1]);
        height = atoi(argv[2]);
    }
    
    // An OpenGL prefers textures that are power of two (POT) sizes, 
    // things are a little more complicated for non-POT (NPOT)
    // textures. The following flag shows where in the code changes 
    // need to be made for that case
    
    isPOT = osgispower2(width) && osgispower2(height);
    
    
    // To check OpenGL extensions, the Window needs to have run through
    // frameInit at least once. This automatically happens when rendering,
    // but we don't don't to wait for that here.
    gwin->activate();
    gwin->frameInit();
    
    // Now we can check for OpenGL extensions    
    hasRectTex = gwin->hasExtension("GL_ARB_texture_rectangle");
    
    // Print what we've got
    SLOG << "Got " << (isPOT?"":"non-") << "power-of-two images and "
         << (hasRectTex?"can":"cannot") << " use rectangular textures" 
         << ", changing " << (changeOnlyPart?"part":"all") 
         << " of the screen"
         << endLog;
    
    
    // Ok, now for the meat of the code...
    // first we need an Image to hold the picture(s) to show
    image = Image::create();
    
    beginEditCP(image);
    {
        // set the image's size and type, and allocate memory
        // this example uses RGB. On some systems (e.g. Windows) BGR
        // or BGRA might be faster, it depends on how the images are 
        // acquired
        image->set(Image::OSG_RGB_PF, width, height);
    }
    endEditCP(image);
    
    // Now create the texture to be used for the background
    tex = TextureChunk::create();
    
    beginEditCP(tex);
    {
        // Associate image and texture
        tex->setImage(image);
        // Set filtering modes. LINEAR is cheap and good if the image size
        // changes very little (i.e. the window is about the same size as 
        // the images).
        tex->setMinFilter(GL_LINEAR);
        tex->setMagFilter(GL_LINEAR);        
        
        // Set the wrapping modes. We don't need repetition, it might actually
        // introduce artifactes at the borders, so switch it off.
        tex->setWrapS(GL_CLAMP_TO_EDGE);
        tex->setWrapT(GL_CLAMP_TO_EDGE);        
       
        
        if(isPOT)
        {
            // power-of-two image. Nice, nothing special to do here.
        }
        else if(hasRectTex)
        {
            // Rectangular textures are available, but they need to be 
            // explicitly enabled
            tex->setTarget(GL_TEXTURE_RECTANGLE_ARB);
        }
        else
        {
            // OpenGL can only handle POT textures. When using NPOT 
            // textures they need to be embedded in a POT texture. By default
            // OpenSG scales up the image to fill the whole texture, to make 
            // repetition work. But this is very expensive and not useable
            // for images that change a lot.
            // So tell OpenSG not to scale the image. In this case, only the 
            // lower left corner of the texture will be used.
            tex->setScale(false);
        }
    }
    endEditCP(tex);
    
    // Create the background
    TextureBackgroundPtr back = TextureBackground::create();
    
    beginEditCP(back);
    {
        // Set the texture to use
        back->setTexture(tex);
        
        // Set up texture coordinates for the background
        
        if(isPOT)
        {
            // Standard texture coords for power-of-two image.
            back->getTexCoords().push_back(Pnt2f(0,0));
            back->getTexCoords().push_back(Pnt2f(1,0));
            back->getTexCoords().push_back(Pnt2f(1,1));
            back->getTexCoords().push_back(Pnt2f(0,1));
        }
        else if(hasRectTex)
        {
            // Rectangular textures have pixel-based texture
            // coordinates
            back->getTexCoords().push_back(Pnt2f(0,0));
            back->getTexCoords().push_back(Pnt2f(width-1,0));
            back->getTexCoords().push_back(Pnt2f(width-1,height-1));
            back->getTexCoords().push_back(Pnt2f(0,height-1));
        }
        else
        {
            // Using NPOT texture embedded in larger POT texture
            // Set the texcoords so that only the used part is visible
           
            Real32 w = static_cast<Real32>(width) / osgnextpower2(width);
            Real32 h = static_cast<Real32>(height) / osgnextpower2(height);
           
            back->getTexCoords().push_back(Pnt2f(0,0));
            back->getTexCoords().push_back(Pnt2f(w,0));
            back->getTexCoords().push_back(Pnt2f(w,h));
            back->getTexCoords().push_back(Pnt2f(0,h));
            
        }
    }
    endEditCP(back);
    

    // create the SimpleSceneManager helper
    mgr = new SimpleSceneManager;

    // tell the manager what to manage
    mgr->setWindow(gwin );
    mgr->setRoot  (scene);
    mgr->setStatistics(true);
    
    // replace the background
    // This has to be done after the viewport has been created, which the 
    // SSM does in setRoot().
    ViewportPtr vp = gwin->getPort()[0];
    
    beginEditCP(vp, Viewport::BackgroundFieldMask);
    {
        vp->setBackground(back);
    }
    endEditCP(vp, Viewport::BackgroundFieldMask);
    
    
    // show the whole scene
    mgr->showAll();

    // GLUT main loop
    glutMainLoop();

    return 0;
}

//
// GLUT callback functions
//

// react to size changes
void reshape(int w, int h)
{
    mgr->resize(w, h);
    glutPostRedisplay();
}

// react to mouse button presses
void mouse(int button, int state, int x, int y)
{
    if (state)
        mgr->mouseButtonRelease(button, x, y);
    else
        mgr->mouseButtonPress(button, x, y);
        
    glutPostRedisplay();
}

// react to mouse motions with pressed buttons
void motion(int x, int y)
{
    mgr->mouseMove(x, y);
    glutPostRedisplay();
}

// react to keys
void keyboard(unsigned char k, int x, int y)
{
    switch(k)
    {
        case 27:  
        {
            OSG::osgExit();
            exit(0);
        }
        break;
    }
}

// setup the GLUT library which handles the windows for us
int setupGLUT(int *argc, char *argv[])
{
    glutInit(argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    
    int winid = glutCreateWindow("OpenSG");
    
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutKeyboardFunc(keyboard);

    // call the redraw function whenever there's nothing else to do
    glutIdleFunc(display);

    return winid;
}

Reply via email to