// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkOpenGLCellGridMapper.h" #include "vtkActor.h" #include "vtkCellAttribute.h" #include "vtkCellGrid.h" #include "vtkCellGridMapper.h" #include "vtkCellGridRenderRequest.h" #include "vtkColorTransferFunction.h" #include "vtkHardwareSelector.h" #include "vtkImageData.h" #include "vtkInformation.h" #include "vtkLogger.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkOpenGLActor.h" #include "vtkOpenGLError.h" #include "vtkOpenGLRenderWindow.h" #include "vtkOpenGLRenderer.h" #include "vtkOpenGLResourceFreeCallback.h" #include "vtkRenderer.h" #include "vtkRenderingCellGrid.h" #include "vtkSetGet.h" #include "vtkSmartPointer.h" #include "vtkStringToken.h" #include #include #include #include #include #include #include #include VTK_ABI_NAMESPACE_BEGIN using namespace vtk::literals; class vtkOpenGLCellGridMapper::vtkInternals { public: explicit vtkInternals(vtkOpenGLCellGridMapper* Mapper); ~vtkInternals() = default; vtkInternals(const vtkInternals&) = delete; void operator=(const vtkInternals&) = delete; vtkNew RenderQuery; }; vtkOpenGLCellGridMapper::vtkInternals::vtkInternals(vtkOpenGLCellGridMapper* mapper) { this->RenderQuery->SetMapper(mapper); } vtkStandardNewMacro(vtkOpenGLCellGridMapper); vtkOpenGLCellGridMapper::vtkOpenGLCellGridMapper() : Internal(new vtkInternals(this)) { // std::cout << "Constructing " << this->GetObjectDescription() << std::endl; // We default to interpolating scalars before mapping // (because the GLSL shaders do this per fragment). // Currently, there is no other mode supported. this->InterpolateScalarsBeforeMapping = 1; this->ResourceCallback = new vtkOpenGLResourceFreeCallback( this, &vtkOpenGLCellGridMapper::ReleaseGraphicsResources); #ifndef NDEBUG // this->DebugOn(); // Uncomment this for informational messages during renders. #endif // Plugins are expected to register responders, but for the base functionality provided // by VTK itself, we use this object to register responders at construction. // Since the vtkCellGridMapper owns an instance of this request, the registration // is guaranteed to occur in time for the first render of cell types supported by VTK. vtkRenderingCellGrid::RegisterCellsAndResponders(); } vtkOpenGLCellGridMapper::~vtkOpenGLCellGridMapper() { // std::cout << "Destructing " << this->GetObjectDescription() << std::endl; // std::cout << "First deleting this->Internal" << std::endl; delete this->Internal; this->Internal = nullptr; if (this->ResourceCallback) { // std::cout << "Now triggering a release" << std::endl; this->ResourceCallback->Release(); delete this->ResourceCallback; this->ResourceCallback = nullptr; } } void vtkOpenGLCellGridMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Internal: " << this->Internal << "\n"; } void vtkOpenGLCellGridMapper::ReleaseGraphicsResources(vtkWindow* window) { // std::cout << "Inside vtkOpenGLCellGridMapper::ReleaseGraphicsResources -> " << // this->GetObjectDescription() << std::endl; if (!this->ResourceCallback->IsReleasing()) { this->ResourceCallback->Release(); return; } // If called from our own destructor (where we delete this->Internal), do nothing. if (!this->Internal) { // std::cout << " called from our own destructor, exiting early." << std::endl; return; } auto* cellGrid = this->GetInput(); if (cellGrid) { this->Internal->RenderQuery->SetIsReleasingResources(true); this->Internal->RenderQuery->SetWindow(window); // std::cout << " issuing query to release resources" << std::endl; cellGrid->Query(this->Internal->RenderQuery); } this->Modified(); } void vtkOpenGLCellGridMapper::ShallowCopy(vtkAbstractMapper*) {} void vtkOpenGLCellGridMapper::Render(vtkRenderer* ren, vtkActor* act) { vtkDebugMacro(<< __func__); if (ren->GetRenderWindow()->CheckAbortStatus()) { return; } this->ResourceCallback->RegisterGraphicsResources( static_cast(ren->GetRenderWindow())); auto* cellGrid = this->GetInput(); if (cellGrid) { // TODO: Here, we hardwire a colormap for the vtkCellAttribute used for coloring. // In practice, we need another vtkCellQuery for choosing the colormap to // be consistent across all cell types (i.e., to get the field range correct). auto* colorAttribute = cellGrid->GetCellAttributeByName(this->GetArrayName()); if (colorAttribute) { // If the mapper has a colormap, use that. If not, use the cell-attribute's. // If there is still no colormap, create a default. auto cmap = this->LookupTable ? this->LookupTable : colorAttribute->GetColormap(); if (!cmap) { // Create a cool-to-warm (blue to red) diverging colormap by default: vtkNew ctf; // Create a cool-to-warm (blue to red) diverging colormap by default: if (this->GetArrayComponent() >= 0) { ctf->SetVectorModeToComponent(); ctf->SetVectorComponent(this->GetArrayComponent()); } else { ctf->SetVectorModeToMagnitude(); } ctf->SetColorSpaceToDiverging(); ctf->AddRGBPoint(0.0, 59. / 255., 76. / 255., 192. / 255.); ctf->AddRGBPoint(0.5, 221. / 255., 221. / 255., 221. / 255.); ctf->AddRGBPoint(1.0, 180. / 255., 4. / 255., 38. / 255.); ctf->Build(); colorAttribute->SetColormap(ctf); cmap = ctf; } // Now, if there is no colormap texture, make one from the colormap if (!this->LookupTable || this->LookupTable->GetMTime() < cmap->GetMTime()) { this->SetLookupTable(cmap); } if (!this->ColorTextureMap || this->ColorTextureMap->GetMTime() < this->LookupTable->GetMTime()) { this->CreateColormapTexture(); // populate this->ColorTexture from this->LookupTable } // The RenderQuery responders can now call this->GetColorTextureMap() // and use it for color lookup. } // Render the cells using our render-query. this->Internal->RenderQuery->SetRenderer(ren); this->Internal->RenderQuery->SetActor(act); cellGrid->Query(this->Internal->RenderQuery); } } VTK_ABI_NAMESPACE_END