Commit 389c88ea authored by Marcus D. Hanwell's avatar Marcus D. Hanwell

Context OpenGL and OpenGL2 backends

This will enable us to switch the backend at will, the OpenGL works
whereas the OpenGL2 needs some additional improvements mainly to
use point sprites (where most of the tests are failing.

Change-Id: I648c18ca33b4c6796c4b7a829a2902f7e91ff412
parent c5121871
......@@ -10,6 +10,7 @@ vtk_module(vtkChartsCore
vtkTestingCore
vtkTestingRendering
vtkViewsContext2D
vtkIOExport
vtkRenderingContext${VTK_RENDERING_BACKEND}
#vtkIOExport
vtkIOInfovis
)
......@@ -8,6 +8,7 @@ vtk_module(vtkRenderingContext2D
vtkCommonDataModel
vtkCommonMath
vtkCommonTransforms
vtkRendering${VTK_RENDERING_BACKEND}
vtkRenderingFreeType
TEST_DEPENDS
vtkRenderingContext${VTK_RENDERING_BACKEND}
)
......@@ -14,7 +14,9 @@
=========================================================================*/
#include "vtkAbstractContextBufferId.h"
#include "vtkObjectFactory.h"
vtkAbstractObjectFactoryNewMacro(vtkAbstractContextBufferId)
// ----------------------------------------------------------------------------
vtkAbstractContextBufferId::vtkAbstractContextBufferId()
......
......@@ -38,12 +38,16 @@
#include "vtkRenderingContext2DModule.h" // For export macro
#include "vtkObject.h"
class vtkRenderWindow;
class VTKRENDERINGCONTEXT2D_EXPORT vtkAbstractContextBufferId : public vtkObject
{
public:
vtkTypeMacro(vtkAbstractContextBufferId, vtkObject);
virtual void PrintSelf(ostream &os, vtkIndent indent);
static vtkAbstractContextBufferId * New();
// Description:
// Number of columns. Initial value is 0.
vtkGetMacro(Width,int);
......@@ -60,6 +64,16 @@ public:
// Set the number of rows. Initial value is 0.
vtkSetMacro(Height,int);
// Description:
// Set/Get the OpenGL context owning the texture object resource.
virtual void SetContext(vtkRenderWindow *context) = 0;
virtual vtkRenderWindow *GetContext() = 0;
// Description:
// Returns if the context supports the required extensions.
// \pre context_is_set: this->GetContext()!=0
virtual bool IsSupported() = 0;
// Description:
// Allocate the memory for at least Width*Height elements.
// \pre positive_width: GetWidth()>0
......
......@@ -15,25 +15,17 @@
#include "vtkContextActor.h"
#include "vtkContext2D.h"
#include "vtkOpenGLContextDevice2D.h"
#include "vtkOpenGL2ContextDevice2D.h"
#include "vtkContextDevice2D.h"
#include "vtkContext3D.h"
#include "vtkOpenGLContextDevice3D.h"
#include "vtkContextScene.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGL2ContextDevice2D.h"
#include "vtkOpenGLContextDevice2D.h"
#include "vtkOpenGLExtensionManager.h"
#include "vtkOpenGLRenderer.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkTransform2D.h"
#include "vtkViewport.h"
#include "vtkWindow.h"
#include <algorithm>
namespace
{
// vtkViewportSpecification is a helper class that makes it easier to do some
......@@ -118,7 +110,7 @@ namespace
}
}
vtkStandardNewMacro(vtkContextActor);
vtkObjectFactoryNewMacro(vtkContextActor);
//----------------------------------------------------------------------------
vtkContextActor::vtkContextActor()
......@@ -157,17 +149,6 @@ void vtkContextActor::SetScene(vtkContextScene *scene)
//----------------------------------------------------------------------------
void vtkContextActor::ReleaseGraphicsResources(vtkWindow *window)
{
vtkOpenGLContextDevice2D *device =
vtkOpenGLContextDevice2D::SafeDownCast(this->Context->GetDevice());
if (device)
{
device->ReleaseGraphicsResources(window);
}
if(this->Scene.GetPointer())
{
this->Scene->ReleaseGraphicsResources();
}
}
//----------------------------------------------------------------------------
......@@ -243,34 +224,9 @@ int vtkContextActor::RenderOverlay(vtkViewport* viewport)
}
//----------------------------------------------------------------------------
void vtkContextActor::Initialize(vtkViewport* viewport)
void vtkContextActor::Initialize(vtkViewport*)
{
vtkOpenGLContextDevice3D *dev = vtkOpenGLContextDevice3D::New();
this->Context3D->Begin(dev);
dev->Delete();
vtkContextDevice2D *device = NULL;
if (vtkOpenGL2ContextDevice2D::IsSupported(viewport))
{
vtkDebugMacro("Using OpenGL 2 for 2D rendering.")
device = vtkOpenGL2ContextDevice2D::New();
}
else
{
vtkDebugMacro("Using OpenGL 1 for 2D rendering.")
device = vtkOpenGLContextDevice2D::New();
}
if (device)
{
this->Context->Begin(device);
device->Delete();
this->Initialized = true;
}
else
{
// Failed
vtkErrorMacro("Error: failed to initialize the render device.")
}
// Initialization deferred to the derived actor classes.
}
//----------------------------------------------------------------------------
......
......@@ -66,7 +66,7 @@ protected:
// Description:
// Initialize the actor - right now we just decide which device to initialize.
void Initialize(vtkViewport* viewport);
virtual void Initialize(vtkViewport* viewport);
vtkSmartPointer<vtkContextScene> Scene;
vtkNew<vtkContext2D> Context;
......
......@@ -21,10 +21,11 @@
#include "vtkRect.h"
#include "vtkStdString.h"
#include "vtkObjectFactory.h"
#include <cassert>
vtkAbstractObjectFactoryNewMacro(vtkContextDevice2D)
vtkContextDevice2D::vtkContextDevice2D()
{
this->Geometry[0] = 0;
......
......@@ -48,6 +48,8 @@ public:
vtkTypeMacro(vtkContextDevice2D, vtkObject);
virtual void PrintSelf(ostream &os, vtkIndent indent);
static vtkContextDevice2D * New();
// Description:
// Draw a poly line using the points - fastest code path due to memory
// layout of the coordinates. The line will be colored by
......
......@@ -14,6 +14,9 @@
=========================================================================*/
#include "vtkContextDevice3D.h"
#include "vtkObjectFactory.h"
vtkAbstractObjectFactoryNewMacro(vtkContextDevice3D)
vtkContextDevice3D::vtkContextDevice3D()
{
......
......@@ -41,6 +41,8 @@ public:
vtkTypeMacro(vtkContextDevice3D, vtkObject);
virtual void PrintSelf(ostream &os, vtkIndent indent);
static vtkContextDevice3D * New();
// Description:
// Draw a polyline between the specified points.
virtual void DrawPoly(const float *verts, int n,
......
......@@ -22,6 +22,7 @@
#include "vtkContextScenePrivate.h"
#include "vtkContextMouseEvent.h"
#include "vtkContextKeyEvent.h"
#include "vtkNew.h"
// Get my new commands
#include "vtkCommand.h"
......@@ -31,9 +32,7 @@
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkObjectFactory.h"
#include "vtkContextBufferId.h"
#include "vtkOpenGLContextBufferId.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkAbstractContextBufferId.h"
// My STL containers
#include <cassert>
......@@ -322,15 +321,13 @@ bool vtkContextScene::ProcessSelectionEvent(unsigned int rect[5])
// ----------------------------------------------------------------------------
void vtkContextScene::TestBufferIdSupport()
{
if(!this->BufferIdSupportTested)
if (!this->BufferIdSupportTested)
{
vtkOpenGLContextBufferId *b=vtkOpenGLContextBufferId::New();
b->SetContext(static_cast<vtkOpenGLRenderWindow *>(
this->Renderer->GetRenderWindow()));
this->BufferIdSupported=b->IsSupported();
vtkNew<vtkAbstractContextBufferId> b;
b->SetContext(this->Renderer->GetRenderWindow());
this->BufferIdSupported = b->IsSupported();
b->ReleaseGraphicsResources();
b->Delete();
this->BufferIdSupportTested=true;
this->BufferIdSupportTested = true;
}
}
......@@ -343,16 +340,14 @@ void vtkContextScene::UpdateBufferId()
this->Renderer->GetTiledSizeAndOrigin(&width,&height,lowerLeft,
lowerLeft+1);
if(this->BufferId==0 || this->BufferIdDirty ||
width!=this->BufferId->GetWidth() ||
height!=this->BufferId->GetHeight())
if (this->BufferId==0 || this->BufferIdDirty ||
width!=this->BufferId->GetWidth() ||
height!=this->BufferId->GetHeight())
{
if(this->BufferId==0)
if (this->BufferId == 0)
{
vtkOpenGLContextBufferId *b=vtkOpenGLContextBufferId::New();
this->BufferId=b;
b->SetContext(static_cast<vtkOpenGLRenderWindow *>(
this->Renderer->GetRenderWindow()));
this->BufferId = vtkAbstractContextBufferId::New();
this->BufferId->SetContext(this->Renderer->GetRenderWindow());
}
this->BufferId->SetWidth(width);
this->BufferId->SetHeight(height);
......@@ -362,7 +357,7 @@ void vtkContextScene::UpdateBufferId()
this->PaintIds();
this->LastPainter->BufferIdModeEnd();
this->BufferIdDirty=false;
this->BufferIdDirty = false;
}
}
......
set(module_SRCS
#vtkContextBufferId.cxx
vtkOpenGLContextActor.cxx
vtkOpenGL2ContextDevice2D.cxx
vtkOpenGLContextBufferId.cxx
vtkOpenGLContextDevice2D.cxx
vtkOpenGLContextDevice3D.cxx
)
# Now we need to generate the object factory for this module. Create a list of
# overrides, and then generate the class that overrides those classes.
macro(vtk_add_override base override)
list(APPEND vtk_module_overrides ${base})
set(vtk_module_${base}_override ${override})
endmacro()
set(_opengl_overrides
"ContextActor"
"ContextDevice2D"
"ContextDevice3D")
foreach(_override ${_opengl_overrides})
vtk_add_override("vtk${_override}" "vtkOpenGL${_override}")
endforeach()
vtk_add_override("vtkAbstractContextBufferId" "vtkOpenGLContextBufferId")
# Now we iterate and create that class file...
foreach(_class ${vtk_module_overrides})
set(_override ${vtk_module_${_class}_override})
set(_vtk_override_includes "${_vtk_override_includes}
#include \"${_override}.h\"")
set(_vtk_override_creates "${_vtk_override_creates}
VTK_CREATE_CREATE_FUNCTION(${_override})")
set(_vtk_override_do "${_vtk_override_do}
this->RegisterOverride(\"${_class}\",
\"${_override}\",
\"Override for ${vtk-module} module\", 1,
vtkObjectFactoryCreate${_override});")
endforeach()
# Now lets create the object factory classes
string(TOUPPER ${vtk-module} VTK-MODULE)
configure_file(${VTK_CMAKE_DIR}/vtkObjectFactory.h.in
${CMAKE_CURRENT_BINARY_DIR}/${vtk-module}ObjectFactory.h)
configure_file(${VTK_CMAKE_DIR}/vtkObjectFactory.cxx.in
${CMAKE_CURRENT_BINARY_DIR}/${vtk-module}ObjectFactory.cxx)
list(APPEND module_SRCS
${CMAKE_CURRENT_BINARY_DIR}/${vtk-module}ObjectFactory.cxx)
vtk_module_library(${vtk-module} ${module_SRCS})
vtk_module(vtkRenderingContextOpenGL
DEPENDS
vtkRenderingOpenGL
IMPLEMENTS
vtkRenderingContext2D
BACKEND
OpenGL
PRIVATE_DEPENDS
vtkRenderingFreeType
EXCLUDE_FROM_WRAPPING
)
......@@ -31,10 +31,9 @@
#ifndef __vtkOpenGL2ContextDevice2D_h
#define __vtkOpenGL2ContextDevice2D_h
#include "vtkRenderingContext2DModule.h" // For export macro
#include "vtkOpenGLContextDevice2D.h"
class VTKRENDERINGCONTEXT2D_EXPORT vtkOpenGL2ContextDevice2D :
class VTKRENDERINGCONTEXTOPENGL_EXPORT vtkOpenGL2ContextDevice2D :
public vtkOpenGLContextDevice2D
{
public:
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkOpenGLContextActor.cxx
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 "vtkOpenGLContextActor.h"
#include "vtkContext2D.h"
#include "vtkOpenGLContextDevice2D.h"
#include "vtkOpenGL2ContextDevice2D.h"
#include "vtkContext3D.h"
#include "vtkOpenGLContextDevice3D.h"
#include "vtkContextScene.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGL2ContextDevice2D.h"
#include "vtkOpenGLContextDevice2D.h"
#include "vtkOpenGLExtensionManager.h"
#include "vtkOpenGLRenderer.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkTransform2D.h"
#include "vtkViewport.h"
#include "vtkWindow.h"
#include <algorithm>
namespace
{
// vtkViewportSpecification is a helper class that makes it easier to do some
// of the arithmetic for dealing with tiled displays (in VTK, for saving large
// images and in ParaView for actual tiled display).
template <class T>
class vtkViewportSpecification
{
public:
vtkViewportSpecification(const T* input)
{
this->Data[0] = input[0];
this->Data[1] = input[1];
this->Data[2] = input[2];
this->Data[3] = input[3];
}
vtkViewportSpecification(const vtkViewportSpecification<T> &other)
{
this->Data[0] = other.Data[0];
this->Data[1] = other.Data[1];
this->Data[2] = other.Data[2];
this->Data[3] = other.Data[3];
}
// returns false is intersection results in an empty box, otherwise returns true.
// here we assume that typename T handles signed values correctly.
bool intersect(const vtkViewportSpecification<T> &other)
{
vtkViewportSpecification<T> clone(*this);
this->Data[0] = std::max(other.x(), clone.x());
this->Data[1] = std::max(other.y(), clone.y());
T _width = std::min(clone.x() + clone.width(),
other.x() + other.width()) - this->Data[0];
T _height = std::min(clone.y() + clone.height(),
other.y() + other.height()) - this->Data[1];
_width = std::max(0, _width);
_height = std::max(0, _height);
this->Data[2] = this->x() + _width;
this->Data[3] = this->y() + _height;
return (_width !=0 && _height != 0);
}
const T* data() const { return this->Data; }
const T& x() const { return this->Data[0]; }
const T& y() const { return this->Data[1]; }
T width() const { return this->Data[2] - this->Data[0]; }
T height() const { return this->Data[3] - this->Data[1]; }
private:
T Data[4];
};
template <class T>
ostream& operator << (ostream& str, const vtkViewportSpecification<T>& other)
{
str << other.data()[0] << ", "
<< other.data()[1] << ", "
<< other.data()[2] << ", "
<< other.data()[3];
return str;
}
// use this method to convert from normalized-to-display space i.e. [0.0, 1.0]
// to screen pixels.
vtkViewportSpecification<int> convert(
const vtkViewportSpecification<double>& other,
int width, int height)
{
int value[4];
value[0] = static_cast<int>(other.data()[0] * width);
value[1] = static_cast<int>(other.data()[1] * height);
value[2] = static_cast<int>(other.data()[2] * width);
value[3] = static_cast<int>(other.data()[3] * height);
return vtkViewportSpecification<int>(value);
}
}
vtkStandardNewMacro(vtkOpenGLContextActor);
//----------------------------------------------------------------------------
vtkOpenGLContextActor::vtkOpenGLContextActor()
{
this->Initialized = false;
this->Scene = vtkSmartPointer<vtkContextScene>::New();
this->Context->SetContext3D(this->Context3D.GetPointer());
}
//----------------------------------------------------------------------------
vtkOpenGLContextActor::~vtkOpenGLContextActor()
{
if (this->Context.GetPointer())
{
this->Context->End();
}
if (this->Context3D.GetPointer())
{
this->Context3D->End();
}
}
//----------------------------------------------------------------------------
vtkContextScene * vtkOpenGLContextActor::GetScene()
{
return this->Scene.GetPointer();
}
//----------------------------------------------------------------------------
void vtkOpenGLContextActor::SetScene(vtkContextScene *scene)
{
this->Scene = scene;
}
//----------------------------------------------------------------------------
void vtkOpenGLContextActor::ReleaseGraphicsResources(vtkWindow *window)
{
vtkOpenGLContextDevice2D *device =
vtkOpenGLContextDevice2D::SafeDownCast(this->Context->GetDevice());
if (device)
{
device->ReleaseGraphicsResources(window);
}
if(this->Scene.GetPointer())
{
this->Scene->ReleaseGraphicsResources();
}
}
//----------------------------------------------------------------------------
// Renders an actor2D's property and then it's mapper.
int vtkOpenGLContextActor::RenderOverlay(vtkViewport* viewport)
{
vtkDebugMacro(<< "vtkOpenGLContextActor::RenderOverlay");
if (!this->Context.GetPointer())
{
vtkErrorMacro(<< "vtkOpenGLContextActor::Render - No painter set");
return 0;
}
// view_viewport is a normalized viewport specification for this view in a
// large "single" window where 0.0 is min and 1.0 is max. For multi-tile
// views, the range (0-1) will span across multiple tiles.
vtkViewportSpecification<double> view_viewport(
viewport->GetViewport());
// tileviewport is a normalized viewport specification for this "window"
// mapping where in a multi-tile display, does the current window correspond.
vtkViewportSpecification<double> tile_viewport(
viewport->GetVTKWindow()->GetTileViewport());
// this size is already scaled using TileScale.
const int *tile_size = viewport->GetVTKWindow()->GetSize();
// convert both to pixel space before we start doing our arithmetic.
vtkViewportSpecification<int> tile_viewport_pixels =
convert(tile_viewport, tile_size[0], tile_size[1]);
vtkViewportSpecification<int> view_viewport_pixels=
convert(view_viewport, tile_size[0], tile_size[1]);
// interacted space.
vtkViewportSpecification<int> actual_viewport_pixels(view_viewport_pixels);
if (!actual_viewport_pixels.intersect(tile_viewport_pixels))
{
return 1;
}
vtkTransform2D* transform = this->Scene->GetTransform();
transform->Identity();
transform->Translate(
view_viewport_pixels.x() - actual_viewport_pixels.x(),
view_viewport_pixels.y() - actual_viewport_pixels.y());
if (!this->Initialized)
{
this->Initialize(viewport);
}
// Pass the viewport details onto the context device.
int size[2];
size[0] = view_viewport_pixels.width();
size[1] = view_viewport_pixels.height();
vtkRecti viewportRect(actual_viewport_pixels.x() - view_viewport_pixels.x(),
actual_viewport_pixels.y() - view_viewport_pixels.y(),
actual_viewport_pixels.width(),
actual_viewport_pixels.height());
this->Context->GetDevice()->SetViewportSize(vtkVector2i(size));
this->Context->GetDevice()->SetViewportRect(viewportRect);
// This is the entry point for all 2D rendering.
// First initialize the drawing device.
this->Context->GetDevice()->Begin(viewport);
this->Scene->SetGeometry(size);
this->Scene->Paint(this->Context.GetPointer());
this->Context->GetDevice()->End();
return 1;
}
//----------------------------------------------------------------------------
void vtkOpenGLContextActor::Initialize(vtkViewport* viewport)
{
vtkOpenGLContextDevice3D *dev = vtkOpenGLContextDevice3D::New();
this->Context3D->Begin(dev);
dev->Delete();
vtkContextDevice2D *device = NULL;
if (vtkOpenGL2ContextDevice2D::IsSupported(viewport))
{
vtkDebugMacro("Using OpenGL 2 for 2D rendering.")
device = vtkOpenGL2ContextDevice2D::New();
}
else
{
vtkDebugMacro("Using OpenGL 1 for 2D rendering.")
device = vtkOpenGLContextDevice2D::New();
}
if (device)
{
this->Context->Begin(device);
device->Delete();
this->Initialized = true;
}
else
{
// Failed
vtkErrorMacro("Error: failed to initialize the render device.")
}
}
//----------------------------------------------------------------------------
void vtkOpenGLContextActor::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Context: " << this->Context << "\n";
if (this->Context.GetPointer())
{
this->Context->PrintSelf(os, indent.GetNextIndent());
}
}
/*=========================================================================
Program: Visualization Toolkit
Module: vtkOpenGLContextActor.h
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.
=========================================================================*/
// .NAME vtkOpenGLContextActor - provides a vtkProp derived object.
// .SECTION Description
// This object provides the entry point for the vtkContextScene to be rendered
// in a vtkRenderer. Uses the RenderOverlay pass to render the 2D
// vtkContextScene.
#ifndef __vtkOpenGLContextActor_h
#define __vtkOpenGLContextActor_h
#include "vtkRenderingContextOpenGLModule.h" // For export macro
#include "vtkProp.h"
#include "vtkNew.h" // For ivars
#include "vtkSmartPointer.h" // For ivars
class vtkContext2D;
class vtkContext3D;
class vtkContextScene;
class VTKRENDERINGCONTEXTOPENGL_EXPORT vtkOpenGLContextActor : public vtkProp
{
public:
void PrintSelf(ostream& os, vtkIndent indent);
vtkTypeMacro(vtkOpenGLContextActor, vtkProp);
static vtkOpenGLContextActor* New();
// Description:
// We only render in the overlay for the context scene.
virtual int RenderOverlay(vtkViewport *viewport);
// Description:
// Get the vtkContext2D for the actor.
vtkGetNewMacro(Context, vtkContext2D);
// Description:
// Get the chart object for the actor.
vtkContextScene * GetScene();
// Description:
// Set the scene for the actor.
void SetScene(vtkContextScene *scene);
// Description: