1 // Copyright (C) 2023 CEA, EDF
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "vtkCADMapper.h"
22 #include <vtkCellData.h>
23 #include <vtkObjectFactory.h>
24 #include <vtkOpenGLBufferObject.h>
25 #include <vtkOpenGLCellToVTKCellMap.h>
26 #include <vtkOpenGLRenderWindow.h>
27 #include <vtkPolyData.h>
28 #include <vtkProperty.h>
29 #include <vtkRenderer.h>
30 #include <vtkTextureObject.h>
31 #include <vtkSelectionNode.h>
33 vtkStandardNewMacro(vtkCADMapper);
35 //-----------------------------------------------------------------------------
36 void vtkCADMapper::SetOpacity(vtkIdType cellId, unsigned char opacity)
38 if(this->PrimColors.empty())
43 for (vtkIdType primId : this->CellToPrimMap[cellId])
45 this->PrimColors[4 * primId + 3] = opacity;
49 //-----------------------------------------------------------------------------
50 void vtkCADMapper::ToggleResetColor(vtkIdType cellId)
52 if(this->PrimColors.empty())
57 const int opacity = this->GroupModeEnabled ? 0 : 255;
59 // Retrieve "default" colors
60 unsigned char color[4];
61 this->Colors->GetTypedTuple(cellId, color);
63 for (vtkIdType primId : this->CellToPrimMap[cellId])
65 this->PrimColors[4 * primId] = color[0];
66 this->PrimColors[4 * primId + 1] = color[1];
67 this->PrimColors[4 * primId + 2] = color[2];
68 this->PrimColors[4 * primId + 3] = opacity;
72 //-----------------------------------------------------------------------------
73 void vtkCADMapper::ToggleSelectColor(vtkIdType cellId)
75 if(this->PrimColors.empty())
80 auto* selectionColors =
81 this->GroupModeEnabled ? this->GroupSelectionColor : this->SelectionColor;
83 const int opacity = this->GroupModeEnabled ? this->SavedCellOpacities[cellId] : 255;
85 for (vtkIdType primId : this->CellToPrimMap[cellId])
87 this->PrimColors[4 * primId] = selectionColors[0];
88 this->PrimColors[4 * primId + 1] = selectionColors[1];
89 this->PrimColors[4 * primId + 2] = selectionColors[2];
90 this->PrimColors[4 * primId + 3] = opacity;
94 //-----------------------------------------------------------------------------
95 void vtkCADMapper::TogglePreselectColor(vtkIdType cellId)
97 if(this->PrimColors.empty())
102 for (vtkIdType primId : this->CellToPrimMap[cellId])
104 this->PrimColors[4 * primId] = this->PreselectionColor[0];
105 this->PrimColors[4 * primId + 1] = this->PreselectionColor[1];
106 this->PrimColors[4 * primId + 2] = this->PreselectionColor[2];
107 this->PrimColors[4 * primId + 3] = 255;
111 //-----------------------------------------------------------------------------
112 void vtkCADMapper::ForceUpdate()
115 this->NeedUpdate = true;
118 //-----------------------------------------------------------------------------
119 void vtkCADMapper::BuildCellTextures(vtkRenderer* ren, vtkActor* vtkNotUsed(actor),
120 vtkCellArray* vtkNotUsed(prims)[4], int vtkNotUsed(representation))
122 if (!this->NeedUpdate)
127 // Add the preselection
129 this->SelectionCache[std::make_tuple(0, 0, this->PreselectedCellId)])
131 this->TogglePreselectColor(idx);
134 // Fill OpenGL related buffers
135 if (!this->CellScalarTexture)
137 this->CellScalarTexture = vtkTextureObject::New();
138 this->CellScalarBuffer = vtkOpenGLBufferObject::New();
139 this->CellScalarBuffer->SetType(vtkOpenGLBufferObject::TextureBuffer);
141 this->CellScalarTexture->SetContext(static_cast<vtkOpenGLRenderWindow*>(ren->GetVTKWindow()));
142 this->CellScalarBuffer->Upload(this->PrimColors, vtkOpenGLBufferObject::TextureBuffer);
143 this->CellScalarTexture->CreateTextureBuffer(
144 static_cast<unsigned int>(this->PrimColors.size() / 4), 4, VTK_UNSIGNED_CHAR,
145 this->CellScalarBuffer);
147 // Reset preselection
149 this->SelectionCache[std::make_tuple(0, 0, this->PreselectedCellId)])
151 this->ToggleResetColor(idx);
154 this->NeedUpdate = false;
157 //-----------------------------------------------------------------------------
158 void vtkCADMapper::BeginSelect()
160 this->Selecting = true;
163 //-----------------------------------------------------------------------------
164 void vtkCADMapper::EndSelect()
166 this->Selecting = false;
169 //-----------------------------------------------------------------------------
170 void vtkCADMapper::CreateGroup()
172 this->SavedGroups.emplace_back(std::make_pair(this->SelectedIds, this->CurrentArrayName));
173 this->SavedGroupVisibilities.emplace_back(false);
174 this->ResetSelection();
177 //-----------------------------------------------------------------------------
178 void vtkCADMapper::SetGroupVisibility(int groupIdx, bool visibility)
180 if(!this->GroupModeEnabled)
185 // Reconstruct the cache if needed (if a different array for selection by value is choosen)
186 this->BuildSelectionCache(this->SavedGroups[groupIdx].second.c_str(), 0, this->CurrentInput);
188 // Save the group visibility
189 this->SavedGroupVisibilities[groupIdx] = visibility;
191 // Show the selected group
192 for (vtkIdType id : this->SavedGroups[groupIdx].first)
194 for (vtkIdType idx : this->SelectionCache[std::make_tuple(0, 0, id)])
198 this->ToggleSelectColor(idx);
202 this->ToggleResetColor(idx);
205 this->SelectedIds.emplace(id);
210 //-----------------------------------------------------------------------------
211 void vtkCADMapper::SetGroupOpacity(int groupIdx, unsigned char opacity)
213 if(!this->GroupModeEnabled)
218 // Reconstruct the cache if needed (if a different array for selection by value is choosen)
219 this->BuildSelectionCache(this->SavedGroups[groupIdx].second.c_str(), 0, this->CurrentInput);
221 // Save the opacity of the selected group and update it directly if currently visible
222 for (vtkIdType id : this->SavedGroups[groupIdx].first)
224 for (vtkIdType idx : this->SelectionCache[std::make_tuple(0, 0, id)])
226 this->SavedCellOpacities[idx] = opacity;
227 if(this->SavedGroupVisibilities[groupIdx])
229 this->SetOpacity(idx, opacity);
236 //-----------------------------------------------------------------------------
237 void vtkCADMapper::SetGroupModeEnabled(bool enabled)
239 this->GroupModeEnabled = enabled;
241 // Set the group mode colors and opacity and clear the selections
242 this->InitializePrimColors();
243 this->SelectedIds.clear();
244 this->PreselectedCellId = -1;
246 // Show all visible groups
247 for (vtkIdType groupId = 0; groupId < this->SavedGroups.size(); groupId++)
249 if (this->SavedGroupVisibilities[groupId])
251 this->SetGroupVisibility(groupId, true);
258 //-----------------------------------------------------------------------------
259 void vtkCADMapper::ResetSelection()
261 for (vtkIdType id : this->SelectedIds)
263 for (vtkIdType idx : this->SelectionCache[std::make_tuple(0, 0, id)])
265 this->ToggleResetColor(idx);
269 this->SelectedIds.clear();
270 this->PreselectedCellId = -1;
274 //-----------------------------------------------------------------------------
275 void vtkCADMapper::Initialize()
277 vtkPolyData* input = vtkPolyData::SafeDownCast(this->GetInput());
280 vtkErrorMacro("Unable to retrieve input polydata.");
284 vtkCellArray* prims[4];
286 prims[0] = input->GetVerts();
287 prims[1] = input->GetLines();
288 prims[2] = input->GetPolys();
289 prims[3] = input->GetStrips();
291 vtkIdType nbVerts = input->GetNumberOfVerts();
292 vtkIdType nbLines = input->GetNumberOfLines();
293 vtkIdType nbPolys = input->GetNumberOfPolys();
295 // Store the mapping from OpenGL primitives to VTK cells
296 this->CellCellMap->BuildCellSupportArrays(prims, VTK_SURFACE, input->GetPoints());
298 // Create the mapping from VTK cells to OpenGL primitives (inverse of CellCellMap)
299 this->CellToPrimMap.clear();
300 this->CellToPrimMap.resize(nbVerts + nbLines + nbPolys);
301 for (auto& v : this->CellToPrimMap)
303 // heuristic : for performances, we assume that we will have at most 10 primitives per cell
304 // it's just a reserve, the algorithm will still works if there is more primitives
308 for (size_t i = 0; i < this->CellCellMap->GetSize(); i++)
310 this->CellToPrimMap[this->CellCellMap->GetValue(i)].push_back(i);
313 // Reset the default colors for all VTK cells
314 if (vtkUnsignedCharArray::SafeDownCast(input->GetCellData()->GetArray("RGB")))
316 input->GetCellData()->RemoveArray("RGB");
319 vtkNew<vtkUnsignedCharArray> colorArray;
320 colorArray->SetNumberOfComponents(3);
321 colorArray->SetNumberOfTuples(nbVerts + nbLines + nbPolys);
322 colorArray->SetName("RGB");
324 input->GetCellData()->SetScalars(colorArray);
326 for (int i = 0; i < nbVerts; i++)
328 colorArray->SetTypedTuple(i, this->VertexColor);
331 for (int i = 0; i < nbLines; i++)
333 colorArray->SetTypedTuple(nbVerts + i, this->EdgeColor);
336 for (int i = 0; i < nbPolys; i++)
338 colorArray->SetTypedTuple(nbVerts + nbLines + i, this->FaceColor);
341 // Initialize the primitive colors from the created color array
342 this->InitializePrimColors();
344 // Clear saved group visibilities
345 this->SavedGroupVisibilities.clear();
347 // Initialize saved cell opacities
348 this->SavedCellOpacities.clear();
349 this->SavedCellOpacities.resize(nbVerts + nbLines + nbPolys, 255);
351 // Reset texture and selection
352 if (this->CellScalarTexture)
354 this->CellScalarTexture->Delete();
355 this->CellScalarTexture = nullptr;
358 if (this->CellScalarBuffer)
360 this->CellScalarBuffer->Delete();
361 this->CellScalarBuffer = nullptr;
364 this->SelectedIds.clear();
365 this->PreselectedCellId = -1;
369 //----------------------------------------------------------------------------
370 void vtkCADMapper::InitializePrimColors()
372 vtkPolyData* input = vtkPolyData::SafeDownCast(this->GetInput());
375 vtkErrorMacro("Unable to retrieve input polydata.");
379 vtkUnsignedCharArray* colorArray = vtkUnsignedCharArray::SafeDownCast(input->GetCellData()->GetAbstractArray("RGB"));
382 vtkErrorMacro("Unable to retrieve the input color array.");
386 // Map the VTK cell color values to the OpenGL primitives color values
387 unsigned char* colorPtr = colorArray->GetPointer(0);
388 const int opacity = this->GroupModeEnabled ? 0 : 255;
390 this->PrimColors.clear();
391 this->PrimColors.reserve(4 * this->CellCellMap->GetSize());
392 for (size_t i = 0; i < this->CellCellMap->GetSize(); i++)
394 for (int j = 0; j < 3; j++)
396 this->PrimColors.push_back(colorPtr[this->CellCellMap->GetValue(i) * 3 + j]);
398 this->PrimColors.push_back(opacity);
402 //----------------------------------------------------------------------------
403 void vtkCADMapper::PrintSelf(ostream& os, vtkIndent indent)
405 this->Superclass::PrintSelf(os, indent);
408 //----------------------------------------------------------------------------
409 void vtkCADMapper::AddCellIdsToSelectionPrimitives(vtkPolyData* poly, const char* arrayName,
410 unsigned int processId, unsigned int compositeIndex, vtkIdType selectedId)
412 this->BuildSelectionCache(arrayName, false, poly);
413 this->CurrentArrayName = arrayName;
415 // If we are selecting an already selected cell, remove it
416 auto idIterator = this->SelectedIds.find(selectedId);
417 if (idIterator != this->SelectedIds.end())
419 if (!this->Selecting)
424 this->SelectionCache[std::make_tuple(processId, compositeIndex, selectedId)])
426 this->ToggleResetColor(idx);
428 this->SelectedIds.erase(idIterator);
432 if (!this->Selecting)
434 if (this->PreselectedCellId == selectedId)
438 this->PreselectedCellId = selectedId;
443 this->PreselectedCellId = -1;
445 this->SelectionCache[std::make_tuple(processId, compositeIndex, selectedId)])
447 this->ToggleSelectColor(idx);
449 this->SelectedIds.emplace(selectedId);