/*========================================================================= Program: Visualization Toolkit Module: vtkOpenGLRayCastImageDisplayHelper.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 "vtkOpenGLRayCastImageDisplayHelper.h" #include "vtkFixedPointRayCastImage.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkOpenGLRenderUtilities.h" #include "vtkOpenGLRenderWindow.h" #include "vtkOpenGLShaderCache.h" #include "vtkOpenGLState.h" #include "vtkOpenGLVertexArrayObject.h" #include "vtkProperty.h" #include "vtkRenderer.h" #include "vtkShaderProgram.h" #include "vtkTextureObject.h" #include "vtkTransform.h" #include "vtkVolume.h" #include "vtkOpenGLHelper.h" #include "vtkOpenGLError.h" #include #include "vtkTextureObjectVS.h" // a pass through shader vtkStandardNewMacro(vtkOpenGLRayCastImageDisplayHelper); //------------------------------------------------------------------------------ // Construct a new vtkOpenGLRayCastImageDisplayHelper with default values vtkOpenGLRayCastImageDisplayHelper::vtkOpenGLRayCastImageDisplayHelper() { this->TextureObject = vtkTextureObject::New(); this->ShaderProgram = nullptr; } //------------------------------------------------------------------------------ // Destruct a vtkOpenGLRayCastImageDisplayHelper - clean up any memory used vtkOpenGLRayCastImageDisplayHelper::~vtkOpenGLRayCastImageDisplayHelper() { if (this->TextureObject) { this->TextureObject->Delete(); this->TextureObject = nullptr; } if (this->ShaderProgram) { delete this->ShaderProgram; this->ShaderProgram = nullptr; } } //------------------------------------------------------------------------------ // imageMemorySize is how big the texture is - this is always a power of two // // imageViewportSize is how big the renderer viewport is in pixels // // imageInUseSize is the rendered image - equal or smaller than imageMemorySize // and imageViewportSize // // imageOrigin is the starting pixel of the imageInUseSize image on the // the imageViewportSize viewport // void vtkOpenGLRayCastImageDisplayHelper::RenderTexture( vtkVolume* vol, vtkRenderer* ren, vtkFixedPointRayCastImage* image, float requestedDepth) { this->RenderTextureInternal(vol, ren, image->GetImageMemorySize(), image->GetImageViewportSize(), image->GetImageInUseSize(), image->GetImageOrigin(), requestedDepth, VTK_UNSIGNED_SHORT, image->GetImage()); } //------------------------------------------------------------------------------ void vtkOpenGLRayCastImageDisplayHelper::RenderTexture(vtkVolume* vol, vtkRenderer* ren, int imageMemorySize[2], int imageViewportSize[2], int imageInUseSize[2], int imageOrigin[2], float requestedDepth, unsigned char* image) { this->RenderTextureInternal(vol, ren, imageMemorySize, imageViewportSize, imageInUseSize, imageOrigin, requestedDepth, VTK_UNSIGNED_CHAR, static_cast(image)); } //------------------------------------------------------------------------------ void vtkOpenGLRayCastImageDisplayHelper::RenderTexture(vtkVolume* vol, vtkRenderer* ren, int imageMemorySize[2], int imageViewportSize[2], int imageInUseSize[2], int imageOrigin[2], float requestedDepth, unsigned short* image) { this->RenderTextureInternal(vol, ren, imageMemorySize, imageViewportSize, imageInUseSize, imageOrigin, requestedDepth, VTK_UNSIGNED_SHORT, static_cast(image)); } //------------------------------------------------------------------------------ void vtkOpenGLRayCastImageDisplayHelper::RenderTextureInternal(vtkVolume* vol, vtkRenderer* ren, int imageMemorySize[2], int imageViewportSize[2], int imageInUseSize[2], int imageOrigin[2], float requestedDepth, int imageScalarType, void* image) { vtkOpenGLClearErrorMacro(); // Set the context vtkOpenGLRenderWindow* ctx = vtkOpenGLRenderWindow::SafeDownCast(ren->GetRenderWindow()); this->TextureObject->SetContext(ctx); float offsetX, offsetY; float depth; if (requestedDepth > 0.0 && requestedDepth <= 1.0) { depth = requestedDepth * 2.0 - 1.0; } else { // Pass the center of the volume through the world to view function // of the renderer to get the z view coordinate to use for the // view to world transformation of the image bounds. This way we // will draw the image at the depth of the center of the volume ren->SetWorldPoint(vol->GetCenter()[0], vol->GetCenter()[1], vol->GetCenter()[2], 1.0); ren->WorldToDisplay(); depth = ren->GetDisplayPoint()[2]; } // Don't write into the Zbuffer - just use it for comparisons vtkOpenGLState* ostate = ctx->GetState(); ostate->vtkglDepthMask(0); this->TextureObject->SetMinificationFilter(vtkTextureObject::Linear); this->TextureObject->SetMagnificationFilter(vtkTextureObject::Linear); if (imageScalarType == VTK_UNSIGNED_CHAR) { this->TextureObject->Create2DFromRaw(imageMemorySize[0], imageMemorySize[1], 4, VTK_UNSIGNED_CHAR, static_cast(image)); } else { this->TextureObject->Create2DFromRaw(imageMemorySize[0], imageMemorySize[1], 4, VTK_UNSIGNED_SHORT, static_cast(image)); } offsetX = .5 / static_cast(imageMemorySize[0]); offsetY = .5 / static_cast(imageMemorySize[1]); float tcoords[8]; tcoords[0] = 0.0 + offsetX; tcoords[1] = 0.0 + offsetY; tcoords[2] = (float)imageInUseSize[0] / (float)imageMemorySize[0] - offsetX; tcoords[3] = offsetY; tcoords[4] = (float)imageInUseSize[0] / (float)imageMemorySize[0] - offsetX; tcoords[5] = (float)imageInUseSize[1] / (float)imageMemorySize[1] - offsetY; tcoords[6] = offsetX; tcoords[7] = (float)imageInUseSize[1] / (float)imageMemorySize[1] - offsetY; float verts[12] = { 2.0f * imageOrigin[0] / imageViewportSize[0] - 1.0f, 2.0f * imageOrigin[1] / imageViewportSize[1] - 1.0f, depth, 2.0f * (imageOrigin[0] + imageInUseSize[0]) / imageViewportSize[0] - 1.0f, 2.0f * imageOrigin[1] / imageViewportSize[1] - 1.0f, depth, 2.0f * (imageOrigin[0] + imageInUseSize[0]) / imageViewportSize[0] - 1.0f, 2.0f * (imageOrigin[1] + imageInUseSize[1]) / imageViewportSize[1] - 1.0f, depth, 2.0f * imageOrigin[0] / imageViewportSize[0] - 1.0f, 2.0f * (imageOrigin[1] + imageInUseSize[1]) / imageViewportSize[1] - 1.0f, depth }; if (!this->ShaderProgram) { this->ShaderProgram = new vtkOpenGLHelper; // build the shader source code std::string VSSource = vtkTextureObjectVS; std::string FSSource = "//VTK::System::Dec\n" "//VTK::Output::Dec\n" "in vec2 tcoordVC;\n" "uniform sampler2D source;\n" "uniform float scale;\n" "void main(void)\n" "{\n" " gl_FragData[0] = texture2D(source,tcoordVC)*scale;\n" "}\n"; std::string GSSource; // compile and bind it if needed vtkShaderProgram* newShader = ctx->GetShaderCache()->ReadyShaderProgram( VSSource.c_str(), FSSource.c_str(), GSSource.c_str()); // if the shader changed reinitialize the VAO if (newShader != this->ShaderProgram->Program) { this->ShaderProgram->Program = newShader; this->ShaderProgram->VAO->ShaderProgramChanged(); // reset the VAO as the shader has changed } this->ShaderProgram->ShaderSourceTime.Modified(); } else { ctx->GetShaderCache()->ReadyShaderProgram(this->ShaderProgram->Program); } ostate->vtkglEnable(GL_BLEND); // backup current GL blend state vtkOpenGLState::ScopedglBlendFuncSeparate bfsaver(ostate); if (this->PreMultipliedColors) { // make the blend function correct for textures premultiplied by alpha. ostate->vtkglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } // bind and activate this texture this->TextureObject->Activate(); int sourceId = this->TextureObject->GetTextureUnit(); this->ShaderProgram->Program->SetUniformi("source", sourceId); this->ShaderProgram->Program->SetUniformf("scale", this->PixelScale); vtkOpenGLRenderUtilities::RenderQuad( verts, tcoords, this->ShaderProgram->Program, this->ShaderProgram->VAO); this->TextureObject->Deactivate(); vtkOpenGLCheckErrorMacro("failed after RenderTextureInternal"); } //------------------------------------------------------------------------------ void vtkOpenGLRayCastImageDisplayHelper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ void vtkOpenGLRayCastImageDisplayHelper::ReleaseGraphicsResources(vtkWindow* win) { this->TextureObject->ReleaseGraphicsResources(win); if (this->ShaderProgram) { this->ShaderProgram->ReleaseGraphicsResources(win); delete this->ShaderProgram; this->ShaderProgram = nullptr; } }