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:
@@ -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
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
283
src/Gui/SoFCSelectionContext.cpp
Normal file
283
src/Gui/SoFCSelectionContext.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
135
src/Gui/SoFCSelectionContext.h
Normal file
135
src/Gui/SoFCSelectionContext.h
Normal 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
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user