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.
nmWTAI-Platform/3rd/VTK7.1/source/VTK-7.1.1/Rendering/OpenGL/vtkOpenGLRenderer.cxx

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,
&params);
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,&params);
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,&params);
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,&params);
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,&params);
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;
}