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.
 
 
 
 
 
 

710 lines
20 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkCompressCompositer.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.
=========================================================================*/
// This software and ancillary information known as vtk_ext (and
// herein called "SOFTWARE") is made available under the terms
// described below. The SOFTWARE has been approved for release with
// associated LA_CC Number 99-44, granted by Los Alamos National
// Laboratory in July 1999.
//
// Unless otherwise indicated, this SOFTWARE has been authored by an
// employee or employees of the University of California, operator of
// the Los Alamos National Laboratory under Contract No. W-7405-ENG-36
// with the United States Department of Energy.
//
// The United States Government has rights to use, reproduce, and
// distribute this SOFTWARE. The public may copy, distribute, prepare
// derivative works and publicly display this SOFTWARE without charge,
// provided that this Notice and any statement of authorship are
// reproduced on all copies.
//
// Neither the U. S. Government, the University of California, nor the
// Advanced Computing Laboratory makes any warranty, either express or
// implied, nor assumes any liability or responsibility for the use of
// this SOFTWARE.
//
// If SOFTWARE is modified to produce derivative works, such modified
// SOFTWARE should be clearly marked, so as not to confuse it with the
// version available from Los Alamos National Laboratory.
#ifdef VTK_USE_MPI
#include <mpi.h>
#endif
#include "vtkCompressCompositer.h"
#include "vtkObjectFactory.h"
#include "vtkToolkits.h"
#include "vtkFloatArray.h"
#include "vtkUnsignedCharArray.h"
#include "vtkMultiProcessController.h"
#include "vtkTimerLog.h"
vtkCxxRevisionMacro(vtkCompressCompositer, "$Revision: 1.14 $");
vtkStandardNewMacro(vtkCompressCompositer);
// Different pixel types to template.
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
} vtkCharRGBType;
typedef struct {
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} vtkCharRGBAType;
typedef struct {
float r;
float g;
float b;
float a;
} vtkFloatRGBAType;
//-------------------------------------------------------------------------
vtkCompressCompositer::vtkCompressCompositer()
{
this->InternalPData = NULL;
this->InternalZData = NULL;
this->Timer = vtkTimerLog::New();
}
//-------------------------------------------------------------------------
vtkCompressCompositer::~vtkCompressCompositer()
{
if (this->InternalPData)
{
this->InternalPData->Delete();
this->InternalPData = NULL;
}
if (this->InternalZData)
{
this->InternalZData->Delete();
this->InternalZData = NULL;
}
this->Timer->Delete();
this->Timer = NULL;
}
//-------------------------------------------------------------------------
// Compress background pixels with runlength encoding.
// z values above 1.0 mean: Repeat background for that many pixels.
// We could easily compress inplace, but it works out better for buffer
// managment if we do not. zIn == zOut is allowed....
template <class P>
int vtkCompressCompositerCompress(float *zIn, P *pIn, float *zOut, P *pOut,
int numPixels)
{
float* endZ;
int length = 0;
int compressCount;
// Do not go past the last pixel (zbuf check/correct)
endZ = zIn+numPixels-1;
if (*zIn < 0.0 || *zIn > 1.0)
{
*zIn = 1.0;
}
while (zIn < endZ)
{
++length;
// Always copy the first pixel value.
*pOut++ = *pIn++;
// Find the length of any compressed run.
compressCount = 0;
while (*zIn == 1.0 && zIn < endZ)
{
++compressCount;
++zIn;
if (*zIn < 0.0 || *zIn > 1.0)
{
*zIn = 1.0;
}
}
if (compressCount > 0)
{ // Only compress runs of 2 or more.
// Move the pixel pointer past compressed region.
pIn += (compressCount-1);
// Set the special z value.
*zOut++ = (float)(compressCount);
}
else
{
*zOut++ = *zIn++;
if (*zIn < 0.0 || *zIn > 1.0)
{
*zIn = 1.0;
}
}
}
// Put the last pixel in.
*pOut = *pIn;
*zOut = *zIn;
return length;
}
//-------------------------------------------------------------------------
// Compress background pixels with runlength encoding.
// z values above 1.0 mean: Repeat background for that many pixels.
// We could easily compress inplace, but it works out better for buffer
// managment if we do not. zIn == zOut is allowed....
void vtkCompressCompositer::Compress(vtkFloatArray *zIn, vtkDataArray *pIn,
vtkFloatArray *zOut, vtkDataArray *pOut)
{
float* pzf1 = zIn->GetPointer(0);
float* pzf2 = zOut->GetPointer(0);
void* ppv1 = pIn->GetVoidPointer(0);
void* ppv2 = pOut->GetVoidPointer(0);
int totalPixels = zIn->GetNumberOfTuples();
int length;
vtkTimerLog::MarkStartEvent("Compress");
// This is just a complex switch statment
// to call the correct templated function.
if (pIn->GetDataType() == VTK_UNSIGNED_CHAR)
{
if (pIn->GetNumberOfComponents() == 3)
{
length = vtkCompressCompositerCompress(
pzf1, reinterpret_cast<vtkCharRGBType*>(ppv1),
pzf2, reinterpret_cast<vtkCharRGBType*>(ppv2),
totalPixels);
}
else if (pIn->GetNumberOfComponents() == 4)
{
length = vtkCompressCompositerCompress(
pzf1, reinterpret_cast<vtkCharRGBAType*>(ppv1),
pzf2, reinterpret_cast<vtkCharRGBAType*>(ppv2),
totalPixels);
}
else
{
vtkGenericWarningMacro("Pixels have unexpected number of components.");
return;
}
}
else if (pIn->GetDataType() == VTK_FLOAT &&
pIn->GetNumberOfComponents() == 4)
{
length = vtkCompressCompositerCompress(
pzf1, reinterpret_cast<vtkFloatRGBAType*>(ppv1),
pzf2, reinterpret_cast<vtkFloatRGBAType*>(ppv2),
totalPixels);
}
else
{
vtkGenericWarningMacro("Unexpected pixel type.");
return;
}
zOut->SetNumberOfTuples(length);
pOut->SetNumberOfTuples(length);
vtkTimerLog::MarkEndEvent("Compress");
}
//-------------------------------------------------------------------------
// z values above 1.0 mean: Repeat background for that many pixels.
// Assume that the array has enough allocated space for the uncompressed.
// In place/reverse order.
template <class P>
void vtkCompressCompositerUncompress(float *zIn, P *pIn, float *zOut, P *pOut,
int lengthIn)
{
float* endZ;
int count;
P background;
endZ = zIn + lengthIn;
while (zIn < endZ)
{
// Expand any compressed data.
if (*zIn > 1.0)
{
background = *pIn++;
count = (int)(*zIn++);
while (count-- > 0)
{
*pOut++ = background;
*zOut++ = 1.0;
}
}
else
{
*pOut++ = *pIn++;
*zOut++ = *zIn++;
}
}
}
//-------------------------------------------------------------------------
// Compress background pixels with runlength encoding.
// z values above 1.0 mean: Repeat background for that many pixels.
// We could easily compress inplace, but it works out better for buffer
// managment if we do not. zIn == zOut is allowed....
void vtkCompressCompositer::Uncompress(vtkFloatArray *zIn, vtkDataArray *pIn,
vtkFloatArray *zOut, vtkDataArray *pOut,
int lengthOut)
{
float* pzf1 = zIn->GetPointer(0);
float* pzf2 = zOut->GetPointer(0);
void* ppv1 = pIn->GetVoidPointer(0);
void* ppv2 = pOut->GetVoidPointer(0);
int lengthIn = zIn->GetNumberOfTuples();
vtkTimerLog::MarkStartEvent("Uncompress");
// This is just a complex switch statment
// to call the correct templated function.
if (pIn->GetDataType() == VTK_UNSIGNED_CHAR)
{
if (pIn->GetNumberOfComponents() == 3)
{
vtkCompressCompositerUncompress(pzf1,
reinterpret_cast<vtkCharRGBType*>(ppv1),
pzf2,
reinterpret_cast<vtkCharRGBType*>(ppv2),
lengthIn);
}
else if (pIn->GetNumberOfComponents() == 4)
{
vtkCompressCompositerUncompress(pzf1,
reinterpret_cast<vtkCharRGBAType*>(ppv1),
pzf2,
reinterpret_cast<vtkCharRGBAType*>(ppv2),
lengthIn);
}
else
{
vtkGenericWarningMacro("Pixels have unexpected number of components.");
return;
}
}
else if (pIn->GetDataType() == VTK_FLOAT &&
pIn->GetNumberOfComponents() == 4)
{
vtkCompressCompositerUncompress(pzf1,
reinterpret_cast<vtkFloatRGBAType*>(ppv1),
pzf2,
reinterpret_cast<vtkFloatRGBAType*>(ppv2),
lengthIn);
}
else
{
vtkGenericWarningMacro("Unexpected pixel type.");
return;
}
//zOut->SetNumberOfTuples(lengthOut);
pOut->SetNumberOfTuples(lengthOut);
vtkTimerLog::MarkEndEvent("Uncompress");
}
//-------------------------------------------------------------------------
// Can handle compositing compressed buffers.
// z values above 1.0 mean: Repeat background for that many pixels.
template <class P>
int vtkCompressCompositerCompositePair(float *z1, P *p1, float *z2, P *p2,
float *zOut, P *pOut, int length1)
{
float* startZOut = zOut;
float* endZ1;
// These counts keep track of the length of compressed runs.
// Value -1 means pointer is not on a compression run.
// Value 0 means pointer is on a used up compression run.
int cCount1 = 0;
int cCount2 = 0;
int cCount3;
int length3;
// This is for the end test.
// We are assuming that the uncompressed buffer length of 1 and 2
// are the same.
endZ1 = z1 + length1;
while(z1 != endZ1)
{
// Initialize a new state if necessary.
if (cCount1 == 0 && *z1 > 1.0)
{ // Detect a new run in buffer 1.
cCount1 = (int)(*z1);
}
if (cCount2 == 0 && *z2 > 1.0)
{ // Detect a new run in buffer 2.
cCount2 = (int)(*z2);
}
// Case 1: Neither buffer is compressed.
// We could keep the length of uncompressed runs ...
if (cCount1 == 0 && cCount2 == 0)
{
// Loop through buffers doing standard compositing.
while (*z1 <= 1.0 && *z2 <= 1.0 && z1 != endZ1)
{
if (*z1 < *z2)
{
*zOut++ = *z1++;
++z2;
*pOut++ = *p1++;
++p2;
}
else
{
*zOut++ = *z2++;
++z1;
*pOut++ = *p2++;
++p1;
}
}
// Let the next iteration determine the new state (counts).
}
else if (cCount1 > 0 && cCount2 > 0)
{ // segment where both are compressed
// Pick the smaller compressed run an duplicate in output.
cCount3 = (cCount1 < cCount2) ? cCount1 : cCount2;
cCount2 -= cCount3;
cCount1 -= cCount3;
// Set the output pixel.
*zOut++ = (float)(cCount3);
// either pixel will do.
*pOut++ = *p1;
if (cCount1 == 0)
{
++z1;
++p1;
}
if (cCount2 == 0)
{
++z2;
++p2;
}
}
else if (cCount1 > 0 && cCount2 == 0)
{ //1 is in a compressed run but 2 is not.
// Copy from 2 until we hit a compressed region,
// or we run out of the 1 compressed run.
while (cCount1 && *z2 <= 1.0)
{
*zOut++ = *z2++;
*pOut++ = *p2++;
--cCount1;
}
if (cCount1 == 0)
{
++z1;
++p1;
}
}
else if (cCount1 == 0 && cCount2 > 0)
{ //2 is in a compressed run but 1 is not.
// Copy from 1 until we hit a compressed region,
// or we run out of the 2 compressed run.
while (cCount2 && *z1 <= 1.0)
{
*zOut++ = *z1++;
*pOut++ = *p1++;
--cCount2;
}
if (cCount2 == 0)
{
++z2;
++p2;
}
} // end case if.
} // while not finished (process cases).
// Here is a scary way to determine the length of the new buffer.
length3 = zOut - startZOut;
return length3;
}
//-------------------------------------------------------------------------
// Can handle compositing compressed buffers.
// z values above 1.0 mean: Repeat background for that many pixels.
void vtkCompressCompositer::CompositeImagePair(
vtkFloatArray *localZ, vtkDataArray *localP,
vtkFloatArray *remoteZ, vtkDataArray *remoteP,
vtkFloatArray *outZ, vtkDataArray *outP)
{
float* z1 = localZ->GetPointer(0);
float* z2 = remoteZ->GetPointer(0);
float* z3 = outZ->GetPointer(0);
void* p1 = localP->GetVoidPointer(0);
void* p2 = remoteP->GetVoidPointer(0);
void* p3 = outP->GetVoidPointer(0);
int length1 = localZ->GetNumberOfTuples();
int l3;
//vtkTimerLog::MarkStartEvent("Coomposite Image Pair");
// This is just a complex switch statment
// to call the correct templated function.
if (localP->GetDataType() == VTK_UNSIGNED_CHAR)
{
if (localP->GetNumberOfComponents() == 3)
{
l3 = vtkCompressCompositerCompositePair(
z1, reinterpret_cast<vtkCharRGBType*>(p1),
z2, reinterpret_cast<vtkCharRGBType*>(p2),
z3, reinterpret_cast<vtkCharRGBType*>(p3),
length1);
}
else if (localP->GetNumberOfComponents() == 4)
{
l3 = vtkCompressCompositerCompositePair(
z1, reinterpret_cast<vtkCharRGBAType*>(p1),
z2, reinterpret_cast<vtkCharRGBAType*>(p2),
z3, reinterpret_cast<vtkCharRGBAType*>(p3),
length1);
}
else
{
vtkGenericWarningMacro("Pixels have unexpected number of components.");
return;
}
}
else if (localP->GetDataType() == VTK_FLOAT &&
localP->GetNumberOfComponents() == 4)
{
l3 = vtkCompressCompositerCompositePair(
z1, reinterpret_cast<vtkFloatRGBAType*>(p1),
z2, reinterpret_cast<vtkFloatRGBAType*>(p2),
z3, reinterpret_cast<vtkFloatRGBAType*>(p3),
length1);
}
else
{
vtkGenericWarningMacro("Unexpected pixel type.");
return;
}
outZ->SetNumberOfTuples(l3);
outP->SetNumberOfTuples(l3);
//vtkTimerLog::MarkEndEvent("Coomposite Image Pair");
}
#define vtkTCPow2(j) (1 << (j))
//----------------------------------------------------------------------------
inline int vtkTCLog2(int j, int& exact)
{
int counter=0;
exact = 1;
while(j)
{
if ( ( j & 1 ) && (j >> 1) )
{
exact = 0;
}
j = j >> 1;
counter++;
}
return counter-1;
}
//----------------------------------------------------------------------------
void vtkCompressCompositer::CompositeBuffer(vtkDataArray *pBuf,
vtkFloatArray *zBuf,
vtkDataArray *pTmp,
vtkFloatArray *zTmp)
{
int myId = this->Controller->GetLocalProcessId();
int numProcs = this->NumberOfProcesses;
int i, id;
int exactLog;
int logProcs = vtkTCLog2(numProcs,exactLog);
int uncompressedLength = zBuf->GetNumberOfTuples();
int bufSize=0;
int numComps = pBuf->GetNumberOfComponents();
vtkDataArray *p1, *p2, *p3;
vtkFloatArray *z1, *z2, *z3;
//this->Timer->StartTimer();
// Make sure we have an internal buffer of the correct length.
if (this->InternalPData == NULL ||
this->InternalPData->GetDataType() != pBuf->GetDataType() ||
this->InternalPData->GetNumberOfTuples() != pBuf->GetNumberOfTuples() ||
this->InternalPData->GetSize() < pBuf->GetSize())
{
if (this->InternalPData)
{
vtkCompositer::DeleteArray(this->InternalPData);
this->InternalPData = NULL;
}
if (pBuf->GetDataType() == VTK_UNSIGNED_CHAR)
{
this->InternalPData = vtkUnsignedCharArray::New();
vtkCompositer::ResizeUnsignedCharArray(
static_cast<vtkUnsignedCharArray*>(this->InternalPData),
numComps, pBuf->GetSize());
}
else
{
this->InternalPData = vtkFloatArray::New();
vtkCompositer::ResizeFloatArray(
static_cast<vtkFloatArray*>(this->InternalPData),
numComps, pBuf->GetSize());
}
}
// Now float array.
if (this->InternalZData == NULL ||
this->InternalZData->GetSize() < zBuf->GetSize())
{
if (this->InternalZData)
{
vtkCompositer::DeleteArray(this->InternalZData);
this->InternalZData = NULL;
}
this->InternalZData = vtkFloatArray::New();
vtkCompositer::ResizeFloatArray(
static_cast<vtkFloatArray*>(this->InternalZData),
1, zBuf->GetSize());
}
// Compress the incoming buffers (in place operation).
this->Compress(zBuf, pBuf, zTmp, pTmp);
// We are going to need to shuffle these around during compositing.
p1 = pTmp;
z1 = zTmp;
p2 = this->InternalPData;
z2 = this->InternalZData;
// not a power of 2 -- need an additional level
if ( !exactLog )
{
logProcs++;
}
#ifdef MPIPROALLOC
vtkCommunicator::SetUseCopy(0);
#endif
for (i = 0; i < logProcs; i++)
{
if ((myId % (int)vtkTCPow2(i)) == 0)
{ // Find participants
if ((myId % (int)vtkTCPow2(i+1)) < vtkTCPow2(i))
{
// receivers
id = myId+vtkTCPow2(i);
// only send or receive if sender or receiver id is valid
// (handles non-power of 2 cases)
if (id < numProcs)
{
this->Controller->Receive(&bufSize, 1, id, 98);
this->Controller->Receive(zBuf->GetPointer(0), bufSize, id, 99);
this->Controller->Receive(&bufSize, 1, id, 98);
if (pTmp->GetDataType() == VTK_UNSIGNED_CHAR)
{
this->Controller->Receive(reinterpret_cast<unsigned char*>
(pBuf->GetVoidPointer(0)),
bufSize, id, 99);
}
else
{
this->Controller->Receive(reinterpret_cast<float*>
(pBuf->GetVoidPointer(0)),
bufSize, id, 99);
}
// notice the result is stored as the local data
this->CompositeImagePair(z1, p1, zBuf, pBuf, z2, p2);
// Swap the temp buffers (p3/z3 are just temporary storage).
p3 = p1;
z3 = z1;
p1 = p2;
z1 = z2;
p2 = p3;
z2 = z3;
}
}
else
{ // The current data is always in buffer 1.
id = myId-vtkTCPow2(i);
if (id < numProcs)
{
bufSize = z1->GetNumberOfTuples();
this->Controller->Send(&bufSize, 1, id, 98);
this->Controller->Send(z1->GetPointer(0), bufSize, id, 99);
bufSize = p1->GetNumberOfTuples() * numComps;
this->Controller->Send(&bufSize, 1, id, 98);
if (p1->GetDataType() == VTK_UNSIGNED_CHAR)
{
this->Controller->Send(reinterpret_cast<unsigned char*>
(p1->GetVoidPointer(0)),
bufSize, id, 99);
}
else
{
this->Controller->Send(reinterpret_cast<float*>
(p1->GetVoidPointer(0)),
bufSize, id, 99);
}
}
}
}
}
#ifdef MPIPROALLOC
vtkCommunicator::SetUseCopy(1);
#endif
if (myId == 0)
{
// Now we want to decompress into the original buffers.
this->Uncompress(z1, p1, zBuf, pBuf, uncompressedLength);
}
//this->Timer->StopTimer();
//float time = this->Timer->GetElapsedTime();
//cerr << "Composite " << " took " << time << " seconds.\n";
}
//----------------------------------------------------------------------------
void vtkCompressCompositer::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}