Gui: add support of selection context

The patch implements context-aware selection and rendering in 3D view.

Please check [here](https://git.io/fjiY5) for more details, including
the following 'Render Caching' section.

The patch also includes modification of View3DInventorViewer to support
always-on-top selection rendering using the secondary selection context
and the new coin node SoFCPathAnnotation.

Another small change in SoQtQuarterAdaptor for more responsive frame
rate display. The original implementation reports skewed frame rate
in the presence of long idle period.
This commit is contained in:
Zheng, Lei
2019-07-07 16:08:38 +08:00
committed by wmayer
parent c88e1335d8
commit c9ba972d26
25 changed files with 3500 additions and 957 deletions

View File

@@ -1022,6 +1022,7 @@ SET(Inventor_CPP_SRCS
SoFCOffscreenRenderer.cpp
SoFCSelection.cpp
SoFCUnifiedSelection.cpp
SoFCSelectionContext.cpp
SoFCSelectionAction.cpp
SoFCVectorizeSVGAction.cpp
SoFCVectorizeU3DAction.cpp
@@ -1047,6 +1048,7 @@ SET(Inventor_SRCS
SoFCOffscreenRenderer.h
SoFCSelection.h
SoFCUnifiedSelection.h
SoFCSelectionContext.h
SoFCSelectionAction.h
SoFCVectorizeSVGAction.h
SoFCVectorizeU3DAction.h

View File

@@ -145,6 +145,39 @@ will be shown at the lower left in opened files</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="renderCacheLabel">
<property name="text">
<string>Render cache</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="renderCache">
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Auto</string>
</property>
</item>
<item>
<property name="text">
<string>Distributed</string>
</property>
</item>
<item>
<property name="text">
<string>Centralized</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Gui::PrefCheckBox" name="CheckBox_UseAutoRotation">
<property name="enabled">

View File

@@ -88,6 +88,9 @@ void DlgSettings3DViewImp::saveSettings()
index = this->naviCubeCorner->currentIndex();
hGrp->SetInt("CornerNaviCube", index);
index = this->renderCache->currentIndex();
hGrp->SetInt("RenderCache", index);
QVariant const &vBoxMarkerSize = this->boxMarkerSize->itemData(this->boxMarkerSize->currentIndex());
hGrp->SetInt("MarkerSize", vBoxMarkerSize.toInt());
@@ -158,6 +161,9 @@ void DlgSettings3DViewImp::loadSettings()
index = hGrp->GetInt("CornerNaviCube", 1);
naviCubeCorner->setCurrentIndex(index);
index = hGrp->GetInt("RenderCache", 0);
renderCache->setCurrentIndex(index);
int const current = hGrp->GetInt("MarkerSize", 9L);
this->boxMarkerSize->addItem(tr("5px"), QVariant(5));
this->boxMarkerSize->addItem(tr("7px"), QVariant(7));

View File

@@ -714,32 +714,37 @@ bool SIM::Coin3D::Quarter::SoQTQuarterAdaptor::processSoEvent(const SoEvent* eve
*/
void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::paintEvent(QPaintEvent* event)
{
double start = SbTime::getTimeOfDay().getValue();
QuarterWidget::paintEvent(event);
this->framesPerSecond = addFrametime(SbTime::getTimeOfDay().getValue());
this->framesPerSecond = addFrametime(start);
}
void SIM::Coin3D::Quarter::SoQTQuarterAdaptor::resetFrameCounter(void)
{
this->framecount = 0;
this->frames.assign(100, 0.0f);
this->totaldraw = 0.0f;
this->frametime = 0.0f;
this->drawtime = 0.0f;
this->starttime = SbTime::getTimeOfDay().getValue();
this->framesPerSecond = SbVec2f(0, 0);
}
SbVec2f SIM::Coin3D::Quarter::SoQTQuarterAdaptor::addFrametime(double timeofday)
SbVec2f SIM::Coin3D::Quarter::SoQTQuarterAdaptor::addFrametime(double starttime)
{
int framearray_size = 100;
this->framecount++;
int arrayptr = (this->framecount - 1) % framearray_size;
double timeofday = SbTime::getTimeOfDay().getValue();
double renderTime = timeofday - this->starttime;
this->totaldraw += (float(renderTime) - this->frames[arrayptr]);
float drawfps = this->totaldraw / std::min<int>(this->framecount, framearray_size);
// draw time is the actual time spent on rendering
double drawtime = timeofday - starttime;
#define FPS_FACTOR 0.7
this->drawtime = (drawtime*FPS_FACTOR) + this->drawtime*(1.0-FPS_FACTOR);
// frame time is the time spent since the last frame. There could an
// indefinite pause between the last frame because the scene is not
// changing. So we limit the skew to 5 second.
double frametime = std::min(timeofday-this->starttime, std::max(drawtime,5000.0));
this->frametime = (frametime*FPS_FACTOR) + this->frametime*(1.0-FPS_FACTOR);
this->frames[arrayptr] = static_cast<float>(renderTime);
this->starttime = timeofday;
return SbVec2f(1000 * drawfps, 1.0f / drawfps);
return SbVec2f(1000 * this->drawtime, 1.0f / this->frametime);
}

View File

@@ -117,9 +117,8 @@ private:
SoCallbackList m_interactionStartCallback;
SoCallbackList m_interactionEndCallback;
// Keep track of the frames-per-second counter.
std::vector<float> frames;
float totaldraw;
double frametime;
double drawtime;
double starttime;
int framecount;

View File

@@ -25,6 +25,7 @@
#ifndef _PreComp_
# include <Inventor/nodes/SoSeparator.h>
# include <QHeaderView>
# include <QTextStream>
#endif
#include "SceneInspector.h"
@@ -102,12 +103,21 @@ void SceneModel::setNode(QModelIndex index, SoNode* node)
setNode(this->index(i, 0, index), child);
QHash<SoNode*, QString>::iterator it = nodeNames.find(child);
if (it != nodeNames.end()) {
this->setData(this->index(i, 1, index), QVariant(it.value()));
}
else {
this->setData(this->index(i, 1, index), QVariant(QString::fromLatin1(child->getName())));
QString name;
QTextStream stream(&name);
stream << child << ", ";
if(child->isOfType(SoSwitch::getClassTypeId())) {
auto pcSwitch = static_cast<SoSwitch*>(child);
stream << pcSwitch->whichChild.getValue() << ", ";
} else if (child->isOfType(SoSeparator::getClassTypeId())) {
auto pcSeparator = static_cast<SoSeparator*>(child);
stream << pcSeparator->renderCaching.getValue() << ", ";
}
if (it != nodeNames.end())
stream << it.value();
else
stream << child->getName();
this->setData(this->index(i, 1, index), QVariant(name));
}
}
// insert icon

View File

@@ -122,6 +122,9 @@ void Gui::SoFCDB::init()
MarkerBitmaps ::initClass();
SoFCCSysDragger ::initClass();
SmSwitchboard ::initClass();
SoFCSeparator ::initClass();
SoFCSelectionRoot ::initClass();
SoFCPathAnnotation ::initClass();
PropertyItem ::init();
PropertySeparatorItem ::init();
@@ -203,6 +206,9 @@ void Gui::SoFCDB::finish()
SoFCSelectionColorAction ::finish();
SoUpdateVBOAction ::finish();
SoFCHighlightColorAction ::finish();
SoFCSeparator ::finish();
SoFCSelectionRoot ::finish();
SoFCPathAnnotation ::finish();
storage->unref();
storage = nullptr;

View File

@@ -23,6 +23,7 @@
#include "PreCompiled.h"
#include <Inventor/elements/SoOverrideElement.h>
#include "SoFCInteractiveElement.h"
using namespace Gui;
@@ -248,6 +249,16 @@ void SoGLVBOActivatedElement::get(SoState * state, SbBool& active)
const SoGLVBOActivatedElement* self = static_cast<const SoGLVBOActivatedElement *>
(SoElement::getConstElement(state, classStackIndex));
active = self->active;
if(active) {
uint32_t flags = SoOverrideElement::getFlags(state);
if(flags & (SoOverrideElement::COLOR_INDEX|
SoOverrideElement::DIFFUSE_COLOR|
SoOverrideElement::MATERIAL_BINDING|
SoOverrideElement::TRANSPARENCY|
SoOverrideElement::NORMAL_VECTOR|
SoOverrideElement::NORMAL_BINDING))
active = false;
}
}
void SoGLVBOActivatedElement::push(SoState * state)

View File

@@ -54,13 +54,20 @@
#include "Selection.h"
#include "SoFCSelectionAction.h"
#include "SoFCInteractiveElement.h"
#include "SoFCUnifiedSelection.h"
#include "ViewParams.h"
// For 64-bit system the method using the front buffer doesn't work at all for lines.
// Thus, use the method which forces a redraw every time. This is a bit slower but at
// least it works.
#if defined(_OCC64) // is set by configure or cmake
//
// Disable front buffer in all cases, in order to spare the repeating logic of
// handling selection contextn. SoFCSelection is not really used that much
// anyway.
//
// #if defined(_OCC64) // is set by configure or cmake
# define NO_FRONTBUFFER
#endif
// #endif
using namespace Gui;
@@ -87,6 +94,7 @@ SoFCSelection::SoFCSelection()
SO_NODE_ADD_FIELD(documentName, (""));
SO_NODE_ADD_FIELD(objectName, (""));
SO_NODE_ADD_FIELD(subElementName, (""));
SO_NODE_ADD_FIELD(useNewSelection, (true));
SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE);
SO_NODE_DEFINE_ENUM_VALUE(Styles, EMISSIVE_DIFFUSE);
@@ -111,6 +119,10 @@ SoFCSelection::SoFCSelection()
bCtrl = false;
selected = NOTSELECTED;
useNewSelection = ViewParams::instance()->getUseNewSelection();
selContext = std::make_shared<SelContext>();
selContext2 = std::make_shared<SelContext>();
}
/*!
@@ -151,6 +163,46 @@ SoFCSelection::turnOffCurrentHighlight(SoGLRenderAction * action)
void SoFCSelection::doAction(SoAction *action)
{
if(useNewSelection.getValue() && action->getCurPathCode()!=SoAction::OFF_PATH) {
if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) {
Gui::SoHighlightElementAction* hlaction = static_cast<Gui::SoHighlightElementAction*>(action);
if(!hlaction->isHighlighted()) {
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx->isHighlighted()) {
ctx->highlightIndex = -1;
touch();
}
}else{
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
ctx->highlightColor = hlaction->getColor();
if(!ctx->isHighlighted()) {
ctx->highlightIndex = 0;
touch();
}
}
return;
} else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) {
Gui::SoSelectionElementAction* selaction = static_cast<Gui::SoSelectionElementAction*>(action);
if (selaction->getType() == Gui::SoSelectionElementAction::All ||
selaction->getType() == Gui::SoSelectionElementAction::Append) {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
ctx->selectionColor = selaction->getColor();
if(!ctx->isSelectAll()) {
ctx->selectAll();
this->touch();
}
} else if (selaction->getType() == Gui::SoSelectionElementAction::None ||
selaction->getType() == Gui::SoSelectionElementAction::Remove) {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx && ctx->isSelected()) {
ctx->selectionIndex.clear();
this->touch();
}
}
return;
}
}
if (action->getTypeId() == SoFCDocumentAction::getClassTypeId()) {
SoFCDocumentAction *docaction = (SoFCDocumentAction*)action;
this->documentName = docaction->documentName;
@@ -164,84 +216,87 @@ void SoFCSelection::doAction(SoAction *action)
objaction->setHandled();
}
if (action->getTypeId() == SoFCEnableHighlightAction::getClassTypeId()) {
SoFCEnableHighlightAction *preaction = (SoFCEnableHighlightAction*)action;
if (preaction->highlight) {
this->highlightMode = SoFCSelection::AUTO;
}
else {
this->highlightMode = SoFCSelection::OFF;
}
}
if(!useNewSelection.getValue()) {
if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
SoFCEnableSelectionAction *selaction = (SoFCEnableSelectionAction*)action;
if (selaction->selection) {
this->selectionMode = SoFCSelection::SEL_ON;
}
else {
this->selectionMode = SoFCSelection::SEL_OFF;
if (selected.getValue() == SELECTED) {
this->selected = NOTSELECTED;
if (action->getTypeId() == SoFCEnableHighlightAction::getClassTypeId()) {
SoFCEnableHighlightAction *preaction = (SoFCEnableHighlightAction*)action;
if (preaction->highlight) {
this->highlightMode = SoFCSelection::AUTO;
}
else {
this->highlightMode = SoFCSelection::OFF;
}
}
}
if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
SoFCSelectionColorAction *colaction = (SoFCSelectionColorAction*)action;
this->colorSelection = colaction->selectionColor;
}
if (action->getTypeId() == SoFCEnableSelectionAction::getClassTypeId()) {
SoFCEnableSelectionAction *selaction = (SoFCEnableSelectionAction*)action;
if (selaction->selection) {
this->selectionMode = SoFCSelection::SEL_ON;
}
else {
this->selectionMode = SoFCSelection::SEL_OFF;
if (selected.getValue() == SELECTED) {
this->selected = NOTSELECTED;
}
}
}
if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
SoFCHighlightColorAction *colaction = (SoFCHighlightColorAction*)action;
this->colorHighlight = colaction->highlightColor;
}
if (action->getTypeId() == SoFCSelectionColorAction::getClassTypeId()) {
SoFCSelectionColorAction *colaction = (SoFCSelectionColorAction*)action;
this->colorSelection = colaction->selectionColor;
}
if (selectionMode.getValue() == SEL_ON && action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
SoFCSelectionAction *selaction = static_cast<SoFCSelectionAction*>(action);
if (action->getTypeId() == SoFCHighlightColorAction::getClassTypeId()) {
SoFCHighlightColorAction *colaction = (SoFCHighlightColorAction*)action;
this->colorHighlight = colaction->highlightColor;
}
if (selaction->SelChange.Type == SelectionChanges::AddSelection ||
selaction->SelChange.Type == SelectionChanges::RmvSelection) {
if (documentName.getValue() == selaction->SelChange.pDocName &&
objectName.getValue() == selaction->SelChange.pObjectName &&
(subElementName.getValue() == selaction->SelChange.pSubName ||
*(selaction->SelChange.pSubName) == '\0') ) {
if (selaction->SelChange.Type == SelectionChanges::AddSelection) {
if(selected.getValue() == NOTSELECTED){
if (selectionMode.getValue() == SEL_ON && action->getTypeId() == SoFCSelectionAction::getClassTypeId()) {
SoFCSelectionAction *selaction = static_cast<SoFCSelectionAction*>(action);
if (selaction->SelChange.Type == SelectionChanges::AddSelection ||
selaction->SelChange.Type == SelectionChanges::RmvSelection) {
if (documentName.getValue() == selaction->SelChange.pDocName &&
objectName.getValue() == selaction->SelChange.pObjectName &&
(subElementName.getValue() == selaction->SelChange.pSubName ||
*(selaction->SelChange.pSubName) == '\0') ) {
if (selaction->SelChange.Type == SelectionChanges::AddSelection) {
if(selected.getValue() == NOTSELECTED){
selected = SELECTED;
}
}
else {
if(selected.getValue() == SELECTED){
selected = NOTSELECTED;
}
}
return;
}
}
else if (selaction->SelChange.Type == SelectionChanges::ClrSelection) {
if (documentName.getValue() == selaction->SelChange.pDocName ||
strcmp(selaction->SelChange.pDocName,"") == 0){
if(selected.getValue() == SELECTED){
selected = NOTSELECTED;
}
}
}
else if (selaction->SelChange.Type == SelectionChanges::SetSelection) {
bool sel = Selection().isSelected(
documentName.getValue().getString(),
objectName.getValue().getString()/*,
subElementName.getValue().getString()*/);
if (sel) {
if (selected.getValue() == NOTSELECTED) {
selected = SELECTED;
}
}
else {
if(selected.getValue() == SELECTED){
if (selected.getValue() == SELECTED) {
selected = NOTSELECTED;
}
}
return;
}
}
else if (selaction->SelChange.Type == SelectionChanges::ClrSelection) {
if (documentName.getValue() == selaction->SelChange.pDocName ||
strcmp(selaction->SelChange.pDocName,"") == 0){
if(selected.getValue() == SELECTED){
selected = NOTSELECTED;
}
}
}
else if (selaction->SelChange.Type == SelectionChanges::SetSelection) {
bool sel = Selection().isSelected(
documentName.getValue().getString(),
objectName.getValue().getString()/*,
subElementName.getValue().getString()*/);
if (sel) {
if (selected.getValue() == NOTSELECTED) {
selected = SELECTED;
}
}
else {
if (selected.getValue() == SELECTED) {
selected = NOTSELECTED;
}
}
}
}
@@ -309,6 +364,11 @@ SoFCSelection::getPickedPoint(SoHandleEventAction* action) const
void
SoFCSelection::handleEvent(SoHandleEventAction * action)
{
if(useNewSelection.getValue()) {
inherited::handleEvent( action );
return;
}
static char buf[513];
HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
const SoEvent * event = action->getEvent();
@@ -337,12 +397,13 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
}
}
snprintf(buf,512,"Preselected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
const auto &pt = pp->getPoint();
snprintf(buf,512,"Preselected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,fabs(pt[0])>1e-7?pt[0]:0.0
,fabs(pt[1])>1e-7?pt[1]:0.0
,fabs(pt[2])>1e-7?pt[2]:0.0);
getMainWindow()->showMessage(QString::fromLatin1(buf));
}
@@ -380,6 +441,7 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
// Otherwise the tree signals that an object is preselected even though it is hidden. (Werner)
const SoPickedPoint * pp = this->getPickedPoint(action);
if (pp && pp->getPath()->containsPath(action->getCurPath())) {
const auto &pt = pp->getPoint();
if (bCtrl) {
if (Gui::Selection().isSelected(documentName.getValue().getString()
,objectName.getValue().getString()
@@ -391,17 +453,15 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,pt[0] ,pt[1] ,pt[2]);
if (mymode == OFF) {
snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,fabs(pt[0])>1e-7?pt[0]:0.0
,fabs(pt[1])>1e-7?pt[1]:0.0
,fabs(pt[2])>1e-7?pt[2]:0.0);
getMainWindow()->showMessage(QString::fromLatin1(buf));
}
@@ -415,27 +475,22 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,pt[0] ,pt[1] ,pt[2]);
}
else {
Gui::Selection().clearSelection(documentName.getValue().getString());
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,0
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,0 ,pt[0] ,pt[1] ,pt[2]);
}
if (mymode == OFF) {
snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,fabs(pt[0])>1e-7?pt[0]:0.0
,fabs(pt[1])>1e-7?pt[1]:0.0
,fabs(pt[2])>1e-7?pt[2]:0.0);
getMainWindow()->showMessage(QString::fromLatin1(buf));
}
@@ -544,6 +599,7 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
// Otherwise the tree signals that an object is preselected even though it is hidden. (Werner)
const SoPickedPoint * pp = this->getPickedPoint(action);
if (pp && pp->getPath()->containsPath(action->getCurPath())) {
const auto &pt = pp->getPoint();
if (bCtrl) {
if (Gui::Selection().isSelected(documentName.getValue().getString()
,objectName.getValue().getString()
@@ -556,17 +612,15 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,pt[0] ,pt[1] ,pt[2]);
if (mymode == OFF) {
snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,fabs(pt[0])>1e-7?pt[0]:0.0
,fabs(pt[1])>1e-7?pt[1]:0.0
,fabs(pt[2])>1e-7?pt[2]:0.0);
getMainWindow()->showMessage(QString::fromLatin1(buf));
}
@@ -580,27 +634,22 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,pt[0] ,pt[1] ,pt[2]);
}
else {
Gui::Selection().clearSelection(documentName.getValue().getString());
Gui::Selection().addSelection(documentName.getValue().getString()
,objectName.getValue().getString()
,0
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,0 ,pt[0] ,pt[1] ,pt[2]);
}
if (mymode == OFF) {
snprintf(buf,512,"Selected: %s.%s.%s (%f,%f,%f)",documentName.getValue().getString()
snprintf(buf,512,"Selected: %s.%s.%s (%g, %g, %g)",documentName.getValue().getString()
,objectName.getValue().getString()
,subElementName.getValue().getString()
,pp->getPoint()[0]
,pp->getPoint()[1]
,pp->getPoint()[2]);
,fabs(pt[0])>1e-7?pt[0]:0.0
,fabs(pt[1])>1e-7?pt[1]:0.0
,fabs(pt[2])>1e-7?pt[2]:0.0);
getMainWindow()->showMessage(QString::fromLatin1(buf));
}
@@ -621,15 +670,24 @@ SoFCSelection::handleEvent(SoHandleEventAction * action)
void
SoFCSelection::GLRenderBelowPath(SoGLRenderAction * action)
{
SoState * state = action->getState();
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
if(selContext2->checkGlobal(ctx))
ctx = selContext2;
if(!useNewSelection.getValue() && selContext == ctx) {
ctx->selectionColor = this->colorSelection.getValue();
ctx->highlightColor = this->colorHighlight.getValue();
if(this->selected.getValue()==SELECTED)
ctx->selectAll();
else
ctx->selectionIndex.clear();
ctx->highlightIndex = this->highlighted?0:-1;
}
#ifdef NO_FRONTBUFFER
// check if preselection is active
HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
bool preselected = highlighted && mymode == AUTO;
SoState * state = action->getState();
state->push();
if (preselected || this->highlightMode.getValue() == ON || this->selected.getValue() == SELECTED) {
this->setOverride(action);
}
this->setOverride(action,ctx);
inherited::GLRenderBelowPath(action);
state->pop();
#else
@@ -652,22 +710,65 @@ SoFCSelection::GLRenderBelowPath(SoGLRenderAction * action)
void SoFCSelection::GLRender(SoGLRenderAction * action)
{
SoState * state = action->getState();
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
if(selContext2->checkGlobal(ctx))
ctx = selContext2;
if(!useNewSelection.getValue() && selContext == ctx) {
ctx->selectionColor = this->colorSelection.getValue();
ctx->highlightColor = this->colorHighlight.getValue();
if(this->selected.getValue()==SELECTED)
ctx->selectAll();
else
ctx->selectionIndex.clear();
ctx->highlightIndex = this->highlighted?0:-1;
}
#ifdef NO_FRONTBUFFER
// check if preselection is active
state->push();
this->setOverride(action,ctx);
inherited::GLRender(action);
state->pop();
#else
// Set up state for locate highlighting (if necessary)
GLint oldDepthFunc;
SbBool drawHighlighted = preRender(action, oldDepthFunc);
// now invoke the parent method
inherited::GLRender(action);
// Restore old depth buffer model if needed
if (drawHighlighted || highlighted)
glDepthFunc((GLenum)oldDepthFunc);
// Clean up state if needed
if (drawHighlighted)
action->getState()->pop();
#endif
}
// doc from parent
void
SoFCSelection::GLRenderInPath(SoGLRenderAction * action)
{
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext);
if(selContext2->checkGlobal(ctx))
ctx = selContext2;
if(!useNewSelection.getValue() && selContext == ctx) {
ctx->selectionColor = this->colorSelection.getValue();
ctx->highlightColor = this->colorHighlight.getValue();
if(this->selected.getValue()==SELECTED)
ctx->selectAll();
else
ctx->selectionIndex.clear();
ctx->highlightIndex = this->highlighted?0:-1;
}
#ifdef NO_FRONTBUFFER
// check if preselection is active
HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
bool preselected = highlighted && mymode == AUTO;
SoState * state = action->getState();
state->push();
if (preselected || this->highlightMode.getValue() == ON || this->selected.getValue() == SELECTED) {
this->setOverride(action);
}
this->setOverride(action,ctx);
inherited::GLRenderInPath(action);
state->pop();
#else
@@ -848,24 +949,41 @@ SoFCSelection::readInstance ( SoInput * in, unsigned short flags )
// update override state before rendering
//
void
SoFCSelection::setOverride(SoGLRenderAction * action)
SoFCSelection::setOverride(SoGLRenderAction * action, SelContextPtr ctx)
{
HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
bool preselected = ctx && ctx->isHighlighted() && (useNewSelection.getValue()||mymode == AUTO);
if (!preselected && mymode!=ON && (!ctx || !ctx->isSelected()))
return;
// uniqueId is returned by SoNode::getNodeId(). It is used to notify change
// and for render cache update. In order to update cache on selection state
// change, We manually change the id here by using a combined hash of the
// original id and context pointer.
auto oldId = this->uniqueId;
this->uniqueId ^= std::hash<void*>()(ctx.get()) + 0x9e3779b9 + (oldId << 6) + (oldId >> 2);
//Base::Console().Log("SoFCSelection::setOverride() (%p)\n",this);
SoState * state = action->getState();
if(this->selected.getValue() == SELECTED)
SoLazyElement::setEmissive(state, &this->colorSelection.getValue());
else
SoLazyElement::setEmissive(state, &this->colorHighlight.getValue());
SoMaterialBindingElement::set(state,SoMaterialBindingElement::OVERALL);
if(!preselected)
SoLazyElement::setEmissive(state, &ctx->selectionColor);
else
SoLazyElement::setEmissive(state, &ctx->highlightColor);
SoOverrideElement::setEmissiveColorOverride(state, this, true);
Styles mystyle = (Styles) this->style.getValue();
if (mystyle == SoFCSelection::EMISSIVE_DIFFUSE) {
if(this->selected.getValue() == SELECTED)
SoLazyElement::setDiffuse(state, this,1, &this->colorSelection.getValue(),&colorpacker);
if(!preselected)
SoLazyElement::setDiffuse(state, this,1, &ctx->selectionColor,&colorpacker);
else
SoLazyElement::setDiffuse(state, this,1, &this->colorHighlight.getValue(),&colorpacker);
SoLazyElement::setDiffuse(state, this,1, &ctx->highlightColor,&colorpacker);
SoOverrideElement::setDiffuseColorOverride(state, this, true);
}
this->uniqueId = oldId;
}
// private convenience method

View File

@@ -41,6 +41,9 @@
#include <Inventor/fields/SoSFEnum.h>
#include <Inventor/fields/SoSFString.h>
#include <Inventor/nodes/SoLightModel.h>
#include <Inventor/fields/SoSFBool.h>
#include <memory>
#include "SoFCSelectionContext.h"
class SoFullPath;
class SoPickedPoint;
@@ -94,6 +97,7 @@ public:
SoSFString documentName;
SoSFString objectName;
SoSFString subElementName;
SoSFBool useNewSelection;
virtual void doAction(SoAction *action);
virtual void GLRender(SoGLRenderAction * action);
@@ -105,13 +109,20 @@ public:
protected:
virtual ~SoFCSelection();
typedef SoFCSelectionContext SelContext;
typedef std::shared_ptr<SelContext> SelContextPtr;
SelContextPtr selContext;
SelContextPtr selContext2;
virtual void redrawHighlighted(SoAction * act, SbBool flag);
virtual SbBool readInstance(SoInput * in, unsigned short flags);
private:
static int getPriority(const SoPickedPoint*);
static void turnoffcurrent(SoAction * action);
void setOverride(SoGLRenderAction * action);
void setOverride(SoGLRenderAction * action, SelContextPtr);
SbBool isHighlighted(SoAction *action);
SbBool preRender(SoGLRenderAction *act, GLint &oldDepthFunc);
const SoPickedPoint* getPickedPoint(SoHandleEventAction*) const;

View File

@@ -0,0 +1,283 @@
/****************************************************************************
* Copyright (c) 2018 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
****************************************************************************/
#include "PreCompiled.h"
#include <boost/algorithm/string/predicate.hpp>
#include <Inventor/misc/SoState.h>
#include <Inventor/elements/SoGLCacheContextElement.h>
#include <Inventor/elements/SoCacheElement.h>
#include "SoFCUnifiedSelection.h"
#include "Selection.h"
using namespace Gui;
/////////////////////////////////////////////////////////////////////////////
SoFCSelectionContext::~SoFCSelectionContext() {
if(counter)
*counter -= 1;
}
bool SoFCSelectionContext::checkGlobal(SoFCSelectionContextPtr ctx) {
bool sel = false;
bool hl = false;
SoFCSelectionRoot::checkSelection(sel,selectionColor,hl,highlightColor);
if(sel)
selectionIndex.insert(-1);
else if(ctx && hl) {
selectionColor = ctx->selectionColor;
selectionIndex = ctx->selectionIndex;
}else
selectionIndex.clear();
if(hl)
highlightAll();
else if(ctx && sel) {
highlightIndex = ctx->highlightIndex;
highlightColor = ctx->highlightColor;
}else
removeHighlight();
return sel||hl;
}
bool SoFCSelectionContext::removeIndex(int index) {
auto it = selectionIndex.find(index);
if(it != selectionIndex.end()) {
selectionIndex.erase(it);
return true;
}
return false;
}
int SoFCSelectionContext::merge(int status, SoFCSelectionContextBasePtr &output,
SoFCSelectionContextBasePtr input, SoFCSelectionRoot *)
{
auto ctx = std::dynamic_pointer_cast<SoFCSelectionContext>(input);
if(!ctx)
return status;
if(ctx->selectionIndex.empty()) {
output = ctx;
return -1;
}
auto ret = std::dynamic_pointer_cast<SoFCSelectionContext>(output);
if(!ret) {
output = ctx;
return 0;
}
if(ctx->isSelectAll())
return status;
if(ret->isSelectAll()) {
if(!status) {
output = ret->copy();
ret = std::dynamic_pointer_cast<SoFCSelectionContext>(ret);
assert(ret);
}
ret->selectionIndex = ctx->selectionIndex;
return status;
}
std::vector<int> remove;
for(auto idx : ret->selectionIndex) {
if(!ctx->selectionIndex.count(idx))
remove.push_back(idx);
}
for(auto idx : remove) {
if(!status) {
status = 1;
output = ret->copy();
ret = std::dynamic_pointer_cast<SoFCSelectionContext>(ret);
assert(ret);
}
ret->selectionIndex.erase(idx);
if(ret->selectionIndex.empty())
return -1;
}
return status;
}
/////////////////////////////////////////////////////////////////////////////////////
bool SoFCSelectionContextEx::setColors(
const std::map<std::string,App::Color> &colors, const std::string &element) {
std::map<int,App::Color> tmp;
auto it = colors.find("");
if(it!=colors.end())
tmp[-1] = it->second;
for(auto it=colors.lower_bound(element);it!=colors.end();++it) {
if(!boost::starts_with(it->first,element))
break;
if(it->first.size()==element.size())
tmp[-1] = it->second;
else {
int idx = std::atoi(it->first.c_str()+4);
if(idx>0) {
idx -= 1;
tmp[idx] = it->second;
}
}
}
if(tmp == this->colors)
return false;
this->colors.swap(tmp);
return true;
}
uint32_t SoFCSelectionContextEx::packColor(const App::Color &c, bool &hasTransparency) {
float trans = std::max(trans0,c.a);
if(trans>0)
hasTransparency = true;
return SbColor(c.r,c.g,c.b).getPackedValue(trans);
}
bool SoFCSelectionContextEx::applyColor(int idx, std::vector<uint32_t> &packedColors, bool &hasTransparency) {
if(colors.empty())
return false;
auto it = colors.find(idx);
if(it==colors.end()) {
if(colors.begin()->first >= 0)
return false;
it = colors.begin();
}
packedColors.push_back(packColor(it->second,hasTransparency));
return true;
}
bool SoFCSelectionContextEx::isSingleColor(uint32_t &color, bool &hasTransparency) {
if(colors.size() && colors.begin()->first<0) {
color = packColor(colors.begin()->second,hasTransparency);
return colors.size()==1;
}
return false;
}
int SoFCSelectionContextEx::merge(int status, SoFCSelectionContextBasePtr &output,
SoFCSelectionContextBasePtr input, SoFCSelectionRoot *node)
{
auto ctx = std::dynamic_pointer_cast<SoFCSelectionContextEx>(input);
if(!ctx) {
if(node && node->hasColorOverride()) {
if(!status)
status = 2;
else if(status == 1)
status = 3;
}
return status;
}
int status_copy = status;
if(status==2)
status_copy = 0;
else if(status==3)
status_copy = 1;
status_copy = SoFCSelectionContext::merge(status_copy,output,input,node);
if(status_copy < 0)
return status_copy;
if(status>1) {
// When status>1 it means there is color override before us, all
// subsequent color override will be bypassed
if(status_copy==1)
status = 3;
else
status = 2;
return status;
}
status = status_copy;
auto ret = std::dynamic_pointer_cast<SoFCSelectionContextEx>(output);
assert(ret);
for(auto &v : ctx->colors) {
if(ret->colors.count(v.first))
continue;
if(!status) {
status = 1;
output = ret->copy();
ret = std::dynamic_pointer_cast<SoFCSelectionContextEx>(output);
assert(ret);
}
ret->colors.insert(v);
}
if(node && node->hasColorOverride()) {
if(!status)
status = 2;
else if(status == 1)
status = 3;
}
return status;
}
///////////////////////////////////////////////////////////////////////
SoFCSelectionCounter::SoFCSelectionCounter()
:counter(std::make_shared<int>(0))
,hasSelection(false)
,hasPreselection(false)
{}
SoFCSelectionCounter::~SoFCSelectionCounter()
{}
bool SoFCSelectionCounter::checkRenderCache(SoState *state) {
if(*counter ||
(hasSelection && Selection().hasSelection()) ||
(hasPreselection && Selection().hasPreselection()))
{
if(SoFCSelectionRoot::getCacheMode()!=SoSeparator::OFF)
SoCacheElement::invalidate(state);
return false;
}
if(!Selection().hasPreselection())
hasPreselection = false;
if(!Selection().hasSelection())
hasSelection = false;
return true;
}
void SoFCSelectionCounter::checkAction(SoHighlightElementAction *hlaction) {
if(hlaction->isHighlighted())
hasPreselection = true;
}
void SoFCSelectionCounter::checkAction(SoSelectionElementAction *selaction, SoFCSelectionContextPtr ctx) {
switch(selaction->getType()) {
case SoSelectionElementAction::None:
return;
case SoSelectionElementAction::All:
case SoSelectionElementAction::Append:
hasSelection = true;
break;
default:
break;
}
if(selaction->isSecondary()) {
if(ctx && !ctx->counter) {
*counter += 1;
ctx->counter = counter;
}
}
}

View File

@@ -0,0 +1,135 @@
/****************************************************************************
* Copyright (c) 2018 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
****************************************************************************/
#ifndef GUI_SOFCSELECTIONCONTEXT_H
#define GUI_SOFCSELECTIONCONTEXT_H
#include <map>
#include <vector>
#include <set>
#include <memory>
#include <climits>
#include <App/Material.h>
namespace Gui {
class SoFCSelectionRoot;
struct SoFCSelectionContextBase;
typedef std::shared_ptr<SoFCSelectionContextBase> SoFCSelectionContextBasePtr;
struct GuiExport SoFCSelectionContextBase {
virtual ~SoFCSelectionContextBase() {}
typedef int MergeFunc(int status, SoFCSelectionContextBasePtr &output,
SoFCSelectionContextBasePtr input, SoFCSelectionRoot *node);
};
struct SoFCSelectionContext;
typedef std::shared_ptr<SoFCSelectionContext> SoFCSelectionContextPtr;
struct GuiExport SoFCSelectionContext : SoFCSelectionContextBase
{
int highlightIndex = -1;
std::set<int> selectionIndex;
SbColor selectionColor;
SbColor highlightColor;
std::shared_ptr<int> counter;
virtual ~SoFCSelectionContext();
bool isSelected() const {
return !selectionIndex.empty();
}
void selectAll() {
selectionIndex.clear();
selectionIndex.insert(-1);
}
bool isSelectAll() const{
return selectionIndex.size() && *selectionIndex.begin()<0;
}
bool isHighlighted() const {
return highlightIndex>=0;
}
bool isHighlightAll() const{
return highlightIndex==INT_MAX && (selectionIndex.empty() || isSelectAll());
}
void highlightAll() {
highlightIndex = INT_MAX;
}
void removeHighlight() {
highlightIndex = -1;
}
bool removeIndex(int index);
bool checkGlobal(SoFCSelectionContextPtr ctx);
virtual SoFCSelectionContextBasePtr copy() {
return std::make_shared<SoFCSelectionContext>(*this);
}
static MergeFunc merge;
};
struct SoFCSelectionContextEx;
typedef std::shared_ptr<SoFCSelectionContextEx> SoFCSelectionContextExPtr;
struct GuiExport SoFCSelectionContextEx : SoFCSelectionContext
{
std::map<int,App::Color> colors;
float trans0 = 0.0;
bool setColors(const std::map<std::string,App::Color> &colors, const std::string &element);
uint32_t packColor(const App::Color &c, bool &hasTransparency);
bool applyColor(int idx, std::vector<uint32_t> &packedColors, bool &hasTransparency);
bool isSingleColor(uint32_t &color, bool &hasTransparency);
virtual SoFCSelectionContextBasePtr copy() {
return std::make_shared<SoFCSelectionContextEx>(*this);
}
static MergeFunc merge;
};
class SoHighlightElementAction;
class SoSelectionElementAction;
class GuiExport SoFCSelectionCounter {
public:
SoFCSelectionCounter();
virtual ~SoFCSelectionCounter();
bool checkRenderCache(SoState *state);
void checkAction(SoHighlightElementAction *hlaction);
void checkAction(SoSelectionElementAction *selaction, SoFCSelectionContextPtr ctx);
protected:
std::shared_ptr<int> counter;
bool hasSelection;
bool hasPreselection;
static int cachingMode;
};
}
#endif //GUI_SOFCSELECTIONCONTEXT_H

File diff suppressed because it is too large Load Diff

View File

@@ -32,7 +32,10 @@
#include <Inventor/nodes/SoLightModel.h>
#include <Inventor/lists/SoPathList.h>
#include "View3DInventorViewer.h"
#include "SoFCSelectionContext.h"
#include <list>
#include <unordered_set>
#include <unordered_map>
class SoFullPath;
class SoPickedPoint;
@@ -42,6 +45,7 @@ class SoDetail;
namespace Gui {
class Document;
class ViewProviderDocumentObject;
/** Unified Selection node
* This is the new selection node for the 3D Viewer which will
@@ -75,6 +79,7 @@ public:
SoSFEnum highlightMode;
SoSFEnum selectionMode;
SoSFBool selectionRole;
SoSFBool useNewSelection;
virtual void doAction(SoAction *action);
//virtual void GLRender(SoGLRenderAction * action);
@@ -86,6 +91,8 @@ public:
bool checkSelectionStyle(int type, ViewProvider *vp);
static bool hasHighlight();
friend class View3DInventorViewer;
protected:
@@ -114,19 +121,262 @@ private:
//SbBool isHighlighted(SoAction *action);
//SbBool preRender(SoGLRenderAction *act, GLint &oldDepthFunc);
static int getPriority(const SoPickedPoint* p);
const SoPickedPoint* getPickedPoint(SoHandleEventAction*) const;
struct PickedInfo {
const SoPickedPoint *pp;
ViewProviderDocumentObject *vpd;
std::string element;
PickedInfo():pp(0),vpd(0)
{}
};
bool setHighlight(const PickedInfo &);
bool setHighlight(SoFullPath *path, const SoDetail *det,
ViewProviderDocumentObject *vpd, const char *element, float x, float y, float z);
bool setSelection(const std::vector<PickedInfo> &, bool ctrlDown=false);
std::vector<PickedInfo> getPickedList(SoHandleEventAction* action, bool singlePick) const;
Gui::Document *pcDocument;
static SoFullPath * currenthighlight;
SoFullPath * detailPath;
SoPathList selectionList;
SbBool highlighted;
SbBool setPreSelection;
// -1 = not handled, 0 = not selected, 1 = selected
int32_t preSelection;
SoColorPacker colorpacker;
};
class GuiExport SoFCPathAnnotation : public SoSeparator {
typedef SoSeparator inherited;
SO_NODE_HEADER(Gui::SoFCPathAnnotation);
public:
static void initClass(void);
static void finish(void);
SoFCPathAnnotation();
void setPath(SoPath *);
SoPath *getPath() {return path;}
void setDetail(SoDetail *d);
SoDetail *getDetail() {return det;}
virtual void GLRenderBelowPath(SoGLRenderAction * action);
virtual void GLRender(SoGLRenderAction * action);
virtual void GLRenderInPath(SoGLRenderAction * action);
protected:
virtual ~SoFCPathAnnotation();
protected:
SoPath *path;
SoTempPath *tmpPath;
SoDetail *det;
};
class GuiExport SoFCSeparator : public SoSeparator {
typedef SoSeparator inherited;
SO_NODE_HEADER(Gui::SoFCSeparator);
public:
static void initClass(void);
static void finish(void);
SoFCSeparator(bool trackCacheMode=true);
virtual void GLRenderBelowPath(SoGLRenderAction * action);
static void setCacheMode(CacheEnabled mode) {
CacheMode = mode;
}
static CacheEnabled getCacheMode() {
return CacheMode;
}
private:
bool trackCacheMode;
static CacheEnabled CacheMode;
};
class GuiExport SoFCSelectionRoot : public SoFCSeparator {
typedef SoFCSeparator inherited;
SO_NODE_HEADER(Gui::SoFCSelectionRoot);
public:
static void initClass(void);
static void finish(void);
SoFCSelectionRoot(bool trackCacheMode=false);
virtual void GLRenderBelowPath(SoGLRenderAction * action);
virtual void GLRenderInPath(SoGLRenderAction * action);
virtual void doAction(SoAction *action);
virtual void pick(SoPickAction * action);
virtual void rayPick(SoRayPickAction * action);
virtual void handleEvent(SoHandleEventAction * action);
virtual void search(SoSearchAction * action);
virtual void getPrimitiveCount(SoGetPrimitiveCountAction * action);
virtual void getBoundingBox(SoGetBoundingBoxAction * action);
virtual void getMatrix(SoGetMatrixAction * action);
virtual void callback(SoCallbackAction *action);
template<class T>
static std::shared_ptr<T> getRenderContext(SoNode *node, std::shared_ptr<T> def = std::shared_ptr<T>()) {
return std::dynamic_pointer_cast<T>(getNodeContext(SelStack,node,def));
}
/** Returns selection context for rendering.
*
* @param node: the querying node
* @param def: default context if none is found
* @param ctx2: secondary context output
*
* @return Returned the primary context for selection, and the context is
* always stored in the first encounted SoFCSelectionRoot in the path. It
* is keyed using the entires sequence of SoFCSelectionRoot along the path
* to \c node, replacing the first SoFCSelectionRoot with the given node.
*
* @return Secondary context returned in \c ctx2 is for customized
* highlighting, and is not affected by mouse event. The highlight is
* applied manually using SoSelectionElementAction. It is stored in the
* last encountered SoFCSelectionRoot, and is keyed using the querying
* \c node and (if there are more than one SoFCSelectionRoot along the
* path) the first SoFCSelectionRoot. The reason is so that any link to a
* node (new links means additional SoFCSelectionRoot added in front) with
* customized subelement highlight will also show the highlight. Secondary
* context can be chained, which why the secondary context type must provide
* an function called merge() for getRenderContext() to merge the context.
* See SoFCSelectionContext::merge() for an implementation of merging multiple
* context.
*
* @note For simplicity reason, currently secondary context is only freed
* when the storage SoFCSSelectionRoot node is freed.
*/
template<class T>
static std::shared_ptr<T> getRenderContext(SoNode *node, std::shared_ptr<T> def, std::shared_ptr<T> &ctx2)
{
ctx2 = std::dynamic_pointer_cast<T>(getNodeContext2(SelStack,node,T::merge));
return std::dynamic_pointer_cast<T>(getNodeContext(SelStack,node,def));
}
/** Get the selection context for an action.
*
* @param action: the action. SoSelectionElementAction has any option to
* query for secondary context. \sa getRenderContext for detail about
* secondary context
* @param node: the querying node
* @param def: default context if none is found, only used if querying
* non-secondary context
* @param create: create a new context if none is found
*
* @return If no SoFCSelectionRoot is found in the current path of action,
* \c def is returned. Otherwise a selection context returned. A new one
* will be created if none is found.
*/
template<class T>
static std::shared_ptr<T> getActionContext(
SoAction *action, SoNode *node, std::shared_ptr<T> def=std::shared_ptr<T>(), bool create=true)
{
auto res = findActionContext(action,node,create,false);
if(!res.second) {
if(res.first)
return std::shared_ptr<T>();
// default context is only applicable for non-secondary context query
return def;
}
// make a new context if there is none
auto &ctx = *res.second;
if(ctx) {
auto ret = std::dynamic_pointer_cast<T>(ctx);
if(!ret)
ctx.reset();
}
if(!ctx && create)
ctx = std::make_shared<T>();
return std::static_pointer_cast<T>(ctx);
}
static bool removeActionContext(SoAction *action, SoNode *node) {
return findActionContext(action,node,false,true).second!=0;
}
static void checkSelection(bool &sel, SbColor &selColor, bool &hl, SbColor &hlColor);
static SoNode *getCurrentRoot(bool front, SoNode *def);
void resetContext();
static bool checkColorOverride(SoState *state);
bool hasColorOverride() const {
return overrideColor;
}
void setColorOverride(App::Color c) {
overrideColor = true;
colorOverride = SbColor(c.r,c.g,c.b);
transOverride = c.a;
}
void removeColorOverride() {
overrideColor = false;
}
protected:
virtual ~SoFCSelectionRoot();
void renderPrivate(SoGLRenderAction *, bool inPath);
class Stack : public std::vector<SoFCSelectionRoot*> {
public:
std::unordered_set<SoFCSelectionRoot*> nodeSet;
size_t offset = 0;
};
static SoFCSelectionContextBasePtr getNodeContext(
Stack &stack, SoNode *node, SoFCSelectionContextBasePtr def);
static SoFCSelectionContextBasePtr getNodeContext2(
Stack &stack, SoNode *node, SoFCSelectionContextBase::MergeFunc *merge);
static std::pair<bool,SoFCSelectionContextBasePtr*> findActionContext(
SoAction *action, SoNode *node, bool create, bool erase);
static Stack SelStack;
static std::unordered_map<SoAction*,Stack> ActionStacks;
struct StackComp {
bool operator()(const Stack &a, const Stack &b) const;
};
typedef std::map<Stack,SoFCSelectionContextBasePtr,StackComp> ContextMap;
ContextMap contextMap;
ContextMap contextMap2;//holding secondary context
struct SelContext: SoFCSelectionContextBase {
public:
SbColor selColor;
SbColor hlColor;
bool selAll = false;
bool hlAll = false;
bool hideAll = false;
static MergeFunc merge;
};
typedef std::shared_ptr<SelContext> SelContextPtr;
typedef std::vector<SbColor> ColorStack;
static ColorStack SelColorStack;
static ColorStack HlColorStack;
static SoFCSelectionRoot *ShapeColorNode;
bool overrideColor = false;
SbColor colorOverride;
float transOverride;
SoColorPacker shapeColorPacker;
bool doActionPrivate(Stack &stack, SoAction *);
};
/**
* @author Werner Mayer
*/
@@ -167,17 +417,36 @@ class GuiExport SoSelectionElementAction : public SoAction
SO_ACTION_HEADER(SoSelectionElementAction);
public:
enum Type {None, Append, Remove, All};
enum Type {None, Append, Remove, All, Color, Hide, Show};
SoSelectionElementAction (Type);
SoSelectionElementAction (Type=None, bool secondary = false);
~SoSelectionElementAction();
Type getType() const;
void setType(Type type) {
_type = type;
}
void setColor(const SbColor&);
const SbColor& getColor() const;
void setElement(const SoDetail*);
const SoDetail* getElement() const;
bool isSecondary() const {return _secondary;}
void setSecondary(bool enable) {
_secondary = enable;
}
const std::map<std::string,App::Color> &getColors() const {
return _colors;
}
void setColors(const std::map<std::string,App::Color> &colors) {
_colors = colors;
}
void swapColors(std::map<std::string,App::Color> &colors) {
_colors.swap(colors);
}
static void initClass();
protected:
@@ -190,6 +459,8 @@ private:
Type _type;
SbColor _color;
const SoDetail* _det;
std::map<std::string,App::Color> _colors;
bool _secondary;
};
/**

View File

@@ -171,6 +171,7 @@ View3DInventor::View3DInventor(Gui::Document* pcDocument, QWidget* parent,
OnChange(*hGrp,"ShowNaviCube");
OnChange(*hGrp,"CornerNaviCube");
OnChange(*hGrp,"UseVBO");
OnChange(*hGrp,"RenderCache");
OnChange(*hGrp,"Orthographic");
OnChange(*hGrp,"HeadlightColor");
OnChange(*hGrp,"HeadlightDirection");
@@ -376,6 +377,9 @@ void View3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::M
else if (strcmp(Reason,"UseVBO") == 0) {
_viewer->setEnabledVBO(rGrp.GetBool("UseVBO",false));
}
else if (strcmp(Reason,"RenderCache") == 0) {
_viewer->setRenderCache(rGrp.GetInt("RenderCache",0));
}
else if (strcmp(Reason,"Orthographic") == 0) {
// check whether a perspective or orthogrphic camera should be set
if (rGrp.GetBool("Orthographic", true))

View File

@@ -75,6 +75,8 @@
# include <Inventor/SoOffscreenRenderer.h>
# include <Inventor/SoPickedPoint.h>
# include <Inventor/VRMLnodes/SoVRMLGroup.h>
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoTransparencyType.h>
# include <QEventLoop>
# include <QKeyEvent>
# include <QWheelEvent>
@@ -85,6 +87,8 @@
# include <QMimeData>
#endif
#include <Inventor/SoEventManager.h>
#if !defined(FC_OS_MACOSX)
# include <GL/gl.h>
# include <GL/glu.h>
@@ -100,6 +104,7 @@
#include <Base/Sequencer.h>
#include <Base/Tools.h>
#include <Base/UnitsApi.h>
#include <App/GeoFeatureGroupExtension.h>
#include "View3DInventorViewer.h"
#include "ViewProviderDocumentObject.h"
@@ -142,6 +147,10 @@
#include "WinNativeGestureRecognizers.h"
#include "Document.h"
#include "ViewProviderLink.h"
FC_LOG_LEVEL_INIT("3DViewer",true,true);
//#define FC_LOGGING_CB
using namespace Gui;
@@ -344,7 +353,8 @@ public:
// *************************************************************************
View3DInventorViewer::View3DInventorViewer(QWidget* parent, const QtGLWidget* sharewidget)
: Quarter::SoQTQuarterAdaptor(parent, sharewidget), editViewProvider(0), navigation(0),
: Quarter::SoQTQuarterAdaptor(parent, sharewidget), SelectionObserver(false,0),
editViewProvider(0), navigation(0),
renderType(Native), framebuffer(0), axisCross(0), axisGroup(0), editing(false), redirected(false),
allowredir(false), overrideMode("As Is"), _viewerPy(0)
{
@@ -352,7 +362,8 @@ View3DInventorViewer::View3DInventorViewer(QWidget* parent, const QtGLWidget* sh
}
View3DInventorViewer::View3DInventorViewer(const QtGLFormat& format, QWidget* parent, const QtGLWidget* sharewidget)
: Quarter::SoQTQuarterAdaptor(format, parent, sharewidget), editViewProvider(0), navigation(0),
: Quarter::SoQTQuarterAdaptor(format, parent, sharewidget), SelectionObserver(false,0),
editViewProvider(0), navigation(0),
renderType(Native), framebuffer(0), axisCross(0), axisGroup(0), editing(false), redirected(false),
allowredir(false), overrideMode("As Is"), _viewerPy(0)
{
@@ -361,11 +372,18 @@ View3DInventorViewer::View3DInventorViewer(const QtGLFormat& format, QWidget* pa
void View3DInventorViewer::init()
{
static bool _cacheModeInited;
if(!_cacheModeInited) {
_cacheModeInited = true;
pcViewProviderRoot = 0;
setRenderCache(-1);
}
shading = true;
fpsEnabled = false;
vboEnabled = false;
Gui::Selection().Attach(this);
attachSelection();
// Coin should not clear the pixel-buffer, so the background image
// is not removed.
@@ -471,6 +489,32 @@ void View3DInventorViewer::init()
pcViewProviderRoot->addChild(cb);
#endif
pcGroupOnTop = new SoSeparator;
pcGroupOnTop->ref();
pcViewProviderRoot->addChild(pcGroupOnTop);
auto pcGroupOnTopPickStyle = new SoPickStyle;
pcGroupOnTopPickStyle->style = SoPickStyle::UNPICKABLE;
// pcGroupOnTopPickStyle->style = SoPickStyle::SHAPE_ON_TOP;
pcGroupOnTopPickStyle->setOverride(true);
pcGroupOnTop->addChild(pcGroupOnTopPickStyle);
coin_setenv("COIN_SEPARATE_DIFFUSE_TRANSPARENCY_OVERRIDE", "1", TRUE);
auto pcOnTopMaterial = new SoMaterial;
pcOnTopMaterial->transparency = 0.5;
pcOnTopMaterial->diffuseColor.setIgnored(true);
pcOnTopMaterial->setOverride(true);
pcGroupOnTop->addChild(pcOnTopMaterial);
pcGroupOnTopSel = new SoFCSelectionRoot;
pcGroupOnTopSel->setName("GroupOnTopSel");
pcGroupOnTopSel->ref();
pcGroupOnTop->addChild(pcGroupOnTopSel);
pcGroupOnTopPreSel = new SoFCSelectionRoot;
pcGroupOnTopPreSel->setName("GroupOnTopPreSel");
pcGroupOnTopPreSel->ref();
pcGroupOnTop->addChild(pcGroupOnTopPreSel);
// Set our own render action which show a bounding box if
// the SoFCSelection::BOX style is set
//
@@ -573,13 +617,23 @@ View3DInventorViewer::~View3DInventorViewer()
this->backlight->unref();
this->backlight = 0;
this->pcGroupOnTop->unref();
this->pcGroupOnTopPreSel->unref();
this->pcGroupOnTopSel->unref();
this->pcEditingRoot->unref();
this->pcEditingTransform->unref();
if(this->pcClipPlane)
this->pcClipPlane->unref();
delete this->navigation;
// Note: When closing the application the main window doesn't exist any more.
if (getMainWindow())
getMainWindow()->setPaneText(2, QLatin1String(""));
Gui::Selection().Detach(this);
detachSelection();
removeEventFilter(viewerEventFilter);
delete viewerEventFilter;
@@ -615,6 +669,15 @@ void View3DInventorViewer::setDocument(Gui::Document* pcDocument)
// write the document the viewer belongs to the selection node
guiDocument = pcDocument;
selectionRoot->pcDocument = pcDocument;
if(pcDocument) {
const auto &sels = Selection().getSelection(pcDocument->getDocument()->getName(),0);
for(auto &sel : sels) {
SelectionChanges Chng(SelectionChanges::ShowSelection,
sel.DocName,sel.FeatName,sel.SubName);
onSelectionChanged(Chng);
}
}
}
Document* View3DInventorViewer::getDocument() {
@@ -631,21 +694,232 @@ void View3DInventorViewer::initialize()
this->axiscrossSize = 10;
}
/// @cond DOXERR
void View3DInventorViewer::OnChange(Gui::SelectionSingleton::SubjectType& rCaller,
Gui::SelectionSingleton::MessageType Reason)
{
Q_UNUSED(rCaller);
if (Reason.Type == SelectionChanges::AddSelection ||
Reason.Type == SelectionChanges::RmvSelection ||
Reason.Type == SelectionChanges::SetSelection ||
Reason.Type == SelectionChanges::ClrSelection) {
SoFCSelectionAction cAct(Reason);
cAct.apply(pcViewProviderRoot);
void View3DInventorViewer::clearGroupOnTop() {
if(objectsOnTop.size() || objectsOnTopPreSel.size()) {
objectsOnTop.clear();
objectsOnTopPreSel.clear();
SoSelectionElementAction action(SoSelectionElementAction::None,true);
action.apply(pcGroupOnTopPreSel);
action.apply(pcGroupOnTopSel);
coinRemoveAllChildren(pcGroupOnTopSel);
coinRemoveAllChildren(pcGroupOnTopPreSel);
FC_LOG("clear annoation");
}
else if (Reason.Type == SelectionChanges::RmvPreselect ||
Reason.Type == SelectionChanges::SetPreselect) {
SoFCHighlightAction cAct(Reason);
}
void View3DInventorViewer::checkGroupOnTop(const SelectionChanges &Reason) {
if(Reason.Type == SelectionChanges::SetSelection || Reason.Type == SelectionChanges::ClrSelection) {
clearGroupOnTop();
if(Reason.Type == SelectionChanges::ClrSelection)
return;
}
if(Reason.Type == SelectionChanges::RmvPreselect ||
Reason.Type == SelectionChanges::RmvPreselectSignal)
{
SoSelectionElementAction action(SoSelectionElementAction::None,true);
action.apply(pcGroupOnTopPreSel);
coinRemoveAllChildren(pcGroupOnTopPreSel);
objectsOnTopPreSel.clear();
return;
}
if(!getDocument() || !Reason.pDocName || !Reason.pDocName[0] || !Reason.pObjectName)
return;
auto obj = getDocument()->getDocument()->getObject(Reason.pObjectName);
if(!obj || !obj->getNameInDocument())
return;
std::string key(obj->getNameInDocument());
key += '.';
auto subname = Reason.pSubName;
if(subname)
key += subname;
if(Reason.Type == SelectionChanges::RmvSelection) {
auto &objs = objectsOnTop;
auto pcGroup = pcGroupOnTopSel;
auto it = objs.find(key.c_str());
if(it == objs.end())
return;
int index = pcGroup->findChild(it->second);
if(index >= 0) {
auto node = static_cast<SoFCPathAnnotation*>(it->second);
SoSelectionElementAction action(node->getDetail()?
SoSelectionElementAction::Remove:SoSelectionElementAction::None,true);
auto path = node->getPath();
SoTempPath tmpPath(2+path?path->getLength():0);
tmpPath.ref();
tmpPath.append(pcGroup);
tmpPath.append(node);
tmpPath.append(node->getPath());
action.setElement(node->getDetail());
action.apply(&tmpPath);
tmpPath.unrefNoDelete();
pcGroup->removeChild(index);
FC_LOG("remove annoation " << Reason.Type << " " << key);
}else
FC_LOG("remove annoation object " << Reason.Type << " " << key);
objs.erase(it);
return;
}
auto &objs = Reason.Type==SelectionChanges::SetPreselect?objectsOnTopPreSel:objectsOnTop;
auto pcGroup = Reason.Type==SelectionChanges::SetPreselect?pcGroupOnTopPreSel:pcGroupOnTopSel;
if(objs.find(key.c_str())!=objs.end())
return;
auto vp = dynamic_cast<ViewProviderDocumentObject*>(
Application::Instance->getViewProvider(obj));
if(!vp || !vp->isSelectable() || !vp->isShow())
return;
auto svp = vp;
if(subname && *subname) {
auto sobj = obj->getSubObject(subname);
if(!sobj || !sobj->getNameInDocument())
return;
if(sobj!=obj) {
svp = dynamic_cast<ViewProviderDocumentObject*>(
Application::Instance->getViewProvider(sobj));
if(!svp || !svp->isSelectable())
return;
}
}
int onTop;
// onTop==2 means on top only if whole object is selected,
// onTop==3 means on top only if some sub-element is selected
// onTop==1 means either
onTop = Gui::Selection().needPickedList()
|| vp->OnTopWhenSelected.getValue()
|| svp->OnTopWhenSelected.getValue();
if(Reason.Type == SelectionChanges::SetPreselect) {
SoHighlightElementAction action;
action.setHighlighted(true);
action.setColor(selectionRoot->colorHighlight.getValue());
action.apply(pcGroupOnTopPreSel);
if(!onTop)
onTop = 2;
}else {
if(!onTop)
return;
SoSelectionElementAction action(SoSelectionElementAction::All);
action.setColor(selectionRoot->colorSelection.getValue());
action.apply(pcGroupOnTopSel);
}
if(onTop==2 || onTop==3) {
if(subname && *subname) {
size_t len = strlen(subname);
if(subname[len-1]=='.') {
// ending with '.' means whole object selection
if(onTop == 3)
return;
}else if(onTop==2)
return;
}else if(onTop==3)
return;
}
std::vector<ViewProvider*> groups;
auto grpVp = vp;
for(auto childVp=vp;;childVp=grpVp) {
auto grp = App::GeoFeatureGroupExtension::getGroupOfObject(childVp->getObject());
if(!grp || !grp->getNameInDocument()) break;
grpVp = dynamic_cast<ViewProviderDocumentObject*>(
Application::Instance->getViewProvider(grp));
if(!grpVp) break;
auto childRoot = grpVp->getChildRoot();
auto modeSwitch = grpVp->getModeSwitch();
auto idx = modeSwitch->whichChild.getValue();
if(idx<0 || idx>=modeSwitch->getNumChildren() ||
modeSwitch->getChild(idx)!=childRoot)
{
FC_LOG("skip " << obj->getFullName() << '.' << (subname?subname:"")
<< ", hidden inside geo group");
return;
}
if(childRoot->findChild(childVp->getRoot())<0) {
FC_WARN("cannot find '" << childVp->getObject()->getFullName()
<< "' in geo group '" << grp->getNameInDocument() << "'");
break;
}
groups.push_back(grpVp);
}
SoTempPath path(10);
path.ref();
for(auto it=groups.rbegin();it!=groups.rend();++it) {
auto grpVp = *it;
path.append(grpVp->getRoot());
path.append(grpVp->getModeSwitch());
path.append(grpVp->getChildRoot());
}
SoDetail *det = 0;
if(vp->getDetailPath(subname, &path,true,det) && path.getLength()) {
auto node = new SoFCPathAnnotation;
node->setPath(&path);
pcGroup->addChild(node);
if(det) {
SoSelectionElementAction action(SoSelectionElementAction::Append,true);
action.setElement(det);
SoTempPath tmpPath(path.getLength()+2);
tmpPath.ref();
tmpPath.append(pcGroup);
tmpPath.append(node);
tmpPath.append(&path);
action.apply(&tmpPath);
tmpPath.unrefNoDelete();
node->setDetail(det);
det = 0;
}
FC_LOG("add annoation " << Reason.Type << " " << key);
objs[key.c_str()] = node;
}
delete det;
path.unrefNoDelete();
}
/// @cond DOXERR
void View3DInventorViewer::onSelectionChanged(const SelectionChanges &_Reason)
{
if(!getDocument())
return;
SelectionChanges Reason(_Reason);
if(Reason.pDocName && *Reason.pDocName &&
strcmp(getDocument()->getDocument()->getName(),Reason.pDocName)!=0)
return;
switch(Reason.Type) {
case SelectionChanges::ShowSelection:
case SelectionChanges::HideSelection:
if(Reason.Type == SelectionChanges::ShowSelection)
Reason.Type = SelectionChanges::AddSelection;
else
Reason.Type = SelectionChanges::RmvSelection;
// fall through
case SelectionChanges::SetPreselect:
if(Reason.SubType!=2) // 2 means it is triggered from tree view
break;
case SelectionChanges::RmvPreselect:
case SelectionChanges::RmvPreselectSignal:
case SelectionChanges::SetSelection:
case SelectionChanges::AddSelection:
case SelectionChanges::RmvSelection:
case SelectionChanges::ClrSelection:
checkGroupOnTop(Reason);
break;
case SelectionChanges::SetPreselectSignal:
break;
default:
return;
}
if(Reason.Type == SelectionChanges::RmvPreselect ||
Reason.Type == SelectionChanges::RmvPreselectSignal)
{
SoFCHighlightAction cAct(SelectionChanges::RmvPreselect);
cAct.apply(pcViewProviderRoot);
} else {
SoFCSelectionAction cAct(Reason);
cAct.apply(pcViewProviderRoot);
}
}
@@ -672,7 +946,8 @@ void View3DInventorViewer::addViewProvider(ViewProvider* pcProvider)
SoSeparator* root = pcProvider->getRoot();
if (root) {
pcViewProviderRoot->addChild(root);
if(pcProvider->canAddToSceneGraph())
pcViewProviderRoot->addChild(root);
_ViewProviderMap[root] = pcProvider;
}
@@ -695,8 +970,10 @@ void View3DInventorViewer::removeViewProvider(ViewProvider* pcProvider)
SoSeparator* root = pcProvider->getRoot();
if (root && (pcViewProviderRoot->findChild(root) != -1)) {
pcViewProviderRoot->removeChild(root);
if (root) {
int index = pcViewProviderRoot->findChild(root);
if(index>=0)
pcViewProviderRoot->removeChild(index);
_ViewProviderMap.erase(root);
}
@@ -731,9 +1008,10 @@ SbBool View3DInventorViewer::setEditingViewProvider(Gui::ViewProvider* p, int Mo
void View3DInventorViewer::resetEditingViewProvider()
{
if (this->editViewProvider) {
// In case the event action still has grabbed a node when leaving edit mode
// force to release it now
SoEventManager* mgr = this->getSoEventManager();
SoEventManager* mgr = getSoEventManager();
SoHandleEventAction* heaction = mgr->getHandleEventAction();
if (heaction && heaction->getGrabber())
heaction->releaseGrabber();
@@ -870,6 +1148,26 @@ bool View3DInventorViewer::isEnabledVBO() const
return vboEnabled;
}
void View3DInventorViewer::setRenderCache(int mode)
{
if(mode<0) {
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/View");
int setting = hGrp->GetInt("RenderCache",0);
if(mode==-2) {
if(pcViewProviderRoot && setting!=1)
pcViewProviderRoot->renderCaching = SoSeparator::ON;
mode = 2;
}else{
if(pcViewProviderRoot)
pcViewProviderRoot->renderCaching = SoSeparator::AUTO;
mode = setting;
}
}
SoFCSeparator::setCacheMode(
mode==0?SoSeparator::AUTO:(mode==1?SoSeparator::ON:SoSeparator::OFF));
}
void View3DInventorViewer::setEnabledNaviCube(bool on)
{
naviCubeEnabled = on;
@@ -2433,54 +2731,51 @@ void View3DInventorViewer::viewAll(float factor)
void View3DInventorViewer::viewSelection()
{
#if 0
// Search for all SoFCSelection nodes
SoSearchAction searchAction;
searchAction.setType(SoFCSelection::getClassTypeId());
searchAction.setInterest(SoSearchAction::ALL);
searchAction.apply(pcViewProviderRoot);
SoPathList& paths = searchAction.getPaths();
int countPaths = paths.getLength();
SoGroup* root = new SoGroup();
root->ref();
for (int i=0; i<countPaths; i++) {
SoPath* path = paths[i];
SoNode* node = path->getTail();
if (!node || node->getTypeId() != SoFCSelection::getClassTypeId())
continue; // should not happen
SoFCSelection* select = static_cast<SoFCSelection*>(node);
// Check only document and object name but not sub-element name
if (Selection().isSelected(select->documentName.getValue().getString(),
select->objectName.getValue().getString())) {
root->addChild(select);
}
Base::BoundBox3d bbox;
for(auto &sel : Selection().getSelection(0,0)) {
auto vp = Application::Instance->getViewProvider(sel.pObject);
if(!vp)
continue;
bbox.Add(vp->getBoundingBox(sel.SubName,true));
}
#else
SoGroup* root = new SoGroup();
root->ref();
std::vector<App::DocumentObject*> selection = Selection().getObjectsOfType(App::DocumentObject::getClassTypeId());
for (std::vector<App::DocumentObject*>::iterator it = selection.begin(); it != selection.end(); ++it) {
ViewProvider* vp = Application::Instance->getViewProvider(*it);
if (vp) {
root->addChild(vp->getRoot());
}
}
#endif
SoCamera* cam = this->getSoRenderManager()->getCamera();
if (cam)
cam->viewAll(root, this->getSoRenderManager()->getViewportRegion());
root->unref();
if (cam && bbox.IsValid()) {
SbBox3f box(bbox.MinX,bbox.MinY,bbox.MinZ,bbox.MaxX,bbox.MaxY,bbox.MaxZ);
#if (COIN_MAJOR_VERSION >= 4)
float aspectratio = getSoRenderManager()->getViewportRegion().getViewportAspectRatio();
switch (cam->viewportMapping.getValue()) {
case SoCamera::CROP_VIEWPORT_FILL_FRAME:
case SoCamera::CROP_VIEWPORT_LINE_FRAME:
case SoCamera::CROP_VIEWPORT_NO_FRAME:
aspectratio = 1.0f;
break;
default:
break;
}
cam->viewBoundingBox(box,aspectratio,1.0);
#else
SoTempPath path(2);
path.ref();
auto pcGroup = new SoGroup;
pcGroup->ref();
auto pcTransform = new SoTransform;
pcGroup->addChild(pcTransform);
pcTransform->translation = box.getCenter();
auto *pcCube = new SoCube;
pcGroup->addChild(pcCube);
float sizeX,sizeY,sizeZ;
box.getSize(sizeX,sizeY,sizeZ);
pcCube->width = sizeX;
pcCube->height = sizeY;
pcCube->depth = sizeZ;
path.append(pcGroup);
path.append(pcCube);
cam->viewAll(&path,getSoRenderManager()->getViewportRegion());
path.unrefNoDelete();
pcGroup->unref();
#endif
}
}
/*!
@@ -2958,16 +3253,16 @@ void View3DInventorViewer::removeEventCallback(SoType eventtype, SoEventCallback
ViewProvider* View3DInventorViewer::getViewProviderByPath(SoPath* path) const
{
// FIXME Use the viewprovider map introduced for the selection
for (std::set<ViewProvider*>::const_iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); ++it) {
for (int i = 0; i<path->getLength(); i++) {
SoNode* node = path->getNode(i);
if ((*it)->getRoot() == node) {
return (*it);
for (int i = 0; i < path->getLength(); i++) {
SoNode* node = path->getNode(i);
if (node->isOfType(SoSeparator::getClassTypeId())) {
auto it = _ViewProviderMap.find(static_cast<SoSeparator*>(node));
if (it != _ViewProviderMap.end()) {
return it->second;
}
}
}
return 0;
}
@@ -3096,3 +3391,4 @@ void View3DInventorViewer::dragLeaveEvent(QDragLeaveEvent *e)
{
inherited::dragLeaveEvent(e);
}

View File

@@ -54,6 +54,7 @@ class SbBox2s;
class SoVectorizeAction;
class QImage;
class SoGroup;
class SoPickStyle;
class NaviCube;
namespace Quarter = SIM::Coin3D::Quarter;
@@ -65,7 +66,6 @@ class SoFCBackgroundGradient;
class NavigationStyle;
class SoFCUnifiedSelection;
class Document;
class SoFCUnifiedSelection;
class GLGraphicsItem;
class SoShapeScale;
class ViewerEventFilter;
@@ -73,7 +73,7 @@ class ViewerEventFilter;
/** GUI view into a 3D scene provided by View3DInventor
*
*/
class GuiExport View3DInventorViewer : public Quarter::SoQTQuarterAdaptor, public Gui::SelectionSingleton::ObserverType
class GuiExport View3DInventorViewer : public Quarter::SoQTQuarterAdaptor, public SelectionObserver
{
typedef Quarter::SoQTQuarterAdaptor inherited;
@@ -133,8 +133,9 @@ public:
void init();
/// Observer message from the Selection
virtual void OnChange(Gui::SelectionSingleton::SubjectType &rCaller,
Gui::SelectionSingleton::MessageType Reason);
virtual void onSelectionChanged(const SelectionChanges &Reason);
void checkGroupOnTop(const SelectionChanges &Reason);
void clearGroupOnTop();
SoDirectionalLight* getBacklight(void) const;
void setBacklight(SbBool on);
@@ -352,6 +353,7 @@ public:
NaviCube* getNavigationCube() const;
void setEnabledVBO(bool b);
bool isEnabledVBO() const;
void setRenderCache(int);
NavigationStyle* navigationStyle() const;
@@ -415,6 +417,13 @@ private:
SoDirectionalLight* backlight;
SoSeparator * pcViewProviderRoot;
SoGroup * pcGroupOnTop;
SoGroup * pcGroupOnTopSel;
SoGroup * pcGroupOnTopPreSel;
std::map<std::string,SoNode*> objectsOnTop;
std::map<std::string,SoNode*> objectsOnTopPreSel;
SoEventCallback* pEventCallback;
NavigationStyle* navigation;
SoFCUnifiedSelection* selectionRoot;

View File

@@ -57,6 +57,7 @@
#include "View3DInventorViewer.h"
#include "SoFCDB.h"
#include "ViewProviderExtension.h"
#include "SoFCUnifiedSelection.h"
#include "ViewParams.h"
#include <boost/bind.hpp>
@@ -84,7 +85,7 @@ ViewProvider::ViewProvider()
{
setStatus(UpdateData, true);
pcRoot = new SoSeparator();
pcRoot = new SoFCSeparator;
pcRoot->ref();
pcModeSwitch = new SoSwitch();
pcModeSwitch->ref();
@@ -94,6 +95,8 @@ ViewProvider::ViewProvider()
pcRoot->addChild(pcModeSwitch);
sPixmap = "px";
pcModeSwitch->whichChild = _iActualMode;
setRenderCacheMode(ViewParams::instance()->getRenderCache());
}
ViewProvider::~ViewProvider()
@@ -974,6 +977,11 @@ void ViewProvider::beforeDelete() {
ext->extensionBeforeDelete();
}
void ViewProvider::setRenderCacheMode(int mode) {
pcRoot->renderCaching =
mode==0?SoSeparator::AUTO:(mode==1?SoSeparator::ON:SoSeparator::OFF);
}
Base::BoundBox3d ViewProvider::getBoundingBox(const char *subname, bool transform, MDIView *view) const {
if(!pcRoot || !pcModeSwitch || pcRoot->findChild(pcModeSwitch)<0)
return Base::BoundBox3d();

View File

@@ -496,6 +496,8 @@ public:
int getDefaultMode() const;
//@}
virtual void setRenderCacheMode(int);
protected:
/** Helper method to check that the node is valid, i.e. it must not cause
* and infinite recursion.

View File

@@ -56,6 +56,7 @@
# include <Inventor/details/SoFaceDetail.h>
# include <Inventor/details/SoLineDetail.h>
# include <Inventor/misc/SoState.h>
# include <Inventor/elements/SoCacheElement.h>
#endif
#include "SoBrepEdgeSet.h"
@@ -64,36 +65,97 @@
using namespace PartGui;
SO_NODE_SOURCE(SoBrepEdgeSet);
struct SoBrepEdgeSet::SelContext: Gui::SoFCSelectionContext {
std::vector<int32_t> hl, sl;
};
void SoBrepEdgeSet::initClass()
{
SO_NODE_INIT_CLASS(SoBrepEdgeSet, SoIndexedLineSet, "IndexedLineSet");
}
SoBrepEdgeSet::SoBrepEdgeSet()
:selContext(std::make_shared<SelContext>())
,selContext2(std::make_shared<SelContext>())
{
SO_NODE_CONSTRUCTOR(SoBrepEdgeSet);
SO_NODE_ADD_FIELD(highlightIndex, (-1));
SO_NODE_ADD_FIELD(selectionIndex, (-1));
selectionIndex.setNum(0);
}
void SoBrepEdgeSet::GLRender(SoGLRenderAction *action)
{
if (this->selectionIndex.getNum() > 0)
renderSelection(action);
if (this->highlightIndex.getValue() >= 0)
renderHighlight(action);
inherited::GLRender(action);
auto state = action->getState();
selCounter.checkRenderCache(state);
SelContextPtr ctx2;
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext,ctx2);
if(ctx2 && ctx2->selectionIndex.empty())
return;
if(selContext2->checkGlobal(ctx)) {
if(selContext2->isSelectAll()) {
selContext2->sl.clear();
selContext2->sl.push_back(-1);
}else if(ctx)
selContext2->sl = ctx->sl;
if(selContext2->highlightIndex==INT_MAX) {
selContext2->hl.clear();
selContext2->hl.push_back(-1);
}else if(ctx)
selContext2->hl = ctx->hl;
ctx = selContext2;
}
if(ctx && ctx->highlightIndex==INT_MAX) {
if(ctx->selectionIndex.empty() || ctx->isSelectAll()) {
if(ctx2) {
ctx2->selectionColor = ctx->highlightColor;
renderSelection(action,ctx2);
} else
renderHighlight(action,ctx);
}else{
if(!action->isRenderingDelayedPaths())
renderSelection(action,ctx);
if(ctx2) {
ctx2->selectionColor = ctx->highlightColor;
renderSelection(action,ctx2);
} else
renderHighlight(action,ctx);
if(action->isRenderingDelayedPaths())
renderSelection(action,ctx);
}
return;
}
if(!action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
if(ctx && ctx->selectionIndex.size()) {
if(ctx->isSelectAll()) {
if(ctx2) {
ctx2->selectionColor = ctx->selectionColor;
renderSelection(action,ctx2);
}else if(ctx->isSelectAll())
renderSelection(action,ctx);
if(action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
return;
}
if(!action->isRenderingDelayedPaths())
renderSelection(action,ctx);
}
if(ctx2 && ctx2->selectionIndex.size())
renderSelection(action,ctx2,false);
else
inherited::GLRender(action);
// Workaround for #0000433
//#if !defined(FC_OS_WIN32)
if (this->highlightIndex.getValue() >= 0)
renderHighlight(action);
if (this->selectionIndex.getNum() > 0)
renderSelection(action);
if(!action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
if(ctx && ctx->selectionIndex.size())
renderSelection(action,ctx);
if(action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
//#endif
}
@@ -125,17 +187,18 @@ void SoBrepEdgeSet::renderShape(const SoGLCoordinateElement * const coords,
}
}
void SoBrepEdgeSet::renderHighlight(SoGLRenderAction *action)
void SoBrepEdgeSet::renderHighlight(SoGLRenderAction *action, SelContextPtr ctx)
{
if(!ctx || ctx->highlightIndex<0)
return;
SoState * state = action->getState();
state->push();
//SoLineWidthElement::set(state, this, 4.0f);
SoLazyElement::setEmissive(state, &this->highlightColor);
SoOverrideElement::setEmissiveColorOverride(state, this, true);
SoLazyElement::setDiffuse(state, this,1, &this->highlightColor,&this->colorpacker1);
SoOverrideElement::setDiffuseColorOverride(state, this, true);
SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
SoLazyElement::setEmissive(state, &ctx->highlightColor);
packedColor = ctx->highlightColor.getPackedValue(0.0);
SoLazyElement::setPacked(state, this,1, &packedColor,false);
const SoCoordinateElement * coords;
const SbVec3f * normals;
@@ -152,33 +215,35 @@ void SoBrepEdgeSet::renderHighlight(SoGLRenderAction *action)
SoMaterialBundle mb(action);
mb.sendFirst(); // make sure we have the correct material
int num = (int)this->hl.size();
int num = (int)ctx->hl.size();
if (num > 0) {
const int32_t* id = &(this->hl[0]);
if (!validIndexes(coords, this->hl)) {
SoDebugError::postWarning("SoBrepEdgeSet::renderHighlight", "highlightIndex out of range");
if (ctx->hl[0] < 0) {
renderShape(static_cast<const SoGLCoordinateElement*>(coords), cindices, numcindices);
}
else {
renderShape(static_cast<const SoGLCoordinateElement*>(coords), id, num);
const int32_t* id = &(ctx->hl[0]);
if (!validIndexes(coords, ctx->hl)) {
SoDebugError::postWarning("SoBrepEdgeSet::renderHighlight", "highlightIndex out of range");
}
else {
renderShape(static_cast<const SoGLCoordinateElement*>(coords), id, num);
}
}
}
state->pop();
}
void SoBrepEdgeSet::renderSelection(SoGLRenderAction *action)
void SoBrepEdgeSet::renderSelection(SoGLRenderAction *action, SelContextPtr ctx, bool push)
{
int numSelected = this->selectionIndex.getNum();
if (numSelected == 0) return;
SoState * state = action->getState();
state->push();
//SoLineWidthElement::set(state, this, 4.0f);
if(push){
state->push();
//SoLineWidthElement::set(state, this, 4.0f);
SoLazyElement::setEmissive(state, &this->selectionColor);
SoOverrideElement::setEmissiveColorOverride(state, this, true);
SoLazyElement::setDiffuse(state, this,1, &this->selectionColor,&this->colorpacker2);
SoOverrideElement::setDiffuseColorOverride(state, this, true);
SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
SoLazyElement::setEmissive(state, &ctx->selectionColor);
packedColor = ctx->selectionColor.getPackedValue(0.0);
SoLazyElement::setPacked(state, this,1, &packedColor,false);
}
const SoCoordinateElement * coords;
const SbVec3f * normals;
@@ -195,15 +260,15 @@ void SoBrepEdgeSet::renderSelection(SoGLRenderAction *action)
SoMaterialBundle mb(action);
mb.sendFirst(); // make sure we have the correct material
int num = (int)this->sl.size();
int num = (int)ctx->sl.size();
if (num > 0) {
if (this->sl[0] < 0) {
if (ctx->sl[0] < 0) {
renderShape(static_cast<const SoGLCoordinateElement*>(coords), cindices, numcindices);
}
else {
cindices = &(this->sl[0]);
numcindices = (int)this->sl.size();
if (!validIndexes(coords, this->sl)) {
cindices = &(ctx->sl[0]);
numcindices = (int)ctx->sl.size();
if (!validIndexes(coords, ctx->sl)) {
SoDebugError::postWarning("SoBrepEdgeSet::renderSelection", "selectionIndex out of range");
}
else {
@@ -211,7 +276,7 @@ void SoBrepEdgeSet::renderSelection(SoGLRenderAction *action)
}
}
}
state->pop();
if(push) state->pop();
}
bool SoBrepEdgeSet::validIndexes(const SoCoordinateElement* coords, const std::vector<int32_t>& pts) const
@@ -224,128 +289,143 @@ bool SoBrepEdgeSet::validIndexes(const SoCoordinateElement* coords, const std::v
return true;
}
static void createIndexArray(const int32_t* segm, int numsegm,
const int32_t* cindices, int numcindices,
std::vector<int32_t>& out)
{
std::vector<int32_t> v;
for (int j=0; j<numsegm; j++) {
int index = segm[j];
int start=0, num=0;
int section=0;
for (int i=0;i<numcindices;i++) {
if (section < index)
start++;
else if (section == index)
num++;
else if (section > index)
break;
if (cindices[i] < 0)
section++;
}
v.insert(v.end(), cindices+start, cindices+start+num);
}
out.swap(v);
}
void SoBrepEdgeSet::doAction(SoAction* action)
{
if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) {
Gui::SoHighlightElementAction* hlaction = static_cast<Gui::SoHighlightElementAction*>(action);
selCounter.checkAction(hlaction);
if (!hlaction->isHighlighted()) {
this->highlightIndex = -1;
this->hl.clear();
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx) {
ctx->highlightIndex = -1;
ctx->hl.clear();
touch();
}
return;
}
const SoDetail* detail = hlaction->getElement();
if (detail) {
if (!detail->isOfType(SoLineDetail::getClassTypeId())) {
this->highlightIndex = -1;
this->hl.clear();
return;
}
this->highlightColor = hlaction->getColor();
int32_t index = static_cast<const SoLineDetail*>(detail)->getLineIndex();
const int32_t* cindices = this->coordIndex.getValues(0);
int numcindices = this->coordIndex.getNum();
createIndexArray(&index, 1, cindices, numcindices, this->hl);
this->highlightIndex.setValue(index);
if (!detail) {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
ctx->highlightColor = hlaction->getColor();
ctx->highlightIndex = INT_MAX;
ctx->hl.clear();
ctx->hl.push_back(-1);
touch();
return;
}
if (!detail->isOfType(SoLineDetail::getClassTypeId())) {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx) {
ctx->highlightIndex = -1;
ctx->hl.clear();
touch();
}
return;
}
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
ctx->highlightColor = hlaction->getColor();
int index = static_cast<const SoLineDetail*>(detail)->getLineIndex();
const int32_t* cindices = this->coordIndex.getValues(0);
int numcindices = this->coordIndex.getNum();
ctx->hl.clear();
for(int section=0,i=0;i<numcindices;i++) {
if(cindices[i] < 0) {
if(++section > index)
break;
}else if(section == index)
ctx->hl.push_back(cindices[i]);
}
if(ctx->hl.size())
ctx->highlightIndex = index;
else
ctx->highlightIndex = -1;
touch();
return;
}
else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) {
Gui::SoSelectionElementAction* selaction = static_cast<Gui::SoSelectionElementAction*>(action);
this->selectionColor = selaction->getColor();
if (selaction->getType() == Gui::SoSelectionElementAction::All) {
//const int32_t* cindices = this->coordIndex.getValues(0);
//int numcindices = this->coordIndex.getNum();
//unsigned int num = std::count_if(cindices, cindices+numcindices,
// std::bind2nd(std::equal_to<int32_t>(), -1));
//this->sl.clear();
//this->selectionIndex.setNum(num);
//int32_t* v = this->selectionIndex.startEditing();
//for (unsigned int i=0; i<num;i++)
// v[i] = i;
//this->selectionIndex.finishEditing();
//int numsegm = this->selectionIndex.getNum();
//if (numsegm > 0) {
// const int32_t* selsegm = this->selectionIndex.getValues(0);
// const int32_t* cindices = this->coordIndex.getValues(0);
// int numcindices = this->coordIndex.getNum();
// createIndexArray(selsegm, numsegm, cindices, numcindices, this->sl);
//}
this->selectionIndex.setValue(-1); // all
this->sl.clear();
this->sl.push_back(-1);
switch(selaction->getType()) {
case Gui::SoSelectionElementAction::None: {
if(selaction->isSecondary()) {
if(Gui::SoFCSelectionRoot::removeActionContext(action,this))
touch();
}else {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx) {
ctx->selectionIndex.clear();
ctx->sl.clear();
touch();
}
}
return;
}
else if (selaction->getType() == Gui::SoSelectionElementAction::None) {
this->selectionIndex.setNum(0);
this->sl.clear();
} case Gui::SoSelectionElementAction::All: {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
selCounter.checkAction(selaction,ctx);
ctx->selectionColor = selaction->getColor();
ctx->selectionIndex.clear();
ctx->selectionIndex.insert(-1); // all
ctx->sl.clear();
ctx->sl.push_back(-1);
touch();
return;
}
const SoDetail* detail = selaction->getElement();
if (detail) {
if (!detail->isOfType(SoLineDetail::getClassTypeId())) {
} case Gui::SoSelectionElementAction::Append:
case Gui::SoSelectionElementAction::Remove: {
const SoDetail* detail = selaction->getElement();
if (!detail || !detail->isOfType(SoLineDetail::getClassTypeId())) {
if(selaction->isSecondary()) {
// For secondary context, a detail of different type means
// the user may want to partial render only other type of
// geometry. So we call below to obtain a action context.
// If no secondary context exist, it will create an empty
// one, and an empty secondary context inhibites drawing
// here.
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
selCounter.checkAction(selaction,ctx);
touch();
}
return;
}
int index = static_cast<const SoLineDetail*>(detail)->getLineIndex();
switch (selaction->getType()) {
case Gui::SoSelectionElementAction::Append:
{
if (this->selectionIndex.find(index) < 0) {
int start = this->selectionIndex.getNum();
this->selectionIndex.set1Value(start, index);
}
}
break;
case Gui::SoSelectionElementAction::Remove:
{
int start = this->selectionIndex.find(index);
if (start >= 0)
this->selectionIndex.deleteValues(start,1);
}
break;
default:
break;
SelContextPtr ctx;
if(selaction->getType() == Gui::SoSelectionElementAction::Append) {
ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
selCounter.checkAction(selaction,ctx);
ctx->selectionColor = selaction->getColor();
if(ctx->isSelectAll())
ctx->selectionIndex.clear();
if(!ctx->selectionIndex.insert(index).second)
return;
}else{
ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(!ctx || !ctx->removeIndex(index))
return;
}
int numsegm = this->selectionIndex.getNum();
if (numsegm > 0) {
const int32_t* selsegm = this->selectionIndex.getValues(0);
ctx->sl.clear();
if(ctx->selectionIndex.size()) {
const int32_t* cindices = this->coordIndex.getValues(0);
int numcindices = this->coordIndex.getNum();
createIndexArray(selsegm, numsegm, cindices, numcindices, this->sl);
auto it = ctx->selectionIndex.begin();
for(int section=0,i=0;i<numcindices;i++) {
if(section == *it)
ctx->sl.push_back(cindices[i]);
if(cindices[i] < 0) {
if(++section > *it) {
if(++it == ctx->selectionIndex.end())
break;
}
}
}
}
touch();
break;
} default :
break;
}
return;
}
inherited::doAction(action);
@@ -362,3 +442,4 @@ SoDetail * SoBrepEdgeSet::createLineSegmentDetail(SoRayPickAction * action,
line_detail->setPartIndex(index);
return detail;
}

View File

@@ -32,6 +32,8 @@
#include <Inventor/elements/SoLazyElement.h>
#include <Inventor/elements/SoReplacedElement.h>
#include <vector>
#include <memory>
#include <Gui/SoFCSelectionContext.h>
class SoCoordinateElement;
class SoGLCoordinateElement;
@@ -48,9 +50,6 @@ public:
static void initClass();
SoBrepEdgeSet();
SoSFInt32 highlightIndex;
SoMFInt32 selectionIndex;
protected:
virtual ~SoBrepEdgeSet() {};
virtual void GLRender(SoGLRenderAction *action);
@@ -62,21 +61,20 @@ protected:
const SoPrimitiveVertex *v2,
SoPickedPoint *pp);
private:
struct SelContext;
typedef std::shared_ptr<SelContext> SelContextPtr;
void renderShape(const SoGLCoordinateElement * const vertexlist,
const int32_t *vertexindices,
int num_vertexindices);
void renderHighlight(SoGLRenderAction *action);
void renderSelection(SoGLRenderAction *action);
const int32_t *vertexindices, int num_vertexindices);
void renderHighlight(SoGLRenderAction *action, SelContextPtr);
void renderSelection(SoGLRenderAction *action, SelContextPtr, bool push=true);
bool validIndexes(const SoCoordinateElement*, const std::vector<int32_t>&) const;
private:
std::vector<int32_t> hl, sl;
SbColor selectionColor;
SbColor highlightColor;
//#0000834: Minor preselection color bug
//To solve this we need a separate color packer for highlighting and selection
SoColorPacker colorpacker1;
SoColorPacker colorpacker2;
SelContextPtr selContext;
SelContextPtr selContext2;
Gui::SoFCSelectionCounter selCounter;
uint32_t packedColor;
};
} // namespace PartGui

View File

@@ -55,6 +55,9 @@
# include <Inventor/details/SoLineDetail.h>
# include <Inventor/misc/SoState.h>
# include <Inventor/misc/SoContextHandler.h>
# include <Inventor/elements/SoShapeStyleElement.h>
# include <Inventor/elements/SoCacheElement.h>
# include <Inventor/elements/SoTextureEnabledElement.h>
# ifdef FC_OS_WIN32
# include <windows.h>
# include <GL/gl.h>
@@ -72,6 +75,7 @@
# include <Inventor/C/glue/gl.h>
#endif
#include <boost/algorithm/string/predicate.hpp>
#include "SoBrepFaceSet.h"
#include <Gui/SoFCUnifiedSelection.h>
#include <Gui/SoFCSelectionAction.h>
@@ -79,7 +83,6 @@
using namespace PartGui;
SO_NODE_SOURCE(SoBrepFaceSet);
#define PRIVATE(p) ((p)->pimpl)
@@ -173,9 +176,9 @@ SoBrepFaceSet::SoBrepFaceSet()
{
SO_NODE_CONSTRUCTOR(SoBrepFaceSet);
SO_NODE_ADD_FIELD(partIndex, (-1));
SO_NODE_ADD_FIELD(highlightIndex, (-1));
SO_NODE_ADD_FIELD(selectionIndex, (-1));
selectionIndex.setNum(0);
selContext = std::make_shared<SelContext>();
selContext2 = std::make_shared<SelContext>();
pimpl.reset(new VBO);
}
@@ -188,71 +191,124 @@ void SoBrepFaceSet::doAction(SoAction* action)
{
if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) {
Gui::SoHighlightElementAction* hlaction = static_cast<Gui::SoHighlightElementAction*>(action);
selCounter.checkAction(hlaction);
if (!hlaction->isHighlighted()) {
this->highlightIndex = -1;
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx) {
ctx->highlightIndex = -1;
touch();
}
return;
}
const SoDetail* detail = hlaction->getElement();
if (detail) {
if (detail->isOfType(SoFaceDetail::getClassTypeId())) {
if (!detail) {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
ctx->highlightIndex = INT_MAX;
ctx->highlightColor = hlaction->getColor();
touch();
}else {
if (!detail->isOfType(SoFaceDetail::getClassTypeId())) {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx) {
ctx->highlightIndex = -1;
touch();
}
}else {
int index = static_cast<const SoFaceDetail*>(detail)->getPartIndex();
this->highlightIndex.setValue(index);
this->highlightColor = hlaction->getColor();
}
else {
this->highlightIndex = -1;
return;
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
ctx->highlightIndex = index;
ctx->highlightColor = hlaction->getColor();
touch();
}
}
return;
}
else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) {
Gui::SoSelectionElementAction* selaction = static_cast<Gui::SoSelectionElementAction*>(action);
this->selectionColor = selaction->getColor();
if (selaction->getType() == Gui::SoSelectionElementAction::All) {
//int num = this->partIndex.getNum();
//this->selectionIndex.setNum(num);
//int32_t* v = this->selectionIndex.startEditing();
//for (int i=0; i<num;i++)
// v[i] = i;
//this->selectionIndex.finishEditing();
this->selectionIndex.setValue(-1); // all
PRIVATE(this)->updateVbo = true;
switch(selaction->getType()) {
case Gui::SoSelectionElementAction::All: {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext<SelContext>(action,this,selContext);
selCounter.checkAction(selaction,ctx);
ctx->selectionColor = selaction->getColor();
ctx->selectionIndex.clear();
ctx->selectionIndex.insert(-1);
touch();
return;
}
else if (selaction->getType() == Gui::SoSelectionElementAction::None) {
this->selectionIndex.setNum(0);
PRIVATE(this)->updateVbo = true;
} case Gui::SoSelectionElementAction::None:
if(selaction->isSecondary()) {
if(Gui::SoFCSelectionRoot::removeActionContext(action,this))
touch();
}else {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx) {
ctx->selectionIndex.clear();
ctx->colors.clear();
touch();
}
}
return;
}
const SoDetail* detail = selaction->getElement();
if (detail) {
if (!detail->isOfType(SoFaceDetail::getClassTypeId())) {
case Gui::SoSelectionElementAction::Color:
if(selaction->isSecondary()) {
const auto &colors = selaction->getColors();
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(colors.empty()) {
if(ctx) {
ctx->colors.clear();
if(ctx->isSelectAll())
Gui::SoFCSelectionRoot::removeActionContext(action,this);
touch();
}
return;
}
static std::string element("Face");
if(colors.begin()->first.empty() || colors.lower_bound(element)!=colors.end()) {
if(!ctx) {
ctx = Gui::SoFCSelectionRoot::getActionContext<SelContext>(action,this);
selCounter.checkAction(selaction,ctx);
ctx->selectAll();
}
if(ctx->setColors(selaction->getColors(),element))
touch();
}
}
return;
case Gui::SoSelectionElementAction::Remove:
case Gui::SoSelectionElementAction::Append: {
const SoDetail* detail = selaction->getElement();
if (!detail || !detail->isOfType(SoFaceDetail::getClassTypeId())) {
if(selaction->isSecondary()) {
// For secondary context, a detail of different type means
// the user may want to partial render only other type of
// geometry. So we call below to obtain a action context.
// If no secondary context exist, it will create an empty
// one, and an empty secondary context inhibites drawing
// here.
auto ctx = Gui::SoFCSelectionRoot::getActionContext<SelContext>(action,this);
selCounter.checkAction(selaction,ctx);
touch();
}
return;
}
int index = static_cast<const SoFaceDetail*>(detail)->getPartIndex();
switch (selaction->getType()) {
case Gui::SoSelectionElementAction::Append:
{
if (this->selectionIndex.find(index) < 0) {
int start = this->selectionIndex.getNum();
this->selectionIndex.set1Value(start, index);
}
}
break;
case Gui::SoSelectionElementAction::Remove:
{
int start = this->selectionIndex.find(index);
if (start >= 0)
this->selectionIndex.deleteValues(start,1);
}
break;
default:
break;
if (selaction->getType() == Gui::SoSelectionElementAction::Append) {
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
selCounter.checkAction(selaction,ctx);
ctx->selectionColor = selaction->getColor();
if(ctx->isSelectAll())
ctx->selectionIndex.clear();
if(ctx->selectionIndex.insert(index).second)
touch();
}else{
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx && ctx->removeIndex(index))
touch();
}
break;
} default:
break;
}
return;
}
else if (action->getTypeId() == Gui::SoVRMLAction::getClassTypeId()) {
// update the materialIndex field to match with the number of triangles if needed
@@ -298,6 +354,8 @@ void SoBrepFaceSet::doAction(SoAction* action)
void SoBrepFaceSet::GLRender(SoGLRenderAction *action)
{
SoState * state = action->getState();
// Disable caching for this node
SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
SoMaterialBundle mb(action);
Binding mbind = this->findMaterialBinding(state);
@@ -305,79 +363,92 @@ void SoBrepFaceSet::GLRender(SoGLRenderAction *action)
SoTextureCoordinateBundle tb(action, true, false);
SbBool doTextures = tb.needCoordinates();
int32_t hl_idx = this->highlightIndex.getValue();
int32_t num_selected = this->selectionIndex.getNum();
if (this->coordIndex.getNum() < 3)
if (ctx->coordIndex.getNum() < 3)
return;
if (num_selected > 0)
renderSelection(action);
if (hl_idx >= 0)
renderHighlight(action);
// When setting transparency shouldGLRender() handles the rendering and returns false.
// Therefore generatePrimitives() needs to be re-implemented to handle the materials
// correctly.
if (!this->shouldGLRender(action))
SelContextPtr ctx2;
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext,ctx2);
if(ctx2 && ctx2->selectionIndex.empty())
return;
int32_t hl_idx = ctx?ctx->highlightIndex:-1;
int32_t num_selected = ctx?ctx->selectionIndex.size():0;
renderHighlight(action,ctx);
if(ctx && ctx->selectionIndex.size()) {
if(ctx->isSelectAll()) {
if(ctx2 && ctx2->selectionIndex.size()) {
ctx2->selectionColor = ctx->selectionColor;
renderSelection(action,ctx2);
} else
renderSelection(action,ctx);
return;
}
renderSelection(action,ctx);
}
if(ctx2 && ctx2->selectionIndex.size()) {
renderSelection(action,ctx2,false);
}else{
// When setting transparency shouldGLRender() handles the rendering and returns false.
// Therefore generatePrimitives() needs to be re-implemented to handle the materials
// correctly.
if (!this->shouldGLRender(action))
return;
#ifdef RENDER_GLARRAYS
if (!doTextures && index_array.size() && hl_idx < 0 && num_selected <= 0) {
if (mbind == 0) {
mb.sendFirst(); // only one material -> apply it!
renderSimpleArray();
return;
if (!doTextures && index_array.size() && hl_idx < 0 && num_selected <= 0) {
if (mbind == 0) {
mb.sendFirst(); // only one material -> apply it!
renderSimpleArray();
return;
}
else if (mbind == 1) {
renderColoredArray(&mb);
return;
}
}
else if (mbind == 1) {
renderColoredArray(&mb);
return;
}
}
#endif
Binding nbind = this->findNormalBinding(state);
Binding nbind = this->findNormalBinding(state);
const SoCoordinateElement * coords;
const SbVec3f * normals;
const int32_t * cindices;
int numindices;
const int32_t * nindices;
const int32_t * tindices;
const int32_t * mindices;
const int32_t * pindices;
int numparts;
SbBool normalCacheUsed;
const SoCoordinateElement * coords;
const SbVec3f * normals;
const int32_t * cindices;
int numindices;
const int32_t * nindices;
const int32_t * tindices;
const int32_t * mindices;
const int32_t * pindices;
int numparts;
SbBool normalCacheUsed;
SbBool sendNormals = !mb.isColorOnly() || tb.isFunction();
SbBool sendNormals = !mb.isColorOnly() || tb.isFunction();
this->getVertexData(state, coords, normals, cindices,
nindices, tindices, mindices, numindices,
sendNormals, normalCacheUsed);
this->getVertexData(state, coords, normals, cindices,
nindices, tindices, mindices, numindices,
sendNormals, normalCacheUsed);
mb.sendFirst(); // make sure we have the correct material
mb.sendFirst(); // make sure we have the correct material
// just in case someone forgot
if (!mindices) mindices = cindices;
if (!nindices) nindices = cindices;
pindices = this->partIndex.getValues(0);
numparts = this->partIndex.getNum();
// just in case someone forgot
if (!mindices) mindices = cindices;
if (!nindices) nindices = cindices;
pindices = this->partIndex.getValues(0);
numparts = this->partIndex.getNum();
renderShape(state, vboAvailable, static_cast<const SoGLCoordinateElement*>(coords), cindices, numindices,
pindices, numparts, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0);
renderShape(state, vboAvailable, static_cast<const SoGLCoordinateElement*>(coords), cindices, numindices,
pindices, numparts, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0);
// Disable caching for this node
SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
if(normalCacheUsed)
this->readUnlockNormalCache();
}
// Workaround for #0000433
//#if !defined(FC_OS_WIN32)
if (hl_idx >= 0)
renderHighlight(action);
if (num_selected > 0)
renderSelection(action);
renderHighlight(action,ctx);
renderSelection(action,ctx);
//#endif
if(normalCacheUsed)
this->readUnlockNormalCache();
}
//****************************************************************************
@@ -441,6 +512,7 @@ void SoBrepFaceSet::renderColoredArray(SoMaterialBundle *const materials)
glDisableClientState(GL_NORMAL_ARRAY);
}
#else
void SoBrepFaceSet::GLRender(SoGLRenderAction *action)
{
//SoBase::staticDataLock();
@@ -454,85 +526,367 @@ void SoBrepFaceSet::GLRender(SoGLRenderAction *action)
if (this->coordIndex.getNum() < 3)
return;
if (this->selectionIndex.getNum() > 0)
renderSelection(action);
if (this->highlightIndex.getValue() >= 0)
renderHighlight(action);
SelContextPtr ctx2;
std::vector<SelContextPtr> ctxs;
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext(this,selContext,ctx2);
if(ctx2 && ctx2->selectionIndex.empty())
return;
if(selContext2->checkGlobal(ctx))
ctx = selContext2;
if(ctx && (!ctx->selectionIndex.size() && ctx->highlightIndex<0))
ctx.reset();
auto state = action->getState();
selCounter.checkRenderCache(state);
// override material binding to PER_PART_INDEX to achieve
// preselection/selection with transparency
bool pushed = overrideMaterialBinding(action,ctx,ctx2);
if(!pushed){
// for non transparent cases, we still use the old selection rendering
// code, because it can override emission color, which gives a more
// distinguishable selection highlight. The above material binding
// override method can't, because Coin does not support per part
// emission color
// There are a few factors affects the rendering order.
//
// 1) For normal case, the highlight (pre-selection) is the top layer. And since
// the depth buffer clipping is on here, we shall draw highlight first, then
// selection, then the rest part.
//
// 2) If action->isRenderingDelayedPaths() is true, it means we are rendering
// with depth buffer clipping turned off (always on top rendering), so we shall
// draw the top layer last, i.e. renderHighlight() last
//
// 3) If highlightIndex==INT_MAX, it means we are rendering full object highlight
// In order to not obscure selection layer, we shall draw highlight after selection
// if and only if it is not a full object selection.
//
// Transparency complicates stuff even more, but not here. It will be handled inside
// overrideMaterialBinding()
//
if(ctx && ctx->highlightIndex==INT_MAX) {
if(ctx->selectionIndex.empty() || ctx->isSelectAll()) {
if(ctx2) {
ctx2->selectionColor = ctx->highlightColor;
renderSelection(action,ctx2);
} else
renderHighlight(action,ctx);
}else{
if(!action->isRenderingDelayedPaths())
renderSelection(action,ctx);
if(ctx2) {
ctx2->selectionColor = ctx->highlightColor;
renderSelection(action,ctx2);
} else
renderHighlight(action,ctx);
if(action->isRenderingDelayedPaths())
renderSelection(action,ctx);
}
return;
}
if(!action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
if(ctx && ctx->selectionIndex.size()) {
if(ctx->isSelectAll()) {
if(ctx2) {
ctx2->selectionColor = ctx->selectionColor;
renderSelection(action,ctx2);
} else
renderSelection(action,ctx);
if(action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
return;
}
if(!action->isRenderingDelayedPaths())
renderSelection(action,ctx);
}
if(ctx2) {
renderSelection(action,ctx2,false);
if(action->isRenderingDelayedPaths()) {
renderSelection(action,ctx);
renderHighlight(action,ctx);
}
return;
}
}
SoMaterialBundle mb(action);
// It is important to send material before shouldGLRender(), otherwise
// material override with transparncy won't work.
mb.sendFirst();
// When setting transparency shouldGLRender() handles the rendering and returns false.
// Therefore generatePrimitives() needs to be re-implemented to handle the materials
// correctly.
if (!this->shouldGLRender(action))
return;
if(this->shouldGLRender(action)) {
Binding mbind = this->findMaterialBinding(state);
Binding nbind = this->findNormalBinding(state);
SbBool hasVBO = PRIVATE(this)->vboAvailable;
SoState * state = action->getState();
if (hasVBO) {
// get the VBO status of the viewer
Gui::SoGLVBOActivatedElement::get(state, hasVBO);
}
const SoCoordinateElement * coords;
const SbVec3f * normals;
const int32_t * cindices;
int numindices;
const int32_t * nindices;
const int32_t * tindices;
const int32_t * mindices;
const int32_t * pindices;
int numparts;
SbBool doTextures;
SbBool normalCacheUsed;
Binding mbind = this->findMaterialBinding(state);
Binding nbind = this->findNormalBinding(state);
SoTextureCoordinateBundle tb(action, true, false);
doTextures = tb.needCoordinates();
SbBool sendNormals = !mb.isColorOnly() || tb.isFunction();
const SoCoordinateElement * coords;
const SbVec3f * normals;
const int32_t * cindices;
int numindices;
const int32_t * nindices;
const int32_t * tindices;
const int32_t * mindices;
const int32_t * pindices;
int numparts;
SbBool doTextures;
SbBool normalCacheUsed;
this->getVertexData(state, coords, normals, cindices,
nindices, tindices, mindices, numindices,
sendNormals, normalCacheUsed);
SoMaterialBundle mb(action);
// just in case someone forgot
if (!mindices) mindices = cindices;
if (!nindices) nindices = cindices;
pindices = this->partIndex.getValues(0);
numparts = this->partIndex.getNum();
SoTextureCoordinateBundle tb(action, true, false);
doTextures = tb.needCoordinates();
SbBool sendNormals = !mb.isColorOnly() || tb.isFunction();
SbBool hasVBO = !ctx2 && PRIVATE(this)->vboAvailable;
if (hasVBO) {
// get the VBO status of the viewer
Gui::SoGLVBOActivatedElement::get(state, hasVBO);
//
//if (SoGLVBOElement::shouldCreateVBO(state, numindices)) {
// this->startVertexArray(action, coords, normals, false, false);
//}
}
renderShape(action, hasVBO, static_cast<const SoGLCoordinateElement*>(coords), cindices, numindices,
pindices, numparts, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0);
this->getVertexData(state, coords, normals, cindices,
nindices, tindices, mindices, numindices,
sendNormals, normalCacheUsed);
mb.sendFirst(); // make sure we have the correct material
// just in case someone forgot
if (!mindices) mindices = cindices;
if (!nindices) nindices = cindices;
pindices = this->partIndex.getValues(0);
numparts = this->partIndex.getNum();
if (hasVBO) {
// get the VBO status of the viewer
Gui::SoGLVBOActivatedElement::get(state, hasVBO);
//
//if (SoGLVBOElement::shouldCreateVBO(state, numindices)) {
// this->startVertexArray(action, coords, normals, false, false);
//}
}
renderShape(action, hasVBO, static_cast<const SoGLCoordinateElement*>(coords), cindices, numindices,
pindices, numparts, normals, nindices, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0);
if (!hasVBO) {
// Disable caching for this node
SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
// if (!hasVBO) {
// // Disable caching for this node
// SoGLCacheContextElement::shouldAutoCache(state, SoGLCacheContextElement::DONT_AUTO_CACHE);
// }else
// SoGLCacheContextElement::setAutoCacheBits(state, SoGLCacheContextElement::DO_AUTO_CACHE);
if (normalCacheUsed)
this->readUnlockNormalCache();
}
// Workaround for #0000433
//#if !defined(FC_OS_WIN32)
if (this->highlightIndex.getValue() >= 0)
renderHighlight(action);
if (this->selectionIndex.getNum() > 0)
renderSelection(action);
//#endif
if(pushed) {
SbBool notify = enableNotify(FALSE);
materialIndex.setNum(0);
if(notify) enableNotify(notify);
state->pop();
}else if(action->isRenderingDelayedPaths()) {
renderSelection(action,ctx);
renderHighlight(action,ctx);
}
}
#endif
bool SoBrepFaceSet::overrideMaterialBinding(SoGLRenderAction *action, SelContextPtr ctx, SelContextPtr ctx2) {
if(!ctx && !ctx2) return false;
auto state = action->getState();
auto mb = SoMaterialBindingElement::get(state);
auto element = SoLazyElement::getInstance(state);
const SbColor *diffuse = element->getDiffusePointer();
if(!diffuse) return false;
int diffuse_size = element->getNumDiffuse();
const float *trans = element->getTransparencyPointer();
int trans_size = element->getNumTransparencies();
if(!trans || !trans_size) return false;
float trans0=0.0;
bool hasTransparency = false;
for(int i=0;i<trans_size;++i) {
if(trans[i]!=0.0) {
hasTransparency = true;
trans0 = trans[i]>0.5?0.5:trans[i];
break;
}
}
// Override material binding to PER_PART_INDEXED so that we can reuse coin
// rendering for both selection, preselection and partial rendering. The
// main purpose is such that selection and preselection can have correct
// transparency, too.
//
// Criteria of using material binding override:
// 1) original material binding is either overall or per_part. We can
// support others, but ommitted here to simplify coding logic, and
// because it seems FC only uses these two.
// 2) either of the following :
// a) has highlight or selection and Selection().needPickPoint, so that
// any preselected/selected part automatically become transparent
// b) has transparency
// c) has color override in secondary context
if((mb==SoMaterialBindingElement::OVERALL ||
(mb==SoMaterialBindingElement::PER_PART && diffuse_size>=partIndex.getNum()))
&&
((ctx && Gui::Selection().needPickedList()) ||
trans0!=0.0 ||
(ctx2 && ctx2->colors.size())))
{
state->push();
packedColors.clear();
if(ctx && Gui::Selection().needPickedList()) {
hasTransparency = true;
if(trans0 < 0.5)
trans0=0.5;
trans_size = 1;
if(ctx2)
ctx2->trans0 = trans0;
}else if(ctx2)
ctx2->trans0 = 0.0;
uint32_t diffuseColor = diffuse[0].getPackedValue(trans0);
int singleColor = 0;
if(ctx && ctx->isHighlightAll()) {
singleColor = 1;
diffuseColor = ctx->highlightColor.getPackedValue(trans0);
}else if(ctx && ctx->isSelectAll()) {
diffuseColor = ctx->selectionColor.getPackedValue(trans0);
singleColor = ctx->isHighlighted()?-1:1;
} else if(ctx2 && ctx2->isSingleColor(diffuseColor,hasTransparency)) {
singleColor = ctx?-1:1;
}
bool partialRender = ctx2 && !ctx2->isSelectAll();
if(singleColor>0 && !partialRender) {
//optimization for single color non-partial rendering
SoMaterialBindingElement::set(state,SoMaterialBindingElement::OVERALL);
SoOverrideElement::setMaterialBindingOverride(state, this, true);
packedColors.push_back(diffuseColor);
SoLazyElement::setPacked(state, this,1, &packedColors[0], hasTransparency);
SoTextureEnabledElement::set(state,this,false);
if(hasTransparency && action->isRenderingDelayedPaths()) {
// rendering delayed paths means we are doing annotation (e.g.
// always on top rendering). To render transparency correctly in
// this case, we shall use openGL transparency blend. Override
// using SoLazyElement::setTransparencyType() doesn't seem to work
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(false);
}
return true;
}
matIndex.clear();
matIndex.reserve(partIndex.getNum());
if(ctx && (ctx->isSelectAll() || ctx->isHighlightAll())) {
matIndex.resize(partIndex.getNum(),0);
if(!partialRender)
packedColors.push_back(diffuseColor);
else {
// default to full transparent
packedColors.push_back(SbColor(1.0,1.0,1.0).getPackedValue(1.0));
packedColors.push_back(diffuseColor);
for(auto idx : ctx2->selectionIndex) {
if(idx>=0 && idx<partIndex.getNum())
matIndex[idx] = packedColors.size()-1; // show only the selected
}
}
if(ctx->highlightIndex>=0 && ctx->highlightIndex<partIndex.getNum()) {
packedColors.push_back(ctx->highlightColor.getPackedValue(trans0));
matIndex[ctx->highlightIndex] = packedColors.size()-1;
}
}else{
if(partialRender) {
packedColors.push_back(SbColor(1.0,1.0,1.0).getPackedValue(1.0));
matIndex.resize(partIndex.getNum(),0);
if(mb == SoMaterialBindingElement::OVERALL || singleColor) {
packedColors.push_back(diffuseColor);
auto cidx = packedColors.size()-1;
for(auto idx : ctx2->selectionIndex) {
if(idx>=0 && idx<partIndex.getNum()) {
if(!singleColor && ctx2->applyColor(idx,packedColors,hasTransparency))
matIndex[idx] = packedColors.size()-1;
else
matIndex[idx] = cidx;
}
}
}else{
assert(diffuse_size >= partIndex.getNum());
for(auto idx : ctx2->selectionIndex) {
if(idx>=0 && idx<partIndex.getNum()) {
if(!ctx2->applyColor(idx,packedColors,hasTransparency)) {
auto t = idx<trans_size?trans[idx]:trans0;
packedColors.push_back(diffuse[idx].getPackedValue(t));
}
matIndex[idx] = packedColors.size()-1;
}
}
}
}else if(mb==SoMaterialBindingElement::OVERALL || singleColor) {
packedColors.push_back(diffuseColor);
matIndex.resize(partIndex.getNum(),0);
if(ctx2 && !singleColor) {
for(auto &v : ctx2->colors) {
int idx = v.first;
if(idx>=0 && idx<partIndex.getNum()) {
packedColors.push_back(ctx2->packColor(v.second,hasTransparency));
matIndex[idx] = packedColors.size()-1;
}
}
}
}else{
assert(diffuse_size >= partIndex.getNum());
packedColors.reserve(diffuse_size+3);
for(int i=0;i<diffuse_size;++i) {
auto t = i<trans_size?trans[i]:trans0;
matIndex.push_back(i);
if(!ctx2 || !ctx2->applyColor(i,packedColors,hasTransparency))
packedColors.push_back(diffuse[i].getPackedValue(t));
}
}
if(ctx && ctx->selectionIndex.size()) {
packedColors.push_back(ctx->selectionColor.getPackedValue(trans0));
for(auto idx : ctx->selectionIndex) {
if(idx>=0 && idx<partIndex.getNum())
matIndex[idx] = packedColors.size()-1;
}
}
if(ctx && ctx->highlightIndex>=0 && ctx->highlightIndex<partIndex.getNum()) {
packedColors.push_back(ctx->highlightColor.getPackedValue(trans0));
matIndex[ctx->highlightIndex] = packedColors.size()-1;
}
}
SbBool notify = enableNotify(FALSE);
materialIndex.setValuesPointer(matIndex.size(),&matIndex[0]);
if(notify) enableNotify(notify);
SoMaterialBindingElement::set(state, this, SoMaterialBindingElement::PER_PART_INDEXED);
SoLazyElement::setPacked(state, this, packedColors.size(), &packedColors[0], hasTransparency);
SoTextureEnabledElement::set(state,this,false);
if(hasTransparency && action->isRenderingDelayedPaths()) {
// rendering delayed paths means we are doing annotation (e.g.
// always on top rendering). To render transparency correctly in
// this case, we shall use openGL transparency blend. Override
// using SoLazyElement::setTransparencyType() doesn't seem to work
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(false);
}
return true;
}
return false;
}
void SoBrepFaceSet::GLRenderBelowPath(SoGLRenderAction * action)
{
inherited::GLRenderBelowPath(action);
@@ -807,18 +1161,21 @@ void SoBrepFaceSet::generatePrimitives(SoAction * action)
#undef DO_VERTEX
void SoBrepFaceSet::renderHighlight(SoGLRenderAction *action)
void SoBrepFaceSet::renderHighlight(SoGLRenderAction *action, SelContextPtr ctx)
{
if(!ctx || ctx->highlightIndex < 0)
return;
SoState * state = action->getState();
state->push();
SoLazyElement::setEmissive(state, &this->highlightColor);
SoOverrideElement::setEmissiveColorOverride(state, this, true);
SoLazyElement::setEmissive(state, &ctx->highlightColor);
// if shading is disabled then set also the diffuse color
if (SoLazyElement::getLightModel(state) == SoLazyElement::BASE_COLOR) {
SoLazyElement::setDiffuse(state, this,1, &this->highlightColor,&this->colorpacker);
SoOverrideElement::setDiffuseColorOverride(state, this, true);
packedColor = ctx->highlightColor.getPackedValue(0.0);
SoLazyElement::setPacked(state, this,1, &packedColor,false);
}
SoTextureEnabledElement::set(state,this,false);
Binding mbind = this->findMaterialBinding(state);
Binding nbind = this->findNormalBinding(state);
@@ -845,8 +1202,8 @@ void SoBrepFaceSet::renderHighlight(SoGLRenderAction *action)
mb.sendFirst(); // make sure we have the correct material
int32_t id = this->highlightIndex.getValue();
if (id >= this->partIndex.getNum()) {
int id = ctx->highlightIndex;
if (id!=INT_MAX && id >= this->partIndex.getNum()) {
SoDebugError::postWarning("SoBrepFaceSet::renderHighlight", "highlightIndex out of range");
}
else {
@@ -856,11 +1213,17 @@ void SoBrepFaceSet::renderHighlight(SoGLRenderAction *action)
pindices = this->partIndex.getValues(0);
// coords
int length = (int)pindices[id]*4;
int start=0;
for (int i=0;i<id;i++)
start+=(int)pindices[i];
start *= 4;
int length;
if(id==INT_MAX) {
length = numindices;
id = 0;
} else {
length = (int)pindices[id]*4;
for (int i=0;i<id;i++)
start+=(int)pindices[i];
start *= 4;
}
// normals
if (nbind == PER_VERTEX_INDEXED)
@@ -883,21 +1246,23 @@ void SoBrepFaceSet::renderHighlight(SoGLRenderAction *action)
this->readUnlockNormalCache();
}
void SoBrepFaceSet::renderSelection(SoGLRenderAction *action)
void SoBrepFaceSet::renderSelection(SoGLRenderAction *action, SelContextPtr ctx, bool push)
{
int numSelected = this->selectionIndex.getNum();
const int32_t* selected = this->selectionIndex.getValues(0);
if (numSelected == 0) return;
if(!ctx || ctx->selectionIndex.empty())
return;
SoState * state = action->getState();
state->push();
SoLazyElement::setEmissive(state, &this->selectionColor);
SoOverrideElement::setEmissiveColorOverride(state, this, true);
// if shading is disabled then set also the diffuse color
if (SoLazyElement::getLightModel(state) == SoLazyElement::BASE_COLOR) {
SoLazyElement::setDiffuse(state, this,1, &this->selectionColor,&this->colorpacker);
SoOverrideElement::setDiffuseColorOverride(state, this, true);
if(push) {
state->push();
SoLazyElement::setEmissive(state, &ctx->selectionColor);
// if shading is disabled then set also the diffuse color
if (SoLazyElement::getLightModel(state) == SoLazyElement::BASE_COLOR) {
packedColor = ctx->selectionColor.getPackedValue(0.0);
SoLazyElement::setPacked(state, this,1, &packedColor,false);
}
SoTextureEnabledElement::set(state,this,false);
}
Binding mbind = this->findMaterialBinding(state);
@@ -930,16 +1295,19 @@ void SoBrepFaceSet::renderSelection(SoGLRenderAction *action)
if (!nindices) nindices = cindices;
pindices = this->partIndex.getValues(0);
// materials
mbind = OVERALL;
doTextures = false;
if(push) {
// materials
mbind = OVERALL;
doTextures = false;
}
for (int i=0; i<numSelected; i++) {
int id = selected[i];
for(auto id : ctx->selectionIndex) {
if (id >= this->partIndex.getNum()) {
SoDebugError::postWarning("SoBrepFaceSet::renderSelection", "selectionIndex out of range");
break;
}
if (id>=0 && id==ctx->highlightIndex)
continue;
// coords
int length=0;
@@ -948,8 +1316,8 @@ void SoBrepFaceSet::renderSelection(SoGLRenderAction *action)
// if < 0 then select everything
if (id < 0) {
length = numindices;
}
else {
id = 0;
} else {
length = (int)pindices[id]*4;
for (int j=0;j<id;j++)
start+=(int)pindices[j];
@@ -969,8 +1337,11 @@ void SoBrepFaceSet::renderSelection(SoGLRenderAction *action)
renderShape(action, false, static_cast<const SoGLCoordinateElement*>(coords), &(cindices[start]), length,
&(pindices[id]), numparts, normals_s, nindices_s, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0);
}
state->pop();
if(push) {
state->pop();
// SoCacheElement::invalidate(state);
}
if (normalCacheUsed)
this->readUnlockNormalCache();
}
@@ -1033,6 +1404,7 @@ void SoBrepFaceSet::VBO::render(SoGLRenderAction * action,
buf.vertex_array_size = 0;
buf.index_array_size = 0;
this->vbomap[contextId] = buf;
this->vboLoaded = false;
}
else {
buf = it->second;

View File

@@ -33,6 +33,7 @@
#include <Inventor/elements/SoReplacedElement.h>
#include <vector>
#include <memory>
#include <Gui/SoFCSelectionContext.h>
class SoGLCoordinateElement;
class SoTextureCoordinateBundle;
@@ -84,8 +85,6 @@ public:
SoBrepFaceSet();
SoMFInt32 partIndex;
SoSFInt32 highlightIndex;
SoMFInt32 selectionIndex;
protected:
virtual ~SoBrepFaceSet();
@@ -129,8 +128,14 @@ private:
const int nbind,
const int mbind,
const int texture);
void renderHighlight(SoGLRenderAction *action);
void renderSelection(SoGLRenderAction *action);
typedef Gui::SoFCSelectionContextEx SelContext;
typedef Gui::SoFCSelectionContextExPtr SelContextPtr;
void renderHighlight(SoGLRenderAction *action, SelContextPtr);
void renderSelection(SoGLRenderAction *action, SelContextPtr, bool push=true);
bool overrideMaterialBinding(SoGLRenderAction *action, SelContextPtr ctx, SelContextPtr ctx2);
#ifdef RENDER_GLARRAYS
void renderSimpleArray();
@@ -142,9 +147,12 @@ private:
std::vector<int32_t> index_array;
std::vector<float> vertex_array;
#endif
SbColor selectionColor;
SbColor highlightColor;
SoColorPacker colorpacker;
SelContextPtr selContext;
SelContextPtr selContext2;
std::vector<int32_t> matIndex;
std::vector<uint32_t> packedColors;
uint32_t packedColor;
Gui::SoFCSelectionCounter selCounter;
// Define some VBO pointer for the current mesh
class VBO;

View File

@@ -64,7 +64,6 @@
using namespace PartGui;
SO_NODE_SOURCE(SoBrepPointSet);
void SoBrepPointSet::initClass()
@@ -73,33 +72,80 @@ void SoBrepPointSet::initClass()
}
SoBrepPointSet::SoBrepPointSet()
:selContext(std::make_shared<SelContext>())
,selContext2(std::make_shared<SelContext>())
{
SO_NODE_CONSTRUCTOR(SoBrepPointSet);
SO_NODE_ADD_FIELD(highlightIndex, (-1));
SO_NODE_ADD_FIELD(selectionIndex, (-1));
selectionIndex.setNum(0);
}
void SoBrepPointSet::GLRender(SoGLRenderAction *action)
{
const SoCoordinateElement* coords = SoCoordinateElement::getInstance(action->getState());
auto state = action->getState();
selCounter.checkRenderCache(state);
const SoCoordinateElement* coords = SoCoordinateElement::getInstance(state);
int num = coords->getNum() - this->startIndex.getValue();
if (num < 0) {
// Fixes: #0000545: Undo revolve causes crash 'illegal storage'
return;
}
if (this->selectionIndex.getNum() > 0)
renderSelection(action);
if (this->highlightIndex.getValue() >= 0)
renderHighlight(action);
inherited::GLRender(action);
SelContextPtr ctx2;
SelContextPtr ctx = Gui::SoFCSelectionRoot::getRenderContext<SelContext>(this,selContext,ctx2);
if(ctx2 && ctx2->selectionIndex.empty())
return;
if(selContext2->checkGlobal(ctx))
ctx = selContext2;
if(ctx && ctx->highlightIndex==INT_MAX) {
if(ctx->selectionIndex.empty() || ctx->isSelectAll()) {
if(ctx2) {
ctx2->selectionColor = ctx->highlightColor;
renderSelection(action,ctx2);
} else
renderHighlight(action,ctx);
}else{
if(!action->isRenderingDelayedPaths())
renderSelection(action,ctx);
if(ctx2) {
ctx2->selectionColor = ctx->highlightColor;
renderSelection(action,ctx2);
} else
renderHighlight(action,ctx);
if(action->isRenderingDelayedPaths())
renderSelection(action,ctx);
}
return;
}
if(!action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
if(ctx && ctx->selectionIndex.size()) {
if(ctx->isSelectAll()) {
if(ctx2 && ctx2->selectionIndex.size()) {
ctx2->selectionColor = ctx->selectionColor;
renderSelection(action,ctx2);
}else
renderSelection(action,ctx);
if(action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
return;
}
if(!action->isRenderingDelayedPaths())
renderSelection(action,ctx);
}
if(ctx2 && ctx2->selectionIndex.size())
renderSelection(action,ctx2,false);
else
inherited::GLRender(action);
// Workaround for #0000433
//#if !defined(FC_OS_WIN32)
if (this->highlightIndex.getValue() >= 0)
renderHighlight(action);
if (this->selectionIndex.getNum() > 0)
renderSelection(action);
if(!action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
if(ctx && ctx->selectionIndex.size())
renderSelection(action,ctx);
if(action->isRenderingDelayedPaths())
renderHighlight(action,ctx);
//#endif
}
@@ -108,35 +154,19 @@ void SoBrepPointSet::GLRenderBelowPath(SoGLRenderAction * action)
inherited::GLRenderBelowPath(action);
}
void SoBrepPointSet::renderShape(const SoGLCoordinateElement * const coords,
const int32_t *cindices,
int numindices)
void SoBrepPointSet::renderHighlight(SoGLRenderAction *action, SelContextPtr ctx)
{
const SbVec3f * coords3d = coords->getArrayPtr3();
if(coords3d == nullptr)
if(!ctx || ctx->highlightIndex<0)
return;
int previ;
const int32_t *end = cindices + numindices;
glBegin(GL_POINTS);
while (cindices < end) {
previ = *cindices++;
glVertex3fv((const GLfloat*) (coords3d + previ));
}
glEnd();
}
void SoBrepPointSet::renderHighlight(SoGLRenderAction *action)
{
SoState * state = action->getState();
state->push();
float ps = SoPointSizeElement::get(state);
if (ps < 4.0f) SoPointSizeElement::set(state, this, 4.0f);
SoLazyElement::setEmissive(state, &this->highlightColor);
SoOverrideElement::setEmissiveColorOverride(state, this, true);
SoLazyElement::setDiffuse(state, this,1, &this->highlightColor,&this->colorpacker);
SoOverrideElement::setDiffuseColorOverride(state, this, true);
SoLazyElement::setEmissive(state, &ctx->highlightColor);
packedColor = ctx->highlightColor.getPackedValue(0.0);
SoLazyElement::setPacked(state, this,1, &packedColor,false);
const SoCoordinateElement * coords;
const SbVec3f * normals;
@@ -146,128 +176,165 @@ void SoBrepPointSet::renderHighlight(SoGLRenderAction *action)
SoMaterialBundle mb(action);
mb.sendFirst(); // make sure we have the correct material
int32_t id = this->highlightIndex.getValue();
if (id < this->startIndex.getValue() || id >= coords->getNum()) {
SoDebugError::postWarning("SoBrepPointSet::renderHighlight", "highlightIndex out of range");
}
else {
renderShape(static_cast<const SoGLCoordinateElement*>(coords), &id, 1);
}
state->pop();
}
void SoBrepPointSet::renderSelection(SoGLRenderAction *action)
{
SoState * state = action->getState();
state->push();
float ps = SoPointSizeElement::get(state);
if (ps < 4.0f) SoPointSizeElement::set(state, this, 4.0f);
SoLazyElement::setEmissive(state, &this->selectionColor);
SoOverrideElement::setEmissiveColorOverride(state, this, true);
SoLazyElement::setDiffuse(state, this,1, &this->selectionColor,&this->colorpacker);
SoOverrideElement::setDiffuseColorOverride(state, this, true);
const SoCoordinateElement * coords;
const SbVec3f * normals;
const int32_t * cindices;
int numcindices;
this->getVertexData(state, coords, normals, false);
SoMaterialBundle mb(action);
mb.sendFirst(); // make sure we have the correct material
cindices = this->selectionIndex.getValues(0);
numcindices = this->selectionIndex.getNum();
if (!validIndexes(coords, this->startIndex.getValue(), cindices, numcindices)) {
SoDebugError::postWarning("SoBrepPointSet::renderSelection", "selectionIndex out of range");
}
else {
renderShape(static_cast<const SoGLCoordinateElement*>(coords), cindices, numcindices);
}
state->pop();
}
bool SoBrepPointSet::validIndexes(const SoCoordinateElement* coords, int32_t startIndex, const int32_t * cindices, int numcindices) const
{
for (int i=0; i<numcindices; i++) {
int32_t id = cindices[i];
if (id < startIndex || id >= coords->getNum()) {
return false;
int id = ctx->highlightIndex;
const SbVec3f * coords3d = coords->getArrayPtr3();
if(coords3d) {
if(id == INT_MAX) {
glBegin(GL_POINTS);
for(int idx=startIndex.getValue();idx<coords->getNum();++idx)
glVertex3fv((const GLfloat*) (coords3d + idx));
glEnd();
}else if (id < this->startIndex.getValue() || id >= coords->getNum()) {
SoDebugError::postWarning("SoBrepPointSet::renderHighlight", "highlightIndex out of range");
}
else {
glBegin(GL_POINTS);
glVertex3fv((const GLfloat*) (coords3d + id));
glEnd();
}
}
return true;
state->pop();
}
void SoBrepPointSet::renderSelection(SoGLRenderAction *action, SelContextPtr ctx, bool push)
{
SoState * state = action->getState();
if(push) {
state->push();
float ps = SoPointSizeElement::get(state);
if (ps < 4.0f) SoPointSizeElement::set(state, this, 4.0f);
SoLazyElement::setEmissive(state, &ctx->selectionColor);
packedColor = ctx->selectionColor.getPackedValue(0.0);
SoLazyElement::setPacked(state, this,1, &packedColor,false);
}
const SoCoordinateElement * coords;
const SbVec3f * normals;
this->getVertexData(state, coords, normals, false);
SoMaterialBundle mb(action);
mb.sendFirst(); // make sure we have the correct material
bool warn = false;
int startIndex = this->startIndex.getValue();
const SbVec3f * coords3d = coords->getArrayPtr3();
if(coords3d) {
glBegin(GL_POINTS);
if(ctx->isSelectAll()) {
for(int idx=startIndex;idx<coords->getNum();++idx)
glVertex3fv((const GLfloat*) (coords3d + idx));
}else{
for(auto idx : ctx->selectionIndex) {
if(idx >= startIndex && idx < coords->getNum())
glVertex3fv((const GLfloat*) (coords3d + idx));
else
warn = true;
}
}
glEnd();
}
if(warn)
SoDebugError::postWarning("SoBrepPointSet::renderSelection", "selectionIndex out of range");
if(push) state->pop();
}
void SoBrepPointSet::doAction(SoAction* action)
{
if (action->getTypeId() == Gui::SoHighlightElementAction::getClassTypeId()) {
Gui::SoHighlightElementAction* hlaction = static_cast<Gui::SoHighlightElementAction*>(action);
selCounter.checkAction(hlaction);
if (!hlaction->isHighlighted()) {
this->highlightIndex = -1;
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx) {
ctx->highlightIndex = -1;
touch();
}
return;
}
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
const SoDetail* detail = hlaction->getElement();
if (detail) {
if (!detail->isOfType(SoPointDetail::getClassTypeId())) {
this->highlightIndex = -1;
return;
}
int index = static_cast<const SoPointDetail*>(detail)->getCoordinateIndex();
this->highlightIndex.setValue(index);
this->highlightColor = hlaction->getColor();
if (!detail) {
ctx->highlightIndex = INT_MAX;
ctx->highlightColor = hlaction->getColor();
touch();
return;
}else if (!detail->isOfType(SoPointDetail::getClassTypeId())) {
ctx->highlightIndex = -1;
touch();
return;
}
int index = static_cast<const SoPointDetail*>(detail)->getCoordinateIndex();
if(index!=ctx->highlightIndex) {
ctx->highlightIndex = index;
ctx->highlightColor = hlaction->getColor();
touch();
}
return;
}
else if (action->getTypeId() == Gui::SoSelectionElementAction::getClassTypeId()) {
Gui::SoSelectionElementAction* selaction = static_cast<Gui::SoSelectionElementAction*>(action);
this->selectionColor = selaction->getColor();
if (selaction->getType() == Gui::SoSelectionElementAction::All) {
const SoCoordinateElement* coords = SoCoordinateElement::getInstance(action->getState());
int num = coords->getNum() - this->startIndex.getValue();
this->selectionIndex.setNum(num);
int32_t* v = this->selectionIndex.startEditing();
int32_t s = this->startIndex.getValue();
for (int i=0; i<num;i++)
v[i] = i + s;
this->selectionIndex.finishEditing();
switch(selaction->getType()) {
case Gui::SoSelectionElementAction::All: {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
selCounter.checkAction(selaction,ctx);
ctx->selectionColor = selaction->getColor();
ctx->selectionIndex.clear();
ctx->selectionIndex.insert(-1);
touch();
return;
}
else if (selaction->getType() == Gui::SoSelectionElementAction::None) {
this->selectionIndex.setNum(0);
} case Gui::SoSelectionElementAction::None:
if(selaction->isSecondary()) {
if(Gui::SoFCSelectionRoot::removeActionContext(action,this))
touch();
} else {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx) {
ctx->selectionIndex.clear();
touch();
}
}
return;
}
const SoDetail* detail = selaction->getElement();
if (detail) {
if (!detail->isOfType(SoPointDetail::getClassTypeId())) {
case Gui::SoSelectionElementAction::Remove:
case Gui::SoSelectionElementAction::Append: {
const SoDetail* detail = selaction->getElement();
if (!detail || !detail->isOfType(SoPointDetail::getClassTypeId())) {
if(selaction->isSecondary()) {
// For secondary context, a detail of different type means
// the user may want to partial render only other type of
// geometry. So we call below to obtain a action context.
// If no secondary context exist, it will create an empty
// one, and an empty secondary context inhibites drawing
// here.
auto ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
selCounter.checkAction(selaction,ctx);
touch();
}
return;
}
int index = static_cast<const SoPointDetail*>(detail)->getCoordinateIndex();
switch (selaction->getType()) {
case Gui::SoSelectionElementAction::Append:
{
if (this->selectionIndex.find(index) < 0) {
int start = this->selectionIndex.getNum();
this->selectionIndex.set1Value(start, index);
}
}
break;
case Gui::SoSelectionElementAction::Remove:
{
int start = this->selectionIndex.find(index);
if (start >= 0)
this->selectionIndex.deleteValues(start,1);
}
break;
default:
break;
if(selaction->getType() == Gui::SoSelectionElementAction::Append) {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext);
selCounter.checkAction(selaction,ctx);
ctx->selectionColor = selaction->getColor();
if(ctx->isSelectAll())
ctx->selectionIndex.clear();
if(ctx->selectionIndex.insert(index).second)
touch();
} else {
SelContextPtr ctx = Gui::SoFCSelectionRoot::getActionContext(action,this,selContext,false);
if(ctx && ctx->removeIndex(index))
touch();
}
break;
} default:
break;
}
return;
}
inherited::doAction(action);
}

View File

@@ -32,6 +32,8 @@
#include <Inventor/elements/SoLazyElement.h>
#include <Inventor/elements/SoReplacedElement.h>
#include <vector>
#include <memory>
#include <Gui/SoFCSelectionContext.h>
class SoCoordinateElement;
class SoGLCoordinateElement;
@@ -48,9 +50,6 @@ public:
static void initClass();
SoBrepPointSet();
SoSFInt32 highlightIndex;
SoMFInt32 selectionIndex;
protected:
virtual ~SoBrepPointSet() {};
virtual void GLRender(SoGLRenderAction *action);
@@ -58,17 +57,16 @@ protected:
virtual void doAction(SoAction* action);
private:
void renderShape(const SoGLCoordinateElement * const vertexlist,
const int32_t *vertexindices,
int num_vertexindices);
void renderHighlight(SoGLRenderAction *action);
void renderSelection(SoGLRenderAction *action);
bool validIndexes(const SoCoordinateElement*, int32_t, const int32_t *, int) const;
typedef Gui::SoFCSelectionContext SelContext;
typedef Gui::SoFCSelectionContextPtr SelContextPtr;
void renderHighlight(SoGLRenderAction *action, SelContextPtr);
void renderSelection(SoGLRenderAction *action, SelContextPtr, bool push=true);
private:
SbColor selectionColor;
SbColor highlightColor;
SoColorPacker colorpacker;
SelContextPtr selContext;
SelContextPtr selContext2;
Gui::SoFCSelectionCounter selCounter;
uint32_t packedColor;
};
} // namespace PartGui