Inclusions and Declarations
|
|
|
OpenGL Volumizer and standard C++
includes.
|
|
#include <stdio.h>
#include <stdlib.h>
#include <
vo
/GeometryActions.h>
#include <
vo
/AppearanceActions.h>
|
Method declaration that returns data
about the geometry's file.
The reader must provide this.
|
|
extern int myGetVolumeSizesIfl(
char *fileName, int &xSize, int &ySize,
int &zSize,
voExternalFormatType
& diskDataFormat,
voDataType
& dataType);
|
Method declaration that returns texture
and geometry values.
The reader must provide this.
|
|
extern int myReadBrickIfl(
char *fileName, void *data,
int xBrickOrigin, int yBrickOrigin,
int zBrickOrigin,
int xBrickSize, int yBrickSize,
int zBrickSize,
int xVolumeSize, int yVolumeSize,
int zVolumeSize);
|
Declaration of scaling factor, one value
for each dimension.
|
|
extern float modelScale[3];
|
The number of bricks in the largest copy
of the volume.
|
|
int maxBrickCount = 0;
|
Determines maximum number of
sampling planes.
|
|
int maxSamplesNumber = 256;
|
Value determines that every voxel is
sampled.
|
|
float samplingRate = 1.0;
|
Vertex format; here only vertex
coordinates are specified, not textures
or colors.
|
|
voInterleavedArrayType
interleavedArrayFormat =
voInterleavedArrayTypeScope
::V3F;
|
Storage for transient polygons.
|
|
voVertexData
*allVertexData;
voIndexedFaceSet
***aPolygonSetArray;
|
Set the Appearance Parameters
|
|
|
Method for displaying an error string.
This also resets the error condition
state.
|
|
void
my_ExceptionHandler(void)
{
fprintf(stderr,
"OpenGL Volumizer error %d: %s\n",
voError
::getErrorNumber(),
voError
::getErrorString());
}
|
Method for handling appearance,
which is a collection of bricksets.
|
|
voBrickSetCollection
*
my_InitAppearance(int argc, char **argv)
{
|
The size of the geometry and texture.
|
|
int xVolumeSize, yVolumeSize, zVolumeSize;
int xBrickSize, yBrickSize, zBrickSize;
|
Data formats to use externally and
internally.
|
|
voExternalFormatType
diskDataFormat;
voExternalFormatType
externalFormat;
voInternalFormatType
internalFormat;
|
Describes what format the voxels are in.
|
|
voDataType
dataType;
|
Specifies whether the texture is
sampled using bilinear or trilinear
interpolation.
|
|
voInterpolationType
interpolationType =
voInterpolationTypeScope
::DEFAULT;
|
Sets rendering mode to monochrome.
|
|
voRenderingMode
renderingMode =
voRenderingModeScope
::MONOCHROME;
float loValue = -1.0, hiValue = -1.0;
|
Prompts user if filename of geometry
was not included on the command line.
|
|
if (argc < 2) {
fprintf(stderr, “Usage: %s inFileName\n”,argv[0]);
exit(1);
}
|
Retrieves the file name of the volume in
the first argument of the command.
|
|
char *dataFileName = argv[1];
|
Get volume sizes and voxel format and
exits.
|
|
if (myGetVolumeSizesIfl(dataFileName,
xVolumeSize, yVolumeSize, zVolumeSize,
diskDataFormat, dataType))
exit(1);
|
Sets the texture size to the geometry
size.
|
|
xBrickSize = xVolumeSize;
yBrickSize = yVolumeSize;
zBrickSize = zVolumeSize;
|
Returns, in the last three arguments, the
optimal size for bricks based on the
current machine's hardware.
|
|
voAppearanceActions
::getBestParameters(
interpolationType, renderingMode, dataType,
diskDataFormat, internalFormat, externalFormat,
xBrickSize, yBrickSize, zBrickSize);
|
Defines the brick collection. This
method does not read or allocate any
data, it only computes bricks' origins
and sizes given the volume dimensions.
|
|
voBrickSetCollection
*aVolume =
new
voBrickSetCollection
(
xVolumeSize, yVolumeSize, zVolumeSize,
xBrickSize, yBrickSize, zBrickSize,
voPartialBrickTypeScope
::TRUNCATE,
1,
internalFormat,
externalFormat,
dataType,
interpolationType);
|
Handles errors.
|
|
if (
voError
::getErrorNumber() !=
voErrorTypeScope
::NO_ERROR) {
fprintf(stderr, “%s”,
voError
::getErrorString());
exit(1);
}
|
Allocate Memory for Bricks
|
|
|
Uses aVolume as the brick set collection
to iterate through.
|
|
voBrickSetCollectionIterator
collectionIter(aVolume);
|
Iterates over all of the brick sets within
the collection of brick sets.
|
|
for (
voBrickSet
* brickSet; brickSet =
collectionIter();) {
|
Iterates over all of the bricks within
each brick set.
|
|
voBrickSetIterator
brickSetIter(brickSet);
for (
voBrick
* brick;brick = brickSetIter();)
|
Inside the double for loop, this line
allocates memory for all of the bricks in
all of the bricksets.
|
|
voAppearanceActions
::dataAlloc(brick);
}
|
Get the brick set of aVolume and then
iterate over all the bricks in the brick set.
brick is a pointer to a brickset.
|
| aVolume->setCurrentBrickSet(
voPlaneOrientationScope
::XY);
voBrickSetIterator
brickSetIter(aVolume->getCurrentBrickSet());
for (voBrick * brick; brick = brickSetIter();) {
int xBrickOrigin, yBrickOrigin, zBrickOrigin;
int xBrickSize, yBrickSize, zBrickSize;
void *vdata = brick->getDataPtr();
|
Gets brick sizes and locations; the brick
sizes might be different from those
requested.
|
|
brick->getBrickSizes(
xBrickOrigin, yBrickOrigin, zBrickOrigin,
xBrickSize, yBrickSize, zBrickSize);
|
Load the Brick Data
|
|
|
Reads in the brick data from disk. It is
okay to use the brick's data area as a
temporary buffer.
|
|
myReadBrickIfl(dataFileName, vdata,
xBrickOrigin, yBrickOrigin, zBrickOrigin,
xBrickSize, yBrickSize, zBrickSize,
xVolumeSize, yVolumeSize, zVolumeSize);
|
Replicate to the desired external format
|
|
voAppearanceActions
::dataConvert(
brick, vdata, diskDataFormat);
|
Converts geometry to the desired
external format. Scales the voxel values
within a brick from a specified dynamic
range to the following standard ranges:
(<0,255> for ubyte, <0,65535> for
ushort, and <0.0,1.0> for floats).
|
|
voAppearanceActions
::dataScaleRange(brick,
loValue, hiValue);
}
|
If the texture is sampled using bilinear
interpolation, transpose the volume.
|
|
if (aVolume->getInterpolationType() ==
voInterpolationTypeScope
::_2D)
voAppearanceActions
::volumeMakeTransposed
(aVolume);
|
Determines the largest number of
bricks in a brick set, in the brick set
collection. This number is used to
allocate the buffers.
|
|
voBrickSetCollectionIterator
aCollectionIterator
(aVolume);
voBrickSet
*aBrickSet;
for (int j1 = 0; aBrickSet = aCollectionIterator();
j1++)
|
Revise the value for maxBrickCount if
the number of bricks in the brickset
exceeds the current value for
maxBrickCount, which was initialized as
256.
|
| if (j1 == 0 || aBrickSet->getBrickCount() >
maxBrickCount)
maxBrickCount = aBrickSet->getBrickCount();
|
Set the maximum number of sampling
surfaces to twice the largest dimension.
|
|
maxSamplesNumber = xVolumeSize;
if (maxSamplesNumber < yVolumeSize)
maxSamplesNumber = yVolumeSize;
if (maxSamplesNumber < zVolumeSize)
maxSamplesNumber = zVolumeSize;
maxSamplesNumber *= 2;
return aVolume;
}
|
Create the Containers to Hold the
Faces
|
|
|
Procedure to create a geometry.
|
|
voIndexedTetraSet
*
my_InitGeometry(
voBrickSetCollection
* aVolume)
{
voError::setErrorHandler(my_ExceptionHandler);
int xVolumeSize, yVolumeSize, zVolumeSize;
aVolume->getCurrentBrickSet()->getVolumeSizes(
xVolumeSize, yVolumeSize, zVolumeSize);
|
Set vertex coordinates. Texgen will be
used to generate tex coords.
|
|
static float vtxData[8][3] = {
0, 0, 0,
xVolumeSize, 0, 0,
xVolumeSize, yVolumeSize, 0,
0, yVolumeSize, 0,
0, 0, zVolumeSize,
xVolumeSize, 0, zVolumeSize,
xVolumeSize, yVolumeSize, zVolumeSize,
0, yVolumeSize, zVolumeSize,
};
|
Defines the geometry to be drawn.
Each row defines one tetrahedron, five
of which define a cube. Values index
into vtxData[].
Constructs the tetra set.
|
| static int cubeIndices[] =
{
0, 2, 5, 7,
3, 2, 0, 7,
1, 2, 5, 0,
2, 7, 6, 5,
5, 4, 0, 7,
};
int tetraCount =
sizeof(cubeIndices) / (VO_TETRA_VERTICES *
sizeof(cubeIndices[0]));
int valuesPerVtx = sizeof(vtxData[0]) / sizeof(float);
|
Allocates storage for transient
polygons; note that all the polygons
share vertex data area allVertexData[]
to minimize fragmentation
boundFaceCount() determines the
maximum number of indices required
to store a polygon (11).
Sizeof refers to the number of vertices.
|
|
voIndexedTetraSet
*aTetraSet = new
voIndexedTetraSet
(
(float *) vtxData,
8,
valuesPerVtx,
cubeIndices,
20);
|
Holds all intermediate PER_VERTEX
information.
|
|
allVertexData = new
voVertexData
(100000,
valuesPerVtx);
aPolygonSetArray = new
voIndexedFaceSetPtrPtr
[maxBrickCount];
for (int j1 = 0; j1 < maxBrickCount; j1++) {
aPolygonSetArray[j1] = new
voIndexedFaceSetPtr
[maxSamplesNumber + 1];
for (int j2 = 0; j2 < maxSamplesNumber + 1; j2++)
aPolygonSetArray[j1][j2] = new
voIndexedFaceSet
(allVertexData,
boundFaceCount(tetraCount));
}
return aTetraSet;
}
|
Set Drawing Parameters
|
|
|
Initializes graphics.
|
|
void my_InitGfx(
voIndexedTetraSet
*,
voBrickSetCollection
* aVolume)
{
|
Optimizes based on performance.
|
|
voAppearanceActions
::volumeOptimize(aVolume,
voOptimizeVolumeTypeScope::BEST_PERFORMANCE);
}
|
Draw the Volume
|
|
|
Defines draw method.
|
|
void my_DrawVolume(
voIndexedTetraSet
* aTetraSet,
voBrickSetCollection
* aVolume)
{
|
Chooses wireframe mode.
|
|
GLboolean wireframe = GL_TRUE;
|
Type definitions of the number of bricks
in the geometry and the modelview and
projection matrices.
|
|
int brickNo;
GLdouble modelMatrix[16], projMatrix[16];
|
Returns the modelview matrix, which is
the cumulative product of multiplying
viewing and modeling transformation
matrices.
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
|
Returns the projection matrix, which is
the viewing frustum.
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
|
If using 2D textures, select an
appropriate BrickSet from among
XY,XZ,YZ. Note, that individual brick
sets may have differrent dimensions
and thus change certain PER_FRAME
properites, for example, BrickCount.
|
| if (aVolume->getInterpolationType() ==
voInterpolationTypeScope::_2D
aVolume->setCurrentBrickSet(
voGeometryActions::findClosestAxisIndex
(
modelMatrix, projMatrix,
voSamplingModeScope::AXIS_ALIGNED));
int BrickCount = aVolume->getCurrentBrickSet()->
getBrickCount();
|
Disables texture and draws opaque
(embedded) geometry.
|
|
voAppearanceActions
::textureDisable(
aVolume->getInterpolationType());
|
Draw tetrahedron wireframes in
yellow.
|
|
if (wireframe == GL_TRUE) {
glColor4f(1.0, 1.0, 0.0, 1.0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
voGeometryActions::draw
(aTetraSet,
interleavedArrayFormat);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
Draw brick outlines in blue, but only if
bricks are 3D.
|
|
if (aVolume->getInterpolationType() ==
voInterpolationTypeScope
::_3D) {
glColor4f(0.0, 0.0, 1.0, 1.0);
for (brickNo=0;brickNo<BrickCount; brickNo++)
voGeometryActions::draw
(
aVolume->getCurrentBrickSet()->getBrick(
brickNo));
}
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
|
Polygonize the Shape
|
|
|
Given a aTetraSet, bricks' dimensions,
and count, sampling mode and rate,
find all slicing polygons and clip them
to brick boundaries.
If aVolume is three-dimensional, make
the face sets viewport aligned;
otherwise make them sampling-axis
aligned.
Specify the number of faces in the face
set, call the face set aPolygonSetArray.
|
| int samplesNumber;
float samplingPeriod[3] = {
samplingRate / modelScale[0],
samplingRate / modelScale[1],
samplingRate / modelScale[2] };
voGeometryActions::polygonize
(
aTetraSet, aVolume->getCurrentBrickSet(),
interleavedArrayFormat,
modelMatrix, projMatrix,
aVolume->getInterpolationType() ==
voInterpolationTypeScope
::_3D ?
voSamplingModeScope
::VIEWPORT_ALIGNED :
voSamplingModeScope
::AXIS_ALIGNED,
voSamplingSpaceScope
::OBJECT,samplingPeriod,
maxSamplesNumber,
samplesNumber,aPolygonSetArray);
|
If not using texgen(), transform texture
coords explicitly.
|
| if (hasTextureComponent(interleavedArrayFormat))
voAppearanceActions
::xfmVox2TexCoords(
aVolume->getCurrentBrickSet(),
samplesNumber,aPolygonSetArray,
interleavedArrayFormat);
|
Visiblity sort the bricks.
End of polygonize.
|
|
voSortAction
aSortAction(
aVolume->getCurrentBrickSet(),
modelMatrix, projMatrix);
|
Draw the Shape
|
|
|
Enable 2D or 3D texturing depending
on the interpolation type.
|
|
voAppearanceActions
::textureEnable(
aVolume->getInterpolationType());
|
If no explicit texture coordinates were
given, enable texgen().
|
| if(!hasTextureComponent(interleavedArrayFormat))
voAppearanceActions
::texgenEnable();
|
Set up drawing mode and color
|
|
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor4f(1.0, 1.0, 1.0, 1.0);
glDepthMask(GL_FALSE);
|
Iterate over all bricks and sort them
back to front.
|
|
for (brickNo = 0; brickNo < BrickCount; brickNo++) {
int brickSortedNo = aSortAction[brickNo];
voBrick
*aBrick = aVolume->
getCurrentBrickSet()->
getBrick(brickSortedNo);
|
Update texgen equation for the current
brick.
|
|
if (!hasTextureComponent(
interleavedArrayFormat))
voAppearanceActions
::texgenSetEquation(
aBrick);
|
Load the texture to texture memory
unless it is already there.
|
|
voAppearanceActions
::textureBind(aBrick);
|
Iterate over all sampling planes and
draw them.
|
|
for (int binNo=0; binNo < samplesNumber; binNo++)
{
voGeometryActions::draw
(
aPolygonSetArray[brickSortedNo][binNo],
interleavedArrayFormat);
}
}
|
Disable the texture and disable the
texture generation.
|
|
voAppearanceActions
::textureDisable(
aVolume->getInterpolationType());
voAppearanceActions
::texgenDisable();
glDepthMask(GL_TRUE);
} // end of procedure my_DrawVolume
|
Clean Up
|
|
|
Deletes geometry and textures.
|
|
void my_Cleanup(
voIndexedTetraSet
*aTetraSet,
voBrickSetCollection
*aVolume)
{
|
Frees storage for transient geometry.
|
|
for (int j1 = 0; j1 < maxBrickCount; j1++) {
for (int j2 = 0; j2 < maxSamplesNumber + 1; j2++)
delete aPolygonSetArray[j1][j2];
delete aPolygonSetArray[j1];
}
delete[]aPolygonSetArray;
delete allVertexData;
|
Frees all voxel data storage.
|
|
voAppearanceActions::volumeUnoptimize
(aVolume);
voBrickSetCollectionIterator
collectionIter(aVolume);
for (
voBrickSet
* brickSet; brickSet =
collectionIter();) {
|
Iterate over all bricks within the brick
collection and release the memory used
for the bricks.
|
|
voBrickSetIterator
brickSetIter(brickSet);
for(
voBrick
* brick; brick=brickSetIter();)
voAppearanceActions
::dataFree(brick);
}
|
Delete volumetric geometry.
|
|
delete aVolume;
delete aTetraSet;
} // end of my_Cleanup
|