Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

555 lines
20 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkOpenGLRayCastImageDisplayHelper.cxx,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkOpenGLRayCastImageDisplayHelper.h"
#include "vtkMatrix4x4.h"
#include "vtkObjectFactory.h"
#include "vtkVolume.h"
#include "vtkRenderer.h"
#include "vtkTransform.h"
#include "vtkCamera.h"
#include "vtkFixedPointRayCastImage.h"
#ifndef VTK_IMPLEMENT_MESA_CXX
# include "vtkOpenGL.h"
#endif
#include <math.h>
#ifndef VTK_IMPLEMENT_MESA_CXX
vtkCxxRevisionMacro(vtkOpenGLRayCastImageDisplayHelper, "$Revision: 1.4 $");
vtkStandardNewMacro(vtkOpenGLRayCastImageDisplayHelper);
#endif
// Construct a new vtkOpenGLRayCastImageDisplayHelper with default values
vtkOpenGLRayCastImageDisplayHelper::vtkOpenGLRayCastImageDisplayHelper()
{
}
// Destruct a vtkOpenGLRayCastImageDisplayHelper - clean up any memory used
vtkOpenGLRayCastImageDisplayHelper::~vtkOpenGLRayCastImageDisplayHelper()
{
}
// imageMemorySize is how big the texture is - this is always a power of two
//
// imageViewportSize is how big the renderer viewport is in pixels
//
// imageInUseSize is the rendered image - equal or smaller than imageMemorySize
// and imageViewportSize
//
// imageOrigin is the starting pixel of the imageInUseSize image on the
// the imageViewportSize viewport
//
void vtkOpenGLRayCastImageDisplayHelper::RenderTexture( vtkVolume *vol,
vtkRenderer *ren,
vtkFixedPointRayCastImage *image,
float requestedDepth )
{
this->RenderTextureInternal( vol, ren, image->GetImageMemorySize(), image->GetImageViewportSize(),
image->GetImageInUseSize(), image->GetImageOrigin(),
requestedDepth, VTK_UNSIGNED_SHORT, image->GetImage() );
}
void vtkOpenGLRayCastImageDisplayHelper::RenderTexture( vtkVolume *vol,
vtkRenderer *ren,
int imageMemorySize[2],
int imageViewportSize[2],
int imageInUseSize[2],
int imageOrigin[2],
float requestedDepth,
unsigned char *image )
{
this->RenderTextureInternal( vol, ren, imageMemorySize, imageViewportSize,
imageInUseSize, imageOrigin, requestedDepth,
VTK_UNSIGNED_CHAR, static_cast<void *>(image) );
}
void vtkOpenGLRayCastImageDisplayHelper::RenderTexture( vtkVolume *vol,
vtkRenderer *ren,
int imageMemorySize[2],
int imageViewportSize[2],
int imageInUseSize[2],
int imageOrigin[2],
float requestedDepth,
unsigned short *image )
{
this->RenderTextureInternal( vol, ren, imageMemorySize, imageViewportSize,
imageInUseSize, imageOrigin, requestedDepth,
VTK_UNSIGNED_SHORT, static_cast<void *>(image) );
}
void vtkOpenGLRayCastImageDisplayHelper::RenderTextureInternal( vtkVolume *vol,
vtkRenderer *ren,
int imageMemorySize[2],
int imageViewportSize[2],
int imageInUseSize[2],
int imageOrigin[2],
float requestedDepth,
int imageScalarType,
void *image )
{
int i;
float offsetX, offsetY;
float xMinOffset, xMaxOffset, yMinOffset, yMaxOffset;
float tcoords[8];
float depth;
if ( requestedDepth > 0.0 && requestedDepth <= 1.0 )
{
depth = requestedDepth;
}
else
{
// Pass the center of the volume through the world to view function
// of the renderer to get the z view coordinate to use for the
// view to world transformation of the image bounds. This way we
// will draw the image at the depth of the center of the volume
ren->SetWorldPoint( vol->GetCenter()[0],
vol->GetCenter()[1],
vol->GetCenter()[2],
1.0 );
ren->WorldToView();
depth = ren->GetViewPoint()[2];
}
// Convert the four corners of the image into world coordinates
float verts[12];
vtkMatrix4x4 *viewToWorldMatrix = vtkMatrix4x4::New();
float in[4], out[4];
vtkCamera *cam = ren->GetActiveCamera();
ren->ComputeAspect();
double *aspect = ren->GetAspect();
vtkTransform *perspectiveTransform = vtkTransform::New();
perspectiveTransform->Identity();
perspectiveTransform->Concatenate(
cam->GetPerspectiveTransformMatrix(aspect[0]/aspect[1],
0.0, 1.0 ));
perspectiveTransform->Concatenate(cam->GetViewTransformMatrix());
// get the perspective transformation from the active camera
viewToWorldMatrix->DeepCopy( perspectiveTransform->GetMatrix() );
perspectiveTransform->Delete();
// use the inverse matrix
viewToWorldMatrix->Invert();
// These two values never change
in[2] = depth;
in[3] = 1.0;
// This is the lower left corner
in[0] = (float)imageOrigin[0]/imageViewportSize[0] * 2.0 - 1.0;
in[1] = (float)imageOrigin[1]/imageViewportSize[1] * 2.0 - 1.0;
viewToWorldMatrix->MultiplyPoint( in, out );
verts[0] = out[0] / out[3];
verts[1] = out[1] / out[3];
verts[2] = out[2] / out[3];
// This is the lower right corner
in[0] = (float)(imageOrigin[0]+imageInUseSize[0]) /
imageViewportSize[0] * 2.0 - 1.0;
in[1] = (float)imageOrigin[1]/imageViewportSize[1] * 2.0 - 1.0;
viewToWorldMatrix->MultiplyPoint( in, out );
verts[3] = out[0] / out[3];
verts[4] = out[1] / out[3];
verts[5] = out[2] / out[3];
// This is the upper right corner
in[0] = (float)(imageOrigin[0]+imageInUseSize[0]) /
imageViewportSize[0] * 2.0 - 1.0;
in[1] = (float)(imageOrigin[1]+imageInUseSize[1]) /
imageViewportSize[1] * 2.0 - 1.0;
viewToWorldMatrix->MultiplyPoint( in, out );
verts[6] = out[0] / out[3];
verts[7] = out[1] / out[3];
verts[8] = out[2] / out[3];
// This is the upper left corner
in[0] = (float)imageOrigin[0]/imageViewportSize[0] * 2.0 - 1.0;
in[1] = (float)(imageOrigin[1]+imageInUseSize[1]) /
imageViewportSize[1] * 2.0 - 1.0;
viewToWorldMatrix->MultiplyPoint( in, out );
verts[9] = out[0] / out[3];
verts[10] = out[1] / out[3];
verts[11] = out[2] / out[3];
viewToWorldMatrix->Delete();
// Save state
glPushAttrib(GL_ENABLE_BIT |
GL_COLOR_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT |
GL_POLYGON_BIT |
GL_PIXEL_MODE_BIT |
GL_TEXTURE_BIT);
glPixelTransferf( GL_RED_SCALE, this->PixelScale );
glPixelTransferf( GL_GREEN_SCALE, this->PixelScale );
glPixelTransferf( GL_BLUE_SCALE, this->PixelScale );
glPixelTransferf( GL_ALPHA_SCALE, this->PixelScale );
if ( this->PreMultipliedColors )
{
// Values in the texture map have already been pre-multiplied by alpha
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
}
else
{
// Values in the texture map have not been pre-multiplied by alpha
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
// Turn lighting off - the texture already has illumination in it
glDisable( GL_LIGHTING );
// Turn texturing on so that we can draw the textured hexagon
glEnable( GL_TEXTURE_2D );
#ifdef GL_VERSION_1_1
GLuint tempIndex;
glGenTextures(1, &tempIndex);
glBindTexture(GL_TEXTURE_2D, tempIndex);
#endif
// Don't write into the Zbuffer - just use it for comparisons
glDepthMask( 0 );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// Specify the texture
glColor3f(1.0,1.0,1.0);
int newTextureSize[2];
#ifdef GL_VERSION_1_1
if ( imageScalarType == VTK_UNSIGNED_CHAR )
{
// Test the texture to see if it fits in memory
glTexImage2D( GL_PROXY_TEXTURE_2D, 0, GL_RGBA8,
imageMemorySize[0], imageMemorySize[1],
0, GL_RGBA, GL_UNSIGNED_BYTE,
static_cast<unsigned char *>(image) );
}
else
{
// Test the texture to see if it fits in memory
glTexImage2D( GL_PROXY_TEXTURE_2D, 0, GL_RGBA8,
imageMemorySize[0], imageMemorySize[1],
0, GL_RGBA, GL_UNSIGNED_SHORT,
static_cast<unsigned short *>(image) );
}
GLint params[1];
glGetTexLevelParameteriv ( GL_PROXY_TEXTURE_2D, 0,
GL_TEXTURE_WIDTH, params );
// if it does, we will render it later. define the texture here
if ( params[0] != 0 )
{
if ( imageScalarType == VTK_UNSIGNED_CHAR )
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8,
imageMemorySize[0], imageMemorySize[1],
0, GL_RGBA, GL_UNSIGNED_BYTE,
static_cast<unsigned char *>(image) );
}
else
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8,
imageMemorySize[0], imageMemorySize[1],
0, GL_RGBA, GL_UNSIGNED_SHORT,
static_cast<unsigned short *>(image) );
}
}
// if it doesn't, we are going to break it up now and render it.
// That's because we want this in the ifdef because this only works in
// 1.1 and later.
else
{
// Figure out our new texture size. Keep dividing the big one in half until
// OpenGL says this texture is OK
newTextureSize[0] = imageMemorySize[0];
newTextureSize[1] = imageMemorySize[1];
while ( params[0] == 0 && newTextureSize[0] >= 32 &&
newTextureSize[1] >= 32 )
{
if ( newTextureSize[0] > newTextureSize[1] )
{
newTextureSize[0] /= 2;
}
else
{
newTextureSize[1] /= 2;
}
if ( imageScalarType == VTK_UNSIGNED_CHAR )
{
glTexImage2D( GL_PROXY_TEXTURE_2D, 0, GL_RGBA8,
newTextureSize[0], newTextureSize[1],
0, GL_RGBA, GL_UNSIGNED_BYTE,
static_cast<unsigned char *>(image) );
}
else
{
glTexImage2D( GL_PROXY_TEXTURE_2D, 0, GL_RGBA8,
newTextureSize[0], newTextureSize[1],
0, GL_RGBA, GL_UNSIGNED_SHORT,
static_cast<unsigned short *>(image) );
}
glGetTexLevelParameteriv ( GL_PROXY_TEXTURE_2D, 0,
GL_TEXTURE_WIDTH, params );
}
// If we got down to 32 by 32 and OpenGL still doesn't like it, something
// must be seriously wrong and we will ignore it. Otherwise, we have our
// new texture size and let's start chopping up the image
if ( newTextureSize[0] >= 32 && newTextureSize[1] >= 32 )
{
// How many tiles in x?
int xLimit = 1 + static_cast<int>(
static_cast<float>(imageInUseSize[0]) /
static_cast<float>((newTextureSize[0]-2)));
// How many tiles in y?
int yLimit = 1 + static_cast<int>(
static_cast<float>(imageInUseSize[1]) /
static_cast<float>((newTextureSize[1]-2)));
// Create memory for the new texture
unsigned char *newTextureChar = NULL;
unsigned short *newTextureShort = NULL;
if ( imageScalarType == VTK_UNSIGNED_CHAR )
{
newTextureChar =
new unsigned char [newTextureSize[0] * newTextureSize[1] * 4];
}
else
{
newTextureShort =
new unsigned short [newTextureSize[0] * newTextureSize[1] * 4];
}
// This is the 1/2 pixel offset for texture coordinates
offsetX = .5 / static_cast<float>(newTextureSize[0]);
offsetY = .5 / static_cast<float>(newTextureSize[1]);
int ii, jj;
float newVerts[12];
float vx1, vx2, vy1, vy2;
int px1, py1, pxSize, pySize;
// loop through the tiles in y
for ( jj = 0; jj < yLimit; jj++ )
{
vy1 = static_cast<float>(jj) / static_cast<float>(yLimit);
vy2 = static_cast<float>(jj+1) / static_cast<float>(yLimit);
py1 = static_cast<int>(vy1 * static_cast<float>(
imageInUseSize[1]));
pySize = static_cast<int>(2 - py1 + vy2 * static_cast<float>(
imageInUseSize[1]-1));
if ( py1 + pySize > imageInUseSize[1] )
{
pySize = imageInUseSize[1] - py1;
}
yMinOffset = 2.0 * offsetY *
(vy1*static_cast<float>(imageInUseSize[1]-1)-static_cast<float>(py1));
yMaxOffset = 2.0 * offsetY *
(static_cast<float>(py1+pySize-1)-vy2*static_cast<float>(imageInUseSize[1]-1));
// loop through the tiles in x
for ( ii = 0; ii < xLimit; ii++ )
{
vx1 = static_cast<float>(ii) / static_cast<float>(xLimit);
vx2 = static_cast<float>(ii+1) / static_cast<float>(xLimit);
px1 = static_cast<int>(vx1 * static_cast<float>(
imageInUseSize[0]));
pxSize = static_cast<int>(2 - px1 + vx2 * static_cast<float>(
imageInUseSize[0]-1));
if ( px1 + pxSize > imageInUseSize[0] )
{
pxSize = imageInUseSize[0] - px1;
}
xMinOffset = 2.0 * offsetX *
(vx1*static_cast<float>(imageInUseSize[0]-1) -
static_cast<float>(px1));
xMaxOffset = 2.0 * offsetX *
(static_cast<float>(px1+pxSize-1) -
vx2*static_cast<float>(imageInUseSize[0]-1));
if ( px1 + pxSize > imageInUseSize[0] )
{
pxSize = imageInUseSize[0] - px1;
}
// copy subtexture of image into newTexture
int loop;
for ( loop = 0; loop < pySize; loop++ )
{
if ( imageScalarType == VTK_UNSIGNED_CHAR )
{
memcpy( newTextureChar + 4*loop*newTextureSize[0],
static_cast<unsigned char *>(image) +
4*(py1+loop)*imageMemorySize[0] + 4*px1,
pxSize * sizeof(unsigned char) * 4 );
}
else
{
memcpy( newTextureShort + 4*loop*newTextureSize[0],
static_cast<unsigned short *>(image) +
4*(py1+loop)*imageMemorySize[0] + 4*px1,
pxSize * sizeof(unsigned short) * 4 );
}
}
newVerts[ 0] = verts[0] + vx1*(verts[3]-verts[0]) + vy1*(verts[ 9]-verts[0]);
newVerts[ 1] = verts[1] + vx1*(verts[4]-verts[1]) + vy1*(verts[10]-verts[1]);
newVerts[ 2] = verts[2] + vx1*(verts[5]-verts[2]) + vy1*(verts[11]-verts[2]);
newVerts[ 3] = verts[0] + vx2*(verts[3]-verts[0]) + vy1*(verts[ 9]-verts[0]);
newVerts[ 4] = verts[1] + vx2*(verts[4]-verts[1]) + vy1*(verts[10]-verts[1]);
newVerts[ 5] = verts[2] + vx2*(verts[5]-verts[2]) + vy1*(verts[11]-verts[2]);
newVerts[ 6] = verts[0] + vx2*(verts[3]-verts[0]) + vy2*(verts[ 9]-verts[0]);
newVerts[ 7] = verts[1] + vx2*(verts[4]-verts[1]) + vy2*(verts[10]-verts[1]);
newVerts[ 8] = verts[2] + vx2*(verts[5]-verts[2]) + vy2*(verts[11]-verts[2]);
newVerts[ 9] = verts[0] + vx1*(verts[3]-verts[0]) + vy2*(verts[ 9]-verts[0]);
newVerts[10] = verts[1] + vx1*(verts[4]-verts[1]) + vy2*(verts[10]-verts[1]);
newVerts[11] = verts[2] + vx1*(verts[5]-verts[2]) + vy2*(verts[11]-verts[2]);
tcoords[0] = offsetX + xMinOffset;
tcoords[1] = offsetY + yMinOffset;
tcoords[2] = (float)pxSize/(float)newTextureSize[0] - offsetX - xMaxOffset;
tcoords[3] = offsetY + yMinOffset;
tcoords[4] = (float)pxSize/(float)newTextureSize[0] - offsetX - xMaxOffset;
tcoords[5] = (float)pySize/(float)newTextureSize[1] - offsetY - yMaxOffset;
tcoords[6] = offsetX + xMaxOffset;
tcoords[7] = (float)pySize/(float)newTextureSize[1] - offsetY - yMaxOffset;
if ( imageScalarType == VTK_UNSIGNED_CHAR )
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8,
newTextureSize[0], newTextureSize[1],
0, GL_RGBA, GL_UNSIGNED_BYTE, newTextureChar );
}
else
{
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8,
newTextureSize[0], newTextureSize[1],
0, GL_RGBA, GL_UNSIGNED_SHORT, newTextureShort );
}
// Render the polygon
glBegin( GL_POLYGON );
for ( i = 0; i < 4; i++ )
{
glTexCoord2fv( tcoords+i*2 );
glVertex3fv( newVerts+i*3 );
}
glEnd();
}
}
// Delete the memory we created
delete [] newTextureChar;
delete [] newTextureShort;
}
glFlush();
glDeleteTextures(1, &tempIndex);
// Restore state
glPopAttrib();
return;
}
#else
if ( imageScalarType == VTK_UNSIGNED_CHAR )
{
glTexImage2D( GL_TEXTURE_2D, 0, 4,
imageMemorySize[0], imageMemorySize[1],
0, GL_RGBA, GL_UNSIGNED_BYTE,
static_cast<unsigned char *>(image) );
}
else
{
glTexImage2D( GL_TEXTURE_2D, 0, 4,
imageMemorySize[0], imageMemorySize[1],
0, GL_RGBA, GL_UNSIGNED_SHORT,
static_cast<unsigned short *>(image) );
}
#endif
offsetX = .5 / static_cast<float>(imageMemorySize[0]);
offsetY = .5 / static_cast<float>(imageMemorySize[1]);
tcoords[0] = 0.0 + offsetX;
tcoords[1] = 0.0 + offsetY;
tcoords[2] =
(float)imageInUseSize[0]/(float)imageMemorySize[0] - offsetX;
tcoords[3] = offsetY;
tcoords[4] =
(float)imageInUseSize[0]/(float)imageMemorySize[0] - offsetX;
tcoords[5] =
(float)imageInUseSize[1]/(float)imageMemorySize[1] - offsetY;
tcoords[6] = offsetX;
tcoords[7] =
(float)imageInUseSize[1]/(float)imageMemorySize[1] - offsetY;
// Render the polygon
glBegin( GL_POLYGON );
for ( i = 0; i < 4; i++ )
{
glTexCoord2fv( tcoords+i*2 );
glVertex3fv( verts+i*3 );
}
glEnd();
#ifdef GL_VERSION_1_1
glFlush();
glDeleteTextures(1, &tempIndex);
#endif
// Restore state
glPopAttrib();
}
void vtkOpenGLRayCastImageDisplayHelper::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
}