Salome HOME
updated copyright message
[modules/paravis.git] / src / Plugins / CADRepresentation / cadRepresentations / CADRepresentations / vtkCADMapper.cxx
1 // Copyright (C) 2023  CEA, EDF
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "vtkCADMapper.h"
21
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>
32
33 vtkStandardNewMacro(vtkCADMapper);
34
35 //-----------------------------------------------------------------------------
36 void vtkCADMapper::SetOpacity(vtkIdType cellId, unsigned char opacity)
37 {
38   if(this->PrimColors.empty())
39   {
40     return;
41   }
42
43   for (vtkIdType primId : this->CellToPrimMap[cellId])
44   {
45     this->PrimColors[4 * primId + 3] = opacity;
46   }
47 }
48
49 //-----------------------------------------------------------------------------
50 void vtkCADMapper::ToggleResetColor(vtkIdType cellId)
51 {
52   if(this->PrimColors.empty())
53   {
54     return;
55   }
56
57   const int opacity = this->GroupModeEnabled ? 0 : 255;
58
59   // Retrieve "default" colors
60   unsigned char color[4];
61   this->Colors->GetTypedTuple(cellId, color);
62
63   for (vtkIdType primId : this->CellToPrimMap[cellId])
64   {
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;
69   }
70 }
71
72 //-----------------------------------------------------------------------------
73 void vtkCADMapper::ToggleSelectColor(vtkIdType cellId)
74 {
75   if(this->PrimColors.empty())
76   {
77     return;
78   }
79
80   auto* selectionColors =
81       this->GroupModeEnabled ? this->GroupSelectionColor : this->SelectionColor;
82
83   const int opacity = this->GroupModeEnabled ? this->SavedCellOpacities[cellId] : 255;
84
85   for (vtkIdType primId : this->CellToPrimMap[cellId])
86   {
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;
91   }
92 }
93
94 //-----------------------------------------------------------------------------
95 void vtkCADMapper::TogglePreselectColor(vtkIdType cellId)
96 {
97   if(this->PrimColors.empty())
98   {
99     return;
100   }
101
102   for (vtkIdType primId : this->CellToPrimMap[cellId])
103   {
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;
108   }
109 }
110
111 //-----------------------------------------------------------------------------
112 void vtkCADMapper::ForceUpdate()
113 {
114   this->Modified();
115   this->NeedUpdate = true;
116 }
117
118 //-----------------------------------------------------------------------------
119 void vtkCADMapper::BuildCellTextures(vtkRenderer* ren, vtkActor* vtkNotUsed(actor),
120   vtkCellArray* vtkNotUsed(prims)[4], int vtkNotUsed(representation))
121 {
122   if (!this->NeedUpdate)
123   {
124     return;
125   }
126
127   // Add the preselection
128   for (vtkIdType idx :
129     this->SelectionCache[std::make_tuple(0, 0, this->PreselectedCellId)])
130   {
131     this->TogglePreselectColor(idx);
132   }
133
134   // Fill OpenGL related buffers
135   if (!this->CellScalarTexture)
136   {
137     this->CellScalarTexture = vtkTextureObject::New();
138     this->CellScalarBuffer = vtkOpenGLBufferObject::New();
139     this->CellScalarBuffer->SetType(vtkOpenGLBufferObject::TextureBuffer);
140   }
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);
146
147   // Reset preselection
148   for (vtkIdType idx :
149     this->SelectionCache[std::make_tuple(0, 0, this->PreselectedCellId)])
150   {
151     this->ToggleResetColor(idx);
152   }
153
154   this->NeedUpdate = false;
155 }
156
157 //-----------------------------------------------------------------------------
158 void vtkCADMapper::BeginSelect()
159 {
160   this->Selecting = true;
161 }
162
163 //-----------------------------------------------------------------------------
164 void vtkCADMapper::EndSelect()
165 {
166   this->Selecting = false;
167 }
168
169 //-----------------------------------------------------------------------------
170 void vtkCADMapper::CreateGroup()
171 {
172   this->SavedGroups.emplace_back(std::make_pair(this->SelectedIds, this->CurrentArrayName));
173   this->SavedGroupVisibilities.emplace_back(false);
174   this->ResetSelection();
175 }
176
177 //-----------------------------------------------------------------------------
178 void vtkCADMapper::SetGroupVisibility(int groupIdx, bool visibility)
179 {
180   if(!this->GroupModeEnabled)
181   {
182     return;
183   }
184
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);
187
188   // Save the group visibility
189   this->SavedGroupVisibilities[groupIdx] = visibility;
190
191   // Show the selected group
192   for (vtkIdType id : this->SavedGroups[groupIdx].first)
193   {
194     for (vtkIdType idx : this->SelectionCache[std::make_tuple(0, 0, id)])
195     {
196       if (visibility)
197       {
198         this->ToggleSelectColor(idx);
199       }
200       else
201       {
202         this->ToggleResetColor(idx);
203       }
204     }
205     this->SelectedIds.emplace(id);
206   }
207   this->ForceUpdate();
208 }
209
210 //-----------------------------------------------------------------------------
211 void vtkCADMapper::SetGroupOpacity(int groupIdx, unsigned char opacity)
212 {
213   if(!this->GroupModeEnabled)
214   {
215     return;
216   }
217
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);
220
221   // Save the opacity of the selected group and update it directly if currently visible
222   for (vtkIdType id : this->SavedGroups[groupIdx].first)
223   {
224     for (vtkIdType idx : this->SelectionCache[std::make_tuple(0, 0, id)])
225     {
226       this->SavedCellOpacities[idx] = opacity;
227       if(this->SavedGroupVisibilities[groupIdx])
228       {
229         this->SetOpacity(idx, opacity);
230       }
231     }
232   }
233   this->ForceUpdate();
234 }
235
236 //-----------------------------------------------------------------------------
237 void vtkCADMapper::SetGroupModeEnabled(bool enabled)
238 {
239   this->GroupModeEnabled = enabled;
240
241   // Set the group mode colors and opacity and clear the selections
242   this->InitializePrimColors();
243   this->SelectedIds.clear();
244   this->PreselectedCellId = -1;
245
246   // Show all visible groups
247   for (vtkIdType groupId = 0; groupId < this->SavedGroups.size(); groupId++)
248   {
249     if (this->SavedGroupVisibilities[groupId])
250     {
251       this->SetGroupVisibility(groupId, true);
252     }
253   }
254
255   this->ForceUpdate();
256 }
257
258 //-----------------------------------------------------------------------------
259 void vtkCADMapper::ResetSelection()
260 {
261   for (vtkIdType id : this->SelectedIds)
262   {
263     for (vtkIdType idx : this->SelectionCache[std::make_tuple(0, 0, id)])
264     {
265       this->ToggleResetColor(idx);
266     }
267   }
268
269   this->SelectedIds.clear();
270   this->PreselectedCellId = -1;
271   this->ForceUpdate();
272 }
273
274 //-----------------------------------------------------------------------------
275 void vtkCADMapper::Initialize()
276 {
277   vtkPolyData* input = vtkPolyData::SafeDownCast(this->GetInput());
278   if(!input)
279   {
280     vtkErrorMacro("Unable to retrieve input polydata.");
281     return;
282   }
283
284   vtkCellArray* prims[4];
285
286   prims[0] = input->GetVerts();
287   prims[1] = input->GetLines();
288   prims[2] = input->GetPolys();
289   prims[3] = input->GetStrips();
290
291   vtkIdType nbVerts = input->GetNumberOfVerts();
292   vtkIdType nbLines = input->GetNumberOfLines();
293   vtkIdType nbPolys = input->GetNumberOfPolys();
294
295   // Store the mapping from OpenGL primitives to VTK cells
296   this->CellCellMap->BuildCellSupportArrays(prims, VTK_SURFACE, input->GetPoints());
297
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)
302   {
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
305     v.reserve(10);
306   }
307
308   for (size_t i = 0; i < this->CellCellMap->GetSize(); i++)
309   {
310     this->CellToPrimMap[this->CellCellMap->GetValue(i)].push_back(i);
311   }
312
313   // Reset the default colors for all VTK cells
314   if (vtkUnsignedCharArray::SafeDownCast(input->GetCellData()->GetArray("RGB")))
315   {
316     input->GetCellData()->RemoveArray("RGB");
317   }
318
319   vtkNew<vtkUnsignedCharArray> colorArray;
320   colorArray->SetNumberOfComponents(3);
321   colorArray->SetNumberOfTuples(nbVerts + nbLines + nbPolys);
322   colorArray->SetName("RGB");
323
324   input->GetCellData()->SetScalars(colorArray);
325
326   for (int i = 0; i < nbVerts; i++)
327   {
328     colorArray->SetTypedTuple(i, this->VertexColor);
329   }
330
331   for (int i = 0; i < nbLines; i++)
332   {
333     colorArray->SetTypedTuple(nbVerts + i, this->EdgeColor);
334   }
335
336   for (int i = 0; i < nbPolys; i++)
337   {
338     colorArray->SetTypedTuple(nbVerts + nbLines + i, this->FaceColor);
339   }
340
341   // Initialize the primitive colors from the created color array
342   this->InitializePrimColors();
343
344   // Clear saved group visibilities
345   this->SavedGroupVisibilities.clear();
346
347   // Initialize saved cell opacities
348   this->SavedCellOpacities.clear();
349   this->SavedCellOpacities.resize(nbVerts + nbLines + nbPolys, 255);
350
351   // Reset texture and selection
352   if (this->CellScalarTexture)
353   {
354     this->CellScalarTexture->Delete();
355     this->CellScalarTexture = nullptr;
356   }
357
358   if (this->CellScalarBuffer)
359   {
360     this->CellScalarBuffer->Delete();
361     this->CellScalarBuffer = nullptr;
362   }
363
364   this->SelectedIds.clear();
365   this->PreselectedCellId = -1;
366   this->ForceUpdate();
367 }
368
369 //----------------------------------------------------------------------------
370 void vtkCADMapper::InitializePrimColors()
371 {
372   vtkPolyData* input = vtkPolyData::SafeDownCast(this->GetInput());
373   if(!input)
374   {
375     vtkErrorMacro("Unable to retrieve input polydata.");
376     return;
377   }
378
379   vtkUnsignedCharArray* colorArray = vtkUnsignedCharArray::SafeDownCast(input->GetCellData()->GetAbstractArray("RGB"));
380   if(!colorArray)
381   {
382     vtkErrorMacro("Unable to retrieve the input color array.");
383     return;
384   }
385
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;
389
390   this->PrimColors.clear();
391   this->PrimColors.reserve(4 * this->CellCellMap->GetSize());
392   for (size_t i = 0; i < this->CellCellMap->GetSize(); i++)
393   {
394     for (int j = 0; j < 3; j++)
395     {
396       this->PrimColors.push_back(colorPtr[this->CellCellMap->GetValue(i) * 3 + j]);
397     }
398     this->PrimColors.push_back(opacity);
399   }
400 }
401
402 //----------------------------------------------------------------------------
403 void vtkCADMapper::PrintSelf(ostream& os, vtkIndent indent)
404 {
405   this->Superclass::PrintSelf(os, indent);
406 }
407
408 //----------------------------------------------------------------------------
409 void vtkCADMapper::AddCellIdsToSelectionPrimitives(vtkPolyData* poly, const char* arrayName,
410   unsigned int processId, unsigned int compositeIndex, vtkIdType selectedId)
411 {
412   this->BuildSelectionCache(arrayName, false, poly);
413   this->CurrentArrayName = arrayName;
414
415   // If we are selecting an already selected cell, remove it
416   auto idIterator = this->SelectedIds.find(selectedId);
417   if (idIterator != this->SelectedIds.end())
418   {
419     if (!this->Selecting)
420     {
421       return;
422     }
423     for (vtkIdType idx :
424       this->SelectionCache[std::make_tuple(processId, compositeIndex, selectedId)])
425     {
426       this->ToggleResetColor(idx);
427     }
428     this->SelectedIds.erase(idIterator);
429     return;
430   }
431
432   if (!this->Selecting)
433   {
434     if (this->PreselectedCellId == selectedId)
435     {
436       return;
437     }
438     this->PreselectedCellId = selectedId;
439     this->ForceUpdate();
440   }
441   else
442   {
443     this->PreselectedCellId = -1;
444     for (vtkIdType idx :
445       this->SelectionCache[std::make_tuple(processId, compositeIndex, selectedId)])
446     {
447       this->ToggleSelectColor(idx);
448     }
449     this->SelectedIds.emplace(selectedId);
450     this->ForceUpdate();
451   }
452 }