1
/***************************************************************************
2
* Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
30
# include <OpenGL/gl.h>
36
# include <Inventor/SoPickedPoint.h>
37
# include <Inventor/SoPrimitiveVertex.h>
38
# include <Inventor/actions/SoGetBoundingBoxAction.h>
39
# include <Inventor/actions/SoGLRenderAction.h>
40
# include <Inventor/bundles/SoMaterialBundle.h>
41
# include <Inventor/details/SoLineDetail.h>
42
# include <Inventor/elements/SoCoordinateElement.h>
43
# include <Inventor/elements/SoGLCoordinateElement.h>
44
# include <Inventor/elements/SoLineWidthElement.h>
45
# include <Inventor/errors/SoDebugError.h>
46
# include <Inventor/misc/SoState.h>
49
#include <Gui/SoFCUnifiedSelection.h>
50
#include "SoBrepEdgeSet.h"
53
using namespace PartGui;
55
SO_NODE_SOURCE(SoBrepEdgeSet)
57
struct SoBrepEdgeSet::SelContext: Gui::SoFCSelectionContext {
58
std::vector<int32_t> hl, sl;
61
void SoBrepEdgeSet::initClass()
63
SO_NODE_INIT_CLASS(SoBrepEdgeSet, SoIndexedLineSet, "IndexedLineSet");
66
SoBrepEdgeSet::SoBrepEdgeSet()
67
: selContext(std::make_shared<SelContext>())
68
, selContext2(std::make_shared<SelContext>())
70
SO_NODE_CONSTRUCTOR(SoBrepEdgeSet);
73
void SoBrepEdgeSet::GLRender(SoGLRenderAction *action)
75
auto state = action->getState();
76
selCounter.checkRenderCache(state);
79
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext,ctx2);
80
if(ctx2 && ctx2->selectionIndex.empty())
82
if(selContext2->checkGlobal(ctx)) {
83
if(selContext2->isSelectAll()) {
84
selContext2->sl.clear();
85
selContext2->sl.push_back(-1);
87
selContext2->sl = ctx->sl;
88
if(selContext2->highlightIndex==INT_MAX) {
89
selContext2->hl.clear();
90
selContext2->hl.push_back(-1);
92
selContext2->hl = ctx->hl;
96
if(ctx && ctx->highlightIndex==INT_MAX) {
97
if(ctx->selectionIndex.empty() || ctx->isSelectAll()) {
99
ctx2->selectionColor = ctx->highlightColor;
100
renderSelection(action,ctx2);
102
renderHighlight(action,ctx);
104
if(!action->isRenderingDelayedPaths())
105
renderSelection(action,ctx);
107
ctx2->selectionColor = ctx->highlightColor;
108
renderSelection(action,ctx2);
110
renderHighlight(action,ctx);
111
if(action->isRenderingDelayedPaths())
112
renderSelection(action,ctx);
117
if(!action->isRenderingDelayedPaths())
118
renderHighlight(action,ctx);
119
if(ctx && !ctx->selectionIndex.empty()) {
120
if(ctx->isSelectAll()) {
122
ctx2->selectionColor = ctx->selectionColor;
123
renderSelection(action,ctx2);
124
}else if(ctx->isSelectAll())
125
renderSelection(action,ctx);
126
if(action->isRenderingDelayedPaths())
127
renderHighlight(action,ctx);
130
if(!action->isRenderingDelayedPaths())
131
renderSelection(action,ctx);
133
if(ctx2 && !ctx2->selectionIndex.empty())
134
renderSelection(action,ctx2,false);
136
inherited::GLRender(action);
138
// Workaround for #0000433
139
//#if !defined(FC_OS_WIN32)
140
if(!action->isRenderingDelayedPaths())
141
renderHighlight(action,ctx);
142
if(ctx && !ctx->selectionIndex.empty())
143
renderSelection(action,ctx);
144
if(action->isRenderingDelayedPaths())
145
renderHighlight(action,ctx);
149
void SoBrepEdgeSet::GLRenderBelowPath(SoGLRenderAction * action)
151
inherited::GLRenderBelowPath(action);
154
void SoBrepEdgeSet::getBoundingBox(SoGetBoundingBoxAction * action) {
156
SelContextPtr ctx2 = Gui::SoFCSelectionRoot::getSecondaryActionContext<SelContext>(action,this);
157
if(!ctx2 || (ctx2->sl.size()==1 && ctx2->sl[0]<0)) {
158
inherited::getBoundingBox(action);
165
auto state = action->getState();
166
auto coords = SoCoordinateElement::getInstance(state);
167
const SbVec3f *coords3d = coords->getArrayPtr3();
169
if(!validIndexes(coords,ctx2->sl))
175
const int32_t *cindices = &ctx2->sl[0];
176
const int32_t *end = cindices + ctx2->sl.size();
177
while (cindices < end) {
178
bbox.extendBy(coords3d[*cindices++]);
179
i = (cindices < end) ? *cindices++ : -1;
181
bbox.extendBy(coords3d[i]);
182
i = cindices < end ? *cindices++ : -1;
186
action->extendBy(bbox);
189
void SoBrepEdgeSet::renderShape(const SoGLCoordinateElement * const coords,
190
const int32_t *cindices, int numindices)
193
const SbVec3f * coords3d = coords->getArrayPtr3();
197
const int32_t *end = cindices + numindices;
198
while (cindices < end) {
199
glBegin(GL_LINE_STRIP);
201
i = (cindices < end) ? *cindices++ : -1;
203
glVertex3fv((const GLfloat*) (coords3d + previ));
204
glVertex3fv((const GLfloat*) (coords3d + i));
206
i = cindices < end ? *cindices++ : -1;
212
void SoBrepEdgeSet::renderHighlight(SoGLRenderAction *action, SelContextPtr ctx)
214
if(!ctx || ctx->highlightIndex<0)
217
SoState * state = action->getState();
219
//SoLineWidthElement::set(state, this, 4.0f);
221
SoLazyElement::setEmissive(state, &ctx->highlightColor);
222
packedColor = ctx->highlightColor.getPackedValue(0.0);
223
SoLazyElement::setPacked(state, this,1, &packedColor,false);
225
const SoCoordinateElement * coords;
226
const SbVec3f * normals;
227
const int32_t * cindices;
229
const int32_t * nindices;
230
const int32_t * tindices;
231
const int32_t * mindices;
232
SbBool normalCacheUsed;
234
this->getVertexData(state, coords, normals, cindices, nindices,
235
tindices, mindices, numcindices, false, normalCacheUsed);
237
SoMaterialBundle mb(action);
238
mb.sendFirst(); // make sure we have the correct material
240
int num = (int)ctx->hl.size();
242
if (ctx->hl[0] < 0) {
243
renderShape(static_cast<const SoGLCoordinateElement*>(coords), cindices, numcindices);
246
const int32_t* id = &(ctx->hl[0]);
247
if (!validIndexes(coords, ctx->hl)) {
248
SoDebugError::postWarning("SoBrepEdgeSet::renderHighlight", "highlightIndex out of range");
251
renderShape(static_cast<const SoGLCoordinateElement*>(coords), id, num);
258
void SoBrepEdgeSet::renderSelection(SoGLRenderAction *action, SelContextPtr ctx, bool push)
260
SoState * state = action->getState();
263
//SoLineWidthElement::set(state, this, 4.0f);
265
SoLazyElement::setEmissive(state, &ctx->selectionColor);
266
packedColor = ctx->selectionColor.getPackedValue(0.0);
267
SoLazyElement::setPacked(state, this,1, &packedColor,false);
270
const SoCoordinateElement * coords;
271
const SbVec3f * normals;
272
const int32_t * cindices;
274
const int32_t * nindices;
275
const int32_t * tindices;
276
const int32_t * mindices;
277
SbBool normalCacheUsed;
279
this->getVertexData(state, coords, normals, cindices, nindices,
280
tindices, mindices, numcindices, false, normalCacheUsed);
282
SoMaterialBundle mb(action);
283
mb.sendFirst(); // make sure we have the correct material
285
int num = (int)ctx->sl.size();
287
if (ctx->sl[0] < 0) {
288
renderShape(static_cast<const SoGLCoordinateElement*>(coords), cindices, numcindices);
291
cindices = &(ctx->sl[0]);
292
numcindices = (int)ctx->sl.size();
293
if (!validIndexes(coords, ctx->sl)) {
294
SoDebugError::postWarning("SoBrepEdgeSet::renderSelection", "selectionIndex out of range");
297
renderShape(static_cast<const SoGLCoordinateElement*>(coords), cindices, numcindices);
301
if(push) state->pop();
304
bool SoBrepEdgeSet::validIndexes(const SoCoordinateElement* coords, const std::vector<int32_t>& pts) const
306
for (int32_t it : pts) {
307
if (it >= coords->getNum()) {
314
void SoBrepEdgeSet::doAction(SoAction* action)
316
if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) {
317
Gui::SoHighlightElementAction* hlaction = static_cast<Gui::SoHighlightElementAction*>(action);
318
selCounter.checkAction(hlaction);
319
if (!hlaction->isHighlighted()) {
320
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
322
ctx->highlightIndex = -1;
328
const SoDetail* detail = hlaction->getElement();
330
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
331
ctx->highlightColor = hlaction->getColor();
332
ctx->highlightIndex = INT_MAX;
334
ctx->hl.push_back(-1);
339
if (!detail->isOfType(SoLineDetail::getClassTypeId())) {
340
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
342
ctx->highlightIndex = -1;
349
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
350
ctx->highlightColor = hlaction->getColor();
351
int index = static_cast<const SoLineDetail*>(detail)->getLineIndex();
352
const int32_t* cindices = this->coordIndex.getValues(0);
353
int numcindices = this->coordIndex.getNum();
356
for(int section=0,i=0;i<numcindices;i++) {
357
if(cindices[i] < 0) {
358
if(++section > index)
360
}else if(section == index)
361
ctx->hl.push_back(cindices[i]);
364
ctx->highlightIndex = index;
366
ctx->highlightIndex = -1;
370
else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) {
371
Gui::SoSelectionElementAction* selaction = static_cast<Gui::SoSelectionElementAction*>(action);
373
switch(selaction->getType()) {
374
case Gui::SoSelectionElementAction::None: {
375
if(selaction->isSecondary()) {
376
if(Gui::SoFCSelectionRoot::removeActionContext(action,this))
379
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
381
ctx->selectionIndex.clear();
387
} case Gui::SoSelectionElementAction::All: {
388
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
389
selCounter.checkAction(selaction,ctx);
390
ctx->selectionColor = selaction->getColor();
391
ctx->selectionIndex.clear();
392
ctx->selectionIndex.insert(-1); // all
394
ctx->sl.push_back(-1);
397
} case Gui::SoSelectionElementAction::Append:
398
case Gui::SoSelectionElementAction::Remove: {
399
const SoDetail* detail = selaction->getElement();
400
if (!detail || !detail->isOfType(SoLineDetail::getClassTypeId())) {
401
if(selaction->isSecondary()) {
402
// For secondary context, a detail of different type means
403
// the user may want to partial render only other type of
404
// geometry. So we call below to obtain a action context.
405
// If no secondary context exist, it will create an empty
406
// one, and an empty secondary context inhibites drawing
408
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
409
selCounter.checkAction(selaction,ctx);
414
int index = static_cast<const SoLineDetail*>(detail)->getLineIndex();
416
if(selaction->getType() == Gui::SoSelectionElementAction::Append) {
417
ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
418
selCounter.checkAction(selaction,ctx);
419
ctx->selectionColor = selaction->getColor();
420
if(ctx->isSelectAll())
421
ctx->selectionIndex.clear();
422
if(!ctx->selectionIndex.insert(index).second)
425
ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
426
if(!ctx || !ctx->removeIndex(index))
430
if(!ctx->selectionIndex.empty()) {
431
const int32_t* cindices = this->coordIndex.getValues(0);
432
int numcindices = this->coordIndex.getNum();
433
auto it = ctx->selectionIndex.begin();
434
for(int section=0,i=0;i<numcindices;i++) {
436
ctx->sl.push_back(cindices[i]);
437
if(cindices[i] < 0) {
438
if(++section > *it) {
439
if(++it == ctx->selectionIndex.end())
453
inherited::doAction(action);
456
SoDetail * SoBrepEdgeSet::createLineSegmentDetail(SoRayPickAction * action,
457
const SoPrimitiveVertex * v1,
458
const SoPrimitiveVertex * v2,
461
SoDetail* detail = inherited::createLineSegmentDetail(action, v1, v2, pp);
462
SoLineDetail* line_detail = static_cast<SoLineDetail*>(detail);
463
int index = line_detail->getLineIndex();
464
line_detail->setPartIndex(index);