You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1404 lines
42 KiB
C++
1404 lines
42 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkOpenGLRenderer.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 "vtkOpenGLRenderer.h"
|
|
|
|
#include "vtkCuller.h"
|
|
#include "vtkHiddenLineRemovalPass.h"
|
|
#include "vtkLightCollection.h"
|
|
#include "vtkNew.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkOpenGLCamera.h"
|
|
#include "vtkOpenGLLight.h"
|
|
#include "vtkOpenGLProperty.h"
|
|
#include "vtkRenderWindow.h"
|
|
#include "vtkOpenGLRenderWindow.h"
|
|
#include "vtkOpenGLExtensionManager.h"
|
|
#include "vtkgl.h" // vtkgl namespace
|
|
#include "vtkImageImport.h"
|
|
#include "vtkPNGWriter.h"
|
|
#include "vtkOpenGLTexture.h"
|
|
#include "vtkTimerLog.h"
|
|
#include "vtkRenderPass.h"
|
|
#include "vtkRenderState.h"
|
|
|
|
#include "vtkOpenGL.h"
|
|
#include "vtkOpenGLError.h"
|
|
|
|
#include "vtkShaderProgram2.h"
|
|
|
|
#include <cmath>
|
|
#include <cassert>
|
|
#include <list>
|
|
|
|
class vtkGLPickInfo
|
|
{
|
|
public:
|
|
GLuint* PickBuffer;
|
|
GLuint PickedId;
|
|
GLuint NumPicked;
|
|
};
|
|
|
|
vtkStandardNewMacro(vtkOpenGLRenderer);
|
|
|
|
vtkCxxSetObjectMacro(vtkOpenGLRenderer,ShaderProgram,vtkShaderProgram2);
|
|
|
|
#define VTK_MAX_LIGHTS 8
|
|
|
|
// List of rgba layers, id are 2D rectangle texture Ids.
|
|
class vtkOpenGLRendererLayerList
|
|
{
|
|
public:
|
|
std::list<GLuint> List;
|
|
};
|
|
|
|
extern const char *vtkOpenGLRenderer_PeelingFS;
|
|
|
|
vtkOpenGLRenderer::vtkOpenGLRenderer()
|
|
{
|
|
this->PickInfo = new vtkGLPickInfo;
|
|
this->NumberOfLightsBound = 0;
|
|
this->PickInfo->PickBuffer = 0;
|
|
this->PickInfo->PickedId = 0;
|
|
this->PickInfo->NumPicked = 0;
|
|
this->PickedZ = 0;
|
|
|
|
this->DepthPeelingIsSupported=0;
|
|
this->DepthPeelingIsSupportedChecked=0;
|
|
this->LayerList=0;
|
|
this->OpaqueLayerZ=0;
|
|
this->TransparentLayerZ=0;
|
|
this->ProgramShader=0;
|
|
this->DepthFormat=0;
|
|
this->DepthPeelingHigherLayer=0;
|
|
|
|
this->ShaderProgram=0;
|
|
this->BackgroundTexture = 0;
|
|
}
|
|
|
|
// Internal method temporarily removes lights before reloading them
|
|
// into graphics pipeline.
|
|
void vtkOpenGLRenderer::ClearLights (void)
|
|
{
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
short curLight;
|
|
float Info[4];
|
|
|
|
// define a lighting model and set up the ambient light.
|
|
// use index 11 for the heck of it. Doesn't matter except for 0.
|
|
|
|
// update the ambient light
|
|
Info[0] = this->Ambient[0];
|
|
Info[1] = this->Ambient[1];
|
|
Info[2] = this->Ambient[2];
|
|
Info[3] = 1.0;
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Info);
|
|
|
|
if ( this->TwoSidedLighting )
|
|
{
|
|
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
|
|
}
|
|
else
|
|
{
|
|
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
|
|
}
|
|
|
|
// now delete all the old lights
|
|
for (curLight = GL_LIGHT0; curLight < GL_LIGHT0 + VTK_MAX_LIGHTS; curLight++)
|
|
{
|
|
glDisable(static_cast<GLenum>(curLight));
|
|
}
|
|
|
|
this->NumberOfLightsBound = 0;
|
|
|
|
vtkOpenGLCheckErrorMacro("failed ater ClearLights");
|
|
}
|
|
|
|
// Ask lights to load themselves into graphics pipeline.
|
|
int vtkOpenGLRenderer::UpdateLights ()
|
|
{
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
vtkLight *light;
|
|
short curLight;
|
|
float status;
|
|
int count;
|
|
|
|
// Check if a light is on. If not then make a new light.
|
|
count = 0;
|
|
curLight= this->NumberOfLightsBound + GL_LIGHT0;
|
|
|
|
vtkCollectionSimpleIterator sit;
|
|
for(this->Lights->InitTraversal(sit);
|
|
(light = this->Lights->GetNextLight(sit)); )
|
|
{
|
|
status = light->GetSwitch();
|
|
if ((status > 0.0)&& (curLight < (GL_LIGHT0+VTK_MAX_LIGHTS)))
|
|
{
|
|
curLight++;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if( !count )
|
|
{
|
|
vtkDebugMacro(<<"No lights are on, creating one.");
|
|
this->CreateLight();
|
|
}
|
|
|
|
count = 0;
|
|
curLight= this->NumberOfLightsBound + GL_LIGHT0;
|
|
|
|
// set the matrix mode for lighting. ident matrix on viewing stack
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
|
|
for(this->Lights->InitTraversal(sit);
|
|
(light = this->Lights->GetNextLight(sit)); )
|
|
{
|
|
|
|
status = light->GetSwitch();
|
|
|
|
// if the light is on then define it and bind it.
|
|
// also make sure we still have room.
|
|
if ((status > 0.0)&& (curLight < (GL_LIGHT0+VTK_MAX_LIGHTS)))
|
|
{
|
|
light->Render(this,curLight);
|
|
glEnable(static_cast<GLenum>(curLight));
|
|
|
|
// increment the current light by one
|
|
curLight++;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
this->NumberOfLightsBound = curLight - GL_LIGHT0;
|
|
|
|
glPopMatrix();
|
|
glEnable(GL_LIGHTING);
|
|
|
|
vtkOpenGLCheckErrorMacro("failed after UpdateLights");
|
|
|
|
return count;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Description:
|
|
// Access to the OpenGL program shader uniform variable "useTexture" from the
|
|
// vtkOpenGLProperty or vtkOpenGLTexture.
|
|
int vtkOpenGLRenderer::GetUseTextureUniformVariable()
|
|
{
|
|
GLint result=vtkgl::GetUniformLocation(this->ProgramShader,"useTexture");
|
|
vtkOpenGLCheckErrorMacro("failed at glGetUniformLocation");
|
|
if(result==-1)
|
|
{
|
|
vtkErrorMacro(<<"useTexture is not a uniform variable");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Description:
|
|
// Access to the OpenGL program shader uniform variable "texture" from the
|
|
// vtkOpenGLProperty or vtkOpenGLTexture.
|
|
int vtkOpenGLRenderer::GetTextureUniformVariable()
|
|
{
|
|
GLint result=vtkgl::GetUniformLocation(this->ProgramShader,"texture");
|
|
vtkOpenGLCheckErrorMacro("failed at glGetUniformLocation");
|
|
if(result==-1)
|
|
{
|
|
vtkErrorMacro(<<"texture is not a uniform variable");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Description:
|
|
// Is rendering at translucent geometry stage using depth peeling and
|
|
// rendering a layer other than the first one? (Boolean value)
|
|
// If so, the uniform variables UseTexture and Texture can be set.
|
|
// (Used by vtkOpenGLProperty or vtkOpenGLTexture)
|
|
int vtkOpenGLRenderer::GetDepthPeelingHigherLayer()
|
|
{
|
|
return this->DepthPeelingHigherLayer;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Concrete open gl render method.
|
|
void vtkOpenGLRenderer::DeviceRender(void)
|
|
{
|
|
vtkTimerLog::MarkStartEvent("OpenGL Dev Render");
|
|
|
|
if(this->Pass!=0)
|
|
{
|
|
vtkRenderState s(this);
|
|
s.SetPropArrayAndCount(this->PropArray, this->PropArrayCount);
|
|
s.SetFrameBuffer(0);
|
|
this->Pass->Render(&s);
|
|
}
|
|
else
|
|
{
|
|
// Do not remove this MakeCurrent! Due to Start / End methods on
|
|
// some objects which get executed during a pipeline update,
|
|
// other windows might get rendered since the last time
|
|
// a MakeCurrent was called.
|
|
this->RenderWindow->MakeCurrent();
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
// standard render method
|
|
this->ClearLights();
|
|
|
|
this->UpdateCamera();
|
|
this->UpdateLightGeometry();
|
|
this->UpdateLights();
|
|
|
|
// set matrix mode for actors
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
this->UpdateGeometry();
|
|
|
|
// clean up the model view matrix set up by the camera
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
GLint mvDepth;
|
|
glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &mvDepth);
|
|
if (mvDepth>1)
|
|
{
|
|
glPopMatrix();
|
|
}
|
|
|
|
vtkOpenGLCheckErrorMacro("failed after DeviceRender");
|
|
}
|
|
|
|
vtkTimerLog::MarkEndEvent("OpenGL Dev Render");
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void vtkOpenGLRenderer::DeviceRenderOpaqueGeometry()
|
|
{
|
|
bool useHLR =
|
|
this->UseHiddenLineRemoval &&
|
|
vtkHiddenLineRemovalPass::WireframePropsExist(this->PropArray,
|
|
this->PropArrayCount);
|
|
|
|
if (useHLR)
|
|
{
|
|
vtkNew<vtkHiddenLineRemovalPass> hlrPass;
|
|
vtkRenderState s(this);
|
|
s.SetPropArrayAndCount(this->PropArray, this->PropArrayCount);
|
|
s.SetFrameBuffer(0);
|
|
hlrPass->Render(&s);
|
|
this->NumberOfPropsRendered += hlrPass->GetNumberOfRenderedProps();
|
|
}
|
|
else
|
|
{
|
|
this->Superclass::DeviceRenderOpaqueGeometry();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Description:
|
|
// Render translucent polygonal geometry. Default implementation just call
|
|
// UpdateTranslucentPolygonalGeometry().
|
|
// Subclasses of vtkRenderer that can deal with depth peeling must
|
|
// override this method.
|
|
void vtkOpenGLRenderer::DeviceRenderTranslucentPolygonalGeometry()
|
|
{
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
vtkOpenGLExtensionManager *extensions = NULL;
|
|
|
|
if(this->UseDepthPeeling)
|
|
{
|
|
vtkOpenGLRenderWindow *context
|
|
= vtkOpenGLRenderWindow::SafeDownCast(this->RenderWindow);
|
|
if (!context)
|
|
{
|
|
vtkErrorMacro("OpenGL render window is required.")
|
|
return;
|
|
}
|
|
extensions = context->GetExtensionManager();
|
|
|
|
if(!this->DepthPeelingIsSupportedChecked)
|
|
{
|
|
this->DepthPeelingIsSupportedChecked=1;
|
|
|
|
int supports_GL_1_3=extensions->ExtensionSupported("GL_VERSION_1_3");
|
|
int supports_GL_1_4=extensions->ExtensionSupported("GL_VERSION_1_4");
|
|
int supports_GL_1_5=extensions->ExtensionSupported("GL_VERSION_1_5");
|
|
int supports_GL_2_0=extensions->ExtensionSupported("GL_VERSION_2_0");
|
|
|
|
int supports_vertex_shader;
|
|
int supports_fragment_shader;
|
|
int supports_shader_objects;
|
|
if(supports_GL_2_0)
|
|
{
|
|
supports_vertex_shader=1;
|
|
supports_fragment_shader=1;
|
|
supports_shader_objects=1;
|
|
}
|
|
else
|
|
{
|
|
supports_vertex_shader=extensions->ExtensionSupported("GL_ARB_vertex_shader");
|
|
supports_fragment_shader=extensions->ExtensionSupported("GL_ARB_fragment_shader");
|
|
supports_shader_objects=extensions->ExtensionSupported("GL_ARB_shader_objects");
|
|
}
|
|
int supports_multitexture=supports_GL_1_3 || extensions->ExtensionSupported("GL_ARB_multitexture");
|
|
int supports_occlusion_query;
|
|
int supports_shadow_funcs;
|
|
if(supports_GL_1_5)
|
|
{
|
|
supports_occlusion_query=1;
|
|
supports_shadow_funcs=1;
|
|
}
|
|
else
|
|
{
|
|
supports_occlusion_query=extensions->ExtensionSupported("GL_ARB_occlusion_query");
|
|
supports_shadow_funcs=extensions->ExtensionSupported("GL_EXT_shadow_funcs");
|
|
}
|
|
|
|
int supports_depth_texture;
|
|
int supports_shadow;
|
|
int supports_blend_func_separate;
|
|
if(supports_GL_1_4)
|
|
{
|
|
supports_depth_texture=1;
|
|
supports_blend_func_separate=1;
|
|
supports_shadow=1;
|
|
}
|
|
else
|
|
{
|
|
supports_depth_texture=extensions->ExtensionSupported("GL_ARB_depth_texture");
|
|
supports_shadow=extensions->ExtensionSupported("GL_ARB_shadow");
|
|
supports_blend_func_separate=extensions->ExtensionSupported("GL_EXT_blend_func_separate");
|
|
}
|
|
|
|
int supports_GL_ARB_texture_rectangle=extensions->ExtensionSupported("GL_ARB_texture_rectangle");
|
|
|
|
// spec claims it is GL_SGIS_texture_edge_clamp, reality shows it is
|
|
// GL_EXT_texture_edge_clamp on Nvidia.
|
|
// part of OpenGL 1.2 core
|
|
// there is no new function with this extension, we don't need to load
|
|
// it.
|
|
int supports_edge_clamp=extensions->ExtensionSupported("GL_VERSION_1_2");
|
|
if(!supports_edge_clamp)
|
|
{
|
|
supports_edge_clamp=extensions->ExtensionSupported("GL_SGIS_texture_edge_clamp");
|
|
if(!supports_edge_clamp)
|
|
{
|
|
// nvidia cards.
|
|
supports_edge_clamp=extensions->ExtensionSupported("GL_EXT_texture_edge_clamp");
|
|
}
|
|
}
|
|
|
|
GLint alphaBits;
|
|
glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
|
|
int supportsAtLeast8AlphaBits=alphaBits>=8;
|
|
|
|
// Mesa with "Offscreen" renderer (ie OS Mesa) supports depth peeling in
|
|
// all versions tested 7.10, 8.0, 8.0.5, 9.0.3, 9.1.3, 9.1.4, 9.1.5
|
|
// Mesa version 7 with "Software Rasterizer" renderer all Opacity/Translucent
|
|
// ctests fail with depth peeling
|
|
// Mesa 9.2.0 with Gallium llvmpipe renderer some of these tests fail
|
|
// Mesa 8 with GMA945 renderer supports depth peeling
|
|
// ATI Radeon HD XXXXX on Windows chokes on PROXY_TEXTURE_RECTANGLE_ARB
|
|
// memory querries however if those are not used all the tests pass.
|
|
// ATI Radeon HD on Mac OS X PROXY_TEXTURE_RECTANGLE_ARB are fine but
|
|
// TestTranslucentLUTDepthPeeling fails. So leave it disabled on Apple
|
|
int driver_support
|
|
= (!(extensions->DriverIsATI()
|
|
&& (extensions->GetDriverGLVersionMajor() < 3))
|
|
&& (!extensions->DriverIsMesa()
|
|
|| extensions->DriverGLRendererHas("Offscreen")
|
|
|| (extensions->DriverVersionAtLeast(6,5,3)
|
|
&& !extensions->DriverGLRendererIs("Software Rasterizer")
|
|
&& !extensions->DriverGLRendererHasToken("llvmpipe"))))
|
|
|| extensions->GetIgnoreDriverBugs("ATI/Mesa depth peeling bug.");
|
|
|
|
this->DepthPeelingIsSupported =
|
|
supports_depth_texture &&
|
|
supports_shadow &&
|
|
supports_blend_func_separate &&
|
|
supports_shadow_funcs &&
|
|
supports_vertex_shader &&
|
|
supports_fragment_shader &&
|
|
supports_shader_objects &&
|
|
supports_occlusion_query &&
|
|
supports_multitexture &&
|
|
supports_GL_ARB_texture_rectangle &&
|
|
supports_edge_clamp &&
|
|
supportsAtLeast8AlphaBits &&
|
|
driver_support;
|
|
|
|
if(this->DepthPeelingIsSupported)
|
|
{
|
|
vtkDebugMacro("depth peeling supported");
|
|
if(supports_GL_1_3)
|
|
{
|
|
extensions->LoadExtension("GL_VERSION_1_3");
|
|
}
|
|
else
|
|
{
|
|
extensions->LoadCorePromotedExtension("GL_ARB_multitexture");
|
|
}
|
|
// GL_ARB_depth_texture, GL_ARB_shadow and GL_EXT_shadow_funcs
|
|
// don't introduce new functions.
|
|
if(supports_GL_1_4)
|
|
{
|
|
extensions->LoadExtension("GL_VERSION_1_4");
|
|
}
|
|
else
|
|
{
|
|
extensions->LoadCorePromotedExtension("GL_EXT_blend_func_separate");
|
|
}
|
|
|
|
if(supports_GL_2_0)
|
|
{
|
|
extensions->LoadExtension("GL_VERSION_2_0");
|
|
}
|
|
else
|
|
{
|
|
extensions->LoadCorePromotedExtension("GL_ARB_vertex_shader");
|
|
extensions->LoadCorePromotedExtension("GL_ARB_fragment_shader");
|
|
extensions->LoadCorePromotedExtension("GL_ARB_shader_objects");
|
|
}
|
|
if(supports_GL_1_5)
|
|
{
|
|
extensions->LoadExtension("GL_VERSION_1_5");
|
|
}
|
|
else
|
|
{
|
|
extensions->LoadCorePromotedExtension("GL_ARB_occlusion_query");
|
|
}
|
|
|
|
extensions->LoadExtension("GL_ARB_texture_rectangle");
|
|
|
|
// Some OpenGL implementations such as Mesa or ATI
|
|
// claim to support both GLSL and GL_ARB_texture_rectangle but
|
|
// don't actually support sampler2DRectShadow in a GLSL code.
|
|
// To test that, we compile the shader, if it fails, we don't use
|
|
// deph peeling
|
|
GLuint shader =
|
|
vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER);
|
|
vtkgl::ShaderSource(
|
|
shader, 1,
|
|
const_cast<const char **>(&vtkOpenGLRenderer_PeelingFS), 0);
|
|
vtkgl::CompileShader(shader);
|
|
GLint params;
|
|
vtkgl::GetShaderiv(shader,vtkgl::COMPILE_STATUS,
|
|
¶ms);
|
|
this->DepthPeelingIsSupported = params==GL_TRUE;
|
|
vtkgl::DeleteShader(shader);
|
|
if(!this->DepthPeelingIsSupported)
|
|
{
|
|
vtkDebugMacro("this OpenGL implementation does not support "
|
|
"GL_ARB_texture_rectangle in GLSL code");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vtkDebugMacro(<<"depth peeling is not supported.");
|
|
if(!supports_depth_texture)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 1.4 nor GL_ARB_depth_texture is supported");
|
|
}
|
|
if(!supports_shadow)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 1.4 nor GL_ARB_shadow is supported");
|
|
}
|
|
if(!supports_shadow_funcs)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 1.5 nor GL_EXT_shadow_funcs is supported");
|
|
}
|
|
if(!supports_vertex_shader)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 2.0 nor GL_ARB_vertex_shader is supported");
|
|
}
|
|
if(!supports_fragment_shader)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 2.0 nor GL_ARB_fragment_shader is supported");
|
|
}
|
|
if(!supports_shader_objects)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 2.0 nor GL_ARB_shader_objects is supported");
|
|
}
|
|
if(!supports_occlusion_query)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 1.5 nor GL_ARB_occlusion_query is supported");
|
|
}
|
|
if(!supports_multitexture)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 1.3 nor GL_ARB_multitexture is supported");
|
|
}
|
|
if(!supports_GL_ARB_texture_rectangle)
|
|
{
|
|
vtkDebugMacro(<<"GL_ARB_texture_rectangle is not supported");
|
|
}
|
|
if(!supports_edge_clamp)
|
|
{
|
|
vtkDebugMacro(<<"neither OpenGL 1.2 nor GL_SGIS_texture_edge_clamp nor GL_EXT_texture_edge_clamp is not supported");
|
|
}
|
|
if(!supportsAtLeast8AlphaBits)
|
|
{
|
|
vtkDebugMacro(<<"at least 8 alpha bits is not supported");
|
|
}
|
|
if (!driver_support)
|
|
{
|
|
vtkDebugMacro(<<"buggy driver (Mesa < 6.5.3 or ATI)");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!this->UseDepthPeeling || !this->DepthPeelingIsSupported)
|
|
{
|
|
// just alpha blending
|
|
this->LastRenderingUsedDepthPeeling=0;
|
|
this->UpdateTranslucentPolygonalGeometry();
|
|
}
|
|
else
|
|
{
|
|
// depth peeling.
|
|
|
|
// get the viewport dimensions
|
|
this->GetTiledSizeAndOrigin(&this->ViewportWidth,&this->ViewportHeight,
|
|
&this->ViewportX,&this->ViewportY);
|
|
|
|
// get z bits
|
|
GLint depthBits;
|
|
glGetIntegerv(GL_DEPTH_BITS,&depthBits);
|
|
if(depthBits==16)
|
|
{
|
|
this->DepthFormat=vtkgl::DEPTH_COMPONENT16_ARB;
|
|
}
|
|
else
|
|
{
|
|
this->DepthFormat=vtkgl::DEPTH_COMPONENT24_ARB;
|
|
}
|
|
|
|
vtkgl::ActiveTexture(vtkgl::TEXTURE1);
|
|
|
|
// check if the GPU supports a viewport sized texture in
|
|
// the formats we will use. If not then we should fallback
|
|
// to alpha blending.
|
|
|
|
// This check is really an anachronism since modern GPU
|
|
// typically support full screen sized textures in all the
|
|
// common formats.
|
|
|
|
GLint depthTexSupport = 1;
|
|
GLint colorTexSupport = 1;
|
|
|
|
if ( extensions->DriverIsATI()
|
|
&& !extensions->GetIgnoreDriverBugs("ATI proxy query bug.") )
|
|
{
|
|
// The ATI Radeon HD drivers currently choke on the proxy
|
|
// query, but depth peeling has been confirmed to work. For
|
|
// those driver fall back on the weaker max texture size
|
|
// check.
|
|
GLint maxTexSize = 0;
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
|
|
if ( (this->ViewportWidth > maxTexSize)
|
|
|| (this->ViewportHeight > maxTexSize) )
|
|
{
|
|
depthTexSupport = 0;
|
|
colorTexSupport = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Not a buggy ATI driver, it's OK to make the proxy query.
|
|
GLuint proxyQueryTex = 0;
|
|
glGenTextures(1, &proxyQueryTex);
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB, proxyQueryTex);
|
|
|
|
// support for depth buffer format
|
|
glTexImage2D(vtkgl::PROXY_TEXTURE_RECTANGLE_ARB, 0, this->DepthFormat,
|
|
this->ViewportWidth, this->ViewportHeight, 0,
|
|
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,0);
|
|
|
|
glGetTexLevelParameteriv(vtkgl::PROXY_TEXTURE_RECTANGLE_ARB, 0,
|
|
GL_TEXTURE_WIDTH, &depthTexSupport);
|
|
|
|
// support for color buffer
|
|
glTexImage2D(vtkgl::PROXY_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
|
|
this->ViewportWidth, this->ViewportHeight, 0, GL_RGBA,
|
|
GL_UNSIGNED_BYTE, 0);
|
|
|
|
glGetTexLevelParameteriv(vtkgl::PROXY_TEXTURE_RECTANGLE_ARB, 0,
|
|
GL_TEXTURE_WIDTH,&colorTexSupport);
|
|
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB, 0);
|
|
glDeleteTextures(1, &proxyQueryTex);
|
|
}
|
|
|
|
if (!(depthTexSupport && colorTexSupport))
|
|
{
|
|
// GPU does not support a view sized texture in this format.
|
|
// Do alpha blending technique instead.
|
|
vtkWarningMacro(
|
|
<< "The GPU supports "
|
|
<< this->ViewportWidth << "x"
|
|
<< this->ViewportHeight << " texture: depth buffer "
|
|
<< (depthTexSupport?"yes":"no") << ", color buffer "
|
|
<< (colorTexSupport?"yes":"no"));
|
|
|
|
vtkgl::ActiveTexture(vtkgl::TEXTURE0);
|
|
this->LastRenderingUsedDepthPeeling = 0;
|
|
this->UpdateTranslucentPolygonalGeometry();
|
|
return;
|
|
}
|
|
|
|
// 1. Grab the RGBAZ of the opaque layer.
|
|
GLuint opaqueLayerZ=0;
|
|
GLuint opaqueLayerRgba=0;
|
|
glGenTextures(1,&opaqueLayerZ);
|
|
this->OpaqueLayerZ=opaqueLayerZ;
|
|
|
|
glGenTextures(1,&opaqueLayerRgba);
|
|
// opaque z format
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,opaqueLayerZ);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,
|
|
GL_NEAREST);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,
|
|
GL_NEAREST);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,
|
|
vtkgl::CLAMP_TO_EDGE);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,
|
|
vtkgl::CLAMP_TO_EDGE);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,
|
|
vtkgl::TEXTURE_COMPARE_MODE,
|
|
vtkgl::COMPARE_R_TO_TEXTURE);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,
|
|
vtkgl::TEXTURE_COMPARE_FUNC,
|
|
GL_LESS);
|
|
|
|
// Allocate memory
|
|
glTexImage2D(vtkgl::TEXTURE_RECTANGLE_ARB,0,this->DepthFormat,
|
|
this->ViewportWidth,this->ViewportHeight, 0,
|
|
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0);
|
|
|
|
// Grab the z-buffer
|
|
glCopyTexSubImage2D(vtkgl::TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->ViewportX,
|
|
this->ViewportY,this->ViewportWidth,
|
|
this->ViewportHeight);
|
|
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,opaqueLayerRgba);
|
|
// opaque rgba format
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,
|
|
GL_NEAREST);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,
|
|
GL_NEAREST);
|
|
|
|
// Allocate memory
|
|
glTexImage2D(vtkgl::TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
|
|
this->ViewportWidth,this->ViewportHeight, 0, GL_RGBA,
|
|
GL_UNSIGNED_BYTE, 0);
|
|
|
|
// Have to be set before a call to UpdateTranslucentPolygonalGeometry()
|
|
// because UpdateTranslucentPolygonalGeometry() will eventually call
|
|
// vtkOpenGLActor::Render() that uses this flag.
|
|
this->LastRenderingUsedDepthPeeling=1;
|
|
|
|
// Grab the rgba-buffer
|
|
glCopyTexSubImage2D(vtkgl::TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->ViewportX,
|
|
this->ViewportY,this->ViewportWidth,
|
|
this->ViewportHeight);
|
|
|
|
GLuint queryId;
|
|
vtkgl::GenQueries(1,&queryId);
|
|
int stop=0;
|
|
int infiniteLoop=this->MaximumNumberOfPeels==0;
|
|
|
|
unsigned int threshold=static_cast<unsigned int>(this->ViewportWidth*this->ViewportHeight*OcclusionRatio);
|
|
this->LayerList=new vtkOpenGLRendererLayerList;
|
|
|
|
// save the default blend function.
|
|
glPushAttrib(GL_COLOR_BUFFER_BIT);
|
|
|
|
int multiSampleStatus=glIsEnabled(vtkgl::MULTISAMPLE);
|
|
|
|
if(multiSampleStatus)
|
|
{
|
|
glDisable(vtkgl::MULTISAMPLE);
|
|
}
|
|
glDisable(GL_BLEND);
|
|
GLuint nbPixels=0;
|
|
GLuint previousNbPixels=0;
|
|
int l=0;
|
|
while(!stop)
|
|
{
|
|
vtkgl::BeginQuery(vtkgl::SAMPLES_PASSED,queryId);
|
|
stop=!this->RenderPeel(l);
|
|
vtkgl::EndQuery(vtkgl::SAMPLES_PASSED);
|
|
// blocking call
|
|
previousNbPixels=nbPixels;
|
|
if(!stop || l>0) // stop && l==0 <=> no translucent geometry
|
|
{
|
|
vtkgl::GetQueryObjectuiv(queryId,vtkgl::QUERY_RESULT,&nbPixels);
|
|
if(!stop)
|
|
{
|
|
stop=(nbPixels<=threshold) || (nbPixels==previousNbPixels);
|
|
++l;
|
|
if(!stop && !infiniteLoop)
|
|
{
|
|
stop=l>=this->MaximumNumberOfPeels;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(multiSampleStatus)
|
|
{
|
|
glEnable(vtkgl::MULTISAMPLE);
|
|
}
|
|
// The two following lines are taken from vtkOpenGLProperty to
|
|
// reset texturing state after rendering the props.
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable (GL_ALPHA_TEST);
|
|
glDepthFunc(GL_LEQUAL);
|
|
vtkgl::DeleteQueries(1,&queryId);
|
|
if(this->TransparentLayerZ!=0)
|
|
{
|
|
GLuint transparentLayerZ=static_cast<GLuint>(this->TransparentLayerZ);
|
|
glDeleteTextures(1,&transparentLayerZ);
|
|
this->TransparentLayerZ=0;
|
|
}
|
|
|
|
// Finally, draw sorted opacity
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrtho(0, this->ViewportWidth, 0, this->ViewportHeight, -1, 1);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glClearColor( static_cast<GLclampf>(0),static_cast<GLclampf>(0),
|
|
static_cast<GLclampf>(0),static_cast<GLclampf>(0));
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
vtkgl::ActiveTexture(vtkgl::TEXTURE0 );
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glEnable(vtkgl::TEXTURE_RECTANGLE_ARB);
|
|
|
|
// actor in wireframe may have change that
|
|
glPolygonMode(GL_FRONT, GL_FILL);
|
|
|
|
glDisable(GL_BLEND);
|
|
// First the opaque layer
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,opaqueLayerRgba);
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0, 0);
|
|
glVertex2f(0, 0);
|
|
glTexCoord2f(this->ViewportWidth, 0);
|
|
glVertex2f(this->ViewportWidth, 0);
|
|
glTexCoord2f(this->ViewportWidth, this->ViewportHeight);
|
|
glVertex2f(this->ViewportWidth, this->ViewportHeight);
|
|
glTexCoord2f(0, this->ViewportHeight);
|
|
glVertex2f(0, this->ViewportHeight);
|
|
glEnd();
|
|
|
|
vtkgl::BlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_BLEND);
|
|
// the transparent layers
|
|
std::list<GLuint>::reverse_iterator it=this->LayerList->List.rbegin();
|
|
std::list<GLuint>::reverse_iterator itEnd=this->LayerList->List.rend();
|
|
while(it!=itEnd)
|
|
{
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,(*it));
|
|
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0, 0);
|
|
glVertex2f(0, 0);
|
|
glTexCoord2f(this->ViewportWidth, 0);
|
|
glVertex2f(this->ViewportWidth, 0);
|
|
glTexCoord2f(this->ViewportWidth, this->ViewportHeight);
|
|
glVertex2f(this->ViewportWidth, this->ViewportHeight);
|
|
glTexCoord2f(0, this->ViewportHeight);
|
|
glVertex2f(0, this->ViewportHeight);
|
|
glEnd();
|
|
++it;
|
|
}
|
|
// Restore the default blend function for the next stage (overlay)
|
|
glPopAttrib();
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glDisable(vtkgl::TEXTURE_RECTANGLE_ARB);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
// Destroy the shader
|
|
if(this->ProgramShader!=0)
|
|
{
|
|
vtkgl::DeleteProgram(this->ProgramShader);
|
|
this->ProgramShader=0;
|
|
}
|
|
|
|
// Destroy the layers
|
|
size_t c=this->LayerList->List.size();
|
|
GLuint *ids=new GLuint[c];
|
|
std::list<GLuint>::const_iterator it2=this->LayerList->List.begin();
|
|
size_t layer=0;
|
|
while(layer<c)
|
|
{
|
|
ids[layer]=(*it2);
|
|
++layer;
|
|
++it2;
|
|
}
|
|
glDeleteTextures(static_cast<GLsizei>(c),ids);
|
|
delete[] ids;
|
|
delete this->LayerList;
|
|
this->LayerList=0;
|
|
|
|
glDeleteTextures(1,&opaqueLayerRgba);
|
|
glDeleteTextures(1,&opaqueLayerZ);
|
|
}
|
|
|
|
vtkOpenGLCheckErrorMacro("failed after DeviceRenderTranslucentPolygonalGeometry");
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Description:
|
|
// Check the compilation status of some fragment shader source.
|
|
void vtkOpenGLRenderer::CheckCompilation(
|
|
unsigned int fragmentShader)
|
|
{
|
|
vtkOpenGLClearErrorMacro();
|
|
GLuint fs=static_cast<GLuint>(fragmentShader);
|
|
GLint params;
|
|
vtkgl::GetShaderiv(fs,vtkgl::COMPILE_STATUS,¶ms);
|
|
if(params==GL_TRUE)
|
|
{
|
|
vtkDebugMacro(<<"shader source compiled successfully");
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro(<<"shader source compile error");
|
|
// include null terminator
|
|
vtkgl::GetShaderiv(fs,vtkgl::INFO_LOG_LENGTH,¶ms);
|
|
if(params>0)
|
|
{
|
|
char *buffer=new char[params];
|
|
vtkgl::GetShaderInfoLog(fs,params,0,buffer);
|
|
vtkErrorMacro(<<"log: "<<buffer);
|
|
delete[] buffer;
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro(<<"no log");
|
|
}
|
|
}
|
|
vtkOpenGLCheckErrorMacro("failed after CheckCompilation");
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Description:
|
|
// Render a peel layer. If there is no more GPU RAM to save the texture,
|
|
// return false otherwise returns true. Also if layer==0 and no prop have
|
|
// been rendered (there is no translucent geometry), it returns false.
|
|
// \pre positive_layer: layer>=0
|
|
int vtkOpenGLRenderer::RenderPeel(int layer)
|
|
{
|
|
assert("pre: positive_layer" && layer>=0);
|
|
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
GLbitfield mask=GL_COLOR_BUFFER_BIT;
|
|
if(layer>0)
|
|
{
|
|
mask=mask|GL_DEPTH_BUFFER_BIT;
|
|
}
|
|
|
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
|
glClear(mask);
|
|
|
|
vtkgl::ActiveTexture(vtkgl::TEXTURE2);
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,this->OpaqueLayerZ);
|
|
vtkgl::ActiveTexture(vtkgl::TEXTURE1 );
|
|
|
|
if(this->ProgramShader==0)
|
|
{
|
|
this->ProgramShader=vtkgl::CreateProgram();
|
|
GLuint shader=vtkgl::CreateShader(vtkgl::FRAGMENT_SHADER);
|
|
vtkgl::ShaderSource(shader,1,const_cast<const char **>(&vtkOpenGLRenderer_PeelingFS),0);
|
|
vtkgl::CompileShader(shader);
|
|
this->CheckCompilation(shader);
|
|
vtkgl::AttachShader(this->ProgramShader,shader);
|
|
vtkgl::LinkProgram(this->ProgramShader);
|
|
|
|
GLint params;
|
|
vtkgl::GetProgramiv(static_cast<GLuint>(this->ProgramShader),vtkgl::LINK_STATUS,¶ms);
|
|
if(params==GL_TRUE)
|
|
{
|
|
vtkDebugMacro(<<"program linked successfully");
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro(<<"program link error");
|
|
// include null terminator
|
|
vtkgl::GetProgramiv(static_cast<GLuint>(this->ProgramShader),vtkgl::INFO_LOG_LENGTH,¶ms);
|
|
if(params>0)
|
|
{
|
|
#if 1
|
|
char *buffer=new char[params];
|
|
vtkgl::GetProgramInfoLog(static_cast<GLuint>(this->ProgramShader),params,0,buffer);
|
|
vtkErrorMacro(<<"log: "<<buffer);
|
|
delete[] buffer;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro(<<"no log: ");
|
|
}
|
|
}
|
|
vtkgl::DeleteShader(shader); // reference counting
|
|
}
|
|
|
|
if(layer>0)
|
|
{
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,this->TransparentLayerZ);
|
|
vtkgl::UseProgram(this->ProgramShader);
|
|
GLint uShadowTex=vtkgl::GetUniformLocation(this->ProgramShader,"shadowTex");
|
|
if(uShadowTex!=-1)
|
|
{
|
|
vtkgl::Uniform1i(uShadowTex,1);
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro(<<"error: shadowTex is not a uniform.");
|
|
}
|
|
GLint uOpaqueShadowTex=vtkgl::GetUniformLocation(this->ProgramShader,"opaqueShadowTex");
|
|
if(uOpaqueShadowTex!=-1)
|
|
{
|
|
vtkgl::Uniform1i(uOpaqueShadowTex,2);
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro(<<"error: opaqueShadowTex is not a uniform.");
|
|
}
|
|
|
|
GLint uOffsetX=vtkgl::GetUniformLocation(this->ProgramShader,"offsetX");
|
|
if(uOffsetX!=-1)
|
|
{
|
|
vtkgl::Uniform1f(uOffsetX,this->ViewportX);
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro(<<"error: offsetX is not a uniform.");
|
|
}
|
|
|
|
GLint uOffsetY=vtkgl::GetUniformLocation(this->ProgramShader,"offsetY");
|
|
if(uOffsetY!=-1)
|
|
{
|
|
vtkgl::Uniform1f(uOffsetY,this->ViewportY);
|
|
}
|
|
else
|
|
{
|
|
vtkErrorMacro(<<"error: offsetY is not a uniform.");
|
|
}
|
|
}
|
|
vtkgl::ActiveTexture(vtkgl::TEXTURE0 );
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
this->DepthPeelingHigherLayer=layer>0;
|
|
int numberOfRenderedProps=this->UpdateTranslucentPolygonalGeometry();
|
|
if(layer>0)
|
|
{
|
|
this->DepthPeelingHigherLayer=0;
|
|
vtkgl::UseProgram(0);
|
|
}
|
|
|
|
vtkgl::ActiveTexture(vtkgl::TEXTURE1 );
|
|
if(layer==0)
|
|
{
|
|
if(numberOfRenderedProps>0)
|
|
{
|
|
GLuint transparentLayerZ;
|
|
glGenTextures(1,&transparentLayerZ);
|
|
this->TransparentLayerZ=static_cast<unsigned int>(transparentLayerZ);
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,this->TransparentLayerZ);
|
|
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,
|
|
GL_NEAREST);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,
|
|
GL_NEAREST);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_S,
|
|
vtkgl::CLAMP_TO_EDGE);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_WRAP_T,
|
|
vtkgl::CLAMP_TO_EDGE);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,
|
|
vtkgl::TEXTURE_COMPARE_MODE,
|
|
vtkgl::COMPARE_R_TO_TEXTURE);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,
|
|
vtkgl::TEXTURE_COMPARE_FUNC,
|
|
GL_GREATER);
|
|
|
|
// Allocate memory, note: verified GPU support for this
|
|
// texture format above.
|
|
glTexImage2D(vtkgl::TEXTURE_RECTANGLE_ARB,0,this->DepthFormat,
|
|
this->ViewportWidth,this->ViewportHeight, 0,
|
|
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,this->TransparentLayerZ);
|
|
}
|
|
if((layer==0 && numberOfRenderedProps>0) || layer>0)
|
|
{
|
|
// Grab the z-buffer
|
|
glCopyTexSubImage2D(vtkgl::TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->ViewportX,
|
|
this->ViewportY,this->ViewportWidth,
|
|
this->ViewportHeight);
|
|
|
|
// Grab the rgba buffer
|
|
GLuint rgba;
|
|
glGenTextures(1,&rgba);
|
|
glBindTexture(vtkgl::TEXTURE_RECTANGLE_ARB,rgba);
|
|
// rgba format
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MIN_FILTER,
|
|
GL_NEAREST);
|
|
glTexParameteri(vtkgl::TEXTURE_RECTANGLE_ARB,GL_TEXTURE_MAG_FILTER,
|
|
GL_NEAREST);
|
|
|
|
// Allocate memory, note: verified GPU support for this
|
|
// texture format above.
|
|
glTexImage2D(vtkgl::TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
|
|
this->ViewportWidth,this->ViewportHeight, 0, GL_RGBA,
|
|
GL_UNSIGNED_BYTE, 0);
|
|
|
|
// Grab the rgba-buffer
|
|
glCopyTexSubImage2D(vtkgl::TEXTURE_RECTANGLE_ARB, 0, 0, 0, this->ViewportX,
|
|
this->ViewportY,this->ViewportWidth,
|
|
this->ViewportHeight);
|
|
this->LayerList->List.push_back(rgba);
|
|
|
|
vtkOpenGLCheckErrorMacro("failed after RenderPeel");
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
vtkOpenGLCheckErrorMacro("failed after RenderPeel");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void vtkOpenGLRenderer::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "Number Of Lights Bound: " <<
|
|
this->NumberOfLightsBound << "\n";
|
|
os << indent << "PickBuffer " << this->PickInfo->PickBuffer << "\n";
|
|
os << indent << "PickedId" << this->PickInfo->PickedId<< "\n";
|
|
os << indent << "NumPicked" << this->PickInfo->NumPicked<< "\n";
|
|
os << indent << "PickedZ " << this->PickedZ << "\n";
|
|
}
|
|
|
|
|
|
void vtkOpenGLRenderer::Clear(void)
|
|
{
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
GLbitfield clear_mask = 0;
|
|
|
|
if (! this->Transparent())
|
|
{
|
|
glClearColor( static_cast<GLclampf>(this->Background[0]),
|
|
static_cast<GLclampf>(this->Background[1]),
|
|
static_cast<GLclampf>(this->Background[2]),
|
|
static_cast<GLclampf>(0.0));
|
|
clear_mask |= GL_COLOR_BUFFER_BIT;
|
|
}
|
|
|
|
if (!this->GetPreserveDepthBuffer())
|
|
{
|
|
glClearDepth(static_cast<GLclampf>(1.0));
|
|
clear_mask |= GL_DEPTH_BUFFER_BIT;
|
|
}
|
|
|
|
vtkDebugMacro(<< "glClear\n");
|
|
glClear(clear_mask);
|
|
|
|
// If gradient background is turned on, draw it now.
|
|
if (!this->Transparent() &&
|
|
(this->GradientBackground || this->TexturedBackground))
|
|
{
|
|
double tile_viewport[4];
|
|
this->GetRenderWindow()->GetTileViewport(tile_viewport);
|
|
glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT);
|
|
glDisable(GL_ALPHA_TEST);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_TEXTURE_1D);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_BLEND);
|
|
glShadeModel(GL_SMOOTH); // color interpolation
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
{
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
{
|
|
glLoadIdentity();
|
|
glOrtho(
|
|
tile_viewport[0],
|
|
tile_viewport[2],
|
|
tile_viewport[1],
|
|
tile_viewport[3],
|
|
-1.0, 1.0);
|
|
|
|
//top vertices
|
|
if(this->TexturedBackground && this->BackgroundTexture)
|
|
{
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
this->BackgroundTexture->Render(this);
|
|
|
|
// NOTE: By default the mode is GL_MODULATE. Since the user
|
|
// cannot set the mode, the default is set to replace.
|
|
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
// NOTE: vtkTexture Render enables the alpha test
|
|
// so that no buffer is affected if alpha of incoming fragment is
|
|
// below the threshold. Here we have to enable it so that it won't
|
|
// rejects the fragments of the quad as the alpha is set to 0 on it.
|
|
glDisable(GL_ALPHA_TEST);
|
|
}
|
|
|
|
glBegin(GL_QUADS);
|
|
glColor4d(this->Background[0],this->Background[1],this->Background[2],
|
|
0.0);
|
|
glTexCoord2f(0.0, 0.0);
|
|
glVertex2f(0.0, 0.0);
|
|
|
|
glTexCoord2f(1.0, 0.0);
|
|
glVertex2f(1.0, 0);
|
|
|
|
//bottom vertices
|
|
glColor4d(this->Background2[0],this->Background2[1],
|
|
this->Background2[2],0.0);
|
|
glTexCoord2f(1.0, 1.0);
|
|
glVertex2f(1.0, 1.0);
|
|
|
|
glTexCoord2f(0.0, 1.0);
|
|
glVertex2f(0.0, 1.0);
|
|
|
|
glEnd();
|
|
}
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
}
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
glPopAttrib();
|
|
}
|
|
vtkOpenGLCheckErrorMacro("failed after Clear");
|
|
}
|
|
|
|
void vtkOpenGLRenderer::StartPick(unsigned int pickFromSize)
|
|
{
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
int bufferSize = pickFromSize * 4;
|
|
|
|
// Do not remove this MakeCurrent! Due to Start / End methods on
|
|
// some objects which get executed during a pipeline update,
|
|
// other windows might get rendered since the last time
|
|
// a MakeCurrent was called.
|
|
this->RenderWindow->MakeCurrent();
|
|
this->RenderWindow->IsPickingOn();
|
|
delete [] this->PickInfo->PickBuffer;
|
|
this->PickInfo->PickBuffer = new GLuint[bufferSize];
|
|
glSelectBuffer(bufferSize, this->PickInfo->PickBuffer);
|
|
// change to selection mode
|
|
(void)glRenderMode(GL_SELECT);
|
|
// initialize the pick names and add a 0 name, for no pick
|
|
glInitNames();
|
|
glPushName(0);
|
|
|
|
vtkOpenGLCheckErrorMacro("failed after StartPick");
|
|
}
|
|
|
|
void vtkOpenGLRenderer::ReleaseGraphicsResources(vtkWindow *w)
|
|
{
|
|
if (w)
|
|
{
|
|
vtkRenderer::ReleaseGraphicsResources(w);
|
|
if (this->Pass)
|
|
{
|
|
this->Pass->ReleaseGraphicsResources(w);
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkOpenGLRenderer::UpdatePickId()
|
|
{
|
|
glLoadName(this->CurrentPickId++);
|
|
vtkOpenGLCheckErrorMacro("failed after UpdatePick");
|
|
}
|
|
|
|
|
|
void vtkOpenGLRenderer::DevicePickRender()
|
|
{
|
|
// Do not remove this MakeCurrent! Due to Start / End methods on
|
|
// some objects which get executed during a pipeline update,
|
|
// other windows might get rendered since the last time
|
|
// a MakeCurrent was called.
|
|
this->RenderWindow->MakeCurrent();
|
|
vtkOpenGLClearErrorMacro();
|
|
|
|
// standard render method
|
|
this->ClearLights();
|
|
|
|
this->UpdateCamera();
|
|
this->UpdateLightGeometry();
|
|
this->UpdateLights();
|
|
|
|
// set matrix mode for actors
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
this->PickGeometry();
|
|
|
|
// clean up the model view matrix set up by the camera
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
vtkOpenGLCheckErrorMacro("failed after DevicePickRender");
|
|
}
|
|
|
|
|
|
void vtkOpenGLRenderer::DonePick()
|
|
{
|
|
glFlush();
|
|
GLuint hits = glRenderMode(GL_RENDER);
|
|
this->PickInfo->NumPicked = hits;
|
|
|
|
unsigned int depth = static_cast<unsigned int>(-1);
|
|
GLuint* ptr = this->PickInfo->PickBuffer;
|
|
this->PickInfo->PickedId = 0;
|
|
for(unsigned int k =0; k < hits; k++)
|
|
{
|
|
int num_names = *ptr;
|
|
int save = 0;
|
|
ptr++; // move to first depth value
|
|
if(*ptr <= depth)
|
|
{
|
|
depth = *ptr;
|
|
save = 1;
|
|
}
|
|
ptr++; // move to next depth value
|
|
if(*ptr <= depth)
|
|
{
|
|
depth = *ptr;
|
|
save = 1;
|
|
}
|
|
// move to first name picked
|
|
ptr++;
|
|
if(save)
|
|
{
|
|
this->PickInfo->PickedId = *ptr;
|
|
}
|
|
// skip additional names
|
|
ptr += num_names;
|
|
}
|
|
// If there was a pick, then get the Z value
|
|
if(this->PickInfo->PickedId)
|
|
{
|
|
// convert from pick depth described as:
|
|
// Returned depth values are mapped such that the largest unsigned
|
|
// integer value corresponds to window coordinate depth 1.0,
|
|
// and zero corresponds to window coordinate depth 0.0.
|
|
|
|
this->PickedZ = depth/static_cast<double>(VTK_UNSIGNED_INT_MAX);
|
|
|
|
// Clamp to range [0,1]
|
|
this->PickedZ = (this->PickedZ < 0.0) ? 0.0 : this->PickedZ;
|
|
this->PickedZ = (this->PickedZ > 1.0) ? 1.0: this->PickedZ;
|
|
}
|
|
|
|
//Don't delete the list, keep it around in case caller wants all
|
|
//of the hits. Delete it elsewhere when needed.
|
|
//delete [] this->PickInfo->PickBuffer;
|
|
//this->PickInfo->PickBuffer = 0;
|
|
|
|
this->RenderWindow->IsPickingOff();
|
|
}
|
|
|
|
double vtkOpenGLRenderer::GetPickedZ()
|
|
{
|
|
return this->PickedZ;
|
|
}
|
|
|
|
unsigned int vtkOpenGLRenderer::GetPickedId()
|
|
{
|
|
return static_cast<unsigned int>(this->PickInfo->PickedId);
|
|
}
|
|
|
|
vtkOpenGLRenderer::~vtkOpenGLRenderer()
|
|
{
|
|
delete [] this->PickInfo->PickBuffer;
|
|
this->PickInfo->PickBuffer = 0;
|
|
delete this->PickInfo;
|
|
|
|
if(this->ShaderProgram!=0)
|
|
{
|
|
this->ShaderProgram->Delete();
|
|
}
|
|
|
|
if(this->Pass!=0)
|
|
{
|
|
this->Pass->UnRegister(this);
|
|
}
|
|
}
|
|
|
|
unsigned int vtkOpenGLRenderer::GetNumPickedIds()
|
|
{
|
|
return static_cast<unsigned int>(this->PickInfo->NumPicked);
|
|
}
|
|
|
|
int vtkOpenGLRenderer::GetPickedIds(unsigned int atMost,
|
|
unsigned int *callerBuffer)
|
|
{
|
|
if (!this->PickInfo->PickBuffer)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
unsigned int max = (atMost < this->PickInfo->NumPicked) ? atMost : this->PickInfo->NumPicked;
|
|
GLuint* iptr = this->PickInfo->PickBuffer;
|
|
unsigned int *optr = callerBuffer;
|
|
unsigned int k;
|
|
for(k =0; k < max; k++)
|
|
{
|
|
int num_names = *iptr;
|
|
iptr++; // move to first depth value
|
|
iptr++; // move to next depth value
|
|
iptr++; // move to first name picked
|
|
*optr = static_cast<unsigned int>(*iptr);
|
|
optr++;
|
|
// skip additional names
|
|
iptr += num_names;
|
|
}
|
|
return k;
|
|
}
|