Re: Strange Culling of Volume in Performer Scene (fwd)

New Message Reply Date view Thread view Subject view Author view

Eric Webster (ewebster@spawar.navy.mil)
Mon, 08 Mar 1999 17:40:06


This is a multi-part message in MIME format.

------=_NextPart_000_0041_01BE698A.B47C4940
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

[Chikai--I wasn't sure if you intended for me to repost this
to the volumizer mailing list, or if you were going to; but
since I had a little bit more to add, I decided to repost
it.]

[Angus--This email is the same as I originally CC'ed to
you, except for the addition of my machine specs.]

Below is a response I originally sent to Chikai and Angus.
Chikai asked permission to post it to the volumizer list.
Since I wanted to add my system configuration info, I decided
to repost it myself. (So if Chikai reposts it as well, you
will see two copies of the forwarded mail on the mailing list.
Sorry if that happens.)

Here is my machine configuration:
Onyx (not Onyx2) InfiniteReality
Triple-pipe, in triple-keyboard mode
IRIX 6.2
c++_dev 7.0
IRIX IM Dev SW (OSF/Motif 1.2.4)
GLUT 3.6
ifl_eoe 1.1.1
inventor_eoe 2.1.2
gl_dev.sw.widget
Performer 2.1
Volumizer 1.0

--Eric Webster (ewebster@spawar.navy.mil
SPAWARSYSCEN, San Diego

-----Original Message-----
From: Eric Webster [mailto:ewebster@spawar.navy.mil]
Sent: Friday, March 05, 1999 1:54 PM
To: Chikai Ohazama
Cc: dorbie@sgi.com
Subject: RE: Strange Culling of Volume in Performer Scene (fwd)

Chikai (and Angus):

Thanks for your quick replies to my problems. After reading
Angus' reply and reviewing my code, I am still unsure as to
the problem.

Before I continue, I should warn you that this email is coming
from a WIN98 machine. The attachments probably all got their
end-of-lines converted to the MSDOS convention. So you
may have to deal with that. (My Performer development system
is cut off from the outside world, so I had to put the code
onto tape to get it out of the lab.)

I am attaching my code (main8.cxx and pfVONode8.cxx), plus
the Makefile (Makefile8) and a script (runit8) for running
the executable. Note that I am not attaching the image data
referenced in runit8, as it is about 10MB in size. The
image data that I am using is some of the images that ship
with the Volumizer release. The image files are
".../Volumizer/data/volumes/Phantom/raw/head*.ima"
(head002.ima, head003.ima ... head078.ima).

In order to compile and link this code it is necessary to have
the OpenGL Volumizer release installed.

My code is based upon the main.cxx and pfVONode.cxx source
that shipped with Volumizer (as the Performer demo).
As I mentioned in my previous email, I replaced the
IFL routines with the myReadBrickRaw() routine used
in the voglRaw example. I had to make some additional
changes to the code in order to use this I/O routine.

In main8.cxx you can see that I add three copies of
x29.sv to the scene (each under a DCS), and then
I add the "VOLUME" node.

In pfVONode8.cxx you can find pfVONode::pfVONode(), which
calls init(), which defines pfVONode as a new pfType.
Then pfVONode() continues on and sets a STATIC bound
for the "VOLUME" node, and it also sets the node's
postDraw callback function.

So the scene looks something like the following

SCENE
/ / | | \
/ / / \ \
__/ / / \ \
/ / / \ \
/ / | \ \
/ / | | \
Light DCS1 DCS2 DCS3 VOLUME
Src | | |
| | |
X29a X29b X29c

Further on in main8.cxx I check the bounds on each
of the nodes, and they seem correct. (The three
X29 DCS's have dynamic bounds, and the VOLUME node
has a STATIC bound as set in pfVONode::pfVONode().

Then, in the main loop of main8.cxx, I have X29a and
X29b rotating about the VOLUME, while X29c (which is
scaled smaller) is stationary in the center of the
VOLUME.

In my previous email, I indicated that the strange
culling of the VOLUME node seemed to be affected solely
by the position of X29c relative to the viewing window.
After further testing, I find the situation is actually
slightly different, as follows:

If the centerpoint of X29c is within the viewing
window, then the VOLUME is drawn, regardless of the
position of X29a and X29b.

If the centerpoint of X29c is out of view, but the
bounding volume of X29c is still in view (for example,
a bit of the tail of X29c is still in view), then the
VOLUME is NOT drawn, regardless of the position of X29a
and X29b.

If X29c is totally out of view (far enough so that it's
bounding volume is completely out of the viewing frustrum),
then the drawing of the VOLUME becomes dependent on
X29a and X29b as follows:

If the centerpoint of either of X29a or X29b is within
view, then the VOLUME is drawn.

If both of the centerpoints of X29a and X29b are
out-of-view, but one or both of their bounding volumes are
still within view, then the VOLUME is NOT drawn.

If X29a and X29b are totally out of view, then
the VOLUME is drawn.

In all cases, the three copies of the X29 appear normal.
(That is, they are always drawn...as long as they are
within view.)

I realize that one solution would be to do as Angus suggests
and "add the volumizer output to the scene graph as a geoset
instead of using a draw callbacks." However, I believe that
if I do this, I will need to replace the voGeometryActions::draw()
with my own code that somehow extracts the "polygonSet" geometry
that is created by voGeometryActions::polygonize() and either
insert it into the scene graph or draw it in some other
fashion. The Volumizer documentation indicates that I will need
to tackle this problem if I ever want to combine translucent
Performer objects with Volumizer objects, but I was hoping to
put that off until I was a little more familiar with
Volumizer.

Is there something I am missing here that is causing this
problem? It seems that, with the boundingVolume set
on the "volume" node, I should not be seeing this problem.
(But, perhaps I did not completely understand Angus'
reply.)

Note that, in the above, when I say that the "VOLUME" is
not drawn, I mean that neither the actual volume nor the
wireframe are drawn. That is, it does indeed appear as
if the volume node's draw callback is not being executed
for those cases described above.

Anyway, thanks for your help!

--Eric Webster (ewebster@spawar.navy.mil)
SPAWARSYSCEN, San Diego

PS: Is there any Performer source code available that
has an example of combining translucent Performer objects
with Volumizer volumes? (I am assuming that such code
would show an example of extracting the polygonSets of
the volume, merge-sorting them with the translucent
Performer objects, and drawing them with something other
than voGeometryActions::draw().)

> -----Original Message-----
> From: Chikai Ohazama [mailto:chikai@talula.engr.sgi.com]
> Sent: Thursday, March 04, 1999 10:15 PM
> To: ewebster@spawar.navy.mil
> Subject: Re: Strange Culling of Volume in Performer Scene (fwd)
>
>
>
> ---------- Forwarded message ----------
> Date: Thu, 04 Mar 1999 18:17:49 -0800
> From: Angus Dorbie <>
> To: Chikai Ohazama <chikai@talula.engr.sgi.com>
> Cc: tzelin@cthulhu, don_burns@cthulhu, dorbie@cthulhu, rg@sgi.com
> Subject: Re: Strange Culling of Volume in Performer Scene (fwd)
>
> The bound box of the x29 or your volumizer geometry has not been
> calculated properly or even at all, when it was added to the scene
> graph.
>
> You need to look at the geoset code, you can make bound box calculations
> automatic or you can set a fixed bound box, automatic would be expensive
> if you have dynamic geometry.
>
> If you are drawing your geometry in a draw callback then what you are
> seeing is exactly as I'd expect, the X29 is being culled and the draw
> callback is never invoked. You need to adjust the bound volume of the
> X29 to include your data, or add the volumizer output to the scene graph
> as a geoset instead of using a draw callbacks. In many respects with
> callbacks Performer doesn't know your data exists, it just calls your
> code whenever it draws the data it knows about.
>
> Cheers,Angus.
>
> Chikai Ohazama wrote:
> >
> > I'm not that famiilar with Performer and I thought you guys may
> have some
> > insight into his problem, so do you guys think you could help out this
> > guy?
> >
> > Thanks.
> >
> > ________________________________________________________________________
> > Chikai J. Ohazama, Ph.D. Silicon Graphics Computer Systems
> > Member of Technical Staff 2011 N. Shoreline Blvd. ms 525
> > Advanced Graphics Division Mountain View, CA 94043.1389
> > Telephone: (650) 933-6533
> > FAX: (650) 964-8671
> >
>
> --
> "Only the mediocre are always at their best." -- Jean Giraudoux
>
> For advanced 3D graphics Performer + OpenGL based examples and tutors:
> http://www.dorbie.com/
>

------=_NextPart_000_0041_01BE698A.B47C4940
Content-Type: application/octet-stream;
name="runit8"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="runit8"

#!/bin/csh -f
#
# OpenGL Volumizer demos using IRIS Performer
# perfvol shows how to build a simple Perfomer wrapper on Volumizer code
#

setenv DATAPATH /usr/share/Volumizer/data/volumes/Phantom/

# simple Performer based Volume viewer
# use mouse buttons to manipulate
./perfvol8 0 256 256 77 1 ushort $DATAPATH/raw/*ima

------=_NextPart_000_0041_01BE698A.B47C4940
Content-Type: application/octet-stream;
name="Makefile8"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="Makefile8"

#!smake
#
include /usr/include/make/commondefs

OPTIMIZER=3D-g

C++FILES =3D \
main8.C \
pfVONode8.C \
$(NULL)

C++OBJS =3D $(C++FILES:.C=3D.o)

TARGETS =3D perfvol8

default all: $(TARGETS)

include $(COMMONRULES)

perfvol8: $(C++OBJS)
$(C++F) -o $@ $(C++OBJS) -lvo -lpfui -lpfutil -lpf -lpfdu -lGL -lGLw =
-lXm -lXt -lX11 -lm -lfpe

------=_NextPart_000_0041_01BE698A.B47C4940
Content-Type: application/octet-stream;
name="main8.cxx"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="main8.cxx"

/**
* (c) Copyright 1996, 1997, 1998 Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the =
above
* copyright notice appear in all copies and that both the copyright =
notice
* and this permission notice appear in supporting documentation, and =
that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without =
specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#include <Performer/pf/pfPipe.h>
#include <Performer/pf/pfPipeWindow.h>
#include <Performer/pf/pfChannel.h>
#include <Performer/pf/pfNode.h>
#include <Performer/pf/pfScene.h>
#include <Performer/pf/pfDCS.h>
#include <Performer/pf/pfLightSource.h>
#include <Performer/pr/pfLinMath.h>
#include <Performer/pf.h>
#include <Performer/prmath.h>
#include <Performer/pfutil.h>
#include <Performer/pfdu.h>
#include <Performer/pfui/pfiXformer.h>

#include "pfVONode.h"

struct SharedData {
pfPipe* p;
pfPipeWindow* pw;
pfChannel* chan;
pfScene* scene;
pfDCS* dcs;
pfVONode* volume;
int exitflag;
pfuMouse mouse;
pfuEventStream events;
pfiTDFXformer* xformer;
};

SharedData* shared;

static void
openPipeWin(pfPipeWindow* pw)
{
pw->open();
}

void
main(int argc, char** argv)
{
pfNode *obj1, *obj2, *obj3;
pfDCS *dcs1, *dcs2, *dcs3;
pfSphere bsphere;
pfSphere bsphere2;
int boundtype;

if (argc < 8) {
fprintf(stderr, "usage: %s headerLength xVolumeSize yVolumeSize =
zVolumeSize cVolumeSize dataType image1 ... imageN\n", argv[0]);
exit(EXIT_FAILURE);
}

// Init Performer
pfInit();
/*
pfNotifyLevel(PFNFY_LEVEL_MAX);
*/
pfNotifyLevel(PFNFY_INFO);
pfMultiprocess(PFMP_APP_CULL_DRAW);
pfMultipipe(1);

// Create internal shared data area
shared =3D =
(SharedData*)pfMalloc(sizeof(SharedData),pfGetSharedArena());
shared->exitflag =3D FALSE;

/* Load all loader DSO's before pfConfig() forks */
pfdInitConverter("x29.sv");

// Create the pipes and start the processes
pfConfig();

pfFilePath(".:/usr/share/Performer/data");

// Construct the scene graph
shared->volume =3D new pfVONode;
if (shared->volume->loadImage(argc, argv))
{
fprintf(stderr, "usage: %s headerLength xVolumeSize yVolumeSize =
zVolumeSize cVolumeSize dataType image1 ... imageN\n", argv[0]);
exit(EXIT_FAILURE);
}

shared->dcs =3D new pfDCS;

shared->scene =3D new pfScene;

shared->scene->addChild(new pfLightSource);

obj1 =3D pfdLoadFile("x29.sv");
dcs1 =3D new pfDCS;
dcs1->addChild(obj1);
dcs1->setScale(3.0f);

obj2 =3D pfdLoadFile("x29.sv");
dcs2 =3D new pfDCS;
dcs2->addChild(obj2);
dcs2->setScale(3.0f);

obj3 =3D pfdLoadFile("x29.sv");
dcs3 =3D new pfDCS;
dcs3->addChild(obj3);
dcs3->setScale(0.3f);

shared->scene->addChild(dcs1);
shared->scene->addChild(dcs2);
shared->scene->addChild(dcs3);

shared->scene->addChild(shared->volume);

pfPhase(PFPHASE_LIMIT);

// Construct the Channel and PipeWindow
shared->p =3D pfGetPipe(0);

shared->pw =3D new pfPipeWindow(shared->p);
shared->pw->setName("Performer/Volumizer Demo");
shared->pw->setSize(512, 512);
shared->pw->setConfigFunc(openPipeWin);
shared->pw->config();

shared->chan =3D new pfChannel(shared->p);
shared->chan->setScene(shared->scene);
shared->chan->setNearFar(.01f, 100000.f);
shared->chan->setTravMode(PFTRAV_CULL, =
PFCULL_VIEW|PFCULL_SORT|PFCULL_GSET);
#if 0
shared->chan->makeOrtho(-256, 256, -256, 256);
#endif
shared->chan->setFOV(50, 50);

// Setup the trackball transformer
pfiInit();

shared->xformer =3D new pfiTDFXformer;
shared->xformer->setAutoInput(shared->chan, &shared->mouse,
&shared->events);
shared->xformer->setNode(shared->scene);
shared->xformer->setAutoPosition(shared->chan, NULL);

pfCoord initPos;
initPos.xyz.set(0, -1000, 0);
initPos.hpr.set(0, 0, 0);
shared->xformer->setResetCoord(&initPos);

shared->xformer->selectModel(PFITDF_FLY);

shared->xformer->stop();
shared->xformer->setCoord(&initPos);

pfMatrix mat;
shared->xformer->getMat(mat);
shared->chan->setViewMat(mat);

pfuInitInput(shared->pw, PFUINPUT_X);

boundtype =3D dcs1->getBound(&bsphere2);
if (boundtype =3D=3D PFBOUND_STATIC)
{
printf("bound(dcs1) =3D (%f, %f, %f) (%f) STATIC\n",
bsphere2.center[0],
bsphere2.center[1],
bsphere2.center[2],
bsphere2.radius);
}
else if (boundtype =3D=3D PFBOUND_DYNAMIC)
{
printf("bound(dcs1) =3D (%f, %f, %f) (%f) DYNAMIC\n",
bsphere2.center[0],
bsphere2.center[1],
bsphere2.center[2],
bsphere2.radius);
}
else
{
printf("bound(dcs1) UNKNOWN TYPE\n");
}

boundtype =3D dcs2->getBound(&bsphere2);
if (boundtype =3D=3D PFBOUND_STATIC)
{
printf("bound(dcs2) =3D (%f, %f, %f) (%f) STATIC\n",
bsphere2.center[0],
bsphere2.center[1],
bsphere2.center[2],
bsphere2.radius);
}
else if (boundtype =3D=3D PFBOUND_DYNAMIC)
{
printf("bound(dcs2) =3D (%f, %f, %f) (%f) DYNAMIC\n",
bsphere2.center[0],
bsphere2.center[1],
bsphere2.center[2],
bsphere2.radius);
}
else
{
printf("bound(dcs2) UNKNOWN TYPE\n");
}

boundtype =3D dcs3->getBound(&bsphere2);
if (boundtype =3D=3D PFBOUND_STATIC)
{
printf("bound(dcs3) =3D (%f, %f, %f) (%f) STATIC\n",
bsphere2.center[0],
bsphere2.center[1],
bsphere2.center[2],
bsphere2.radius);
}
else if (boundtype =3D=3D PFBOUND_DYNAMIC)
{
printf("bound(dcs3) =3D (%f, %f, %f) (%f) DYNAMIC\n",
bsphere2.center[0],
bsphere2.center[1],
bsphere2.center[2],
bsphere2.radius);
}
else
{
printf("bound(dcs3) UNKNOWN TYPE\n");
}

boundtype =3D shared->volume->getBound(&bsphere2);
if (boundtype =3D=3D PFBOUND_STATIC)
{
printf("bound(volume) =3D (%f, %f, %f) (%f) STATIC\n",
bsphere2.center[0],
bsphere2.center[1],
bsphere2.center[2],
bsphere2.radius);
}
else if (boundtype =3D=3D PFBOUND_DYNAMIC)
{
printf("bound(volume) =3D (%f, %f, %f) (%f) DYNAMIC\n",
bsphere2.center[0],
bsphere2.center[1],
bsphere2.center[2],
bsphere2.radius);
}
else
{
printf("bound(volume) UNKNOWN TYPE\n");
}

shared->scene->getBound(&bsphere);

// Main loop
pfFrame();

while (!shared->exitflag) {
float s, c, t;

t =3D pfGetTime();
pfSinCos(10.0f*t, &s, &c);
dcs1->setTrans(bsphere.radius*s, -bsphere.radius*c, 0.0f);
dcs1->setRot(-90.0f+10.0f*t, 0.0f, 0.0f);

pfSinCos(3.8f*t, &s, &c);
dcs2->setTrans(bsphere.radius*s, -bsphere.radius*c, 0.0f);
dcs2->setRot(-90.0f+3.8f*t, 0.0f, 0.0f);

dcs3->setTrans(0.0f, 0.0f, 0.0f);

pfSync();

pfFrame();

// Process input events
pfuGetEvents(&shared->events);

pfuGetMouse(&shared->mouse);
pfiUpdateXformer(shared->xformer);

for (int i=3D0; i < shared->events.numDevs; i++) {
int dev =3D shared->events.devQ[i];

if (shared->events.devCount[dev] > 0) {
switch (dev) {
case PFUDEV_WINQUIT:
shared->exitflag =3D TRUE;
break;

case PFUDEV_KEYBD:
for (int j=3D0; j<shared->events.numKeys; j++) {
int key =3D shared->events.keyQ[i];
if (shared->events.keyCount[key]) {
switch (key) {
case 27:
shared->exitflag =3D TRUE;
break;
case 'r':
shared->xformer->stop();
shared->xformer->setCoord(&initPos);
shared->xformer->getMat(mat);
shared->chan->setViewMat(mat);
break;
default:
break;
}
shared->events.keyCount[key] =3D 0;
}
}
}
}
}
shared->events.numDevs =3D 0;
}

pfuExitInput();
pfuExitUtil();
pfExit();

exit(EXIT_SUCCESS);
}

------=_NextPart_000_0041_01BE698A.B47C4940
Content-Type: application/octet-stream;
name="pfVONode8.cxx"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="pfVONode8.cxx"

/**
* (c) Copyright 1996, 1997, 1998 Silicon Graphics, Inc.
* ALL RIGHTS RESERVED
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that the =
above
* copyright notice appear in all copies and that both the copyright =
notice
* and this permission notice appear in supporting documentation, and =
that
* the name of Silicon Graphics, Inc. not be used in advertising
* or publicity pertaining to distribution of the software without =
specific,
* written prior permission.
*
* THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
* AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
* SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
* KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
* LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
* THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
* ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
* POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
*
* US Government Users Restricted Rights
* Use, duplication, or disclosure by the Government is subject to
* restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
* (c)(1)(ii) of the Rights in Technical Data and Computer Software
* clause at DFARS 252.227-7013 and/or in similar or successor
* clauses in the FAR or the DOD or NASA FAR Supplement.
* Unpublished-- rights reserved under the copyright laws of the
* United States. Contractor/manufacturer is Silicon Graphics,
* Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/

#include <stdlib.h>
#include <alloca.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <iostream.h>
#include <unistd.h>
#include <fcntl.h>

#include <Performer/pf/pfPipe.h>
#include <Performer/pf/pfPipeWindow.h>
#include <Performer/pf/pfChannel.h>
#include <Performer/pf/pfNode.h>
#include <Performer/pf/pfScene.h>
#include <Performer/pf/pfDCS.h>
#include <Performer/pf/pfLightSource.h>
#include <Performer/pr/pfLinMath.h>
#include <Performer/prmath.h>
#include <Performer/pfutil.h>
#include <Performer/pfdu.h>
#include <Performer/pfui/pfiXformer.h>
#include <Performer/pf.h>
#include <Performer/pr/pfGeoSet.h>

/*
#include <ifl/iflTypeNames.h>
#include <ifl/iflDataSize.h>
*/

#include <vo/utPerfMeter.h>

#include "pfVONode.h"

struct SharedData {
pfPipe* p;
pfPipeWindow* pw;
pfChannel* chan;
pfScene* scene;
pfDCS* dcs;
pfVONode* volume;
int exitflag;
pfuMouse mouse;
pfuEventStream events;
pfiTDFXformer* xformer;
};

extern SharedData* shared;

pfType* pfVOData::classType =3D NULL;
pfType* pfVONode::classType =3D NULL;

void*
pfVOData::operator new(size_t s)
{
return operator new(s, pfGetSharedArena());
}

void*
pfVOData::operator new(size_t s, void* arena)
{
return pfMemory::operator new(sizeof(pfMemory), s-sizeof(pfMemory), =
arena);
}

/*
void*
pfVOData::operator new(size_t s, pfFluxMemory* fmem)
{
return pfMemory::operator new(0, s, fmem);
}
*/

void
pfVOData::init()
{
if (classType =3D=3D NULL) {
pfMemory::init();
classType =3D new pfType(pfMemory::getClassType(), "pfVOData");
}
}

pfVOData::pfVOData()
{
init();
setType(classType);
}

void
pfVONode::init()
{
if (classType =3D=3D NULL) {
pfNode::init();
classType =3D new pfType(pfNode::getClassType(), "pfVONode");
}
}

pfVONode::pfVONode()
: volume(NULL), tetraSet(NULL), cubeVertices(NULL), =
polygonVertexData(NULL),
polygonSet(NULL), brickCount(0), sampleCount(0), lut(NULL),
lutEntries(NULL)
{
init();

// Setup initial data
getUpdatableData();

// Misc initialization
setType(classType);

// XXX This is a hack, should really compute bound from volume
// XXX geometry. The fix for this would be to build a loader.
pfSphere bound;
bound.center[0] =3D bound.center[1] =3D bound.center[2] =3D 0;
bound.radius =3D 256;
setBound(&bound, PFBOUND_STATIC);
printf("pfVONode->setBouund(center=3D(%f, %f, %f), radius=3D%f)\n",
bound.center[0], bound.center[1], bound.center[2], bound.radius);

// Setup for Performer drawing
setTravFuncs(PFTRAV_DRAW, NULL, postDrawCB);
setTravData(PFTRAV_DRAW, this);
}

void
pfVONode::cleanup()
{
delete lut;
lut =3D NULL;

delete [] lutEntries;
lutEntries =3D NULL;

for (int i =3D 0; i < brickCount; i++) {
for (int j =3D 0; j <=3D sampleCount; j++)
delete polygonSet[i][j];
delete [] polygonSet[i];
}
delete [] polygonSet;
polygonSet =3D NULL;

delete polygonVertexData;
polygonVertexData =3D NULL;

delete [] cubeVertices;
cubeVertices =3D NULL;

delete tetraSet;
tetraSet =3D NULL;

delete volume;
volume =3D NULL;

}

pfVONode::~pfVONode()
{
cleanup();
}

pfVOData*
pfVONode::getUpdatableData()
{
pfVOData* data =3D getCurData();

// Has data been propagated? If so, the refcount will not be one
if (data =3D=3D NULL || data->getRef() !=3D 1) {
pfVOData* tdata =3D new pfVOData;

if (data =3D=3D NULL) {
tdata->update =3D 0;
tdata->imageFiles =3D NULL;
tdata->interpolationType =3D voInterpolationTypeScope::DEFAULT;
tdata->renderingMode =3D voRenderingModeScope::MONOCHROME;
tdata->rangeLo =3D tdata->rangeHi =3D -1; // XXX don't scale range
tdata->lutType =3D voLookupTableTypeScope::POST_INTERPOLATION;
tdata->lutCenter =3D 128;
tdata->lutWidth =3D 256;
tdata->lutFile[0] =3D '\0';
tdata->scaleX =3D tdata->scaleY =3D 0.94;
tdata->scaleZ =3D 3.0;
tdata->tesselationSize =3D 8;
tdata->tesselationMin =3D 40;
tdata->tesselationMax =3D 255;
} else
*tdata =3D *data;

setUserData(data =3D tdata);
}
return data;
}

int
pfVONode::loadImage(int argc, char** argv)
{
int headerLength;
int xVolumeSize;
int yVolumeSize;
int zVolumeSize;
int cVolumeSize;

// Tell the draw process to load new imagery
pfVOData* data =3D getUpdatableData();

if (sscanf(argv[1], "%d", &headerLength) !=3D 1)
{
return -1;
}
if (sscanf(argv[2], "%d", &xVolumeSize) !=3D 1)
{
return -1;
}
if (sscanf(argv[3], "%d", &yVolumeSize) !=3D 1)
{
return -1;
}
if (sscanf(argv[4], "%d", &zVolumeSize) !=3D 1)
{
return -1;
}
if (sscanf(argv[5], "%d", &cVolumeSize) !=3D 1)
{
return -1;
}
if ( (cVolumeSize !=3D 1) && (cVolumeSize !=3D 4) )
{
fprintf(stderr,
"Usage: %s: 5th argument (cVolumeSize) has to be \"1\" or \"4\".\n",
argv[0]);
return -1;
}
data->headerLength =3D headerLength;
data->xVolumeSize =3D xVolumeSize;
data->yVolumeSize =3D yVolumeSize;
data->zVolumeSize =3D zVolumeSize;
data->cVolumeSize =3D cVolumeSize;
printf("headerLength =3D %d\n", data->headerLength);
printf("xVolumeSize =3D %d\n", data->xVolumeSize);
printf("yVolumeSize =3D %d\n", data->yVolumeSize);
printf("zVolumeSize =3D %d\n", data->zVolumeSize);
printf("cVolumeSize =3D %d\n", data->cVolumeSize);
if (!strcmp(argv[6], "byte")) {
strcpy(data->dataType, argv[6]);
printf("dataType =3D <%s>\n", data->dataType);
} else if (!strcmp(argv[6], "ubyte")) {
strcpy(data->dataType, argv[6]);
printf("dataType =3D <%s>\n", data->dataType);
} else if (!strcmp(argv[6], "short")) {
strcpy(data->dataType, argv[6]);
printf("dataType =3D <%s>\n", data->dataType);
} else if (!strcmp(argv[6], "ushort")) {
strcpy(data->dataType, argv[6]);
printf("dataType =3D <%s>\n", data->dataType);
} else if (!strcmp(argv[6], "float")) {
strcpy(data->dataType, argv[6]);
printf("dataType =3D <%s>\n", data->dataType);
} else {
fprintf(stderr,
"Usage: %s: 6th argument (dataType) has to be \"byte\" =
or \"ubyte\" or \"short\" or \"ushort\" or \"float\".\n",
argv[0]);
return -1;
}

if (argc - 7 !=3D zVolumeSize) {
fprintf(stderr,
"Error: the length of the file list does not match =
zVolumeSize.\n");
return -1;
}
printf("DEBUG: loadImage(): argc-7 =3D %d\n", argc-7);

data->imageFiles =3D argv + 7;
data->update |=3D pfVOData::UpdateImageFile;

return 0;
}

void
pfVONode::setInterpolationType(voInterpolationType itype)
{
if (getCurData()->interpolationType !=3D itype) {
pfVOData* data =3D getUpdatableData();
data->interpolationType =3D itype;
data->update |=3D pfVOData::UpdateInterpolationType;
}
}

void
pfVONode::setRenderingMode(voRenderingMode rmode)
{
if (getCurData()->renderingMode !=3D rmode) {
pfVOData* data =3D getUpdatableData();
data->renderingMode =3D rmode;
data->update |=3D pfVOData::UpdateRenderingMode;
}
}

void
pfVONode::setDataScaleRange(float lo, float hi)
{
pfVOData* data =3D getCurData();
if (data->rangeLo !=3D lo || data->rangeHi !=3D hi) {
data =3D getUpdatableData();
data->rangeLo =3D lo;
data->rangeHi =3D hi;
data->update |=3D pfVOData::UpdateRange;
}
}

void
pfVONode::setLutType(voLookupTableType lutType)
{
if (getCurData()->lutType !=3D lutType) {
pfVOData* data =3D getUpdatableData();
data->lutType =3D lutType;
data->update |=3D pfVOData::UpdateLutParms;
}
}

void
pfVONode::setLutParms(uint_t center, uint_t width)
{
pfVOData* data =3D getCurData();
if (data->lutCenter !=3D center || data->lutWidth !=3D width) {
data =3D getUpdatableData();
data->lutCenter =3D center > 256 ? 256 : center;
data->lutWidth =3D width > 256 ? 256 : width;
data->update |=3D pfVOData::UpdateLutParms;
}
}

void
pfVONode::loadLut(const char* lutFile)
{
pfVOData* data =3D getUpdatableData();
strcpy(data->lutFile, lutFile);
data->update |=3D pfVOData::UpdateLutFile;
}

void
pfVONode::setVoxelSize(float x, float y, float z)
{
pfVOData* data =3D getCurData();
if (data->scaleX !=3D x || data->scaleY !=3D y || data->scaleZ !=3D =
z) {
data =3D getUpdatableData();
data->scaleX =3D x;
data->scaleY =3D y;
data->scaleZ =3D z;
data->update |=3D pfVOData::UpdateScale;
}
}

void
pfVONode::setTesselationParms(int size, float min, float max)
{
pfVOData* data =3D getCurData();
if (data->tesselationSize !=3D size || data->tesselationMin !=3D min =
||
data->tesselationMax !=3D max) {
data =3D getUpdatableData();
data->tesselationSize =3D size;
data->tesselationMin =3D min;
data->tesselationMax =3D max;
data->update |=3D pfVOData::UpdateTesselation;
}
}

int
pfVONode::getTile(char *fileName, void *data,
int xBrickOrigin, int yBrickOrigin,
int xBrickSize, int yBrickSize,
int xVolumeSize, int /* yVolumeSize */,
int headerLength, int bytesPerVoxel)
{

int fd =3D open(fileName, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "%s():Cannot open file %s for reading.\n",
"getTile", fileName);
return -1;
}
char *ptr =3D (char *) data; /* DataType */

for (int j1 =3D yBrickOrigin; j1 < yBrickOrigin + yBrickSize;
j1++) {
int pos =3D
headerLength + (j1 * xVolumeSize + xBrickOrigin) * =
bytesPerVoxel;

if (lseek(fd, pos, SEEK_SET) !=3D pos) {
fprintf(stderr, "%s():Cannont position file %s.\n",
"getTile",
fileName);
close(fd);
return -2;
}
if (read(fd, ptr, bytesPerVoxel * xBrickSize) !=3D bytesPerVoxel =
* xBrickSize) {
fprintf(stderr, "%s():Short read in file %s.\n", "getTile",
fileName);
close(fd);
return -3;
}
ptr +=3D xBrickSize * bytesPerVoxel;
}

close(fd);

return 0;

}

int
pfVONode::myReadBrickRaw(char **fileNames, void *data, /* =
DataType */
int xBrickOrigin, int yBrickOrigin, int zBrickOrigin,
int xBrickSize, int yBrickSize, int zBrickSize,
int xVolumeSize, int yVolumeSize, int zVolumeSize,
int headerLength, int bytesPerVoxel)
{

assert(xBrickOrigin >=3D 0 && xBrickOrigin < xVolumeSize);
assert(yBrickOrigin >=3D 0 && yBrickOrigin < yVolumeSize);
assert(zBrickOrigin >=3D 0 && zBrickOrigin < zVolumeSize);

char *ptr =3D (char *) data; /* DataType */

// is this a full brick?
if ((xBrickOrigin + xBrickSize <=3D xVolumeSize) &&
(yBrickOrigin + yBrickSize <=3D yVolumeSize) &&
(zBrickOrigin + zBrickSize <=3D zVolumeSize)
) {
for (int iz =3D zBrickOrigin; iz < (zBrickOrigin + zBrickSize); =
iz++) {
if (getTile(fileNames[iz], ptr,
xBrickOrigin, yBrickOrigin,
xBrickSize, yBrickSize,
xVolumeSize, yVolumeSize,
headerLength, bytesPerVoxel) !=3D 0) {
fprintf(stderr, "%s(): Unable to read a tile.\n",
"myReadBrickRaw");
return -1;
}
ptr +=3D xBrickSize * yBrickSize * bytesPerVoxel;

} // iz

} else // deal with partial bricks
{
int xPartBrickSize, yPartBrickSize, zPartBrickSize;

xPartBrickSize =3D xBrickOrigin + xBrickSize <=3D xVolumeSize ?
xBrickSize : xVolumeSize - xBrickOrigin;
yPartBrickSize =3D yBrickOrigin + yBrickSize <=3D yVolumeSize ?
yBrickSize : yVolumeSize - yBrickOrigin;
zPartBrickSize =3D zBrickOrigin + zBrickSize <=3D zVolumeSize ?
zBrickSize : zVolumeSize - zBrickOrigin;

char *buffer =3D /* DataType */
new char[xPartBrickSize * yPartBrickSize * zPartBrickSize * =
bytesPerVoxel]; /* DataType */

assert(buffer !=3D NULL);

ptr =3D buffer;

fprintf(stderr, "|\b");
for (int iz =3D zBrickOrigin; iz < (zBrickOrigin + =
zPartBrickSize); iz++) {
if (getTile(fileNames[iz], ptr,
xBrickOrigin, yBrickOrigin,
xPartBrickSize, yPartBrickSize,
xVolumeSize, yVolumeSize,
headerLength, bytesPerVoxel) !=3D 0) {
fprintf(stderr, "%s(): Unable to read a tile.\n",
"myReadBrickRaw");
return -1;
}
ptr +=3D xPartBrickSize * yPartBrickSize * bytesPerVoxel;

} // iz

fprintf(stderr, "/\b");

// KLUDGE does not set all the borders
for (int j0 =3D 0; j0 < zPartBrickSize; j0++)
for (int j1 =3D 0; j1 < yPartBrickSize; j1++) {
memcpy(
(char *) data + (j0 * xBrickSize * yBrickSize =
+ j1 * xBrickSize) * bytesPerVoxel,
buffer + (j0 * xPartBrickSize * yPartBrickSize =
+ j1 * xPartBrickSize) * bytesPerVoxel,
xPartBrickSize);
memset(
buffer + (j0 * xPartBrickSize * yPartBrickSize =
+ j1 * xPartBrickSize + xPartBrickSize) * bytesPerVoxel,
0, (xBrickSize - xPartBrickSize) * =
bytesPerVoxel);
}

delete[]buffer;

fprintf(stderr, "-\b");

}

return 0;

}

int
pfVONode::postDrawCB(pfTraverser* t, void* data)
{
return ((pfVONode*)data)->postDraw(t);
}

int
pfVONode::postDraw(pfTraverser* t)
{
static pfVec4 bgclr(0.1f, 0.1f, 0.1f, 1.0f);

pfVOData* data =3D getCurData();
if (data->imageFiles =3D=3D NULL)
return PFTRAV_CONT;

// Setup best transparency (updates libpr shadow state)
pfTransparency(PFTR_HIGH_QUALITY);

// Push OpenGL state in preparation for draw
glPushAttrib(GL_ALL_ATTRIB_BITS);

glMatrixMode(GL_MODELVIEW);
glPushMatrix();

glDisable(GL_CULL_FACE);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

GLfloat mmat[] =3D { 1, 1, 1 };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mmat);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mmat);

// Do any reload
if (data->update)
updateVolume();

// Draw the volume
drawVolume();

// Restore state
glPopMatrix();
glPopAttrib();

return PFTRAV_CONT;
}

void
pfVONode::updateVolume()
{
pfVOData* data =3D getCurData();
int i;
int bytesPerVoxel;
int xbrickDim, ybrickDim, zbrickDim;

if (data->update =3D=3D 0 || data->imageFiles =3D=3D NULL) {
data->update =3D 0;
return;
}

pfNotify(PFNFY_INFO, PFNFY_INTERNAL, "pfVONode::updateVolume reason =
0x%x\n",
data->update);

// XXX Could be smarter here
cleanup();

//
// INIT THE VOLUME
//
switch (data->cVolumeSize) {
case 1:
fileFormat =3D voExternalFormatTypeScope::LUMINANCE;
bytesPerVoxel =3D 1;
break;
case 4:
fileFormat =3D voExternalFormatTypeScope::RGBA;
bytesPerVoxel =3D 4;
break;
default:
pfNotify(PFNFY_FATAL, PFNFY_USAGE, "pfVONode: node currently only "
"supports luminance or RGBA texture formats, given has %d "
"channels\n", data->cVolumeSize);
exit(EXIT_FAILURE);
/*NOTREACHED*/
}
if (!strcmp(data->dataType, "byte"))
{
fileDataType =3D voDataTypeScope::BYTE;
}
else if (!strcmp(data->dataType, "ubyte"))
{
fileDataType =3D voDataTypeScope::UNSIGNED_BYTE;
}
else if (!strcmp(data->dataType, "short"))
{
fileDataType =3D voDataTypeScope::SHORT;
bytesPerVoxel *=3D 2;
}
else if (!strcmp(data->dataType, "ushort"))
{
fileDataType =3D voDataTypeScope::UNSIGNED_SHORT;
bytesPerVoxel *=3D 2;
}
else if (!strcmp(data->dataType, "float"))
{
fileDataType =3D voDataTypeScope::FLOAT;
bytesPerVoxel *=3D 4;
}
else
{
pfNotify(PFNFY_FATAL, PFNFY_USAGE, "pfVONode: node currently does "
"not support %s component data type\n", data->dataType);
exit(EXIT_FAILURE);
/*NOTREACHED*/
}

xbrickDim =3D data->xVolumeSize;
ybrickDim =3D data->yVolumeSize;
zbrickDim =3D data->zVolumeSize;

voAppearanceActions::getBestParameters(data->interpolationType,
data->renderingMode, fileDataType, fileFormat, intFormat,
extFormat, xbrickDim, ybrickDim, zbrickDim);

printf("getBestParameters()\n");
switch (data->interpolationType)
{
case voInterpolationTypeScope::DEFAULT:
printf(" interpolationType =3D DEFAULT\n");
break;
case voInterpolationTypeScope::_2D:
printf(" interpolationType =3D _2D\n");
break;
case voInterpolationTypeScope::_3D:
printf(" interpolationType =3D _3D\n");
break;
default:
printf(" interpolationType =3D unknown\n");
break;
}
switch (data->renderingMode)
{
case voRenderingModeScope::DEFAULT:
printf(" renderingMode =3D DEFAULT\n");
break;
case voRenderingModeScope::MONOCHROME:
printf(" renderingMode =3D MONOCHROME\n");
break;
case voRenderingModeScope::COLOR:
printf(" renderingMode =3D COLOR\n");
break;
default:
printf(" renderingMode =3D unknown\n");
break;
}
switch (fileDataType)
{
case voDataTypeScope::DEFAULT:
printf(" dataType =3D DEFAULT\n");
break;
case voDataTypeScope::UNSIGNED_BYTE:
printf(" dataType =3D UNSIGNED_BYTE\n");
break;
case voDataTypeScope::BYTE:
printf(" dataType =3D BYTE\n");
break;
case voDataTypeScope::UNSIGNED_BYTE_3_3_2_EXT:
printf(" dataType =3D UNSIGNED_BYTE_3_3_2_EXT\n");
break;
case voDataTypeScope::UNSIGNED_SHORT:
printf(" dataType =3D UNSIGNED_SHORT\n");
break;
case voDataTypeScope::SHORT:
printf(" dataType =3D SHORT\n");
break;
case voDataTypeScope::UNSIGNED_SHORT_4_4_4_4_EXT:
printf(" dataType =3D UNSIGNED_SHORT_4_4_4_4_EXT\n");
break;
case voDataTypeScope::UNSIGNED_SHORT_5_5_5_1_EXT:
printf(" dataType =3D UNSIGNED_SHORT_5_5_5_1_EXT\n");
break;
case voDataTypeScope::UNSIGNED_INT:
printf(" dataType =3D UNSIGNED_INT\n");
break;
case voDataTypeScope::INT:
printf(" dataType =3D INT\n");
break;
case voDataTypeScope::UNSIGNED_INT_8_8_8_8_EXT:
printf(" dataType =3D UNSIGNED_INT_8_8_8_8_EXT\n");
break;
case voDataTypeScope::UNSIGNED_INT_10_10_10_2_EXT:
printf(" dataType =3D UNSIGNED_INT_10_10_10_2_EXT\n");
break;
case voDataTypeScope::FLOAT:
printf(" dataType =3D FLOAT\n");
break;
default:
printf(" dataType =3D unknown\n");
break;
}
switch (fileFormat)
{
case voExternalFormatTypeScope::DEFAULT:
printf(" diskDataFormat =3D DEFAULT\n");
break;
case voExternalFormatTypeScope::INTENSITY:
printf(" diskDataFormat =3D INTENSITY\n");
break;
case voExternalFormatTypeScope::LUMINANCE_ALPHA:
printf(" diskDataFormat =3D LUMINANCE_ALPHA\n");
break;
case voExternalFormatTypeScope::LUMINANCE:
printf(" diskDataFormat =3D LUMINANCE\n");
break;
case voExternalFormatTypeScope::RGBA:
printf(" diskDataFormat =3D RGBA\n");
break;
case voExternalFormatTypeScope::ABGR_EXT:
printf(" diskDataFormat =3D ABGR_EXT\n");
break;
default:
printf(" diskDataFormat =3D unknown\n");
break;
}
switch (intFormat)
{
case voInternalFormatTypeScope::DEFAULT:
printf(" internalFormat =3D DEFAULT\n");
break;
case voInternalFormatTypeScope::INTENSITY8_EXT:
printf(" internalFormat =3D INTENSITY8_EXT\n");
break;
case voInternalFormatTypeScope::LUMINANCE8_EXT:
printf(" internalFormat =3D LUMINANCE8_EXT\n");
break;
case voInternalFormatTypeScope::LUMINANCE8_ALPHA8_EXT:
printf(" internalFormat =3D LUMINANCE8_ALPHA8_EXT\n");
break;
case voInternalFormatTypeScope::RGBA8_EXT:
printf(" internalFormat =3D RGBA8_EXT\n");
break;
case voInternalFormatTypeScope::RGB8_EXT:
printf(" internalFormat =3D RGB8_EXT\n");
break;
case voInternalFormatTypeScope::RGBA4_EXT:
printf(" internalFormat =3D RGBA4_EXT\n");
break;
case voInternalFormatTypeScope::DUAL_LUMINANCE_ALPHA8_SGIS:
printf(" internalFormat =3D DUAL_LUMINANCE_ALPHA8_SGIS\n");
break;
case voInternalFormatTypeScope::DUAL_INTENSITY8_SGIS:
printf(" internalFormat =3D DUAL_INTENSITY8_SGIS\n");
break;
case voInternalFormatTypeScope::QUAD_LUMINANCE8_SGIS:
printf(" internalFormat =3D QUAD_LUMINANCE8_SGIS\n");
break;
default:
printf(" internalFormat =3D unknown\n");
break;
}
switch (extFormat)
{
case voExternalFormatTypeScope::DEFAULT:
printf(" externalFormat =3D DEFAULT\n");
break;
case voExternalFormatTypeScope::INTENSITY:
printf(" externalFormat =3D INTENSITY\n");
break;
case voExternalFormatTypeScope::LUMINANCE_ALPHA:
printf(" externalFormat =3D LUMINANCE_ALPHA\n");
break;
case voExternalFormatTypeScope::LUMINANCE:
printf(" externalFormat =3D LUMINANCE\n");
break;
case voExternalFormatTypeScope::RGBA:
printf(" externalFormat =3D RGBA\n");
break;
case voExternalFormatTypeScope::ABGR_EXT:
printf(" externalFormat =3D ABGR_EXT\n");
break;
default:
printf(" externalFormat =3D unknown\n");
break;
}
printf(" VolumeSize =3D (%d, %d, %d)\n",
data->xVolumeSize, data->yVolumeSize, data->zVolumeSize);
printf(" BrickDim =3D (%d, %d, %d)\n",
xbrickDim, ybrickDim, zbrickDim);

// Create the bricks storage. They'll get filled in later
volume =3D new voBrickSetCollection(data->xVolumeSize, =
data->yVolumeSize,
data->zVolumeSize, xbrickDim, xbrickDim, zbrickDim,
voPartialBrickTypeScope::TRUNCATE, 1, intFormat, extFormat,
fileDataType, data->interpolationType);
if (voError::getErrorNumber() !=3D voErrorTypeScope::NO_ERROR) {
pfNotify(PFNFY_FATAL, PFNFY_INTERNAL, "%s\n",
voError::getErrorString());
exit(EXIT_FAILURE);
}

// Allocate storage for all copies of the volume
{
voBrickSetCollectionIterator iter(volume);
voBrickSet* set;
while (set =3D iter()) {
voBrickSetIterator iter(set);
voBrick* brick;
while (brick =3D iter())
voAppearanceActions::dataAlloc(brick);
}
}

volume->setCurrentBrickSet(voPlaneOrientationScope::XY);

// Read in the bricks
{
voBrickSetIterator iter(volume->getCurrentBrickSet());
voBrick* brick;
while (brick =3D iter()) {
int bx, by, bz, bsx, bsy, bsz;
void* bd =3D brick->getDataPtr();

brick->getBrickSizes(bx, by, bz, bsx, bsy, bsz);
printf("brick (bx,by,bz)=3D(%d, %d, %d) (bsx,bsy,bsz)=3D(%d, %d, =
%d)\n",
bx, by, bz, bsx, bsy, bsz);

if (myReadBrickRaw(data->imageFiles, bd,
bx, by, bz, bsx, bsy, bsz,
data->xVolumeSize, data->yVolumeSize, data->zVolumeSize,
data->headerLength, bytesPerVoxel) )
{
pfNotify(PFNFY_FATAL, PFNFY_INTERNAL, "pfVONode: "
"texture tile read error\n");
exit(EXIT_FAILURE);

}

// replicate to the desired externalFormat
voAppearanceActions::dataConvert(brick, bd, fileFormat);

// expande the values to span the entire dynamic range
data->rangeLo =3D 0;
/*
data->rangeHi =3D 4095;
*/
data->rangeHi =3D 16384;
voAppearanceActions::dataScaleRange(brick, data->rangeLo,
data->rangeHi);
}
}

if (volume->getInterpolationType() =3D=3D =
voInterpolationTypeScope::_2D)
{
voAppearanceActions::volumeMakeTransposed(volume);
printf("getInterpolationType =3D _2D\n");
}
else if (volume->getInterpolationType() =3D=3D =
voInterpolationTypeScope::_3D)
{
printf("getInterpolationType =3D _3D\n");
}
else if (volume->getInterpolationType() =3D=3D =
voInterpolationTypeScope::DEFAULT)
{
printf("getInterpolationType =3D DEFAULT\n");
}
else
{
printf("getInterpolationType =3D unknown\n");
}

// How many bricks does it take to build...
int maxBricks =3D 0;
{
voBrickSetCollectionIterator iter(volume);
voBrickSet* set;
while (set =3D iter())
if (maxBricks < set->getBrickCount())
maxBricks =3D set->getBrickCount();
if (maxBricks =3D=3D 0) {
pfNotify(PFNFY_FATAL, PFNFY_INTERNAL, "pfVONode: no bricks in "
"texture\n");
exit(EXIT_FAILURE);
}
}
printf("maxBricks =3D %d\n", maxBricks);

// Compute max sampling surfaces as 2x largest dimension
int maxSamples =3D data->xVolumeSize;
if (maxSamples < data->yVolumeSize) maxSamples =3D =
data->yVolumeSize;
if (maxSamples < data->zVolumeSize) maxSamples =3D =
data->zVolumeSize;
maxSamples <<=3D 1;
printf("maxSamples =3D %d\n", maxSamples);

//
// INIT THE GEOMETRY
//

//
// Construct the vertices of the viewing cube
// [0]: 0 0 0 0 - 2
// [1]: x 0 0 3 - 5
// [2]: x y 0 6 - 8
// [3]: 0 y 0 9 - 11
// [4]: 0 0 z 12 - 14
// [5]: x 0 z 15 - 17
// [6]: x y z 18 - 20
// [7]: 0 y z 21 - 23
//
cubeVertices =3D new float[24];
for (i =3D 0; i < 24; i++) cubeVertices[i] =3D 0;
cubeVertices[3] =3D cubeVertices[6] =3D cubeVertices[15] =3D
cubeVertices[18] =3D data->xVolumeSize;
cubeVertices[7] =3D cubeVertices[10] =3D cubeVertices[19] =3D
cubeVertices[22] =3D data->yVolumeSize;
cubeVertices[14] =3D cubeVertices[17] =3D cubeVertices[20] =3D
cubeVertices[23] =3D data->zVolumeSize;

// Define the indices into the vertex array (this is fixed)
static int cubeIndices[20] =3D {
0, 2, 5, 7,
3, 2, 0, 7,
1, 2, 5, 0,
2, 7, 6, 5,
5, 4, 0, 7
};
const size_t cubeTetraCount =3D 5;

// Construct the tetrahedron set
tetraSet =3D new voIndexedTetraSet(cubeVertices, 8, 3, cubeIndices, =
20);

// Construct the intermediate polygon vertex storage
polygonVertexData =3D new voVertexData(100000, 3);

// Now the transient polygon set storage
polygonSet =3D new voIndexedFaceSet**[maxBricks];
for (i =3D 0; i < maxBricks; i++) {
polygonSet[i] =3D new voIndexedFaceSet*[maxSamples+1];
for (int j =3D 0; j <=3D maxSamples; j++) {
polygonSet[i][j] =3D new voIndexedFaceSet(polygonVertexData,
boundFaceCount(cubeTetraCount));
}
}
printf("cubeTetraCount =3D %d\n", cubeTetraCount);
printf("boundFaceCount(cubeTetraCount) =3D %d\n", =
boundFaceCount(cubeTetraCount));

//
// INIT THE GFX
//
if (data->lutWidth > 0) {
lutEntries =3D new float[data->lutWidth*4];

// XXX add support for lut file here
#if 0
if (data->lutFile[0] !=3D '\0') {
}
#endif
=09
voInternalFormatType lutIntFormat;
voExternalFormatType lutExtFormat;

voLookupTable::getBestParameters(volume, data->renderingMode,
data->lutWidth, data->lutType, lutIntFormat, lutExtFormat);

if (data->lutType =3D=3D voLookupTableTypeScope::PRE_INTERPOLATION)
lut =3D new voLookupTablePre(lutIntFormat, data->lutWidth,
lutExtFormat, voDataTypeScope::FLOAT, lutEntries);
else
lut =3D new voLookupTablePost(lutIntFormat, data->lutWidth,
lutExtFormat, voDataTypeScope::FLOAT, lutEntries);
=20
#if 0
if (data->lutFile[0] =3D=3D '\0')
#endif
lut->set(voLookupTableShapeScope::LINEAR, data->lutCenter,
data->lutWidth);

lut->load();
lut->enable();
}

// build the texture objects
voAppearanceActions::volumeOptimize(volume,
voOptimizeVolumeTypeScope::BEST_PERFORMANCE);

brickCount =3D maxBricks;
sampleCount =3D maxSamples;
data->update =3D 0;

return;
}

void
pfVONode::drawVolume()
{
int wf =3D TRUE;
pfVOData* data =3D getCurData();

int bno;
GLdouble modelMatrix[16], projMatrix[16];

glRotatef( 180.0, 0.0, 1.0, 0.0 );
glScalef(2.f*data->scaleX, 2.f*data->scaleY, 2.f*data->scaleZ);
glTranslatef(-data->xVolumeSize/2.f,
-data->yVolumeSize/2.f,
-data->zVolumeSize/2.f);

glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);

voutPerfMeter meter;
meter.reset();
meter.start(voutPerfMeter::WHOLE_FRAME);
meter.setEnabled(TRUE);

// If using voInterpolationTypeScope::_2D select an appropriate =
BrickSet
// from among voPlaneOrientationScope::[XYZ] per view. Note, that
// individual BrickSets may have differrent dimensions and thus =
change
// certain PER_FRAME properites e.g., BrickCount

if (volume->getInterpolationType() =3D=3D =
voInterpolationTypeScope::_2D)
volume->setCurrentBrickSet(
voGeometryActions::findClosestAxisIndex(modelMatrix,
projMatrix, voSamplingModeScope::AXIS_ALIGNED));

int maxBricks =3D volume->getCurrentBrickSet()->getBrickCount();

// Draw opaque (embedded) geometry
voAppearanceActions::textureDisable(volume->getInterpolationType());

// Draw tetra wireframes in yellow.
if (wf) {
glColor4f(1.0, 1.0, 0.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
voGeometryActions::draw(tetraSet, =
voInterleavedArrayTypeScope::V3F);

// draw brick outlines in blue, but only if bricks are 3D
if (volume->getInterpolationType() =3D=3D =
voInterpolationTypeScope::_3D) {
glColor4f(0.0, 0.0, 1.0, 1.0);
for (bno =3D 0; bno < maxBricks; bno++)
voGeometryActions::draw(
volume->getCurrentBrickSet()->getBrick(bno));
}
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}

// Given a aTetraSet, bricks' dimensions and count, sampling mode =
and rate,
// find all slicing polygons and clip them to brick boundaries.

const float samplingRate =3D 4.0;

meter.start(voutPerfMeter::POLYGONIZE);

int samplesNumber;
float samplingPeriod[3] =3D {
samplingRate / data->scaleX,
samplingRate / data->scaleY,
samplingRate / data->scaleZ
};

voGeometryActions::polygonize(tetraSet, =
volume->getCurrentBrickSet(),
voInterleavedArrayTypeScope::V3F, modelMatrix, projMatrix,
volume->getInterpolationType() =3D=3D voInterpolationTypeScope::_3D =
?
voSamplingModeScope::VIEWPORT_ALIGNED :
voSamplingModeScope::AXIS_ALIGNED,
voSamplingSpaceScope::OBJECT, samplingPeriod, sampleCount,
samplesNumber, polygonSet);

// If not using texgen() transform texture coords explicitly.
if (hasTextureComponent(voInterleavedArrayTypeScope::V3F))
voAppearanceActions::xfmVox2TexCoords(volume->getCurrentBrickSet(),
samplesNumber, polygonSet, voInterleavedArrayTypeScope::V3F);

// Depth sort the bricks.
voSortAction sort(volume->getCurrentBrickSet(), modelMatrix, =
projMatrix);

meter.stop(voutPerfMeter::POLYGONIZE);
// END POLYGONIZE

// BEGIN DRAWING

glColor4f(1.0, 1.0, 1.0, 1.0);

// Enable 2D or 3D texturing.
voAppearanceActions::textureEnable(volume->getInterpolationType());

// If no explicit texture coordinates were given, enable texgen().
if (!hasTextureComponent(voInterleavedArrayTypeScope::V3F))
voAppearanceActions::texgenEnable();

// prevent Zbuffer fighting among slices
glDepthMask(GL_FALSE);

// Iterate over all bricks.
for (bno =3D 0; bno < maxBricks; bno++) {
int brickSortedNo =3D sort[bno];
voBrick *brick =3D =
volume->getCurrentBrickSet()->getBrick(brickSortedNo);

// Update texgen equation for the current brick.
if (!hasTextureComponent(voInterleavedArrayTypeScope::V3F))
voAppearanceActions::texgenSetEquation(brick);

meter.start(voutPerfMeter::LOAD);
// load the texture from host to texture memory--unless already =
there
voAppearanceActions::textureBind(brick);
meter.stop(voutPerfMeter::LOAD);

// iterate over all sampling planes
meter.start(voutPerfMeter::DRAW);
for (int binNo =3D 0; binNo < samplesNumber ; binNo++)
voGeometryActions::draw(polygonSet[brickSortedNo][binNo],
voInterleavedArrayTypeScope::V3F);
glGetError();
meter.stop(voutPerfMeter::DRAW);
}

glDepthMask(GL_TRUE);

voAppearanceActions::textureDisable(volume->getInterpolationType());
voAppearanceActions::texgenDisable();

#if 0 // this is rather expensive to compute
float area =3D 0;
for (bno =3D 0; bno < maxBricks; bno++)
for (int bin =3D 0; bin < samplesNumber; bin++)
area +=3D =
voGeometryActions::findProjectedArea(polygonSet[bno][bin],
voInterleavedArrayTypeScope::V3F);

meter.stop(voutPerfMeter::WHOLE_FRAME);
meter.report(volume, area);
#endif

}

------=_NextPart_000_0041_01BE698A.B47C4940--


New Message Reply Date view Thread view Subject view Author view

This archive was generated by hypermail 2.0b2 on Mon Nov 01 1999 - 12:03:15 PST