Angus Dorbie (dorbie++at++bitch.reading.sgi.com)
Mon, 12 Feb 1996 13:57:53 +0100
Even if youre not using a Sirius video the key is in using the
subtexload call in the draw process.
Rgds,
Angus.
On Feb 12, 11:26am, Jason Buksh wrote:
> Subject: Playing Video within Performer
> Simple Question
> =============
>
> I'm using Performer 1.2 and need a method
> for playing video footage (Any format). How
> do I go about this ??
>
> Jason Buksh
> VR Solutions
> j.buksh++at++vrsolns.co.uk
>
>-- End of excerpt from Jason Buksh
/*
* complex.c
*
* IRIS Performer example using cull and draw process callbacks.
* Mouse and keyboard go through GL which is simpler than mixed
* model (GLX), but does incur some overhead in the draw process.
*
* $Revision: 1.44 $
* $Date: 1994/03/16 01:54:30 $
*
* Run-time controls:
* ESC-key: exits
* F1-key: profile
* Left-mouse: advance
* Middle-mouse: stop
* Right-mouse: retreat
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <getopt.h> /* for cmdline handler */
#include <gl/device.h>
#include <vl/vl.h>
#include <vl/dev_sirius.h>
#include <Performer/pf.h>
#include "pfutil.h"
#include "pfflt.h"
#include "pfsgi.h"
static void CullChannel(pfChannel *chan, void *data);
static void DrawChannel(pfChannel *chan, void *data);
static void OpenPipeline(pfPipe *p);
static void UpdateView(void);
static void GetGLInput(void);
static void Usage(void);
static long Pre_Vid(pfTraverser *, void *);
static long Post_Vid(pfTraverser *, void *);
/* performer texture for sirius video */
static pfTexture *PVidTex;
/* GL handle on performer texture */
static long VideoTexture;
/*
* VL defines
*/
static VLControlValue size, timing, tex;
static VLControlValue format;
static VLControlValue cap_type;
static VLServer svr;
static VLPath path;
static VLNode src;
static VLNode drn;
static int DoFields = 0;
static float s_scale, t_scale, s_fraction, t_fraction;
static float texture_matrix[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
};
static float ident_matrix[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
};
#define Button1Mask 0x01
#define Button2Mask 0x02
#define Button3Mask 0x04
#define HISPEED 0.1f
#define LOSPEED 0.001f
/*
* structure that resides in shared memory so that the
* application, cull, and draw processes can access it.
*/
typedef struct
{
long exitFlag;
long inWindow;
float mouseX;
float mouseY;
long mouseButtons;
long winOriginX;
long winOriginY;
long winSizeX;
long winSizeY;
pfCoord view;
float sceneSize;
int drawStats;
} SharedData;
static SharedData *Shared;
/* light source created and updated in draw-process */
static pfLight *Sun;
/* for configuring multi-process */
static long ProcSplit = PFMP_APPCULLDRAW;
/* write out scene upon read-in - uses pfDebugPrint */
static long WriteScene = 0;
char ProgName[PF_MAXSTRING];
/*
* Usage() -- print usage advice and exit. This procedure
* is executed in the application process.
*/
static void
Usage (void)
{
fprintf(stderr, "Usage: %s [-p procSplit] [file.ext ...]\n", ProgName);
exit(1);
}
/*
* docmdline() -- use getopt to get command-line arguments,
* executed at the start of the application process.
*/
static long
docmdline(int argc, char *argv[])
{
long opt;
strcpy(ProgName, argv[0]);
/* process command-line arguments */
while ((opt = getopt(argc, argv, "wp:?")) != -1)
{
switch (opt)
{
case 'w':
WriteScene = 1;
break;
case 'p':
ProcSplit = atoi(optarg);
break;
case '?':
Usage();
}
}
return optind;
}
/*
* main() -- program entry point. this procedure
* is executed in the application process.
*/
int
main (int argc, char *argv[])
{
int arg;
int found;
pfNode *root;
pfChannel *chan;
pfScene *scene;
pfPipe *p;
pfEarthSky *eSky;
pfBox bbox;
float far = 10000.0f;
float sceneSize;
if (argc < 2)
Usage();
arg = docmdline(argc, argv);
pfInit();
/* configure multi-process selection */
pfMultiprocess(ProcSplit);
/* allocate shared before fork()'ing parallel processes */
Shared = (SharedData*)pfMalloc(sizeof(SharedData), pfGetSharedArena());
Shared->inWindow = 0;
Shared->exitFlag = 0;
Shared->drawStats = 1;
/* initiate multi-processing mode set in pfMultiprocess call */
pfConfig();
scene = pfNewScene();
/* specify directories where geometry and textures exist */
if (!(getenv("PFPATH")))
pfFilePath(
"."
":./data"
":../data"
":../../data"
":/usr/src/Performer/data"
);
fprintf(stderr,"FilePath: %s\n", pfGetFilePath());
p = pfGetPipe(0);
pfPhase(PFPHASE_FLOAT);
/* Open and configure full screen GL window. */
pfInitPipe(p, OpenPipeline);
pfFrameRate(20.0f);
chan = pfNewChan(p);
pfChanCullFunc(chan, CullChannel);
pfChanDrawFunc(chan, DrawChannel);
pfChanScene(chan, scene);
pfChanNearFar(chan, 0.1f, far);
/* Create an earth/sky model that draws sky/ground/horizon */
eSky = pfNewESky();
pfESkyMode(eSky, PFES_BUFFER_CLEAR, PFES_SKY_GRND);
pfESkyAttr(eSky, PFES_GRND_HT, -10.0f);
pfChanESky(chan, eSky);
/* vertical FOV is matched to window aspect ratio */
pfChanFOV(chan, 45.0f, -1.0f);
/* Set initial view to be "in front" of scene */
/* view point at center of bbox */
pfAddVec3(Shared->view.xyz, bbox.min, bbox.max);
pfScaleVec3(Shared->view.xyz, 0.5f, Shared->view.xyz);
pfSetVec3(Shared->view.hpr, 0.0f, 0.0f, 0.0f);
pfChanView(chan, Shared->view.xyz, Shared->view.hpr);
/* load files named by command line arguments */
for (found = 0; arg < argc; arg++)
{
if ((root = LoadFile(argv[arg], NULL)) != NULL)
{
pfAddChild(scene, root);
if(!found)
pfNodeTravFuncs( root, PFTRAV_DRAW, Pre_Vid, Post_Vid);
/*
pfPrint(root, PFPRINT_VB_ON, PFTRAV_SELF | PFTRAV_DESCEND, stdout);
*/
found++;
}
}
/* if no files successfully loaded, terminate program */
if (!found)
Usage();
/* determine extent of scene's geometry */
pfuTravCalcBBox(scene, &bbox);
/* find max dimension */
sceneSize = bbox.max[PF_X] - bbox.min[PF_X];
sceneSize = PF_MAX2(sceneSize, bbox.max[PF_Y] - bbox.min[PF_Y]);
sceneSize = PF_MAX2(sceneSize, bbox.max[PF_Z] - bbox.min[PF_Z]);
sceneSize = PF_MIN2(sceneSize, 0.5f * far);
Shared->sceneSize = sceneSize;
/* offset so all is visible */
Shared->view.xyz[PF_Y] -= sceneSize;
Shared->view.xyz[PF_Z] += 0.25f*sceneSize;
/* main simulation loop */
while (!Shared->exitFlag)
{
/* wait until next frame boundary */
pfSync();
/* Set view parameters. */
UpdateView();
pfChanView(chan, Shared->view.xyz, Shared->view.hpr);
/* initiate traversal using current state */
pfFrame();
}
/* terminate cull and draw processes (if they exist) */
pfExit();
/* exit to operating system */
exit(0);
}
/*
* UpdateView() updates the eyepoint based on the information
* placed in shared memory by GetGLInput().
*/
static void
UpdateView(void)
{
static float speed = 0.0f;
static float speedLimit = 4.0f;
pfCoord *view = &Shared->view;
float cp;
if (!Shared->inWindow)
{
speed = 0;
return;
}
switch (Shared->mouseButtons)
{
case Button1Mask: /* LEFTMOUSE: faster forward or slower backward*/
if (speed > 0.0f)
speed *= 1.2f;
else
speed /= 1.2f;
if (PF_ABSLT(speed, LOSPEED * Shared->sceneSize))
speed = LOSPEED * Shared->sceneSize;
else if (speed >= HISPEED * Shared->sceneSize)
speed = HISPEED * Shared->sceneSize;
break;
case Button2Mask: /* MIDDLEMOUSE: stop moving and pick */
speed = 0.0f;
break;
case Button3Mask: /* RIGHTMOUSE: faster backward or slower foreward*/
if (speed < 0.0f)
speed *= 1.2f;
else
speed /= 1.2f;
if (PF_ABSLT(speed, LOSPEED * Shared->sceneSize))
speed = -LOSPEED * Shared->sceneSize;
else if (speed <= -HISPEED * Shared->sceneSize)
speed = -HISPEED * Shared->sceneSize;
break;
}
/* update view direction */
view->hpr[PF_H] -= Shared->mouseX * PF_ABS(Shared->mouseX);
view->hpr[PF_P] = Shared->mouseY * PF_ABS(Shared->mouseY) * 90.0f;
view->hpr[PF_R] = 0.0f;
/* update view position */
cp = cosf(PF_DEG2RAD(view->hpr[PF_P]));
view->xyz[PF_X] += speed*sinf(-PF_DEG2RAD(view->hpr[PF_H])*cp);
view->xyz[PF_Y] += speed*cosf(-PF_DEG2RAD(view->hpr[PF_H])*cp);
view->xyz[PF_Z] += speed*sinf( PF_DEG2RAD(view->hpr[PF_P]));
}
/*
* OpenPipeline() -- create a pipeline: setup the window system,
* the IRIS GL, and IRIS Performer. this procedure is executed in
* the draw process (when there is a separate draw process).
*/
static void
OpenPipeline(pfPipe *p)
{
short MAT_mode;
float xSize = 800;
float ySize = 500;
int t_width, t_height;
/* negotiate with window-manager */
foreground();
winopen("IRIS Performer");
winconstraints();
/* register events of note with event-queue manager */
qdevice(ESCKEY);
qdevice(F1KEY);
/* open the server */
if (!(svr = vlOpenVideo(""))) {
printf("couldn't open video\n");
exit(1);
}
/* Get the Video source */
src = vlGetNode(svr, VL_SRC, VL_VIDEO, VL_ANY);
/* Get the Texture drain */
drn = vlGetNode(svr, VL_DRN, VL_TEXTURE, 0);
/* Create path */
path = vlCreatePath(svr, VL_ANY, src, drn);
if (path < 0) {
vlPerror("vlCreatePath");
exit(1);
}
/* setup path */
if (vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE, VL_SHARE) < 0) {
vlPerror("vlSetupPaths");
exit(1);
}
/* select the appropriate events */
if (vlSelectEvents(svr, path, VLStreamPreemptedMask |
VLControlChangedMask ) < 0) {
vlPerror("Select Events");
exit(1);
}
if(DoFields)
cap_type.intVal = VL_CAPTURE_NONINTERLEAVED;
else
cap_type.intVal = VL_CAPTURE_INTERLEAVED;
if (vlSetControl(svr, path, drn, VL_CAP_TYPE, &cap_type) <0) {
vlPerror("VlSetControl");
exit(1);
}
/* Update the video Timing Format (need to do this if a change is made) */
/* Get the timing from input source */
if (vlGetControl(svr, path, src, VL_TIMING, &timing) < 0) {
vlPerror("vlGetControl");
exit(1);
}
/* Set texture drain's timing to input source */
if (vlSetControl(svr, path, drn, VL_TIMING, &timing) < 0) {
vlPerror("vlSetControl");
exit(1);
}
if (vlGetControl(svr, path, src, VL_SIZE, &size) < 0) {
vlPerror("vlSetupPaths");
exit(1);
}
/* negotiate with GL */
pfInitGfx(p);
/* define a performer texture for use with sirius video */
PVidTex = pfNewTex(pfGetSharedArena());
pfTexRepeat(PVidTex, PFTEX_WRAP, PFTEX_CLAMP);
pfTexFilter(PVidTex, PFTEX_MINFILTER, PFTEX_BILINEAR);
pfTexFilter(PVidTex, PFTEX_MAGFILTER, PFTEX_BILINEAR);
pfTexFormat(PVidTex, PFTEX_FAST_DEFINE, PF_ON);
pfTexFormat(PVidTex, PFTEX_INTERNAL_FORMAT, PFTEX_RGB_5);
tex.intVal = SIR_TEX_PACK_RGB_5;
/* 625 textures are bigger than 525 textures */
if ((timing.intVal == VL_TIMING_525_SQ_PIX)
|| (timing.intVal == VL_TIMING_525_CCIR601)) {
t_width = 1024;
t_height = 512;
} else {
t_width = 1024;
t_height = 1024;
}
s_scale = (size.xyVal.x-1) / (float)t_width;
t_scale = size.xyVal.y / (float)t_height;
/* Sirius always transfers 768 pixels */
s_fraction = 768. / (float)t_width; /* for all */
t_fraction = size.xyVal.y / (float)t_height;
if (DoFields) t_height=t_height>>1;
/* frames, in fields is different */
pfTexImage(PVidTex, NULL, SIR_VEN_16BIT_TEXEL, t_width, t_height , 0);
VideoTexture = pfGetGLHandle((pfObject *)PVidTex);
texture_matrix[0][0] = s_scale;
texture_matrix[1][1] = -t_scale;
texture_matrix[3][1] = t_scale;
MAT_mode = getmmode();
mmode(MTEXTURE);
loadmatrix(texture_matrix);
/* Set the Texture packing mode */
if (vlSetControl(svr, path, drn, VL_PACKING, &tex) <0) {
vlPerror("VlSetControl");
exit(1);
}
loadmatrix(ident_matrix);
mmode(MAT_mode);
vlBeginTransfer(svr, path, 0, NULL);
/* create a light source in the "south-west" (QIII) */
Sun = pfNewLight(NULL);
pfLightPos(Sun, -0.3f, -0.3f, 1.0f, 0.0f);
/* create a default texture environment */
pfApplyTEnv(pfNewTEnv(NULL));
/* create a default lighting model */
pfApplyLModel(pfNewLModel(NULL));
pfApplyMtl(pfNewMtl(NULL));
/* enable culling of back-facing polygons */
pfCullFace(PFCF_BACK);
/*
* These enables should be set to reflect the majority of the
* database. If most geometry is not textured, then texture
* should be disabled. However, you then need to change the
* FLIGHT-format file reader. (pfflt.c)
*/
pfEnable(PFEN_TEXTURE);
pfEnable(PFEN_LIGHTING);
pfEnable(PFEN_FOG);
}
/*
* CullChannel() -- traverse the scene graph and generate a
* display list for the draw process. This procedure is
* executed in the cull process.
*/
static void
CullChannel(pfChannel *channel, void *data)
{
/*
* pfDrawGeoSet or other display listable Performer routines
* could be invoked before or after pfCull()
*/
pfCull();
}
/*
* DrawChannel() -- draw a channel and read input queue. this
* procedure is executed in the draw process (when there is a
* separate draw process).
*/
static void
DrawChannel (pfChannel *channel, void *data)
{
/* rebind light so it stays fixed in position */
pfLightOn(Sun);
/* erase framebuffer and draw Earth-Sky model */
pfClearChan(channel);
/* invoke Performer draw-processing for this frame */
pfDraw();
/* draw Performer throughput statistics */
if (Shared->drawStats)
pfDrawChanStats(channel);
/* read window origin and size (it may have changed) */
pfGetPipeSize(pfGetChanPipe(channel),
&Shared->winSizeX, &Shared->winSizeY);
pfGetPipeOrigin(pfGetChanPipe(channel),
&Shared->winOriginX, &Shared->winOriginY);
GetGLInput();
}
static void
GetGLInput(void)
{
long x, y;
while (qtest())
{
short value;
long device = qread(&value);
/* only act on key-down transitions */
if (value)
{
switch (device)
{
/* ESC-key signals end of simulation */
case ESCKEY:
Shared->exitFlag = 1;
break;
/* F1-key toggles channel-stats display */
case F1KEY:
Shared->drawStats = !Shared->drawStats;
break;
}
}
}
/* read cursor position (may be outside our window) */
x = getvaluator(MOUSEX);
y = getvaluator(MOUSEY);
Shared->inWindow = 0;
/* update cursor virtual position when cursor inside window */
if (x >= Shared->winOriginX &&
x < (Shared->winOriginX + Shared->winSizeX) &&
y >= Shared->winOriginY &&
y < (Shared->winOriginY + Shared->winSizeY))
{
Shared->inWindow = 1;
Shared->mouseX = 2.0f * ((x - Shared->winOriginX) /
(float)Shared->winSizeX) - 1.0f;
Shared->mouseY = 2.0f * ((y - Shared->winOriginY) /
(float)Shared->winSizeY) - 1.0f;
Shared->mouseButtons = ((getbutton(LEFTMOUSE) ? Button1Mask : 0) |
(getbutton(MIDDLEMOUSE) ? Button2Mask : 0) |
(getbutton(RIGHTMOUSE) ? Button3Mask : 0));
}
}
static long Pre_Vid(pfTraverser *trav, void *data)
{
short MAT_mode;
MAT_mode = getmmode();
mmode(MTEXTURE);
loadmatrix(texture_matrix);
mmode(MAT_mode);
pfApplyTex(PVidTex);
/* Load the texture from Sirius to Texture memory */
subtexload(TX_TEXTURE_0, VideoTexture, 0.0, s_fraction, 0.0, t_fraction,
0, (unsigned long *)0, SIR_VEN_16BIT_TEXEL);
pfOverride(PFSTATE_TEXTURE, PF_ON);
return PFTRAV_CONT;
}
static long Post_Vid(pfTraverser *trav, void *data)
{
short MAT_mode;
MAT_mode = getmmode();
mmode(MTEXTURE);
loadmatrix(ident_matrix);
mmode(MAT_mode);
pfOverride(PFSTATE_TEXTURE, PF_OFF);
return PFTRAV_CONT;
}
This archive was generated by hypermail 2.0b2 on Mon Aug 10 1998 - 17:52:23 PDT