Re: VideoTexture in Movietex.c.

New Message Reply Date view Thread view Subject view Author view

AnitaKishore (kishore++at++electrogig.com)
Thu, 20 Jun 1996 09:40:32 -0700


> If the Performer has some problems texturing video in OpenGL, should we use
our
> own OpenGL Callbacks, like we were doing in Performer 1.2 ?
>

We too experienced some problems at the begining, trying to get it to
work. But thanks to Simon Hui, we were able to make it work with his help.

Here is a sample code of doing video texturing in OpenGL using Performer
libpf library. Hope this helps.

-anita

-------------------------------------------------------------------------------
/* File Name : lv.c */
/*********************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <getopt.h>

/* X Window includes */
#include <X11/X.h>
#include <X11/Xlib.h>

/* VL includes */
#include <vl/vl.h>
#include <vl/dev_sirius.h>

#define PF_CPLUSPLUS_API 0

#include <Performer/pf.h>

typedef struct lvStruct {
 Display * Dsp;
 pfPipeWindow * pw;
 pfGeoState * gst;
 VLServer vlServer;
 VLPath vlPath;
} lvType, * lvHandle;

static int
VideoInit( lvHandle lvData, VLControlValue * vlSize,
                            VLControlValue * vlTiming,
                            VLControlValue * vlTexPack );
static void VideoExit(lvHandle lvData);
static void
setVideoTextureParameters( lvHandle lvData,
                           VLControlValue * vlSize,
                           VLControlValue * vlTiming,
                           VLControlValue * vlTexPack );
static int loadTextureMatrixCB(pfGeoState *gs, void *userData);
static int loadIDMatrixCB(pfGeoState *gs, void *userData);

pfGroup *MkScene();
pfGeoSet *MakeTexCube(void);
void channelDraw(pfChannel *chan, void *data);

static float idmat[4][4] = {
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
};

/* setup parameters */
static int TexSource = PFTEX_SOURCE_VIDEO;
static int glTexFormat = PFTEX_RGB_5; /* PFTEX_RGB_4, PFTEX_RGBA_8 */
static int TexComp = 3;
static int interlace = 0;
static int dofields = 0;
static int isrealityengine = 1;

pfTexture **tex;

lvHandle lvData;
GLXVideoSourceSGIX videosource;

void
OpenPipeWin(pfPipeWindow *pw)
{
 VLControlValue vlSize, vlTiming, vlTexPack;
 pfOpenPWin(pw);
 VideoInit ( lvData, &vlSize, &vlTiming, &vlTexPack );
 setVideoTextureParameters( lvData, &vlSize, &vlTiming, &vlTexPack );
}

int
main(long argc, char *argv[])
{

    pfPipe *p;
    pfChannel *chan;
    pfScene *scene;
    pfGroup *root;
    pfCoord view;

    void *arena=NULL;

    pfInit();
    arena = pfGetSharedArena();
    tex = (pfTexture **) pfMalloc(sizeof(pfTexture *), arena);

    lvData = ( lvHandle )pfMalloc( sizeof ( lvType ), arena);

    pfMultiprocess ( PFMP_APPCULLDRAW );
    pfConfig();

    scene = pfNewScene();
    root = MkScene();
    pfAddChild(scene, root);

    p = pfGetPipe(0);
    lvData -> pw = pfNewPWin(p);

    pfPWinType( lvData -> pw, PFWIN_TYPE_X);
    pfPWinName( lvData -> pw, "Live Video");
    pfPWinOriginSize( lvData -> pw, 100, 100, 720, 486);

    lvData -> Dsp = pfGetCurWSConnection();

    pfPWinConfigFunc ( lvData -> pw, OpenPipeWin);
    pfConfigPWin ( lvData -> pw);

    chan = pfNewChan(p);
    pfChanScene(chan, scene);
    pfChanNearFar(chan, 1.0f, 10000.0f);
    pfChanFOV(chan, 10.0f, -1.0f);
    pfSetVec3(view.hpr, 0, 0, 0);
    pfSetVec3(view.xyz, 0, -50, 0);
    pfChanView(chan, view.xyz, view.hpr);

    pfChanTravFunc(chan, PFTRAV_DRAW, channelDraw );

    /* set some basic formats for doing dynamic textures */
    //pfTexFormat(*tex, PFTEX_SUBLOAD_FORMAT, 1);

    while(TRUE)
    {
        pfSync();
        pfFrame();
    }

    VideoExit( lvData );
    pfExit();
    return 0;
}

void channelDraw(pfChannel *chan, void *data)
{
        int f;

        f = glXMakeCurrentReadSGI(lvData -> Dsp,
                                  pfGetPWinWSDrawable(lvData -> pw),
                                  videosource,
                                  pfGetPWinGLCxt(lvData -> pw));
        if (!f) printf("MakeCurrenRead failed in channelDraw()\n");
        pfClearChan(chan);
        pfLoadTex(*tex);
        pfDraw();
}

pfGroup *MkScene()
{

        pfGroup *group;
        pfGeode *cube;
        pfGeoSet *coloredCube;

        group = pfNewGroup();
        cube = pfNewGeode();
        coloredCube = MakeTexCube();
        pfAddGSet(cube, coloredCube);

        pfAddChild(group,cube);
        return group;

}

#define CUBE_SIZE 1.0f

pfGeoSet *MakeTexCube(void)
{

    pfGeoSet *gset;
    pfTexEnv *tenv;

    static pfVec3 verts[] ={{-CUBE_SIZE, 0, -CUBE_SIZE},
                                    { CUBE_SIZE, 0, -CUBE_SIZE},
                                    { CUBE_SIZE, 0, CUBE_SIZE},
                                    {-CUBE_SIZE, 0, CUBE_SIZE}};

    static ushort vindex[] ={0, 1, 2, 3}; /* front */

    static pfVec3 norms[] ={{ 0.0f, -1.0f, 0.0f}};

    static ushort nindex[] ={0};

    static pfVec2 tcoords[] ={{0.0f, 0.0f},
                                      {1.0f, 0.0f},
                                      {1.0f, 1.0f},
                                      {0.0f, 1.0f}};

    static ushort tindex[] ={0, 1, 2, 3};

    gset = pfNewGSet(pfGetSharedArena());

    pfGSetAttr(gset, PFGS_COORD3, PFGS_PER_VERTEX, verts, vindex);
    pfGSetAttr(gset, PFGS_NORMAL3, PFGS_PER_PRIM, norms, nindex);
    pfGSetAttr(gset, PFGS_TEXCOORD2, PFGS_PER_VERTEX, tcoords, tindex);
    pfGSetPrimType(gset, PFGS_QUADS);
    pfGSetNumPrims(gset, 1);

    lvData -> gst = pfNewGState(pfGetSharedArena());
    pfGStateMode( lvData -> gst, PFSTATE_ENTEXTURE, 1);
    pfGSetGState(gset, lvData -> gst);

    *tex = pfNewTex(pfGetSharedArena());
    //pfLoadTexFile(*tex,
"/disk4/people/kishore/performer/data/smallGlobeDesat.rgb");
    /* set some basic formats for doing dynamic textures */
    pfTexFormat(*tex, PFTEX_SUBLOAD_FORMAT, 1);
    pfTexFilter(*tex, PFTEX_MINFILTER, PFTEX_BILINEAR);

    tenv = pfNewTEnv(pfGetSharedArena());
    //pfTEnvMode(tenv, PFTE_DECAL);
    pfGStateAttr(lvData -> gst, PFSTATE_TEXENV, tenv);
    pfGStateAttr(lvData -> gst, PFSTATE_TEXTURE, *tex);

    return gset;

}

static int
VideoInit( lvHandle lvData, VLControlValue * vlSize,
                            VLControlValue * vlTiming,
                            VLControlValue * vlTexPack )
{
 VLControlValue vlCaptureType;
 VLNode vlSrc, vlDrn;
 int vlInSrc = VL_ANY, vlDevice = VL_ANY;
 fprintf ( stderr, "video init\n");
    /* open the server */
    if (!(lvData -> vlServer = vlOpenVideo(""))) {
        vlPerror("vlOpenVideo");
        fprintf(stderr, "couldn't open video server!\n");
        return 1;
    }

    /* Get the Video source */
    vlSrc = vlGetNode(lvData -> vlServer, VL_SRC, VL_VIDEO, vlInSrc);
    /* Get the Texture drain */
    vlDrn = vlGetNode(lvData -> vlServer, VL_DRN, VL_TEXTURE, 0);
    /* Create path */
    lvData -> vlPath = vlCreatePath(lvData -> vlServer, vlDevice, vlSrc,
vlDrn);
    if (lvData -> vlPath < 0)
    {
        vlPerror("vlCreatePath");
        return -1;
    }

    /* setup path */
    if (vlSetupPaths(lvData -> vlServer, (VLPathList)&lvData ->
vlPath,1,VL_SHARE, VL_SHARE) < 0) {
        vlPerror("vlSetupPaths");
        return -1;
    }

    /* select the appropriate events */
    if (vlSelectEvents(lvData -> vlServer, lvData -> vlPath,
VLStreamPreemptedMask |
                            VLControlChangedMask ) < 0)
    {
        vlPerror("Select Events");
        return -1;
    }

#ifdef XXX
    if (isrealityengine) {
        if (dofields) {
            vlCaptureType.intVal = VL_CAPTURE_NONINTERLEAVED;
        } else {
            vlCaptureType.intVal = VL_CAPTURE_INTERLEAVED;
        }
        vlSetControl(lvData -> vlServer, lvData -> vlPath, vlDrn, VL_CAP_TYPE,
&vlCaptureType);
    }
#endif
 vlCaptureType.intVal = VL_CAPTURE_INTERLEAVED;
 vlSetControl(lvData -> vlServer, lvData -> vlPath, vlDrn, VL_CAP_TYPE,
&vlCaptureType);
 switch( glTexFormat )
  {
   case PFTEX_RGBA_4:
    vlTexPack -> intVal = SIR_TEX_PACK_RGBA_4;
    break;
   case PFTEX_RGB_5:
    vlTexPack -> intVal = SIR_TEX_PACK_RGB_5;
    break;
   case PFTEX_RGBA_8:
    vlTexPack -> intVal = SIR_TEX_PACK_RGBA_8;
    break;
   default:
    vlTexPack -> intVal = SIR_TEX_PACK_RGB_5;
    glTexFormat = PFTEX_RGB_5;
    break;
  }
/* Set the Texture packing mode */

 vlSetControl(lvData -> vlServer, lvData -> vlPath, vlDrn, VL_PACKING,
vlTexPack);

/* Get the timing from input source */
 vlGetControl(lvData -> vlServer, lvData -> vlPath, vlSrc, VL_TIMING,
vlTiming);
/* Set texture drain's timing to input source */
 vlSetControl(lvData -> vlServer, lvData -> vlPath, vlDrn, VL_TIMING,
vlTiming);

/* Get corresponding size */
 vlGetControl(lvData -> vlServer, lvData -> vlPath, vlSrc, VL_SIZE, vlSize);

 fprintf ( stderr, "vl stuff done, now doing OpenGL\n");
#ifndef IRISGL /* OPENGL */
    {
        int f;
        pfWSDrawable drawable;
        pfGLContext context;

        const char *gl_extensions;
        int has_interlace;

        videosource = glXCreateGLXVideoSourceSGIX(lvData -> Dsp, 0 /* screen
*/,
                                                  lvData -> vlServer, lvData ->
vlPath, VL_TEXTURE,
                                                  vlDrn);
        if (videosource == None) {
            fprintf(stderr, "can't create video source\n");
            exit(EXIT_FAILURE);
        }
        else
         fprintf ( stderr, "video source ok\n");
        drawable = pfGetPWinWSDrawable( lvData -> pw);
        context = pfGetPWinGLCxt( lvData -> pw) ;
        fprintf ( stderr, "drawable %x context %x\n", drawable, context );
        f = glXMakeCurrentReadSGI( lvData -> Dsp, pfGetPWinWSDrawable(lvData ->
pw), videosource,
                              pfGetPWinGLCxt(lvData -> pw));
        fprintf ( stderr, "f = %d\n", f );
#ifdef XXX
        if (interlace) {
            gl_extensions = glGetString(GL_EXTENSIONS);
            if (!gl_extensions) {
                fprintf(stderr, "can't get GL_EXTENSIONS\n");
            }
            has_interlace = strstr((const char *) gl_extensions,
                                   "GL_SGIX_interlace") != NULL;
            glEnable(GL_INTERLACE_SGIX);
            if (!has_interlace || !glIsEnabled(GL_INTERLACE_SGIX)) {
                fprintf(stderr, "can't enable interlace extension\n");
                exit(EXIT_FAILURE);
            }
        }
#endif
    }
#endif
 fprintf ( stderr, "video init done\n" );
    return 0;
}

static void
setVideoTextureParameters( lvHandle lvData,
                           VLControlValue * vlSize,
                           VLControlValue * vlTiming,
                           VLControlValue * vlTexPack )

{
 pfMatrix *tmat;
 float s_scale, t_scale;
 int vlTexWidth, vlTexHeight;

 fprintf ( stderr, "video init %d %d %x %d\n", isrealityengine, TexComp,
glTexFormat, interlace );
    if ((vlTiming -> intVal == VL_TIMING_525_SQ_PIX)
|| (vlTiming -> intVal == VL_TIMING_525_CCIR601)) {
        vlTexWidth = 1024;
        vlTexHeight = 512;
    } else {
        vlTexWidth = 1024;
        vlTexHeight = 1024;
    }
    /* create texture matrix for scaling texcoords to valid part of texture */
    tmat = (pfMatrix*) pfCalloc(sizeof(pfMatrix), 1, pfGetSharedArena() );
    pfMakeIdentMat(*tmat);
    s_scale = vlSize -> xyVal.x / (float) vlTexWidth;
    t_scale = vlSize -> xyVal.y / (float) vlTexHeight;
    (*tmat)[0][0] = s_scale;
    (*tmat)[1][1] = -t_scale; /* invert in y because of video origin */
    (*tmat)[3][1] = t_scale; /* this is really a translate */
    /* gset callbacks to manage texture matrix - put matrix in userData */
    pfGStateFuncs( lvData -> gst, loadTextureMatrixCB, loadIDMatrixCB, tmat);

    if (dofields) {
        pfTexImage(*tex, NULL, TexComp, vlTexWidth, vlTexHeight/2, 1);
        if (isrealityengine) {
            pfTexLoadSize(*tex, 768, vlSize -> xyVal.y/2);
        } else {
            pfTexLoadSize(*tex, vlSize -> xyVal.x, vlSize -> xyVal.y/2);
        }
    } else {
        pfTexImage(*tex, NULL, TexComp, vlTexWidth, vlTexHeight, 1);
        if (isrealityengine) {
            pfTexLoadSize(*tex, 768, vlSize -> xyVal.y);
        } else {
            pfTexLoadSize(*tex, vlSize -> xyVal.x, vlSize -> xyVal.y);
        }
    }
    /* specify the texture format, this is the default */
 pfTexFormat ( *tex, PFTEX_INTERNAL_FORMAT, glTexFormat );
 pfTexLoadMode ( *tex, PFTEX_LOAD_SOURCE, PFTEX_SOURCE_VIDEO );
}

static void
VideoExit( lvHandle lvData )
{
 vlEndTransfer (lvData -> vlServer, lvData -> vlPath);
 vlDestroyPath (lvData -> vlServer, lvData -> vlPath);
 vlCloseVideo (lvData -> vlServer);
 exit(0);
}

/* callback to load texture matrix to invert the video image */
static int
loadTextureMatrixCB(pfGeoState *gs, void *userData)
{
    pfMatrix *tmat = (pfMatrix *)(userData);

/*
    int i,j;
    for ( i =0; i < 4; i++, fprintf ( stderr,"\n") )
    for ( j =0; j < 4; j++ )
     fprintf ( stderr, "%f ", (*tmat)[i][j] );
    fprintf ( stderr, "loadTextureMatrixCB %x\n", tmat);
*/
#ifdef IRISGL
    mmode(MTEXTURE);
    pfLoadMatrix(*tmat);
    mmode(MVIEWING);
#else
    glMatrixMode(GL_TEXTURE);
    pfLoadMatrix(*tmat);
    glMatrixMode(GL_MODELVIEW);
#endif

    return 0;
}

static int
loadIDMatrixCB(pfGeoState *gs, void *userData)
{
#ifdef IRISGL
    mmode(MTEXTURE);
    pfLoadMatrix(idmat);
    mmode(MVIEWING);
#else
    glMatrixMode(GL_TEXTURE);
    pfLoadMatrix(idmat);
    glMatrixMode(GL_MODELVIEW);
#endif
    return 0;
}

--------------------------------------------------------------------------------
makefile:

SHELL = /bin/sh

#-- provide a list of alternate locations for file searches
UNIQUE = .

#-- alternate locatins for included files
INCLUDE = \
        -I${UNIQUE} \
        -I/usr/include/Performer

#SRCLIBOPT=_igl
SRCLIBOPT=_ogl

PERFORMER = \
        -lpfdu${SRCLIBOPT} \
        -lpfutil${SRCLIBOPT} \
        -lpf${SRCLIBOPT}

#-- IRIX 4.x uses shared gl {gl_s} library {System-V Make lacks #if
movietex.cs}#LIBGL1 = -lgl
LIBGL1 = -lGL

LIBGL2 = ${LIBGL1:.4=_s}
LIBGL = ${LIBGL2:.5=}

SYSTEM = \
        -lInventor \
        -lmpc \
        -lvl \
        -limage \
        -lfm \
        ${LIBGL} \
        -lX11 \
        -lm \
        -lfpe \
        -lC

LIBRARIES = \
        ${PERFORMER} ${SYSTEM}

#-- select c-compiler options
CFLAGS = -xansi -g -D__STDC__ ${INCLUDE} ${COPT} -DPF_C_API=1 \
                 -DPF_CPLUSPLUS_API=0 \
                 -DPF_MAJOR_VERSION=2 -Xcpluscomm
#-DIRISGL

#-- base name of program
TARGET = lv

#-- object files from which target built {some are in the common directory}
OBJECTS = \
        lv.o

${TARGET}: ${OBJECTS}
        ${CC} ${CFLAGS} -o $++at++ ${OBJECTS} ${LIBRARIES}

#-- objects are built from either unique or common files
lv.o: ${UNIQUE}/lv.c
        ${CC} ${CFLAGS} -c lv.c -o $++at++

clean :
        rm -f lv lv.o

--------------------------------------------------------------------------------
=======================================================================
List Archives, FAQ, FTP: http://www.sgi.com/Technology/Performer.html
            Submissions: info-performer++at++sgi.com
        Admin. requests: info-performer-request++at++sgi.com


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:53:02 PDT

This message has been cleansed for anti-spam protection. Replace '++at++' in any mail addresses with the '@' symbol.