Commit 3553ec2c authored by George Zagaris's avatar George Zagaris
Browse files

Merge remote-tracking branch 'origin/master' into AMR-Refactoring

parents 0cdf6f37 1af4e233
......@@ -477,7 +477,6 @@ SET(shader_files
vtkSurfaceLICPainter_fs1.glsl
vtkSurfaceLICPainter_fs2.glsl
vtkSurfaceLICPainter_vs1.glsl
vtkTextureBicubicARB_fp.asm
)
# Create custom commands to encode each assembly file into a C string
......
......@@ -839,9 +839,13 @@ void vtkImageMapper3D::CheckerboardRGBA(
unsigned char *data, int xsize, int ysize,
double originx, double originy, double spacingx, double spacingy)
{
static double tol = 7.62939453125e-06;
static double maxval = 2147483647;
static double minval = -2147483647;
originx += 1.0 + tol;
originy += 1.0 + tol;
originx = (originx > minval ? originx : minval);
originx = (originx < maxval ? originx : maxval);
originy = (originy > minval ? originy : minval);
......@@ -855,8 +859,8 @@ void vtkImageMapper3D::CheckerboardRGBA(
spacingx = (spacingx != 0 ? spacingx : maxval);
spacingy = (spacingy != 0 ? spacingy : maxval);
int xn = static_cast<int>(spacingx);
int yn = static_cast<int>(spacingy);
int xn = static_cast<int>(spacingx + tol);
int yn = static_cast<int>(spacingy + tol);
double fx = spacingx - xn;
double fy = spacingy - yn;
......
......@@ -105,6 +105,7 @@ public:
// Description:
// Make a checkerboard pattern where the black squares are transparent.
// The pattern is aligned with the camera, and centered by default.
vtkSetMacro(Checkerboard, int);
vtkBooleanMacro(Checkerboard, int);
vtkGetMacro(Checkerboard, int);
......@@ -116,7 +117,7 @@ public:
// Description:
// The phase offset for checkerboarding, in units of spacing. Use a
// value between 0 and 2, where 2 is an offset of two squares.
// value between -1 and +1, where 1 is an offset of one squares.
vtkSetVector2Macro(CheckerboardOffset, double);
vtkGetVector2Macro(CheckerboardOffset, double);
......
......@@ -147,7 +147,9 @@ void vtkImageResliceMapper::Render(vtkRenderer *ren, vtkImageSlice *prop)
this->ImageReslice->UpdateWholeExtent();
// apply checkerboard pattern (should have timestamps)
if (property && property->GetCheckerboard())
if (property && property->GetCheckerboard() &&
this->InternalResampleToScreenPixels &&
this->SliceFacesCamera)
{
this->CheckerboardImage(this->ImageReslice->GetOutput(),
ren->GetActiveCamera(), property);
......
......@@ -427,32 +427,3 @@ void vtkImageSliceMapper::GetDimensionIndices(
}
}
}
//----------------------------------------------------------------------------
void vtkImageSliceMapper::CheckerboardImage(
unsigned char *data, int xsize, int ysize,
const double imageSpacing[3], vtkImageProperty *property)
{
// Get the imagedata dims that correspond to the texture "x" and "y"
int xdim, ydim;
this->GetDimensionIndices(this->Orientation, xdim, ydim);
// Get the checkerboard spacing and the offset fraction
double spacing[2], offset[2];
property->GetCheckerboardSpacing(spacing);
property->GetCheckerboardOffset(offset);
// Adjust the spacing according to the image data spacing, add a tolerance
// to prefer rounding up since ties happen often and can cause different
// platforms/compilers to give different results
spacing[0] = floor(spacing[0]/imageSpacing[xdim] + 0.50000762939453125);
spacing[1] = floor(spacing[1]/imageSpacing[ydim] + 0.50000762939453125);
// Center the checkerboard at the image center, because it looks nice
offset[0] = floor(0.5*xsize + spacing[0]*offset[0] + 0.50000762939453125);
offset[1] = floor(0.5*ysize + spacing[1]*offset[1] + 0.50000762939453125);
// Note that spacing has been converted to integer spacing
vtkImageMapper3D::CheckerboardRGBA(
data, xsize, ysize, offset[0], offset[1], spacing[0], spacing[1]);
}
......@@ -154,12 +154,6 @@ protected:
// Get the dimension indices according to the orientation.
static void GetDimensionIndices(int orientation, int &xdim, int &ydim);
// Description:
// Do a checkerboard pattern to the alpha of an RGBA image
void CheckerboardImage(
unsigned char *data, int xsize, int ysize,
const double imageSpacing[3], vtkImageProperty *property);
vtkTimeStamp LoadTime;
int SliceNumber;
int SliceNumberMinValue;
......
......@@ -28,7 +28,7 @@
class vtkWindow;
class vtkRenderer;
class vtkRenderWindow;
class vtkOpenGLRenderWindow;
class vtkMesaRenderWindow;
class vtkImageSlice;
class vtkImageProperty;
class vtkImageData;
......@@ -56,16 +56,27 @@ protected:
~vtkMesaImageSliceMapper();
// Description:
// Load the texture and geometry.
void Load(vtkRenderer *ren, vtkProp3D *prop, vtkImageProperty *property);
// Call the OpenGL code that does color and lighting.
void RenderColorAndLighting(
double red, double green, double blue,
double alpha, double ambient, double diffuse);
// Description:
// Render an opaque polygon behind the image. This is also used
// in multi-pass rendering to render into the depth buffer.
void RenderBackingPolygon();
// Description:
// Non-recursive internal method, generate a single texture
// and its corresponding geometry.
void InternalLoad(
vtkRenderer *ren, vtkProp3D *prop, vtkImageProperty *property,
void RenderTexturedPolygon(
vtkRenderer *ren, vtkImageProperty *property,
vtkImageData *image, int extent[6], bool recursive);
// Description:
// Build the fragment program to use with the texture.
vtkStdString BuildFragmentProgram(vtkImageProperty *property);
// Description:
// Given an extent that describes a slice (it must have unit thickness
// in one of the three directions), return the dimension indices that
......@@ -83,18 +94,11 @@ protected:
// Description:
// Check various OpenGL capabilities
void CheckOpenGLCapabilities(vtkOpenGLRenderWindow *renWin);
// Description:
// Garbage collection for reference loops.
void ReportReferences(vtkGarbageCollector*);
void CheckOpenGLCapabilities(vtkMesaRenderWindow *renWin);
vtkTimeStamp LoadTime;
long Index; // OpenGL ID for texture or display list
long FragmentShaderIndex; // OpenGL ID for fragment shader
vtkRenderWindow *RenderWindow; // RenderWindow used for previous render
double Coords[12];
double TCoords[8];
int TextureSize[2];
int TextureBytesPerPixel;
int LastOrientation;
......
......@@ -28,7 +28,6 @@
#include "vtkOpenGLRenderer.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLExtensionManager.h"
#include "vtkTextureBicubicARB_fp.h"
#include "vtkTimerLog.h"
#include "vtkGarbageCollector.h"
#include "vtkTemplateAliasMacro.h"
......@@ -165,6 +164,7 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
// get the previous texture load time
unsigned long loadTime = this->LoadTime.GetMTime();
// the render window, needed for state information
vtkOpenGLRenderWindow *renWin =
static_cast<vtkOpenGLRenderWindow *>(ren->GetRenderWindow());
......@@ -182,11 +182,21 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
reuseTexture = false;
}
// get information about the image
double *spacing = input->GetSpacing();
double *origin = input->GetOrigin();
int xdim, ydim, zdim; // orientation of texture wrt input image
vtkImageSliceMapper::GetDimensionIndices(this->Orientation, xdim, ydim);
zdim = (this->Orientation % 3);
// check whether to use a shader for bicubic interpolation
bool checkerboard = (property && property->GetCheckerboard());
bool cubicInterpolation = (property &&
property->GetInterpolationType() == VTK_CUBIC_INTERPOLATION);
bool useFragmentProgram =
(this->UseFragmentProgram &&
property->GetInterpolationType() == VTK_CUBIC_INTERPOLATION &&
!this->ExactPixelMatch);
(!this->ExactPixelMatch || !this->SliceFacesCamera) &&
(cubicInterpolation || checkerboard));
// verify that the orientation and slice has not changed
bool orientationChanged = (this->Orientation != this->LastOrientation);
......@@ -196,7 +206,6 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
// get the mtime of the property, including the lookup table
unsigned long propertyMTime = 0;
bool checkerboard = false;
if (property)
{
propertyMTime = property->GetMTime();
......@@ -211,7 +220,6 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
propertyMTime = mtime;
}
}
checkerboard = (property->GetCheckerboard() != 0);
}
}
......@@ -224,29 +232,19 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
renWin->GetContextCreationTime() > loadTime ||
recursive)
{
// whether to try to use the input data directly as the texture
bool reuseData = true;
if (checkerboard)
{
reuseData = false;
}
// get the data to load as a texture
int xsize = this->TextureSize[0];
int ysize = this->TextureSize[1];
int bytesPerPixel = this->TextureBytesPerPixel;
// whether to try to use the input data directly as the texture
bool reuseData = true;
// generate the data to be used as a texture
unsigned char *data = this->MakeTextureData(
(this->PassColorData ? 0 : property), input, extent, xsize, ysize,
bytesPerPixel, reuseTexture, reuseData);
if (checkerboard)
{
this->CheckerboardImage(
data, xsize, ysize, input->GetSpacing(), property);
}
GLuint tempIndex = 0;
#ifdef GL_VERSION_1_1
......@@ -318,13 +316,14 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
// reliably even with very old hardware and drivers
vtkgl::GenProgramsARB(1, &tempIndex);
this->FragmentShaderIndex = static_cast<long>(tempIndex);
vtkStdString prog = this->BuildFragmentProgram(property);
vtkgl::BindProgramARB(vtkgl::FRAGMENT_PROGRAM_ARB,
this->FragmentShaderIndex);
const char *prog = vtkTextureBicubicARB_fp;
vtkgl::ProgramStringARB(vtkgl::FRAGMENT_PROGRAM_ARB,
vtkgl::PROGRAM_FORMAT_ASCII_ARB,
static_cast<GLsizei>(strlen(prog)), prog);
static_cast<GLsizei>(prog.size()), prog.c_str());
GLint erri;
glGetIntegerv(vtkgl::PROGRAM_ERROR_POSITION_ARB, &erri);
......@@ -381,11 +380,63 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
// not do anything if modern shader objects are also in play.
vtkgl::BindProgramARB(vtkgl::FRAGMENT_PROGRAM_ARB,
this->FragmentShaderIndex);
// checkerboard information
double checkSpacing[2], checkOffset[2];
property->GetCheckerboardSpacing(checkSpacing);
property->GetCheckerboardOffset(checkOffset);
// transformation to permute texture-oriented coords to data coords
double mat[16];
vtkMatrix4x4::Identity(mat);
mat[0] = mat[5] = mat[10] = 0.0;
mat[4*xdim] = mat[1+4*ydim] = 1.0;
int dimsep = ydim - xdim + 3*(xdim > ydim);
mat[2+4*zdim] = (((dimsep % 3) == 1) ? 1.0 : -1.0);
mat[4*zdim+3] = origin[zdim] + spacing[zdim]*this->DisplayExtent[2*zdim];
// checkerboard uses view coordinates
vtkMatrix4x4 *m = this->GetDataToWorldMatrix();
vtkMatrix4x4 *c = ren->GetActiveCamera()->GetViewTransformMatrix();
vtkMatrix4x4::Multiply4x4(*m->Element, mat, mat);
vtkMatrix4x4::Multiply4x4(*c->Element, mat, mat);
// first parameter: texture size needed for bicubic interpolator
vtkgl::ProgramLocalParameter4fARB(vtkgl::FRAGMENT_PROGRAM_ARB, 0,
static_cast<float>(this->TextureSize[0]),
static_cast<float>(this->TextureSize[1]),
static_cast<float>(1.0/this->TextureSize[0]),
static_cast<float>(1.0/this->TextureSize[1]));
static_cast<float>(this->TextureSize[0]),
static_cast<float>(this->TextureSize[1]),
static_cast<float>(1.0/this->TextureSize[0]),
static_cast<float>(1.0/this->TextureSize[1]));
// second parameter: scale and offset for converting texture coords
// into the input image's data coords
vtkgl::ProgramLocalParameter4fARB(vtkgl::FRAGMENT_PROGRAM_ARB, 1,
static_cast<float>(this->TextureSize[0]*spacing[xdim]),
static_cast<float>(this->TextureSize[1]*spacing[ydim]),
static_cast<float>(origin[xdim] +
spacing[xdim]*(this->DisplayExtent[2*xdim] - 0.5)),
static_cast<float>(origin[ydim] +
spacing[ydim]*(this->DisplayExtent[2*ydim] - 0.5)));
// third parameter: scale and offset for converting data coords into
// checkboard square indices, for checkerboarding
vtkgl::ProgramLocalParameter4fARB(vtkgl::FRAGMENT_PROGRAM_ARB, 2,
static_cast<float>(0.5/checkSpacing[0]),
static_cast<float>(0.5/checkSpacing[1]),
static_cast<float>(-0.5*checkOffset[0]),
static_cast<float>(-0.5*checkOffset[1]));
// fourth, fifth param: first two rows of the transformation matrix
// from data coords to camera coords (including a pre-translation of
// z from zero to the z position of the slice, since the texture coords
// are 2D and do not provide the z position)
vtkgl::ProgramLocalParameter4fARB(vtkgl::FRAGMENT_PROGRAM_ARB, 3,
static_cast<float>(mat[0]), static_cast<float>(mat[1]),
static_cast<float>(mat[2]), static_cast<float>(mat[3]));
vtkgl::ProgramLocalParameter4fARB(vtkgl::FRAGMENT_PROGRAM_ARB, 4,
static_cast<float>(mat[4]), static_cast<float>(mat[5]),
static_cast<float>(mat[6]), static_cast<float>(mat[7]));
glEnable(vtkgl::FRAGMENT_PROGRAM_ARB);
}
......@@ -396,7 +447,7 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
static double normals[3][3] =
{ { 1.0, 0.0, 0.0 }, { 0.0, -1.0, 0.0 }, { 0.0, 0.0, 1.0 } };
double *normal = normals[(this->Orientation % 3)];
double *normal = normals[zdim];
if (!this->Points || (this->ExactPixelMatch && this->SliceFacesCamera))
{
......@@ -421,18 +472,16 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
vtkIdType ncoords = points->GetNumberOfPoints();
double coord[3];
double tcoord[2];
double *spacing = input->GetSpacing();
double *origin = input->GetOrigin();
int xdim, ydim;
vtkImageSliceMapper::GetDimensionIndices(this->Orientation, xdim, ydim);
glBegin((ncoords == 4) ? GL_QUADS : GL_POLYGON);
for (vtkIdType i = 0; i < ncoords; i++)
{
points->GetPoint(i, coord);
tcoord[0] = ((coord[0] - origin[xdim] + 0.5*spacing[xdim])/
(this->TextureSize[0]*spacing[xdim]));
tcoord[1] = ((coord[1] - origin[ydim] + 0.5*spacing[ydim])/
tcoord[0] = ((coord[0] - origin[xdim] +
(0.5 - this->DisplayExtent[2*xdim])*spacing[xdim])/
(this->TextureSize[xdim]*spacing[xdim]));
tcoord[1] = ((coord[1] - origin[ydim] +
(0.5 - this->DisplayExtent[2*ydim])*spacing[ydim])/
(this->TextureSize[ydim]*spacing[ydim]));
glNormal3dv(normal);
......@@ -448,6 +497,130 @@ void vtkOpenGLImageSliceMapper::RenderTexturedPolygon(
}
}
//----------------------------------------------------------------------------
vtkStdString vtkOpenGLImageSliceMapper::BuildFragmentProgram(
vtkImageProperty *property)
{
vtkStdString prog =
"!!ARBfp1.0\n"
"\n";
// parameters needed for cubic interpolation:
// texdim is texture size {width, height, 1.0/width, 1.0/height}
// parameters needed for checkerboarding:
// todata is for converting tex coords to VTK data coords
// togrid converts transformed data coords to checkerboard squares
// mx, my are first two rows of matrix for transforming data coords
prog.append(
"PARAM texdim = program.local[0];\n"
"PARAM todata = program.local[1];\n"
"PARAM togrid = program.local[2];\n"
"PARAM mx = program.local[3];\n"
"PARAM my = program.local[4];\n"
"TEMP coord, coord2;\n"
"TEMP c, c1, c2;\n"
"TEMP weightx, weighty;\n"
"\n");
// checkerboard
if (property->GetCheckerboard())
{
prog.append(
"# generate a checkerboard pattern\n"
"MOV coord.xyzw, {0, 0, 0, 1};\n"
"MAD coord.xy, fragment.texcoord.xyxy, todata.xyxy, todata.zwzw;\n"
"DP4 coord2.x, coord, mx;\n"
"DP4 coord2.y, coord, my;\n"
"MAD coord.xy, coord2.xyxy, togrid.xyxy, togrid.zwzw;\n"
"FRC coord.xy, coord;\n"
"SUB coord.xy, coord, {0.5, 0.5, 0.5, 0.5};\n"
"MUL coord.x, coord.x, coord.y;\n"
"KIL coord.x;\n"
"\n");
}
// interpolate
if (property->GetInterpolationType() == VTK_CUBIC_INTERPOLATION)
{
// create a bicubic interpolation program
prog.append(
"# compute the {rx, ry, fx, fy} fraction vector\n"
"MAD coord, fragment.texcoord.xyxy, texdim.xyxy, {0.5, 0.5, 0.5, 0.5};\n"
"FRC coord, coord;\n"
"SUB coord.xy, {1, 1, 1, 1}, coord;\n"
"\n"
"# compute the x weights\n"
"MAD weightx, coord.zzxx, {0.5, 1.5, 1.5, 0.5}, {0,-1,-1, 0};\n"
"MAD weightx, weightx, coord.xzxz, {0,-1,-1, 0};\n"
"MUL weightx, weightx, -coord.xxzz;\n"
"\n"
"# compute the y weights\n"
"MAD weighty, coord.wwyy, {0.5, 1.5, 1.5, 0.5}, {0,-1,-1, 0};\n"
"MAD weighty, weighty, coord.ywyw, {0,-1,-1, 0};\n"
"MUL weighty, weighty, -coord.yyww;\n"
"\n"
"# get the texture coords for the coefficients\n"
"ADD coord, coord.xyxy, {-2,-2,-1,-2};\n"
"MAD coord, coord, texdim.zwzw, fragment.texcoord.xyxy;\n"
"MAD coord2, texdim.zwzw, {2, 0, 2, 0}, coord;\n"
"\n");
// loop through the rows of the kernel
for (int i = 0; i < 4; i++)
{
prog.append(
"# do a row of texture lookups and weights\n"
"TEX c2, coord.xyzw, texture, 2D;\n"
"MUL c1, c2, weightx.xxxx;\n"
"TEX c2, coord.zwxy, texture, 2D;\n"
"MAD c1, c2, weightx.yyyy, c1;\n"
"TEX c2, coord2.xyzw, texture, 2D;\n"
"MAD c1, c2, weightx.zzzz, c1;\n"
"TEX c2, coord2.zwxy, texture, 2D;\n"
"MAD c1, c2, weightx.wwww, c1;\n");
// choose the y weight for current row
static const char *rowsum[4] = {
"MUL c, weighty.xxxx, c1;\n\n",
"MAD c, weighty.yyyy, c1, c;\n\n",
"MAD c, weighty.zzzz, c1, c;\n\n",
"MAD c, weighty.wwww, c1, c;\n\n"
};
prog.append(rowsum[i]);
if (i < 3)
{
prog.append(
"# advance y coord to next row\n"
"ADD coord.yw, coord, texdim.wwww;\n"
"ADD coord2.yw, coord2, texdim.wwww;\n"
"\n");
}
}
}
else
{
// use currently set texture interpolation
prog.append(
"# interpolate the texture\n"
"TEX c, fragment.texcoord, texture, 2D;\n"
"\n");
}
// modulate the fragment color with the texture
prog.append(
"# output the color\n"
"MUL result.color, fragment.color, c;\n"
"\n");
// end program
prog.append(
"END\n");
return prog;
}
//----------------------------------------------------------------------------
void vtkOpenGLImageSliceMapper::ComputeTextureSize(
const int extent[6], int &xdim, int &ydim,
......
......@@ -73,6 +73,10 @@ protected:
vtkRenderer *ren, vtkImageProperty *property,
vtkImageData *image, int extent[6], bool recursive);
// Description:
// Build the fragment program to use with the texture.
vtkStdString BuildFragmentProgram(vtkImageProperty *property);
// Description:
// Given an extent that describes a slice (it must have unit thickness
// in one of the three directions), return the dimension indices that
......@@ -95,8 +99,6 @@ protected:
long Index; // OpenGL ID for texture or display list
long FragmentShaderIndex; // OpenGL ID for fragment shader
vtkRenderWindow *RenderWindow; // RenderWindow used for previous render
double Coords[12];
double TCoords[8];
int TextureSize[2];
int TextureBytesPerPixel;
int LastOrientation;
......
!!ARBfp1.0
# bicubic texture interpolator
# author: David Gobbi
# 1 parameter (max 24)
# 1 texture (max 2)
# 10 temporaries (max 12)
# 16 texture lookups (max 24)
# 55 instructions (max 72)
# width, height, xspacing, yspacing
PARAM texdim = program.local[0];
TEMP coord, coord2;
TEMP weightx, weighty;
TEMP t1, t2, t3, t4;
TEMP c, c1;
# compute the {rx, ry, fx, fy} fraction vector
MAD coord, fragment.texcoord.xyxy, texdim.xyxy, {0.5, 0.5, 0.5, 0.5};
FRC coord, coord;
SUB coord.xy, {1, 1, 1, 1}, coord;
# compute the x weights
MAD weightx, coord.zzxx, {0.5, 1.5, 1.5, 0.5}, {0,-1,-1, 0};
MAD weightx, weightx, coord.xzxz, {0,-1,-1, 0};
MUL weightx, weightx, -coord.xxzz;
# compute the y weights
MAD weighty, coord.wwyy, {0.5, 1.5, 1.5, 0.5}, {0,-1,-1, 0};
MAD weighty, weighty, coord.ywyw, {0,-1,-1, 0};
MUL weighty, weighty, -coord.yyww;
# get the texture coords for the coefficients
ADD coord, coord.xyxy, {-2,-2,-1,-2};
MAD coord, coord, texdim.zwzw, fragment.texcoord.xyxy;
MAD coord2, texdim.zwzw, {2, 0, 2, 0}, coord;
# do first set of X lookups
TEX t1, coord.xyzw, texture, 2D;
TEX t2, coord.zwxy, texture, 2D;
TEX t3, coord2.xyzw, texture, 2D;
TEX t4, coord2.zwxy, texture, 2D;
# multiply by the weights
MUL c1, t1, weightx.xxxx;
MAD c1, t2, weightx.yyyy, c1;
MAD c1, t3, weightx.zzzz, c1;
MAD c1, t4, weightx.wwww, c1;
MUL c, weighty.xxxx, c1;
# advance to next row
ADD coord.yw, coord, texdim.wwww;
ADD coord2.yw, coord2, texdim.wwww;
# do second set of X lookups
TEX t1, coord.xyzw, texture, 2D;
TEX t2, coord.zwxy, texture, 2D;
TEX t3, coord2.xyzw, texture, 2D;
TEX t4, coord2.zwxy, texture, 2D;
# multiply by the weights
MUL c1, t1, weightx.xxxx;
MAD c1, t2, weightx.yyyy, c1;
MAD c1, t3, weightx.zzzz, c1;
MAD c1, t4, weightx.wwww, c1;
MAD c, weighty.yyyy, c1, c;
# advance to next row
ADD coord.yw, coord, texdim.wwww;
ADD coord2.yw, coord2, texdim.wwww;
# do third set of X lookups