/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkActor.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$


Copyright (c) 1993-2000 Ken Martin, Will Schroeder, Bill Lorensen 
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

 * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
   of any contributors may be used to endorse or promote products derived
   from this software without specific prior written permission.

 * Modified source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/
#include <stdlib.h>
#include <math.h>

#include "vtkActor.h"
#include "vtkRenderWindow.h"
#include "vtkGraphicsFactory.h"

// Creates an actor with the following defaults: origin(0,0,0) 
// position=(0,0,0) scale=(1,1,1) visibility=1 pickable=1 dragable=1
// orientation=(0,0,0). No user defined matrix and no texture map.
vtkActor::vtkActor()
{
  this->Mapper = NULL;
  this->Property = NULL;
  this->BackfaceProperty = NULL;
  this->Texture = NULL;

  this->TraversalLocation = 0;
  
  // The mapper bounds are cache to know when the bounds must be recomputed
  // from the mapper bounds.
  this->MapperBounds[0] = this->MapperBounds[2] = this->MapperBounds[4] = 
  this->MapperBounds[1] = this->MapperBounds[3] = this->MapperBounds[5] = 0.0;

}

vtkActor::~vtkActor()
{
  if ( this->Property != NULL) 
    {
    this->Property->UnRegister(this);
    this->Property = NULL;
    }
  
  if ( this->BackfaceProperty != NULL) 
    {
    this->BackfaceProperty->UnRegister(this);
    this->BackfaceProperty = NULL;
    }

  if (this->Mapper)
    {
    this->Mapper->UnRegister(this);
    this->Mapper = NULL;
    }
  this->SetTexture(NULL);
}

// Shallow copy of an actor.
void vtkActor::ShallowCopy(vtkActor *actor)
{
  this->vtkProp3D::ShallowCopy(actor);

  this->SetMapper(actor->GetMapper());
  this->SetProperty(actor->GetProperty());
  this->SetBackfaceProperty(actor->GetBackfaceProperty());
  this->SetTexture(actor->GetTexture());
}


// return the correct type of Actor 
vtkActor *vtkActor::New()
{
  // First try to create the object from the vtkGraphicsFactory
  vtkObject* ret = vtkGraphicsFactory::CreateInstance("vtkActor");
  return (vtkActor*)ret;
}

void vtkActor::GetActors(vtkPropCollection *ac)
{
  ac->AddItem(this);
}

// should be called from the render methods only
int vtkActor::GetIsOpaque()
{
  if (this->Property->GetOpacity() >= 1.0)
    {
    if (this->Texture && this->Texture->GetInput()) 
      {
      this->Texture->GetInput()->Update();
      if (this->Texture->GetInput()->GetPointData()->GetScalars()->GetNumberOfComponents()%2)
        {
        return 1;
        }
      }
    else
      {
      return 1;
      }
    }
  return 0;
}


// This causes the actor to be rendered. It in turn will render the actor's
// property, texture map and then mapper. If a property hasn't been 
// assigned, then the actor will create one automatically. Note that a 
// side effect of this method is that the visualization network is updated.
int vtkActor::RenderOpaqueGeometry(vtkViewport *vp)
{
  int          renderedSomething = 0; 
  vtkRenderer  *ren = (vtkRenderer *)vp;

  if ( ! this->Mapper )
    {
    return 0;
    }

  // make sure we have a property
  if (!this->Property)
    {
    // force creation of a property
    this->GetProperty();
    }

  // is this actor opaque ?
  if (this->GetIsOpaque())
    {
    this->Property->Render(this, ren);

    // render the backface property
    if (this->BackfaceProperty)
      {
      this->BackfaceProperty->BackfaceRender(this, ren);
      }
    
    // render the texture 
    if (this->Texture)
      {
      this->Texture->Render(ren);
      }
    this->Render(ren,this->Mapper);
    this->EstimatedRenderTime += this->Mapper->GetTimeToDraw();

    renderedSomething = 1;
    }

  return renderedSomething;
}

int vtkActor::RenderTranslucentGeometry(vtkViewport *vp)
{
  int          renderedSomething = 0; 
  vtkRenderer *ren = (vtkRenderer *)vp;

  if ( ! this->Mapper )
    {
    return 0;
    }

  // make sure we have a property
  if (!this->Property)
    {
    // force creation of a property
    this->GetProperty();
    }

  // is this actor opaque ?
  if (!this->GetIsOpaque())
    {
    this->Property->Render(this, ren);

    // render the backface property
    if (this->BackfaceProperty)
      {
      this->BackfaceProperty->BackfaceRender(this, ren);
      }
    
    // render the texture 
    if (this->Texture)
      {
      this->Texture->Render(ren);
      }
    this->Render(ren,this->Mapper);
    this->EstimatedRenderTime += this->Mapper->GetTimeToDraw();

    renderedSomething = 1;
    }

  return renderedSomething;
}

void vtkActor::ReleaseGraphicsResources(vtkWindow *win)
{
  vtkRenderWindow *renWin = (vtkRenderWindow *)win;

  // pass this information onto the mapper
  if (this->Mapper)
    {
    this->Mapper->ReleaseGraphicsResources(renWin);
    }

  // pass this information onto the texture
  if (this->Texture)
    {
    this->Texture->ReleaseGraphicsResources(renWin);
    }
}

void vtkActor::SetProperty(vtkProperty *lut)
{
  if ( this->Property == lut) 
    {
    return;
    }
  if ( this->Property != NULL) 
    {
    this->Property->UnRegister(this);
    this->Property = NULL;
    }
  if ( lut != NULL) 
    {
    lut->Register(this);
    }
  
  this->Property = lut;
  this->Modified();
}

vtkProperty *vtkActor::GetProperty()
{
  if ( this->Property == NULL )
    {
    this->Property = vtkProperty::New();
    }
  return this->Property;
}

void vtkActor::SetBackfaceProperty(vtkProperty *lut)
{
  if ( this->BackfaceProperty == lut) 
    {
    return;
    }
  if ( this->BackfaceProperty != NULL) 
    {
    this->BackfaceProperty->UnRegister(this);
    this->BackfaceProperty = NULL;
    }
  if ( lut != NULL) 
    {
    lut->Register(this);
    }
  
  this->BackfaceProperty = lut;
  this->Modified();
}

vtkProperty *vtkActor::GetBackfaceProperty()
{
  return this->BackfaceProperty;
}

// Get the bounds for this Actor as (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
float *vtkActor::GetBounds()
{
  int i,n;
  float *bounds, bbox[24], *fptr;
  float *result;
  //vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
  double matrix[16];

  vtkDebugMacro( << "Getting Bounds" );

  // get the bounds of the Mapper if we have one
  if (!this->Mapper)
    {
      //matrix->Delete();
    return this->Bounds;
    }

  bounds = this->Mapper->GetBounds();

  // Check if we have cached values for these bounds - we cache the
  // values returned by this->Mapper->GetBounds() and we store the time
  // of caching. If the values returned this time are different, or
  // the modified time of this class is newer than the cached time,
  // then we need to rebuild.
  if ( ( memcmp( this->MapperBounds, bounds, 6*sizeof(float) ) != 0 ) ||
       ( this->GetMTime() > this->BoundsMTime ) )
    {
    vtkDebugMacro( << "Recomputing bounds..." );

    memcpy( this->MapperBounds, bounds, 6*sizeof(float) );

    // fill out vertices of a bounding box
    bbox[ 0] = bounds[1]; bbox[ 1] = bounds[3]; bbox[ 2] = bounds[5];
    bbox[ 3] = bounds[1]; bbox[ 4] = bounds[2]; bbox[ 5] = bounds[5];
    bbox[ 6] = bounds[0]; bbox[ 7] = bounds[2]; bbox[ 8] = bounds[5];
    bbox[ 9] = bounds[0]; bbox[10] = bounds[3]; bbox[11] = bounds[5];
    bbox[12] = bounds[1]; bbox[13] = bounds[3]; bbox[14] = bounds[4];
    bbox[15] = bounds[1]; bbox[16] = bounds[2]; bbox[17] = bounds[4];
    bbox[18] = bounds[0]; bbox[19] = bounds[2]; bbox[20] = bounds[4];
    bbox[21] = bounds[0]; bbox[22] = bounds[3]; bbox[23] = bounds[4];
  
    // save the old transform
    this->GetMatrix(matrix);
    this->Transform->Push(); 
    this->Transform->PostMultiply();
    this->Transform->Identity();
    this->Transform->Concatenate(matrix);

    // and transform into actors coordinates
    fptr = bbox;
    for (n = 0; n < 8; n++) 
      {
      this->Transform->SetPoint(fptr[0],fptr[1],fptr[2],1.0);
  
      // now store the result
      result = this->Transform->GetPoint();
      fptr[0] = result[0] / result[3];
      fptr[1] = result[1] / result[3];
      fptr[2] = result[2] / result[3];
      fptr += 3;
      }
  
    this->Transform->PreMultiply();
    this->Transform->Pop();  
  
    // now calc the new bounds
    this->Bounds[0] = this->Bounds[2] = this->Bounds[4] = VTK_LARGE_FLOAT;
    this->Bounds[1] = this->Bounds[3] = this->Bounds[5] = -VTK_LARGE_FLOAT;
    for (i = 0; i < 8; i++)
      {
      for (n = 0; n < 3; n++)
	{
	if (bbox[i*3+n] < this->Bounds[n*2]) 
	  {
	  this->Bounds[n*2] = bbox[i*3+n];
	  }
	if (bbox[i*3+n] > this->Bounds[n*2+1]) 
	  {
	  this->Bounds[n*2+1] = bbox[i*3+n];
	  }
	}
      }
    this->BoundsMTime.Modified();
    }

  //matrix->Delete();
  return this->Bounds;
}

vtkActor *vtkActor::GetNextPart()
{
  if ( this->TraversalLocation++ == 0 )
    {
    return this;
    }
  else
    {
    return NULL;
    }
}

unsigned long int vtkActor::GetMTime()
{
  unsigned long mTime=this->vtkObject::GetMTime();
  unsigned long time;

  if ( this->Property != NULL )
    {
    time = this->Property->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    }

  if ( this->BackfaceProperty != NULL )
    {
    time = this->BackfaceProperty->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    }

  if ( this->UserMatrix != NULL )
    {
    time = this->UserMatrix->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    }

  if ( this->Texture != NULL )
    {
    time = this->Texture->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    }

  return mTime;
}

unsigned long int vtkActor::GetRedrawMTime()
{
  unsigned long mTime=this->GetMTime();
  unsigned long time;

  if ( this->Mapper != NULL )
    {
    time = this->Mapper->GetMTime();
    mTime = ( time > mTime ? time : mTime );
    if (this->GetMapper()->GetInput() != NULL)
      {
      this->GetMapper()->GetInput()->Update();
      time = this->Mapper->GetInput()->GetMTime();
      mTime = ( time > mTime ? time : mTime );
      }
    }

  return mTime;
}

// Update visualization pipeline and any other parts of actor that are
// necessary.
void vtkActor::Update()
{
  if ( this->Mapper )
    {
    this->Mapper->Update();
    }
}

// This method is used in conjunction with the assembly object to build a copy
// of the assembly hierarchy. This hierarchy can then be traversed for 
// rendering or other operations.
void vtkActor::BuildPaths(vtkAssemblyPaths *vtkNotUsed(paths), 
                          vtkActorCollection *path)
{
  vtkActor *copy= vtkActor::New();
  vtkActor *previous;

  copy->ShallowCopy(this);
  previous = path->GetLastActor();

  vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
  matrix->DeepCopy(previous->vtkProp3D::GetMatrixPointer());
  copy->SetUserMatrix(matrix);
  matrix->Delete();

  path->AddItem(copy);
}

void vtkActor::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkProp3D::PrintSelf(os,indent);

  // make sure our bounds are up to date
  if ( this->Mapper )
    {
    this->GetBounds();
    os << indent << "Bounds: \n";
    os << indent << "  Xmin,Xmax: (" << this->Bounds[0] << ", " << this->Bounds[1] << ")\n";
    os << indent << "  Ymin,Ymax: (" << this->Bounds[2] << ", " << this->Bounds[3] << ")\n";
    os << indent << "  Zmin,Zmax: (" << this->Bounds[4] << ", " << this->Bounds[5] << ")\n";
    }
  else
    {
    os << indent << "Bounds: (not defined)\n";
    }

  if ( this->Mapper )
    {
    os << indent << "Mapper:\n";
    this->Mapper->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Mapper: (none)\n";
    }

  if ( this->Property )
    {
    os << indent << "Property:\n";
    this->Property->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Property: (none)\n";
    }

  if ( this->Texture )
    {
    os << indent << "Texture: this->Texture\n";
    }
  else
    {
    os << indent << "Texture: (none)\n";
    }

}




