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.
 
 
 
 
 
 

1485 lines
42 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkRenderer.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 "vtkRenderer.h"
#include "vtkAssemblyNode.h"
#include "vtkAssemblyPath.h"
#include "vtkCamera.h"
#include "vtkCommand.h"
#include "vtkCuller.h"
#include "vtkCullerCollection.h"
#include "vtkFrustumCoverageCuller.h"
#include "vtkGraphicsFactory.h"
#include "vtkLight.h"
#include "vtkLightCollection.h"
#include "vtkMath.h"
#include "vtkMatrix4x4.h"
#include "vtkOutputWindow.h"
#include "vtkPicker.h"
#include "vtkProp3DCollection.h"
#include "vtkRenderWindow.h"
#include "vtkTimerLog.h"
#include "vtkVolume.h"
vtkCxxRevisionMacro(vtkRenderer, "$Revision: 1.219 $");
//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkRenderer);
//----------------------------------------------------------------------------
// Create a vtkRenderer with a black background, a white ambient light,
// two-sided lighting turned on, a viewport of (0,0,1,1), and backface culling
// turned off.
vtkRenderer::vtkRenderer()
{
this->PickedProp = NULL;
this->ActiveCamera = NULL;
this->Ambient[0] = 1;
this->Ambient[1] = 1;
this->Ambient[2] = 1;
this->AllocatedRenderTime = 100;
this->TimeFactor = 1.0;
this->CreatedLight = NULL;
this->AutomaticLightCreation = 1;
this->TwoSidedLighting = 1;
this->BackingStore = 0;
this->BackingImage = NULL;
this->BackingStoreSize[0] = -1;
this->BackingStoreSize[1] = -1;
this->LastRenderTimeInSeconds = -1.0;
this->RenderWindow = NULL;
this->Lights = vtkLightCollection::New();
this->Actors = vtkActorCollection::New();
this->Volumes = vtkVolumeCollection::New();
this->LightFollowCamera = 1;
this->NumberOfPropsRendered = 0;
this->PropArray = NULL;
this->PropArrayCount = 0;
this->PathArray = NULL;
this->PathArrayCount = 0;
this->Layer = 0;
this->ComputedVisiblePropBounds[0] = VTK_DOUBLE_MAX;
this->ComputedVisiblePropBounds[1] = -VTK_DOUBLE_MAX;
this->ComputedVisiblePropBounds[2] = VTK_DOUBLE_MAX;
this->ComputedVisiblePropBounds[3] = -VTK_DOUBLE_MAX;
this->ComputedVisiblePropBounds[4] = VTK_DOUBLE_MAX;
this->ComputedVisiblePropBounds[5] = -VTK_DOUBLE_MAX;
this->Interactive = 1;
this->Cullers = vtkCullerCollection::New();
vtkFrustumCoverageCuller *cull = vtkFrustumCoverageCuller::New();
this->Cullers->AddItem(cull);
cull->Delete();
// a value of 0 indicates it is uninitialized
this->NearClippingPlaneTolerance = 0;
this->Erase = 1;
}
vtkRenderer::~vtkRenderer()
{
this->SetRenderWindow( NULL );
if (this->ActiveCamera)
{
this->ActiveCamera->UnRegister(this);
this->ActiveCamera = NULL;
}
if (this->CreatedLight)
{
this->CreatedLight->UnRegister(this);
this->CreatedLight = NULL;
}
if (this->BackingImage)
{
delete [] this->BackingImage;
}
this->Actors->Delete();
this->Actors = NULL;
this->Volumes->Delete();
this->Volumes = NULL;
this->Lights->Delete();
this->Lights = NULL;
this->Cullers->Delete();
this->Cullers = NULL;
}
// return the correct type of Renderer
vtkRenderer *vtkRenderer::New()
{
// First try to create the object from the vtkObjectFactory
vtkObject* ret = vtkGraphicsFactory::CreateInstance("vtkRenderer");
return (vtkRenderer *)ret;
}
// Concrete render method.
void vtkRenderer::Render(void)
{
double t1, t2;
int i;
vtkProp *aProp;
int *size;
t1 = vtkTimerLog::GetUniversalTime();
this->InvokeEvent(vtkCommand::StartEvent,NULL);
size = this->RenderWindow->GetSize();
// if backing store is on and we have a stored image
if (this->BackingStore && this->BackingImage &&
this->MTime < this->RenderTime &&
this->ActiveCamera->GetMTime() < this->RenderTime &&
this->RenderWindow->GetMTime() < this->RenderTime &&
this->BackingStoreSize[0] == size[0] &&
this->BackingStoreSize[1] == size[1])
{
int mods = 0;
vtkLight *light;
// now we just need to check the lights and actors
vtkCollectionSimpleIterator sit;
for(this->Lights->InitTraversal(sit);
(light = this->Lights->GetNextLight(sit)); )
{
if (light->GetSwitch() &&
light->GetMTime() > this->RenderTime)
{
mods = 1;
goto completed_mod_check;
}
}
vtkCollectionSimpleIterator pit;
for (this->Props->InitTraversal(pit);
(aProp = this->Props->GetNextProp(pit)); )
{
// if it's invisible, we can skip the rest
if (aProp->GetVisibility())
{
if (aProp->GetRedrawMTime() > this->RenderTime)
{
mods = 1;
goto completed_mod_check;
}
}
}
completed_mod_check:
if (!mods)
{
int rx1, ry1, rx2, ry2;
// backing store should be OK, lets use it
// calc the pixel range for the renderer
rx1 = (int)(this->Viewport[0]*(this->RenderWindow->GetSize()[0] - 1));
ry1 = (int)(this->Viewport[1]*(this->RenderWindow->GetSize()[1] - 1));
rx2 = (int)(this->Viewport[2]*(this->RenderWindow->GetSize()[0] - 1));
ry2 = (int)(this->Viewport[3]*(this->RenderWindow->GetSize()[1] - 1));
this->RenderWindow->SetPixelData(rx1,ry1,rx2,ry2,this->BackingImage,0);
this->InvokeEvent(vtkCommand::EndEvent,NULL);
return;
}
}
// Create the initial list of visible props
// This will be passed through AllocateTime(), where
// a time is allocated for each prop, and the list
// maybe re-ordered by the cullers. Also create the
// sublists for the props that need ray casting, and
// the props that need to be rendered into an image.
// Fill these in later (in AllocateTime) - get a
// count of them there too
if ( this->Props->GetNumberOfItems() > 0 )
{
this->PropArray = new vtkProp *[this->Props->GetNumberOfItems()];
}
else
{
this->PropArray = NULL;
}
this->PropArrayCount = 0;
vtkCollectionSimpleIterator pit;
for ( this->Props->InitTraversal(pit);
(aProp = this->Props->GetNextProp(pit)); )
{
if ( aProp->GetVisibility() )
{
this->PropArray[this->PropArrayCount++] = aProp;
}
}
if ( this->PropArrayCount == 0 )
{
vtkDebugMacro( << "There are no visible props!" );
}
else
{
// Call all the culling methods to set allocated time
// for each prop and re-order the prop list if desired
this->AllocateTime();
}
// do the render library specific stuff
this->DeviceRender();
// If we aborted, restore old estimated times
// Setting the allocated render time to zero also sets the
// estimated render time to zero, so that when we add back
// in the old value we have set it correctly.
if ( this->RenderWindow->GetAbortRender() )
{
for ( i = 0; i < this->PropArrayCount; i++ )
{
this->PropArray[i]->RestoreEstimatedRenderTime();
}
}
// Clean up the space we allocated before. If the PropArray exists,
// they all should exist
if ( this->PropArray)
{
delete [] this->PropArray;
this->PropArray = NULL;
}
if (this->BackingStore)
{
if (this->BackingImage)
{
delete [] this->BackingImage;
}
int rx1, ry1, rx2, ry2;
// backing store should be OK, lets use it
// calc the pixel range for the renderer
rx1 = (int)(this->Viewport[0]*(size[0] - 1));
ry1 = (int)(this->Viewport[1]*(size[1] - 1));
rx2 = (int)(this->Viewport[2]*(size[0] - 1));
ry2 = (int)(this->Viewport[3]*(size[1] - 1));
this->BackingImage = this->RenderWindow->GetPixelData(rx1,ry1,rx2,ry2,0);
this->BackingStoreSize[0] = size[0];
this->BackingStoreSize[1] = size[1];
}
// If we aborted, do not record the last render time.
// Lets play around with determining the acuracy of the
// EstimatedRenderTimes. We can try to adjust for bad
// estimates with the TimeFactor.
if ( ! this->RenderWindow->GetAbortRender() )
{
// Measure the actual RenderTime
t2 = vtkTimerLog::GetUniversalTime();
this->LastRenderTimeInSeconds = (double) (t2 - t1);
if (this->LastRenderTimeInSeconds == 0.0)
{
this->LastRenderTimeInSeconds = 0.0001;
}
this->TimeFactor = this->AllocatedRenderTime/this->LastRenderTimeInSeconds;
}
}
double vtkRenderer::GetAllocatedRenderTime()
{
return this->AllocatedRenderTime;
}
double vtkRenderer::GetTimeFactor()
{
return this->TimeFactor;
}
// Ask active camera to load its view matrix.
int vtkRenderer::UpdateCamera ()
{
if (!this->ActiveCamera)
{
vtkDebugMacro(<< "No cameras are on, creating one.");
// the get method will automagically create a camera
// and reset it since one hasn't been specified yet
this->GetActiveCameraAndEventuallyReset();
}
// update the viewing transformation
this->ActiveCamera->Render((vtkRenderer *)this);
return 1;
}
int vtkRenderer::UpdateLightsGeometryToFollowCamera()
{
vtkCamera *camera;
vtkLight *light;
vtkMatrix4x4 *lightMatrix;
// only update the light's geometry if this Renderer is tracking
// this lights. That allows one renderer to view the lights that
// another renderer is setting up.
camera = this->GetActiveCameraAndEventuallyReset();
lightMatrix = camera->GetCameraLightTransformMatrix();
vtkCollectionSimpleIterator sit;
for(this->Lights->InitTraversal(sit);
(light = this->Lights->GetNextLight(sit)); )
{
if (light->LightTypeIsSceneLight())
{
// Do nothing. Don't reset the transform matrix because applications
// may have set a custom matrix. Only reset the transform matrix in
// vtkLight::SetLightTypeToSceneLight()
}
else if (light->LightTypeIsHeadlight())
{
// update position and orientation of light to match camera.
light->SetPosition(camera->GetPosition());
light->SetFocalPoint(camera->GetFocalPoint());
}
else if (light->LightTypeIsCameraLight())
{
light->SetTransformMatrix(lightMatrix);
}
else
{
vtkErrorMacro(<< "light has unknown light type");
}
}
return 1;
}
int vtkRenderer::UpdateLightGeometry()
{
if (this->LightFollowCamera)
{
// only update the light's geometry if this Renderer is tracking
// this lights. That allows one renderer to view the lights that
// another renderer is setting up.
return this->UpdateLightsGeometryToFollowCamera();
}
return 1;
}
// Do all outer culling to set allocated time for each prop.
// Possibly re-order the actor list.
void vtkRenderer::AllocateTime()
{
int initialized = 0;
double renderTime;
double totalTime;
int i;
vtkCuller *aCuller;
vtkProp *aProp;
// Give each of the cullers a chance to modify allocated rendering time
// for the entire set of props. Each culler returns the total time given
// by AllocatedRenderTime for all props. Each culler is required to
// place any props that have an allocated render time of 0.0
// at the end of the list. The PropArrayCount value that is
// returned is the number of non-zero, visible actors.
// Some cullers may do additional sorting of the list (by distance,
// importance, etc).
//
// The first culler will initialize all the allocated render times.
// Any subsequent culling will multiply the new render time by the
// existing render time for an actor.
totalTime = this->PropArrayCount;
this->ComputeAspect();
// It is very likely that the culler framework will call our
// GetActiveCamera (say, to get the view frustrum planes for example).
// This does not reset the camera anymore. If no camera has been
// created though, we want it not only to be created but also reset
// so that it behaves nicely for people who never bother with the camera
// (i.e. neither call GetActiveCamera or ResetCamera)
if ( this->Cullers->GetNumberOfItems())
{
this->GetActiveCameraAndEventuallyReset();
}
vtkCollectionSimpleIterator sit;
for (this->Cullers->InitTraversal(sit);
(aCuller=this->Cullers->GetNextCuller(sit));)
{
totalTime =
aCuller->Cull((vtkRenderer *)this,
this->PropArray, this->PropArrayCount,
initialized );
}
// loop through all props and set the AllocatedRenderTime
for ( i = 0; i < this->PropArrayCount; i++ )
{
aProp = this->PropArray[i];
// If we don't have an outer cull method in any of the cullers,
// then the allocated render time has not yet been initialized
renderTime = (initialized)?(aProp->GetRenderTimeMultiplier()):(1.0);
// We need to divide by total time so that the total rendering time
// (all prop's AllocatedRenderTime added together) would be equal
// to the renderer's AllocatedRenderTime.
aProp->
SetAllocatedRenderTime(( renderTime / totalTime ) *
this->AllocatedRenderTime,
this );
}
}
// Ask actors to render themselves. As a side effect will cause
// visualization network to update.
int vtkRenderer::UpdateGeometry()
{
int i;
this->NumberOfPropsRendered = 0;
if ( this->PropArrayCount == 0 )
{
this->InvokeEvent(vtkCommand::EndEvent,NULL);
return 0;
}
// We can render everything because if it was
// not visible it would not have been put in the
// list in the first place, and if it was allocated
// no time (culled) it would have been removed from
// the list
// loop through props and give them a chance to
// render themselves as opaque geometry
for ( i = 0; i < this->PropArrayCount; i++ )
{
this->NumberOfPropsRendered +=
this->PropArray[i]->RenderOpaqueGeometry(this);
}
// loop through props and give them a chance to
// render themselves as translucent geometry
for ( i = 0; i < this->PropArrayCount; i++ )
{
this->NumberOfPropsRendered +=
this->PropArray[i]->RenderTranslucentGeometry(this);
}
// loop through props and give them a chance to
// render themselves as an overlay (or underlay)
for ( i = 0; i < this->PropArrayCount; i++ )
{
this->NumberOfPropsRendered +=
this->PropArray[i]->RenderOverlay(this);
}
this->InvokeEvent(vtkCommand::EndEvent,NULL);
this->RenderTime.Modified();
vtkDebugMacro( << "Rendered " <<
this->NumberOfPropsRendered << " actors" );
return this->NumberOfPropsRendered;
}
vtkWindow *vtkRenderer::GetVTKWindow()
{
return this->RenderWindow;
}
// Specify the camera to use for this renderer.
void vtkRenderer::SetActiveCamera(vtkCamera *cam)
{
if (this->ActiveCamera == cam)
{
return;
}
if (this->ActiveCamera)
{
this->ActiveCamera->UnRegister(this);
this->ActiveCamera = NULL;
}
if (cam)
{
cam->Register(this);
}
this->ActiveCamera = cam;
this->Modified();
}
//----------------------------------------------------------------------------
vtkCamera* vtkRenderer::MakeCamera()
{
return vtkCamera::New();
}
//----------------------------------------------------------------------------
vtkCamera *vtkRenderer::GetActiveCamera()
{
if ( this->ActiveCamera == NULL )
{
vtkCamera *cam = this->MakeCamera();
this->SetActiveCamera(cam);
cam->Delete();
// The following line has been commented out as it has a lot of
// side effects (like computing the bounds of all props, which will
// eventually call UpdateInformation() on data objects, etc).
// Instead, the rendering code has been updated to internally use
// GetActiveCameraAndEventuallyReset which will reset the camera
// if it gets created
// this->ResetCamera();
}
return this->ActiveCamera;
}
//----------------------------------------------------------------------------
vtkCamera *vtkRenderer::GetActiveCameraAndEventuallyReset()
{
if (this->ActiveCamera == NULL)
{
this->GetActiveCamera();
this->ResetCamera();
}
return this->ActiveCamera;
}
//----------------------------------------------------------------------------
void vtkRenderer::AddActor(vtkProp* p)
{
this->AddViewProp(p);
}
//----------------------------------------------------------------------------
void vtkRenderer::AddVolume(vtkProp* p)
{
this->AddViewProp(p);
}
//----------------------------------------------------------------------------
void vtkRenderer::RemoveActor(vtkProp* p)
{
this->Actors->RemoveItem(p);
this->RemoveViewProp(p);
}
//----------------------------------------------------------------------------
void vtkRenderer::RemoveVolume(vtkProp* p)
{
this->Volumes->RemoveItem(p);
this->RemoveViewProp(p);
}
// Add a light to the list of lights.
void vtkRenderer::AddLight(vtkLight *light)
{
this->Lights->AddItem(light);
}
// look through the props and get all the actors
vtkActorCollection *vtkRenderer::GetActors()
{
vtkProp *aProp;
// clear the collection first
this->Actors->RemoveAllItems();
vtkCollectionSimpleIterator pit;
for (this->Props->InitTraversal(pit);
(aProp = this->Props->GetNextProp(pit)); )
{
aProp->GetActors(this->Actors);
}
return this->Actors;
}
// look through the props and get all the volumes
vtkVolumeCollection *vtkRenderer::GetVolumes()
{
vtkProp *aProp;
// clear the collection first
this->Volumes->RemoveAllItems();
vtkCollectionSimpleIterator pit;
for (this->Props->InitTraversal(pit);
(aProp = this->Props->GetNextProp(pit)); )
{
aProp->GetVolumes(this->Volumes);
}
return this->Volumes;
}
// Remove a light from the list of lights.
void vtkRenderer::RemoveLight(vtkLight *light)
{
this->Lights->RemoveItem(light);
}
// Add an culler to the list of cullers.
void vtkRenderer::AddCuller(vtkCuller *culler)
{
this->Cullers->AddItem(culler);
}
// Remove an actor from the list of cullers.
void vtkRenderer::RemoveCuller(vtkCuller *culler)
{
this->Cullers->RemoveItem(culler);
}
vtkLight *vtkRenderer::MakeLight()
{
return vtkLight::New();
}
void vtkRenderer::CreateLight(void)
{
if ( !this->AutomaticLightCreation )
{
return;
}
if (this->CreatedLight)
{
this->CreatedLight->UnRegister(this);
this->CreatedLight = NULL;
}
// I do not see why UnRegister is used on CreatedLight, but lets be
// consistent.
vtkLight *l = this->MakeLight();
this->CreatedLight = l;
this->CreatedLight->Register(this);
this->AddLight(this->CreatedLight);
l->Delete();
this->CreatedLight->SetLightTypeToHeadlight();
// set these values just to have a good default should LightFollowCamera
// be turned off.
this->CreatedLight->SetPosition(this->GetActiveCamera()->GetPosition());
this->CreatedLight->SetFocalPoint(this->GetActiveCamera()->GetFocalPoint());
}
// Compute the bounds of the visible props
void vtkRenderer::ComputeVisiblePropBounds( double allBounds[6] )
{
vtkProp *prop;
double *bounds;
int nothingVisible=1;
allBounds[0] = allBounds[2] = allBounds[4] = VTK_DOUBLE_MAX;
allBounds[1] = allBounds[3] = allBounds[5] = -VTK_DOUBLE_MAX;
// loop through all props
vtkCollectionSimpleIterator pit;
for (this->Props->InitTraversal(pit);
(prop = this->Props->GetNextProp(pit)); )
{
// if it's invisible, or has no geometry, we can skip the rest
if ( prop->GetVisibility() )
{
bounds = prop->GetBounds();
// make sure we haven't got bogus bounds
if ( bounds != NULL && vtkMath::AreBoundsInitialized(bounds))
{
nothingVisible = 0;
if (bounds[0] < allBounds[0])
{
allBounds[0] = bounds[0];
}
if (bounds[1] > allBounds[1])
{
allBounds[1] = bounds[1];
}
if (bounds[2] < allBounds[2])
{
allBounds[2] = bounds[2];
}
if (bounds[3] > allBounds[3])
{
allBounds[3] = bounds[3];
}
if (bounds[4] < allBounds[4])
{
allBounds[4] = bounds[4];
}
if (bounds[5] > allBounds[5])
{
allBounds[5] = bounds[5];
}
}//not bogus
}
}
if ( nothingVisible )
{
vtkMath::UninitializeBounds(allBounds);
vtkDebugMacro(<< "Can't compute bounds, no 3D props are visible");
return;
}
}
double *vtkRenderer::ComputeVisiblePropBounds()
{
this->ComputeVisiblePropBounds(this->ComputedVisiblePropBounds);
return this->ComputedVisiblePropBounds;
}
// Automatically set up the camera based on the visible actors.
// The camera will reposition itself to view the center point of the actors,
// and move along its initial view plane normal (i.e., vector defined from
// camera position to focal point) so that all of the actors can be seen.
void vtkRenderer::ResetCamera()
{
double allBounds[6];
this->ComputeVisiblePropBounds( allBounds );
if (!vtkMath::AreBoundsInitialized(allBounds))
{
vtkDebugMacro( << "Cannot reset camera!" );
}
else
{
this->ResetCamera(allBounds);
}
// Here to let parallel/distributed compositing intercept
// and do the right thing.
this->InvokeEvent(vtkCommand::ResetCameraEvent,this);
}
// Automatically set the clipping range of the camera based on the
// visible actors
void vtkRenderer::ResetCameraClippingRange()
{
double allBounds[6];
this->ComputeVisiblePropBounds( allBounds );
if (!vtkMath::AreBoundsInitialized(allBounds))
{
vtkDebugMacro( << "Cannot reset camera clipping range!" );
}
else
{
this->ResetCameraClippingRange(allBounds);
}
// Here to let parallel/distributed compositing intercept
// and do the right thing.
this->InvokeEvent(vtkCommand::ResetCameraClippingRangeEvent,this);
}
// Automatically set up the camera based on a specified bounding box
// (xmin,xmax, ymin,ymax, zmin,zmax). Camera will reposition itself so
// that its focal point is the center of the bounding box, and adjust its
// distance and position to preserve its initial view plane normal
// (i.e., vector defined from camera position to focal point). Note: is
// the view plane is parallel to the view up axis, the view up axis will
// be reset to one of the three coordinate axes.
void vtkRenderer::ResetCamera(double bounds[6])
{
double center[3];
double distance;
double vn[3], *vup;
this->GetActiveCamera();
if ( this->ActiveCamera != NULL )
{
this->ActiveCamera->GetViewPlaneNormal(vn);
}
else
{
vtkErrorMacro(<< "Trying to reset non-existant camera");
return;
}
center[0] = (bounds[0] + bounds[1])/2.0;
center[1] = (bounds[2] + bounds[3])/2.0;
center[2] = (bounds[4] + bounds[5])/2.0;
double w1 = bounds[1] - bounds[0];
double w2 = bounds[3] - bounds[2];
double w3 = bounds[5] - bounds[4];
w1 *= w1;
w2 *= w2;
w3 *= w3;
double radius = w1 + w2 + w3;
// If we have just a single point, pick a radius of 1.0
radius = (radius==0)?(1.0):(radius);
// compute the radius of the enclosing sphere
radius = sqrt(radius)*0.5;
// default so that the bounding sphere fits within the view fustrum
// compute the distance from the intersection of the view frustum with the
// bounding sphere. Basically in 2D draw a circle representing the bounding
// sphere in 2D then draw a horizontal line going out from the center of
// the circle. That is the camera view. Then draw a line from the camera
// position to the point where it intersects the circle. (it will be tangent
// to the circle at this point, this is important, only go to the tangent
// point, do not draw all the way to the view plane). Then draw the radius
// from the tangent point to the center of the circle. You will note that
// this forms a right triangle with one side being the radius, another being
// the target distance for the camera, then just find the target dist using
// a sin.
distance =
radius/sin(this->ActiveCamera->GetViewAngle()*vtkMath::Pi()/360.0);
// check view-up vector against view plane normal
vup = this->ActiveCamera->GetViewUp();
if ( fabs(vtkMath::Dot(vup,vn)) > 0.999 )
{
vtkWarningMacro(<<"Resetting view-up since view plane normal is parallel");
this->ActiveCamera->SetViewUp(-vup[2], vup[0], vup[1]);
}
// update the camera
this->ActiveCamera->SetFocalPoint(center[0],center[1],center[2]);
this->ActiveCamera->SetPosition(center[0]+distance*vn[0],
center[1]+distance*vn[1],
center[2]+distance*vn[2]);
this->ResetCameraClippingRange( bounds );
// setup default parallel scale
this->ActiveCamera->SetParallelScale(radius);
}
// Alternative version of ResetCamera(bounds[6]);
void vtkRenderer::ResetCamera(double xmin, double xmax, double ymin, double ymax,
double zmin, double zmax)
{
double bounds[6];
bounds[0] = xmin;
bounds[1] = xmax;
bounds[2] = ymin;
bounds[3] = ymax;
bounds[4] = zmin;
bounds[5] = zmax;
this->ResetCamera(bounds);
}
// Reset the camera clipping range to include this entire bounding box
void vtkRenderer::ResetCameraClippingRange( double bounds[6] )
{
double vn[3], position[3], a, b, c, d;
double range[2], dist;
int i, j, k;
// Don't reset the clipping range when we don't have any 3D visible props
if (!vtkMath::AreBoundsInitialized(bounds))
{
return;
}
this->GetActiveCameraAndEventuallyReset();
if ( this->ActiveCamera == NULL )
{
vtkErrorMacro(<< "Trying to reset clipping range of non-existant camera");
return;
}
// Find the plane equation for the camera view plane
this->ActiveCamera->GetViewPlaneNormal(vn);
this->ActiveCamera->GetPosition(position);
a = -vn[0];
b = -vn[1];
c = -vn[2];
d = -(a*position[0] + b*position[1] + c*position[2]);
// Set the max near clipping plane and the min far clipping plane
range[0] = a*bounds[0] + b*bounds[2] + c*bounds[4] + d;
range[1] = 1e-18;
// Find the closest / farthest bounding box vertex
for ( k = 0; k < 2; k++ )
{
for ( j = 0; j < 2; j++ )
{
for ( i = 0; i < 2; i++ )
{
dist = a*bounds[i] + b*bounds[2+j] + c*bounds[4+k] + d;
range[0] = (dist<range[0])?(dist):(range[0]);
range[1] = (dist>range[1])?(dist):(range[1]);
}
}
}
// Do not let the range behind the camera throw off the calculation.
if (range[0] < 0.0)
{
range[0] = 0.0;
}
// Give ourselves a little breathing room
range[0] = 0.99*range[0] - (range[1] - range[0])*0.5;
range[1] = 1.01*range[1] + (range[1] - range[0])*0.5;
// Make sure near is not bigger than far
range[0] = (range[0] >= range[1])?(0.01*range[1]):(range[0]);
// Make sure near is at least some fraction of far - this prevents near
// from being behind the camera or too close in front. How close is too
// close depends on the resolution of the depth buffer
if (!this->NearClippingPlaneTolerance)
{
this->NearClippingPlaneTolerance = 0.01;
if (this->RenderWindow)
{
int ZBufferDepth = this->RenderWindow->GetDepthBufferSize();
if ( ZBufferDepth > 16 )
{
this->NearClippingPlaneTolerance = 0.001;
}
}
}
// make sure the front clipping range is not too far from the far clippnig
// range, this is to make sure that the zbuffer resolution is effectively
// used
if (range[0] < this->NearClippingPlaneTolerance*range[1])
{
range[0] = this->NearClippingPlaneTolerance*range[1];
}
this->ActiveCamera->SetClippingRange( range );
}
// Alternative version of ResetCameraClippingRange(bounds[6]);
void vtkRenderer::ResetCameraClippingRange(double xmin, double xmax,
double ymin, double ymax,
double zmin, double zmax)
{
double bounds[6];
bounds[0] = xmin;
bounds[1] = xmax;
bounds[2] = ymin;
bounds[3] = ymax;
bounds[4] = zmin;
bounds[5] = zmax;
this->ResetCameraClippingRange(bounds);
}
// Specify the rendering window in which to draw. This is automatically set
// when the renderer is created by MakeRenderer. The user probably
// shouldn't ever need to call this method.
// no reference counting!
void vtkRenderer::SetRenderWindow(vtkRenderWindow *renwin)
{
vtkProp *aProp;
if (renwin != this->RenderWindow)
{
// This renderer is be dis-associated with its previous render window.
// this information needs to be passed to the renderer's actors and
// volumes so they can release and render window specific (or graphics
// context specific) information (such as display lists and texture ids)
vtkCollectionSimpleIterator pit;
this->Props->InitTraversal(pit);
for ( aProp = this->Props->GetNextProp(pit);
aProp != NULL;
aProp = this->Props->GetNextProp(pit) )
{
aProp->ReleaseGraphicsResources(this->RenderWindow);
}
// what about lights?
// what about cullers?
}
this->VTKWindow = renwin;
this->RenderWindow = renwin;
}
// Given a pixel location, return the Z value
double vtkRenderer::GetZ (int x, int y)
{
float *zPtr;
double z;
zPtr = this->RenderWindow->GetZbufferData (x, y, x, y);
if (zPtr)
{
z = *zPtr;
delete [] zPtr;
}
else
{
z = 1.0;
}
return z;
}
// Convert view point coordinates to world coordinates.
void vtkRenderer::ViewToWorld()
{
double result[4];
result[0] = this->ViewPoint[0];
result[1] = this->ViewPoint[1];
result[2] = this->ViewPoint[2];
result[3] = 1.0;
this->ViewToWorld(result[0],result[1],result[2]);
this->SetWorldPoint(result);
}
void vtkRenderer::ViewToWorld(double &x, double &y, double &z)
{
vtkMatrix4x4 *mat = vtkMatrix4x4::New();
double result[4];
// get the perspective transformation from the active camera
mat->DeepCopy(this->ActiveCamera->
GetCompositePerspectiveTransformMatrix(
this->GetTiledAspectRatio(),0,1));
// use the inverse matrix
mat->Invert();
// Transform point to world coordinates
result[0] = x;
result[1] = y;
result[2] = z;
result[3] = 1.0;
mat->MultiplyPoint(result,result);
// Get the transformed vector & set WorldPoint
// while we are at it try to keep w at one
if (result[3])
{
x = result[0] / result[3];
y = result[1] / result[3];
z = result[2] / result[3];
}
mat->Delete();
}
// Convert world point coordinates to view coordinates.
void vtkRenderer::WorldToView()
{
double result[3];
result[0] = this->WorldPoint[0];
result[1] = this->WorldPoint[1];
result[2] = this->WorldPoint[2];
this->WorldToView(result[0], result[1], result[2]);
this->SetViewPoint(result[0], result[1], result[2]);
}
// Convert world point coordinates to view coordinates.
void vtkRenderer::WorldToView(double &x, double &y, double &z)
{
vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
double view[4];
// get the perspective transformation from the active camera
matrix->DeepCopy(this->ActiveCamera->
GetCompositePerspectiveTransformMatrix(
this->GetTiledAspectRatio(),0,1));
view[0] = x*matrix->Element[0][0] + y*matrix->Element[0][1] +
z*matrix->Element[0][2] + matrix->Element[0][3];
view[1] = x*matrix->Element[1][0] + y*matrix->Element[1][1] +
z*matrix->Element[1][2] + matrix->Element[1][3];
view[2] = x*matrix->Element[2][0] + y*matrix->Element[2][1] +
z*matrix->Element[2][2] + matrix->Element[2][3];
view[3] = x*matrix->Element[3][0] + y*matrix->Element[3][1] +
z*matrix->Element[3][2] + matrix->Element[3][3];
if (view[3] != 0.0)
{
x = view[0]/view[3];
y = view[1]/view[3];
z = view[2]/view[3];
}
matrix->Delete();
}
void vtkRenderer::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Near Clipping Plane Tolerance: "
<< this->NearClippingPlaneTolerance << "\n";
os << indent << "Ambient: (" << this->Ambient[0] << ", "
<< this->Ambient[1] << ", " << this->Ambient[2] << ")\n";
os << indent << "Backing Store: " << (this->BackingStore ? "On\n":"Off\n");
os << indent << "Display Point: (" << this->DisplayPoint[0] << ", "
<< this->DisplayPoint[1] << ", " << this->DisplayPoint[2] << ")\n";
os << indent << "Lights:\n";
this->Lights->PrintSelf(os,indent.GetNextIndent());
os << indent << "Light Follow Camera: "
<< (this->LightFollowCamera ? "On\n" : "Off\n");
os << indent << "View Point: (" << this->ViewPoint[0] << ", "
<< this->ViewPoint[1] << ", " << this->ViewPoint[2] << ")\n";
os << indent << "Two Sided Lighting: "
<< (this->TwoSidedLighting ? "On\n" : "Off\n");
os << indent << "Automatic Light Creation: "
<< (this->AutomaticLightCreation ? "On\n" : "Off\n");
os << indent << "Layer = " << this->Layer << "\n";
os << indent << "Interactive = " << (this->Interactive ? "On" : "Off")
<< "\n";
os << indent << "Allocated Render Time: " << this->AllocatedRenderTime
<< "\n";
os << indent << "Last Time To Render (Seconds): "
<< this->LastRenderTimeInSeconds << endl;
os << indent << "TimeFactor: " << this->TimeFactor << endl;
os << indent << "Erase: "
<< (this->Erase ? "On\n" : "Off\n");
// I don't want to print this since it is used just internally
// os << indent << this->NumberOfPropsRendered;
}
int vtkRenderer::VisibleActorCount()
{
vtkProp *aProp;
int count = 0;
// loop through Props
vtkCollectionSimpleIterator pit;
for (this->Props->InitTraversal(pit);
(aProp = this->Props->GetNextProp(pit)); )
{
if (aProp->GetVisibility())
{
count++;
}
}
return count;
}
int vtkRenderer::VisibleVolumeCount()
{
int count = 0;
vtkProp *aProp;
// loop through volumes
vtkCollectionSimpleIterator pit;
for (this->Props->InitTraversal(pit);
(aProp = this->Props->GetNextProp(pit)); )
{
if (aProp->GetVisibility())
{
count++;
}
}
return count;
}
unsigned long int vtkRenderer::GetMTime()
{
unsigned long mTime=this-> vtkViewport::GetMTime();
unsigned long time;
if ( this->ActiveCamera != NULL )
{
time = this->ActiveCamera ->GetMTime();
mTime = ( time > mTime ? time : mTime );
}
if ( this->CreatedLight != NULL )
{
time = this->CreatedLight ->GetMTime();
mTime = ( time > mTime ? time : mTime );
}
return mTime;
}
vtkAssemblyPath* vtkRenderer::PickProp(double selectionX, double selectionY)
{
// initialize picking information
this->CurrentPickId = 1; // start at 1, so 0 can be a no pick
this->PickX = selectionX;
this->PickY = selectionY;
int numberPickFrom;
vtkPropCollection *props;
// Initialize the pick (we're picking a path, the path
// includes info about nodes)
if (this->PickFromProps)
{
props = this->PickFromProps;
}
else
{
props = this->Props;
}
// number determined from number of rendering passes plus reserved "0" slot
numberPickFrom = 2*props->GetNumberOfPaths()*3 + 1;
this->IsPicking = 1; // turn on picking
this->StartPick(numberPickFrom);
this->PathArray = new vtkAssemblyPath *[numberPickFrom];
this->PathArrayCount = 0;
// Actually perform the pick
this->PickRender(props); // do the pick render
this->IsPicking = 0; // turn off picking
this->DonePick();
vtkDebugMacro(<< "z value for pick " << this->GetPickedZ() << "\n");
vtkDebugMacro(<< "pick time " << this->LastRenderTimeInSeconds << "\n");
// Get the pick id of the object that was picked
if ( this->PickedProp != NULL )
{
this->PickedProp->UnRegister(this);
this->PickedProp = NULL;
}
unsigned int pickedId = this->GetPickedId();
if ( pickedId != 0 )
{
pickedId--; // pick ids start at 1, so move back one
// wrap around, as there are twice as many pickid's as PropArrayCount,
// because each Prop has both RenderOpaqueGeometry and
// RenderTranslucentGeometry called on it
pickedId = pickedId % this->PathArrayCount;
this->PickedProp = this->PathArray[pickedId];
this->PickedProp->Register(this);
}
// Clean up stuff from picking after we use it
delete [] this->PathArray;
this->PathArray = NULL;
// Return the pick!
return this->PickedProp; //returns an assembly path
}
// Do a render in pick mode. This is normally done with rendering turned off.
// Before each Prop is rendered the pick id is incremented
void vtkRenderer::PickRender(vtkPropCollection *props)
{
vtkProp *aProp;
vtkAssemblyPath *path;
this->InvokeEvent(vtkCommand::StartEvent,NULL);
if( props->GetNumberOfItems() <= 0)
{
return;
}
// Create a place to store all props that remain after culling
vtkPropCollection* pickFrom = vtkPropCollection::New();
// Extract all the prop3D's out of the props collection.
// This collection will be further culled by using a bounding box
// pick later (vtkPicker). Things that are not vtkProp3D will get
// put into the Paths list directly.
vtkCollectionSimpleIterator pit;
for ( props->InitTraversal(pit); (aProp = props->GetNextProp(pit)); )
{
if ( aProp->GetPickable() && aProp->GetVisibility() )
{
if ( aProp->IsA("vtkProp3D") )
{
pickFrom->AddItem(aProp);
}
else //must be some other type of prop (e.g., vtkActor2D)
{
for ( aProp->InitPathTraversal(); (path=aProp->GetNextPath()); )
{
this->PathArray[this->PathArrayCount++] = path;
}
}
}//pickable & visible
}//for all props
// For a first pass at the pick process, just use a vtkPicker to
// intersect with bounding boxes of the objects. This should greatly
// reduce the number of polygons that the hardware has to pick from, and
// speeds things up substantially.
//
// Create a picker to do the culling process
vtkPicker* cullPicker = vtkPicker::New();
// Add each of the Actors from the pickFrom list into the picker
for ( pickFrom->InitTraversal(pit); (aProp = pickFrom->GetNextProp(pit)); )
{
cullPicker->AddPickList(aProp);
}
// make sure this selects from the pickers list and not the renderers list
cullPicker->PickFromListOn();
// do the pick
cullPicker->Pick(this->PickX, this->PickY, 0, this);
vtkProp3DCollection* cullPicked = cullPicker->GetProp3Ds();
// Put all the ones that were picked by the cull process
// into the PathArray to be picked from
vtkCollectionSimpleIterator p3dit;
for (cullPicked->InitTraversal(p3dit);
(aProp = cullPicked->GetNextProp3D(p3dit));)
{
if ( aProp != NULL )
{
for ( aProp->InitPathTraversal(); (path=aProp->GetNextPath()); )
{
this->PathArray[this->PathArrayCount++] = path;
}
}
}
// Clean picking support objects up
pickFrom->Delete();
cullPicker->Delete();
if ( this->PathArrayCount == 0 )
{
vtkDebugMacro( << "There are no visible props!" );
return;
}
// do the render library specific pick render
this->DevicePickRender();
}
void vtkRenderer::PickGeometry()
{
int i;
this->NumberOfPropsRendered = 0;
if ( this->PathArrayCount == 0 )
{
return ;
}
// We can render everything because if it was
// not visible it would not have been put in the
// list in the first place, and if it was allocated
// no time (culled) it would have been removed from
// the list
// loop through props and give them a change to
// render themselves as opaque geometry
vtkProp *prop;
vtkMatrix4x4 *matrix;
for ( i = 0; i < this->PathArrayCount; i++ )
{
this->UpdatePickId();
prop = this->PathArray[i]->GetLastNode()->GetViewProp();
matrix = this->PathArray[i]->GetLastNode()->GetMatrix();
prop->PokeMatrix(matrix);
this->NumberOfPropsRendered += prop->RenderOpaqueGeometry(this);
prop->PokeMatrix(NULL);
}
// loop through props and give them a chance to
// render themselves as translucent geometry
for ( i = 0; i < this->PathArrayCount; i++ )
{
this->UpdatePickId();
prop = this->PathArray[i]->GetLastNode()->GetViewProp();
matrix = this->PathArray[i]->GetLastNode()->GetMatrix();
prop->PokeMatrix(matrix);
this->NumberOfPropsRendered +=
prop->RenderTranslucentGeometry(this);
prop->PokeMatrix(NULL);
}
for ( i = 0; i < this->PathArrayCount; i++ )
{
this->UpdatePickId();
prop = this->PathArray[i]->GetLastNode()->GetViewProp();
matrix = this->PathArray[i]->GetLastNode()->GetMatrix();
prop->PokeMatrix(matrix);
this->NumberOfPropsRendered +=
prop->RenderOverlay(this);
prop->PokeMatrix(NULL);
}
vtkDebugMacro( << "Pick Rendered " <<
this->NumberOfPropsRendered << " actors" );
}
int vtkRenderer::Transparent()
{
// If our layer is the 0th layer, then we are not transparent, else we are.
return (this->Layer == 0 ? 0 : 1);
}
double vtkRenderer::GetTiledAspectRatio()
{
int usize, vsize;
this->GetTiledSize(&usize,&vsize);
// some renderer subclasses may have more complicated computations for the
// aspect ratio. SO take that into account by computing the difference
// between our simple aspect ratio and what the actual renderer is
// reporting.
double aspect[2];
this->ComputeAspect();
this->GetAspect(aspect);
double aspect2[2];
this->vtkViewport::ComputeAspect();
this->vtkViewport::GetAspect(aspect2);
double aspectModification = aspect[0]*aspect2[1]/(aspect[1]*aspect2[0]);
double finalAspect = 1.0;
if(vsize && usize)
{
finalAspect = aspectModification*usize/vsize;
}
return finalAspect;
}