Gui: refactor bounding box selection style
Previously, box style selection is rendered using customized SoBoxSelectionRenderAction, which does not support selection context, i.e. it does not work with Link. This patch implements context aware bound box rendering inside SoFCSelectionRoot, SoFCSelection and SoFCPathAnnotation (for always on top rendering). The box rendering in SoBoxSelectionRenderAction is disabled on construction. Box style selection can be enabled for individual object through property SelectionStyle (moved from ViewProviderGeometryObject to ViewProviderDocumentObject), or globally through Parameter BaseApp/Preferences/View/ShowSelectionBoundingBox. In addition, the parameter BaseApp/Preferences/View/UseNewSelection is used to override selection model reported from ViewProvider::useNewSelectionModel(). The reason being that, the same parameter is already used to toggle selection model inside SoFCSelection. This avoids inconsistency of selection model choice between view provider and the SoFCSelection node inside. Note that if the parameter 'UseNewSelection' is set to false, those view providers that choose old selection model will not work with Link.
This commit is contained in:
@@ -27,6 +27,9 @@
|
||||
# include <qstring.h>
|
||||
# include <Inventor/details/SoFaceDetail.h>
|
||||
# include <Inventor/details/SoLineDetail.h>
|
||||
# include <Inventor/nodes/SoCube.h>
|
||||
# include <Inventor/actions/SoGetBoundingBoxAction.h>
|
||||
# include <Inventor/nodes/SoCube.h>
|
||||
#endif
|
||||
|
||||
#include <Inventor/elements/SoOverrideElement.h>
|
||||
@@ -686,10 +689,11 @@ SoFCSelection::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
|
||||
#ifdef NO_FRONTBUFFER
|
||||
// check if preselection is active
|
||||
state->push();
|
||||
this->setOverride(action,ctx);
|
||||
inherited::GLRenderBelowPath(action);
|
||||
state->pop();
|
||||
if(this->setOverride(action,ctx)) {
|
||||
inherited::GLRenderBelowPath(action);
|
||||
state->pop();
|
||||
} else
|
||||
inherited::GLRenderBelowPath(action);
|
||||
#else
|
||||
// Set up state for locate highlighting (if necessary)
|
||||
GLint oldDepthFunc;
|
||||
@@ -726,10 +730,11 @@ void SoFCSelection::GLRender(SoGLRenderAction * action)
|
||||
|
||||
#ifdef NO_FRONTBUFFER
|
||||
// check if preselection is active
|
||||
state->push();
|
||||
this->setOverride(action,ctx);
|
||||
inherited::GLRender(action);
|
||||
state->pop();
|
||||
if(this->setOverride(action,ctx)) {
|
||||
inherited::GLRender(action);
|
||||
state->pop();
|
||||
} else
|
||||
inherited::GLRender(action);
|
||||
#else
|
||||
// Set up state for locate highlighting (if necessary)
|
||||
GLint oldDepthFunc;
|
||||
@@ -767,10 +772,11 @@ SoFCSelection::GLRenderInPath(SoGLRenderAction * action)
|
||||
#ifdef NO_FRONTBUFFER
|
||||
// check if preselection is active
|
||||
SoState * state = action->getState();
|
||||
state->push();
|
||||
this->setOverride(action,ctx);
|
||||
inherited::GLRenderInPath(action);
|
||||
state->pop();
|
||||
if(this->setOverride(action,ctx)) {
|
||||
inherited::GLRenderInPath(action);
|
||||
state->pop();
|
||||
} else
|
||||
inherited::GLRenderInPath(action);
|
||||
#else
|
||||
// Set up state for locate highlighting (if necessary)
|
||||
GLint oldDepthFunc;
|
||||
@@ -948,13 +954,13 @@ SoFCSelection::readInstance ( SoInput * in, unsigned short flags )
|
||||
//
|
||||
// update override state before rendering
|
||||
//
|
||||
void
|
||||
bool
|
||||
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;
|
||||
return false;
|
||||
|
||||
// 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
|
||||
@@ -963,10 +969,21 @@ SoFCSelection::setOverride(SoGLRenderAction * action, SelContextPtr ctx)
|
||||
auto oldId = this->uniqueId;
|
||||
this->uniqueId ^= std::hash<void*>()(ctx.get()) + 0x9e3779b9 + (oldId << 6) + (oldId >> 2);
|
||||
|
||||
Styles mystyle = (Styles) this->style.getValue();
|
||||
|
||||
if(mystyle == SoFCSelection::BOX) {
|
||||
SoFCSelectionRoot::renderBBox(
|
||||
action,this,preselected?ctx->highlightColor:ctx->selectionColor);
|
||||
this->uniqueId = oldId;
|
||||
return false;
|
||||
}
|
||||
|
||||
//Base::Console().Log("SoFCSelection::setOverride() (%p)\n",this);
|
||||
SoState * state = action->getState();
|
||||
state->push();
|
||||
|
||||
SoMaterialBindingElement::set(state,SoMaterialBindingElement::OVERALL);
|
||||
SoOverrideElement::setMaterialBindingOverride(state,this,true);
|
||||
|
||||
if(!preselected)
|
||||
SoLazyElement::setEmissive(state, &ctx->selectionColor);
|
||||
@@ -974,8 +991,7 @@ SoFCSelection::setOverride(SoGLRenderAction * action, SelContextPtr ctx)
|
||||
SoLazyElement::setEmissive(state, &ctx->highlightColor);
|
||||
SoOverrideElement::setEmissiveColorOverride(state, this, true);
|
||||
|
||||
Styles mystyle = (Styles) this->style.getValue();
|
||||
if (mystyle == SoFCSelection::EMISSIVE_DIFFUSE) {
|
||||
if(mystyle == SoFCSelection::EMISSIVE_DIFFUSE) {
|
||||
if(!preselected)
|
||||
SoLazyElement::setDiffuse(state, this,1, &ctx->selectionColor,&colorpacker);
|
||||
else
|
||||
@@ -984,6 +1000,7 @@ SoFCSelection::setOverride(SoGLRenderAction * action, SelContextPtr ctx)
|
||||
}
|
||||
|
||||
this->uniqueId = oldId;
|
||||
return true;
|
||||
}
|
||||
|
||||
// private convenience method
|
||||
|
||||
@@ -122,7 +122,7 @@ protected:
|
||||
private:
|
||||
static int getPriority(const SoPickedPoint*);
|
||||
static void turnoffcurrent(SoAction * action);
|
||||
void setOverride(SoGLRenderAction * action, SelContextPtr);
|
||||
bool setOverride(SoGLRenderAction * action, SelContextPtr);
|
||||
SbBool isHighlighted(SoAction *action);
|
||||
SbBool preRender(SoGLRenderAction *act, GLint &oldDepthFunc);
|
||||
const SoPickedPoint* getPickedPoint(SoHandleEventAction*) const;
|
||||
|
||||
@@ -1142,7 +1142,8 @@ SoBoxSelectionRenderAction::constructorCommon(void)
|
||||
// Initialize local variables
|
||||
PRIVATE(this)->initBoxGraph();
|
||||
|
||||
this->hlVisible = true;
|
||||
// this->hlVisible = true;
|
||||
this->hlVisible = false;
|
||||
|
||||
PRIVATE(this)->basecolor->rgb.setValue(1.0f, 0.0f, 0.0f);
|
||||
PRIVATE(this)->drawstyle->linePattern = 0xffff;
|
||||
@@ -1236,20 +1237,6 @@ SoBoxSelectionRenderAction::apply(SoNode * node)
|
||||
}
|
||||
}
|
||||
PRIVATE(this)->searchaction->reset();
|
||||
|
||||
// Search for selections of SoFCUnifiedSelection
|
||||
PRIVATE(this)->searchaction->setType(SoFCUnifiedSelection::getClassTypeId());
|
||||
PRIVATE(this)->searchaction->setInterest(SoSearchAction::FIRST);
|
||||
PRIVATE(this)->searchaction->apply(node);
|
||||
SoFullPath * path = static_cast<SoFullPath *>(PRIVATE(this)->searchaction->getPath());
|
||||
if (path) {
|
||||
SoFCUnifiedSelection * selection = static_cast<SoFCUnifiedSelection *>(path->getTail());
|
||||
if (selection->getNumSelected()) {
|
||||
PRIVATE(this)->basecolor->rgb.setValue(selection->colorSelection.getValue());
|
||||
this->drawBoxes(path, selection->getList());
|
||||
}
|
||||
}
|
||||
PRIVATE(this)->searchaction->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
#include <Inventor/nodes/SoNormalBinding.h>
|
||||
#include <Inventor/events/SoLocation2Event.h>
|
||||
#include <Inventor/SoPickedPoint.h>
|
||||
#include <Inventor/threads/SbStorage.h>
|
||||
|
||||
#ifdef FC_OS_MACOSX
|
||||
# include <OpenGL/gl.h>
|
||||
@@ -215,101 +216,6 @@ void SoFCUnifiedSelection::write(SoWriteAction * action)
|
||||
}
|
||||
}
|
||||
|
||||
int SoFCUnifiedSelection::getNumSelected(void) const
|
||||
{
|
||||
return this->selectionList.getLength();
|
||||
}
|
||||
|
||||
const SoPathList* SoFCUnifiedSelection::getList(void) const
|
||||
{
|
||||
return &this->selectionList;
|
||||
}
|
||||
|
||||
void SoFCUnifiedSelection::addPath(SoPath * path)
|
||||
{
|
||||
this->selectionList.append(path);
|
||||
}
|
||||
|
||||
void SoFCUnifiedSelection::removePath(const int which)
|
||||
{
|
||||
SoPath * path = this->selectionList[which];
|
||||
path->ref();
|
||||
this->selectionList.remove(which);
|
||||
path->unref();
|
||||
}
|
||||
|
||||
SoPath * SoFCUnifiedSelection::copyFromThis(const SoPath * path) const
|
||||
{
|
||||
SoPath * newpath = NULL;
|
||||
path->ref();
|
||||
int i = path->findNode(this);
|
||||
if (i >= 0) {
|
||||
newpath = path->copy(i);
|
||||
}
|
||||
path->unrefNoDelete();
|
||||
return newpath;
|
||||
}
|
||||
|
||||
int SoFCUnifiedSelection::findPath(const SoPath * path) const
|
||||
{
|
||||
int idx = -1;
|
||||
|
||||
// make copy only if necessary
|
||||
if (path->getHead() != this) {
|
||||
SoPath * newpath = this->copyFromThis(path);
|
||||
if (newpath) {
|
||||
newpath->ref();
|
||||
idx = this->selectionList.findPath(*newpath);
|
||||
newpath->unref();
|
||||
}
|
||||
else {
|
||||
idx = -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx = this->selectionList.findPath(*path);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
SoPath * SoFCUnifiedSelection::searchNode(SoNode * node) const
|
||||
{
|
||||
SoSearchAction sa;
|
||||
sa.setNode(node);
|
||||
sa.apply(const_cast<SoFCUnifiedSelection*>(this));
|
||||
SoPath * path = sa.getPath();
|
||||
if (path)
|
||||
path->ref();
|
||||
return path;
|
||||
}
|
||||
|
||||
void SoFCUnifiedSelection::select(SoNode * node)
|
||||
{
|
||||
SoPath * path = this->searchNode(node);
|
||||
if (path) {
|
||||
// don't ref() the path. searchNode() will ref it before returning
|
||||
if (this->findPath(path) < 0)
|
||||
this->addPath(path);
|
||||
path->unref();
|
||||
}
|
||||
}
|
||||
|
||||
void SoFCUnifiedSelection::deselect(const SoPath * path)
|
||||
{
|
||||
int idx = this->findPath(path);
|
||||
if (idx >= 0) this->removePath(idx);
|
||||
}
|
||||
|
||||
void SoFCUnifiedSelection::deselect(SoNode * node)
|
||||
{
|
||||
SoPath * path = this->searchNode(node);
|
||||
if (path) {
|
||||
// don't ref() the path. searchNode() will ref it before returning
|
||||
this->deselect(path);
|
||||
path->unref();
|
||||
}
|
||||
}
|
||||
|
||||
int SoFCUnifiedSelection::getPriority(const SoPickedPoint* p)
|
||||
{
|
||||
const SoDetail* detail = p->getDetail();
|
||||
@@ -344,7 +250,7 @@ SoFCUnifiedSelection::getPickedList(SoHandleEventAction* action, bool singlePick
|
||||
break;
|
||||
}
|
||||
info.vpd = static_cast<ViewProviderDocumentObject*>(vp);
|
||||
if(!info.vpd->useNewSelectionModel() || !info.vpd->isSelectable()) {
|
||||
if(!(useNewSelection.getValue()||info.vpd->useNewSelectionModel()) || !info.vpd->isSelectable()) {
|
||||
if(!singlePick) continue;
|
||||
if(ret.empty()) {
|
||||
info.vpd = 0;
|
||||
@@ -474,7 +380,7 @@ void SoFCUnifiedSelection::doAction(SoAction *action)
|
||||
App::Document* doc = App::GetApplication().getDocument(selaction->SelChange.pDocName);
|
||||
App::DocumentObject* obj = doc->getObject(selaction->SelChange.pObjectName);
|
||||
ViewProvider*vp = Application::Instance->getViewProvider(obj);
|
||||
if (vp && vp->useNewSelectionModel() && vp->isSelectable()) {
|
||||
if (vp && (useNewSelection.getValue()||vp->useNewSelectionModel()) && vp->isSelectable()) {
|
||||
SoDetail *detail = nullptr;
|
||||
detailPath->truncate(0);
|
||||
if(!selaction->SelChange.pSubName || !selaction->SelChange.pSubName[0] ||
|
||||
@@ -494,15 +400,13 @@ void SoFCUnifiedSelection::doAction(SoAction *action)
|
||||
type = SoSelectionElementAction::None;
|
||||
}
|
||||
|
||||
if(checkSelectionStyle(type,vp)) {
|
||||
SoSelectionElementAction action(type);
|
||||
action.setColor(this->colorSelection.getValue());
|
||||
action.setElement(detail);
|
||||
if(detailPath->getLength())
|
||||
action.apply(detailPath);
|
||||
else
|
||||
action.apply(vp->getRoot());
|
||||
}
|
||||
SoSelectionElementAction action(type);
|
||||
action.setColor(this->colorSelection.getValue());
|
||||
action.setElement(detail);
|
||||
if(detailPath->getLength())
|
||||
action.apply(detailPath);
|
||||
else
|
||||
action.apply(vp->getRoot());
|
||||
}
|
||||
detailPath->truncate(0);
|
||||
delete detail;
|
||||
@@ -518,17 +422,15 @@ void SoFCUnifiedSelection::doAction(SoAction *action)
|
||||
vps = this->pcDocument->getViewProvidersOfType(ViewProviderDocumentObject::getClassTypeId());
|
||||
for (std::vector<ViewProvider*>::iterator it = vps.begin(); it != vps.end(); ++it) {
|
||||
ViewProviderDocumentObject* vpd = static_cast<ViewProviderDocumentObject*>(*it);
|
||||
if (vpd->useNewSelectionModel()) {
|
||||
if (useNewSelection.getValue() || vpd->useNewSelectionModel()) {
|
||||
SoSelectionElementAction::Type type;
|
||||
if(Selection().isSelected(vpd->getObject()) && vpd->isSelectable())
|
||||
type = SoSelectionElementAction::All;
|
||||
else
|
||||
type = SoSelectionElementAction::None;
|
||||
if (checkSelectionStyle(type, vpd)) {
|
||||
SoSelectionElementAction action(type);
|
||||
action.setColor(this->colorSelection.getValue());
|
||||
action.apply(vpd->getRoot());
|
||||
}
|
||||
SoSelectionElementAction action(type);
|
||||
action.setColor(this->colorSelection.getValue());
|
||||
action.apply(vpd->getRoot());
|
||||
}
|
||||
}
|
||||
} else if (selaction->SelChange.Type == SelectionChanges::SetPreselectSignal) {
|
||||
@@ -537,7 +439,7 @@ void SoFCUnifiedSelection::doAction(SoAction *action)
|
||||
App::DocumentObject* obj = doc->getObject(selaction->SelChange.pObjectName);
|
||||
ViewProvider*vp = Application::Instance->getViewProvider(obj);
|
||||
if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()) &&
|
||||
vp->useNewSelectionModel() && vp->isSelectable())
|
||||
(useNewSelection.getValue()||vp->useNewSelectionModel()) && vp->isSelectable())
|
||||
{
|
||||
detailPath->truncate(0);
|
||||
SoDetail *det = 0;
|
||||
@@ -780,7 +682,7 @@ bool SoFCUnifiedSelection::setSelection(const std::vector<PickedInfo> &infos, bo
|
||||
getMainWindow()->showMessage(QString::fromLatin1(buf));
|
||||
}
|
||||
|
||||
if (pPath && checkSelectionStyle(type,vpd)) {
|
||||
if (pPath) {
|
||||
FC_TRACE("applying action");
|
||||
SoSelectionElementAction action(type);
|
||||
action.setColor(this->colorSelection.getValue());
|
||||
@@ -855,31 +757,6 @@ SoFCUnifiedSelection::handleEvent(SoHandleEventAction * action)
|
||||
inherited::handleEvent(action);
|
||||
}
|
||||
|
||||
bool SoFCUnifiedSelection::checkSelectionStyle(int type, ViewProvider *vp)
|
||||
{
|
||||
if ((type == SoSelectionElementAction::All || type == SoSelectionElementAction::None) &&
|
||||
vp->isDerivedFrom(ViewProviderGeometryObject::getClassTypeId()) &&
|
||||
static_cast<ViewProviderGeometryObject*>(vp)->SelectionStyle.getValue() == 1)
|
||||
{
|
||||
bool selected = (type == SoSelectionElementAction::All);
|
||||
int numSelected = getNumSelected();
|
||||
if (selected) {
|
||||
select(vp->getRoot());
|
||||
}
|
||||
else {
|
||||
deselect(vp->getRoot());
|
||||
}
|
||||
|
||||
if (numSelected != getNumSelected())
|
||||
this->touch();
|
||||
|
||||
if (selected) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoFCUnifiedSelection::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
{
|
||||
inherited::GLRenderBelowPath(action);
|
||||
@@ -1107,6 +984,7 @@ void SoVRMLAction::callDoAction(SoAction *action, SoNode *node)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
bool SoFCSelectionRoot::StackComp::operator()(const Stack &a, const Stack &b) const {
|
||||
if(a.size()-a.offset < b.size()-b.offset)
|
||||
return true;
|
||||
@@ -1130,13 +1008,17 @@ SoFCSeparator::SoFCSeparator(bool trackCacheMode)
|
||||
:trackCacheMode(trackCacheMode)
|
||||
{
|
||||
SO_NODE_CONSTRUCTOR(SoFCSeparator);
|
||||
if(!trackCacheMode)
|
||||
if(!trackCacheMode) {
|
||||
renderCaching = SoSeparator::OFF;
|
||||
boundingBoxCaching = SoSeparator::OFF;
|
||||
}
|
||||
}
|
||||
|
||||
void SoFCSeparator::GLRenderBelowPath(SoGLRenderAction * action) {
|
||||
if(trackCacheMode && renderCaching.getValue()!=CacheMode)
|
||||
if(trackCacheMode && renderCaching.getValue()!=CacheMode) {
|
||||
renderCaching = CacheMode;
|
||||
boundingBoxCaching = CacheMode;
|
||||
}
|
||||
inherited::GLRenderBelowPath(action);
|
||||
}
|
||||
|
||||
@@ -1150,6 +1032,40 @@ void SoFCSeparator::finish()
|
||||
atexit_cleanup();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Thread local data for bounding box rendering
|
||||
//
|
||||
// The code is inspred by Coin SoLevelOfDetails.cpp.
|
||||
typedef struct {
|
||||
SoGetBoundingBoxAction * bboxaction;
|
||||
SoCube *cube;
|
||||
SoColorPacker *packer;
|
||||
} SoFCBBoxRenderInfo;
|
||||
|
||||
static void so_bbox_construct_data(void * closure)
|
||||
{
|
||||
SoFCBBoxRenderInfo * data = (SoFCBBoxRenderInfo*) closure;
|
||||
data->bboxaction = NULL;
|
||||
data->cube = NULL;
|
||||
data->packer = NULL;
|
||||
}
|
||||
|
||||
static void so_bbox_destruct_data(void * closure)
|
||||
{
|
||||
SoFCBBoxRenderInfo * data = (SoFCBBoxRenderInfo*) closure;
|
||||
delete data->bboxaction;
|
||||
if(data->cube)
|
||||
data->cube->unref();
|
||||
delete data->packer;
|
||||
}
|
||||
|
||||
static SbStorage * so_bbox_storage = NULL;
|
||||
|
||||
// called from atexit
|
||||
static void so_bbox_cleanup(void)
|
||||
{
|
||||
delete so_bbox_storage;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
@@ -1165,6 +1081,11 @@ SoFCSelectionRoot::SoFCSelectionRoot(bool trackCacheMode)
|
||||
:SoFCSeparator(trackCacheMode)
|
||||
{
|
||||
SO_NODE_CONSTRUCTOR(SoFCSelectionRoot);
|
||||
SO_NODE_ADD_FIELD(selectionStyle,(FULL));
|
||||
SO_NODE_DEFINE_ENUM_VALUE(SelectStyles, FULL);
|
||||
SO_NODE_DEFINE_ENUM_VALUE(SelectStyles, BOX);
|
||||
SO_NODE_DEFINE_ENUM_VALUE(SelectStyles, PASSTHROUGH);
|
||||
SO_NODE_SET_SF_ENUM_TYPE(selectionStyle, SelectStyles);
|
||||
}
|
||||
|
||||
SoFCSelectionRoot::~SoFCSelectionRoot()
|
||||
@@ -1174,10 +1095,16 @@ SoFCSelectionRoot::~SoFCSelectionRoot()
|
||||
void SoFCSelectionRoot::initClass(void)
|
||||
{
|
||||
SO_NODE_INIT_CLASS(SoFCSelectionRoot,SoFCSeparator,"FCSelectionRoot");
|
||||
|
||||
so_bbox_storage = new SbStorage(sizeof(SoFCBBoxRenderInfo),
|
||||
so_bbox_construct_data, so_bbox_destruct_data);
|
||||
|
||||
// cc_coin_atexit((coin_atexit_f*) so_bbox_cleanup);
|
||||
}
|
||||
|
||||
void SoFCSelectionRoot::finish()
|
||||
{
|
||||
so_bbox_cleanup();
|
||||
atexit_cleanup();
|
||||
}
|
||||
|
||||
@@ -1220,7 +1147,9 @@ SoFCSelectionRoot::getNodeContext2(Stack &stack, SoNode *node, SoFCSelectionCont
|
||||
stack.back() = static_cast<SoFCSelectionRoot*>(node);
|
||||
for(stack.offset=0;stack.offset<stack.size();++stack.offset) {
|
||||
auto it = map.find(stack);
|
||||
auto ctx = it!=map.end()?it->second:SoFCSelectionContextBasePtr();
|
||||
SoFCSelectionContextBasePtr ctx;
|
||||
if(it!=map.end())
|
||||
ctx = it->second;
|
||||
status = merge(status,ret,ctx,stack.offset==stack.size()-1?0:stack[stack.offset]);
|
||||
if(status<0)
|
||||
break;
|
||||
@@ -1277,6 +1206,54 @@ std::pair<bool,SoFCSelectionContextBasePtr*> SoFCSelectionRoot::findActionContex
|
||||
return res;
|
||||
}
|
||||
|
||||
bool SoFCSelectionRoot::renderBBox(SoGLRenderAction *action, SoNode *node, SbColor color)
|
||||
{
|
||||
auto data = (SoFCBBoxRenderInfo*) so_bbox_storage->get();
|
||||
if (data->bboxaction == NULL) {
|
||||
// The viewport region will be replaced every time the action is
|
||||
// used, so we can just feed it a dummy here.
|
||||
data->bboxaction = new SoGetBoundingBoxAction(SbViewportRegion());
|
||||
data->cube = new SoCube;
|
||||
data->cube->ref();
|
||||
data->packer = new SoColorPacker;
|
||||
}
|
||||
|
||||
SbBox3f bbox;
|
||||
data->bboxaction->setViewportRegion(action->getViewportRegion());
|
||||
data->bboxaction->apply(node);
|
||||
bbox = data->bboxaction->getBoundingBox();
|
||||
if(bbox.isEmpty())
|
||||
return false;
|
||||
|
||||
auto state = action->getState();
|
||||
|
||||
state->push();
|
||||
|
||||
SoMaterialBindingElement::set(state,SoMaterialBindingElement::OVERALL);
|
||||
SoLazyElement::setEmissive(state, &color);
|
||||
SoLazyElement::setDiffuse(state, node,1, &color,data->packer);
|
||||
SoDrawStyleElement::set(state,node,SoDrawStyleElement::LINES);
|
||||
|
||||
const static float trans = 0.0;
|
||||
SoLazyElement::setTransparency(state, node, 1, &trans, data->packer);
|
||||
|
||||
float x, y, z;
|
||||
bbox.getSize(x, y, z);
|
||||
data->cube->width = x+0.001;
|
||||
data->cube->height = y+0.001;
|
||||
data->cube->depth = z+0.001;
|
||||
|
||||
SoModelMatrixElement::translateBy(state,node,bbox.getCenter());
|
||||
|
||||
SoMaterialBundle mb(action);
|
||||
mb.sendFirst();
|
||||
|
||||
data->cube->GLRender(action);
|
||||
|
||||
state->pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::time_t _CyclicLastReported;
|
||||
|
||||
void SoFCSelectionRoot::renderPrivate(SoGLRenderAction * action, bool inPath) {
|
||||
@@ -1291,42 +1268,78 @@ void SoFCSelectionRoot::renderPrivate(SoGLRenderAction * action, bool inPath) {
|
||||
return;
|
||||
}
|
||||
SelStack.push_back(this);
|
||||
auto ctx2 = std::static_pointer_cast<SelContext>(getNodeContext2(SelStack,this,SelContext::merge));
|
||||
if(!ctx2 || !ctx2->hideAll) {
|
||||
auto state = action->getState();
|
||||
SelContextPtr ctx = getRenderContext<SelContext>(this);
|
||||
bool colorPushed = false;
|
||||
if(!ShapeColorNode && overrideColor &&
|
||||
!SoOverrideElement::getDiffuseColorOverride(state) &&
|
||||
(!ctx || (!ctx->selAll && !ctx->hideAll)))
|
||||
{
|
||||
ShapeColorNode = this;
|
||||
colorPushed = true;
|
||||
state->push();
|
||||
auto &packer = ShapeColorNode->shapeColorPacker;
|
||||
auto &trans = ShapeColorNode->transOverride;
|
||||
auto &color = ShapeColorNode->colorOverride;
|
||||
if(!SoOverrideElement::getTransparencyOverride(state) && trans) {
|
||||
SoLazyElement::setTransparency(state, ShapeColorNode, 1, &trans, &packer);
|
||||
SoOverrideElement::setTransparencyOverride(state,ShapeColorNode,true);
|
||||
}
|
||||
SoLazyElement::setDiffuse(state, ShapeColorNode, 1, &color, &packer);
|
||||
SoOverrideElement::setDiffuseColorOverride(state,ShapeColorNode,true);
|
||||
SoMaterialBindingElement::set(state, ShapeColorNode, SoMaterialBindingElement::OVERALL);
|
||||
SoOverrideElement::setMaterialBindingOverride(state,ShapeColorNode,true);
|
||||
if(_renderPrivate(action,inPath)) {
|
||||
if(inPath)
|
||||
SoSeparator::GLRenderInPath(action);
|
||||
else
|
||||
SoSeparator::GLRenderBelowPath(action);
|
||||
}
|
||||
SelStack.pop_back();
|
||||
SelStack.nodeSet.erase(this);
|
||||
}
|
||||
|
||||
SoTextureEnabledElement::set(state,ShapeColorNode,false);
|
||||
bool SoFCSelectionRoot::_renderPrivate(SoGLRenderAction * action, bool inPath) {
|
||||
auto ctx2 = std::static_pointer_cast<SelContext>(getNodeContext2(SelStack,this,SelContext::merge));
|
||||
if(ctx2 && ctx2->hideAll)
|
||||
return false;
|
||||
|
||||
auto state = action->getState();
|
||||
SelContextPtr ctx = getRenderContext<SelContext>(this);
|
||||
int style = selectionStyle.getValue();
|
||||
if((style==SoFCSelectionRoot::BOX || ViewParams::instance()->getShowSelectionBoundingBox())
|
||||
&& ctx && !ctx->hideAll && (ctx->selAll || ctx->hlAll))
|
||||
{
|
||||
if(style==SoFCSelectionRoot::PASSTHROUGH)
|
||||
style = SoFCSelectionRoot::BOX;
|
||||
else {
|
||||
renderBBox(action,this,ctx->hlAll?ctx->hlColor:ctx->selColor);
|
||||
return true;
|
||||
}
|
||||
if(!ctx) {
|
||||
if(inPath)
|
||||
SoSeparator::GLRenderInPath(action);
|
||||
else
|
||||
SoSeparator::GLRenderBelowPath(action);
|
||||
} else {
|
||||
bool selPushed;
|
||||
bool hlPushed;
|
||||
if((selPushed = ctx->selAll)) {
|
||||
SelColorStack.push_back(ctx->selColor);
|
||||
}
|
||||
|
||||
// Here, we are not setting (pre)selection color override here.
|
||||
// Instead, we are checking and setting up for any secondary context
|
||||
// color override.
|
||||
//
|
||||
// When the current selection style is full highlight, we should ignore any
|
||||
// secondary override. If the style is bounding box, however, we should
|
||||
// honour the secondary color override.
|
||||
|
||||
bool colorPushed = false;
|
||||
if(!ShapeColorNode && overrideColor &&
|
||||
!SoOverrideElement::getDiffuseColorOverride(state) &&
|
||||
(style==SoFCSelectionRoot::BOX || !ctx || (!ctx->selAll && !ctx->hideAll)))
|
||||
{
|
||||
ShapeColorNode = this;
|
||||
colorPushed = true;
|
||||
state->push();
|
||||
auto &packer = ShapeColorNode->shapeColorPacker;
|
||||
auto &trans = ShapeColorNode->transOverride;
|
||||
auto &color = ShapeColorNode->colorOverride;
|
||||
if(!SoOverrideElement::getTransparencyOverride(state) && trans) {
|
||||
SoLazyElement::setTransparency(state, ShapeColorNode, 1, &trans, &packer);
|
||||
SoOverrideElement::setTransparencyOverride(state,ShapeColorNode,true);
|
||||
}
|
||||
SoLazyElement::setDiffuse(state, ShapeColorNode, 1, &color, &packer);
|
||||
SoOverrideElement::setDiffuseColorOverride(state,ShapeColorNode,true);
|
||||
SoMaterialBindingElement::set(state, ShapeColorNode, SoMaterialBindingElement::OVERALL);
|
||||
SoOverrideElement::setMaterialBindingOverride(state,ShapeColorNode,true);
|
||||
|
||||
SoTextureEnabledElement::set(state,ShapeColorNode,false);
|
||||
}
|
||||
|
||||
if(!ctx) {
|
||||
if(inPath)
|
||||
SoSeparator::GLRenderInPath(action);
|
||||
else
|
||||
SoSeparator::GLRenderBelowPath(action);
|
||||
} else {
|
||||
bool selPushed;
|
||||
bool hlPushed;
|
||||
if((selPushed = ctx->selAll)) {
|
||||
SelColorStack.push_back(ctx->selColor);
|
||||
|
||||
if(style != SoFCSelectionRoot::BOX) {
|
||||
state->push();
|
||||
auto &color = SelColorStack.back();
|
||||
SoLazyElement::setEmissive(state, &color);
|
||||
@@ -1339,26 +1352,32 @@ void SoFCSelectionRoot::renderPrivate(SoGLRenderAction * action, bool inPath) {
|
||||
SoOverrideElement::setMaterialBindingOverride(state,this,true);
|
||||
}
|
||||
}
|
||||
if((hlPushed = ctx->hlAll))
|
||||
HlColorStack.push_back(ctx->hlColor);
|
||||
if(inPath)
|
||||
SoSeparator::GLRenderInPath(action);
|
||||
else
|
||||
SoSeparator::GLRenderBelowPath(action);
|
||||
if(selPushed) {
|
||||
SelColorStack.pop_back();
|
||||
}
|
||||
|
||||
if((hlPushed = ctx->hlAll))
|
||||
HlColorStack.push_back(ctx->hlColor);
|
||||
|
||||
if(inPath)
|
||||
SoSeparator::GLRenderInPath(action);
|
||||
else
|
||||
SoSeparator::GLRenderBelowPath(action);
|
||||
|
||||
if(selPushed) {
|
||||
SelColorStack.pop_back();
|
||||
|
||||
if(style != SoFCSelectionRoot::BOX)
|
||||
state->pop();
|
||||
}
|
||||
if(hlPushed)
|
||||
HlColorStack.pop_back();
|
||||
}
|
||||
if(colorPushed) {
|
||||
ShapeColorNode = 0;
|
||||
state->pop();
|
||||
}
|
||||
if(hlPushed)
|
||||
HlColorStack.pop_back();
|
||||
}
|
||||
SelStack.pop_back();
|
||||
SelStack.nodeSet.erase(this);
|
||||
|
||||
if(colorPushed) {
|
||||
ShapeColorNode = 0;
|
||||
state->pop();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SoFCSelectionRoot::GLRenderBelowPath(SoGLRenderAction * action) {
|
||||
@@ -1407,6 +1426,16 @@ void SoFCSelectionRoot::resetContext() {
|
||||
contextMap.clear();
|
||||
}
|
||||
|
||||
void SoFCSelectionRoot::moveActionStack(SoAction *from, SoAction *to, bool erase) {
|
||||
auto it = ActionStacks.find(from);
|
||||
if(it == ActionStacks.end())
|
||||
return;
|
||||
auto &stack = ActionStacks[to];
|
||||
assert(stack.empty());
|
||||
stack.swap(it->second);
|
||||
if(erase)
|
||||
ActionStacks.erase(it);
|
||||
}
|
||||
|
||||
#define BEGIN_ACTION \
|
||||
auto &stack = ActionStacks[action];\
|
||||
@@ -1709,10 +1738,39 @@ void SoFCPathAnnotation::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
if (action->isRenderingDelayedPaths()) {
|
||||
SbBool zbenabled = glIsEnabled(GL_DEPTH_TEST);
|
||||
if (zbenabled) glDisable(GL_DEPTH_TEST);
|
||||
inherited::GLRenderInPath(action);
|
||||
|
||||
if(det)
|
||||
inherited::GLRenderInPath(action);
|
||||
else {
|
||||
bool bbox = ViewParams::instance()->getShowSelectionBoundingBox();
|
||||
if(!bbox) {
|
||||
for(int i=0,count=path->getLength();i<count;++i) {
|
||||
if(!path->getNode(i)->isOfType(SoFCSelectionRoot::getClassTypeId()))
|
||||
continue;
|
||||
auto node = static_cast<SoFCSelectionRoot*>(path->getNode(i));
|
||||
if(node->selectionStyle.getValue()==SoFCSelectionRoot::BOX) {
|
||||
bbox = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!bbox)
|
||||
inherited::GLRenderInPath(action);
|
||||
else {
|
||||
bool sel = false;
|
||||
bool hl = false;
|
||||
SbColor selColor,hlColor;
|
||||
SoFCSelectionRoot::checkSelection(sel,selColor,hl,hlColor);
|
||||
if(sel || hl)
|
||||
SoFCSelectionRoot::renderBBox(action,this,hl?hlColor:selColor);
|
||||
else
|
||||
inherited::GLRenderInPath(action);
|
||||
}
|
||||
}
|
||||
|
||||
if (zbenabled) glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
SoCacheElement::invalidate(action->getState());
|
||||
auto curPath = action->getCurPath();
|
||||
SoPath *newPath = new SoPath(curPath->getLength()+path->getLength());
|
||||
@@ -1755,3 +1813,16 @@ void SoFCPathAnnotation::setPath(SoPath *newPath) {
|
||||
path->ref();
|
||||
addChild(path->getNode(0));
|
||||
}
|
||||
|
||||
void SoFCPathAnnotation::getBoundingBox(SoGetBoundingBoxAction * action)
|
||||
{
|
||||
if(path) {
|
||||
SoGetBoundingBoxAction bboxAction(action->getViewportRegion());
|
||||
SoFCSelectionRoot::moveActionStack(action,&bboxAction,false);
|
||||
bboxAction.apply(path);
|
||||
SoFCSelectionRoot::moveActionStack(&bboxAction,action,true);
|
||||
auto bbox = bboxAction.getBoundingBox();
|
||||
if(!bbox.isEmpty())
|
||||
action->extendBy(bbox);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <Inventor/fields/SoSFEnum.h>
|
||||
#include <Inventor/fields/SoSFString.h>
|
||||
#include <Inventor/nodes/SoLightModel.h>
|
||||
#include <Inventor/lists/SoPathList.h>
|
||||
#include "View3DInventorViewer.h"
|
||||
#include "SoFCSelectionContext.h"
|
||||
#include <list>
|
||||
@@ -71,8 +70,6 @@ public:
|
||||
|
||||
const char* getFileFormatName(void) const;
|
||||
void write(SoWriteAction * action);
|
||||
int getNumSelected(void) const;
|
||||
const SoPathList* getList(void) const;
|
||||
|
||||
SoSFColor colorHighlight;
|
||||
SoSFColor colorSelection;
|
||||
@@ -89,8 +86,6 @@ public:
|
||||
//virtual void GLRenderInPath(SoGLRenderAction * action);
|
||||
//static void turnOffCurrentHighlight(SoGLRenderAction * action);
|
||||
|
||||
bool checkSelectionStyle(int type, ViewProvider *vp);
|
||||
|
||||
static bool hasHighlight();
|
||||
|
||||
friend class View3DInventorViewer;
|
||||
@@ -100,21 +95,6 @@ protected:
|
||||
//virtual void redrawHighlighted(SoAction * act, SbBool flag);
|
||||
//virtual SbBool readInstance(SoInput * in, unsigned short flags);
|
||||
|
||||
/** @name Nodes selection.
|
||||
* The SoBoxSelectionRenderAction uses these nodes to draw a
|
||||
* bounding box.
|
||||
*/
|
||||
//@{
|
||||
void addPath(SoPath * path);
|
||||
void removePath(const int which);
|
||||
SoPath * copyFromThis(const SoPath * path) const;
|
||||
SoPath * searchNode(SoNode * node) const;
|
||||
int findPath(const SoPath * path) const;
|
||||
void select(SoNode * node);
|
||||
void deselect(const SoPath * path);
|
||||
void deselect(SoNode * node);
|
||||
//@}
|
||||
|
||||
private:
|
||||
//static void turnoffcurrent(SoAction * action);
|
||||
//void setOverride(SoGLRenderAction * action);
|
||||
@@ -141,7 +121,6 @@ private:
|
||||
|
||||
static SoFullPath * currenthighlight;
|
||||
SoFullPath * detailPath;
|
||||
SoPathList selectionList;
|
||||
|
||||
SbBool setPreSelection;
|
||||
|
||||
@@ -168,6 +147,8 @@ public:
|
||||
virtual void GLRender(SoGLRenderAction * action);
|
||||
virtual void GLRenderInPath(SoGLRenderAction * action);
|
||||
|
||||
virtual void getBoundingBox(SoGetBoundingBoxAction * action);
|
||||
|
||||
protected:
|
||||
virtual ~SoFCPathAnnotation();
|
||||
|
||||
@@ -304,8 +285,18 @@ public:
|
||||
return findActionContext(action,node,false,true).second!=0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static std::shared_ptr<T> getSecondaryActionContext(SoAction *action, SoNode *node) {
|
||||
auto it = ActionStacks.find(action);
|
||||
if(it == ActionStacks.end())
|
||||
return std::shared_ptr<T>();
|
||||
return std::dynamic_pointer_cast<T>(getNodeContext2(it->second,node,T::merge));
|
||||
}
|
||||
|
||||
static void checkSelection(bool &sel, SbColor &selColor, bool &hl, SbColor &hlColor);
|
||||
|
||||
static void moveActionStack(SoAction *from, SoAction *to, bool erase);
|
||||
|
||||
static SoNode *getCurrentRoot(bool front, SoNode *def);
|
||||
|
||||
void resetContext();
|
||||
@@ -326,10 +317,18 @@ public:
|
||||
overrideColor = false;
|
||||
}
|
||||
|
||||
enum SelectStyles {
|
||||
FULL, BOX, PASSTHROUGH
|
||||
};
|
||||
SoSFEnum selectionStyle;
|
||||
|
||||
static bool renderBBox(SoGLRenderAction *action, SoNode *node, SbColor color);
|
||||
|
||||
protected:
|
||||
virtual ~SoFCSelectionRoot();
|
||||
|
||||
void renderPrivate(SoGLRenderAction *, bool inPath);
|
||||
bool _renderPrivate(SoGLRenderAction *, bool inPath);
|
||||
|
||||
class Stack : public std::vector<SoFCSelectionRoot*> {
|
||||
public:
|
||||
@@ -346,7 +345,6 @@ protected:
|
||||
|
||||
static Stack SelStack;
|
||||
static std::unordered_map<SoAction*,Stack> ActionStacks;
|
||||
|
||||
struct StackComp {
|
||||
bool operator()(const Stack &a, const Stack &b) const;
|
||||
};
|
||||
|
||||
@@ -506,11 +506,15 @@ void View3DInventorViewer::init()
|
||||
pcOnTopMaterial->setOverride(true);
|
||||
pcGroupOnTop->addChild(pcOnTopMaterial);
|
||||
|
||||
pcGroupOnTopSel = new SoFCSelectionRoot;
|
||||
auto selRoot = new SoFCSelectionRoot;
|
||||
selRoot->selectionStyle = SoFCSelectionRoot::PASSTHROUGH;
|
||||
pcGroupOnTopSel = selRoot;
|
||||
pcGroupOnTopSel->setName("GroupOnTopSel");
|
||||
pcGroupOnTopSel->ref();
|
||||
pcGroupOnTop->addChild(pcGroupOnTopSel);
|
||||
pcGroupOnTopPreSel = new SoFCSelectionRoot;
|
||||
selRoot = new SoFCSelectionRoot;
|
||||
selRoot->selectionStyle = SoFCSelectionRoot::PASSTHROUGH;
|
||||
pcGroupOnTopPreSel = selRoot;
|
||||
pcGroupOnTopPreSel->setName("GroupOnTopPreSel");
|
||||
pcGroupOnTopPreSel->ref();
|
||||
pcGroupOnTop->addChild(pcGroupOnTopPreSel);
|
||||
@@ -805,9 +809,12 @@ void View3DInventorViewer::checkGroupOnTop(const SelectionChanges &Reason) {
|
||||
// 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(Gui::Selection().needPickedList())
|
||||
onTop = 1;
|
||||
else if(vp->OnTopWhenSelected.getValue())
|
||||
onTop = vp->OnTopWhenSelected.getValue();
|
||||
else
|
||||
onTop = svp->OnTopWhenSelected.getValue();
|
||||
if(Reason.Type == SelectionChanges::SetPreselect) {
|
||||
SoHighlightElementAction action;
|
||||
action.setHighlighted(true);
|
||||
|
||||
@@ -28,7 +28,10 @@
|
||||
|
||||
namespace Gui {
|
||||
|
||||
/** Convenient class to obtain view provider related parameters */
|
||||
/** Convenient class to obtain view provider related parameters
|
||||
*
|
||||
* The parameters are under group "User parameter:BaseApp/Preferences/View"
|
||||
*/
|
||||
class GuiExport ViewParams: public ParameterGrp::ObserverType {
|
||||
public:
|
||||
ViewParams();
|
||||
@@ -55,6 +58,7 @@ public:
|
||||
FC_VIEW_PARAM(DefaultShapeLineWidth,int,Int,2) \
|
||||
FC_VIEW_PARAM(CoinCycleCheck,bool,Bool,true) \
|
||||
FC_VIEW_PARAM(EnablePropertyViewForInactiveDocument,bool,Bool,true) \
|
||||
FC_VIEW_PARAM(ShowSelectionBoundingBox,bool,Bool,false) \
|
||||
|
||||
#undef FC_VIEW_PARAM
|
||||
#define FC_VIEW_PARAM(_name,_ctype,_type,_def) \
|
||||
|
||||
@@ -104,7 +104,15 @@ ViewProvider::ViewProvider()
|
||||
{
|
||||
setStatus(UpdateData, true);
|
||||
|
||||
pcRoot = new SoFCSeparator;
|
||||
|
||||
// SoFCSeparater and SoFCSelectionRoot can both track render cache setting.
|
||||
// We change to SoFCSelectionRoot so that we can dynamically change full
|
||||
// selection mode (full highlight vs. boundbox). Note that comparing to
|
||||
// SoFCSeparater, there are some small overhead with SoFCSelectionRoot for
|
||||
// selection context tracking.
|
||||
//
|
||||
// pcRoot = new SoFCSeparator(true);
|
||||
pcRoot = new SoFCSelectionRoot(true);
|
||||
pcRoot->ref();
|
||||
pcModeSwitch = new SoSwitch();
|
||||
pcModeSwitch->ref();
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include "TaskView/TaskAppearance.h"
|
||||
#include "ViewProviderDocumentObject.h"
|
||||
#include "ViewProviderExtension.h"
|
||||
#include "SoFCUnifiedSelection.h"
|
||||
#include "Tree.h"
|
||||
#include <Gui/ViewProviderDocumentObjectPy.h>
|
||||
|
||||
@@ -75,6 +76,10 @@ ViewProviderDocumentObject::ViewProviderDocumentObject()
|
||||
ADD_PROPERTY(Visibility,(true));
|
||||
ADD_PROPERTY(ShowInTree,(true));
|
||||
|
||||
ADD_PROPERTY(SelectionStyle,((long)0));
|
||||
static const char *SelectionStyleEnum[] = {"Shape","BoundBox",0};
|
||||
SelectionStyle.setEnums(SelectionStyleEnum);
|
||||
|
||||
static const char* OnTopEnum[]= {"Disabled","Enabled","Object","Element",NULL};
|
||||
ADD_PROPERTY(OnTopWhenSelected,((long int)0));
|
||||
ADD_PROPERTY_TYPE(OnTopWhenSelected,((long int)0), "Base", App::Prop_None,
|
||||
@@ -181,6 +186,12 @@ void ViewProviderDocumentObject::onChanged(const App::Property* prop)
|
||||
if(getObject() && getObject()->Visibility.getValue()!=Visibility.getValue())
|
||||
getObject()->Visibility.setValue(Visibility.getValue());
|
||||
}
|
||||
else if (prop == &SelectionStyle) {
|
||||
if(getRoot()->isOfType(SoFCSelectionRoot::getClassTypeId())) {
|
||||
static_cast<SoFCSelectionRoot*>(getRoot())->selectionStyle = SelectionStyle.getValue()
|
||||
?SoFCSelectionRoot::BOX:SoFCSelectionRoot::FULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcDocument && !pcDocument->isModified() && testStatus(Gui::ViewStatus::TouchDocument)) {
|
||||
if (prop)
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
App::PropertyBool Visibility;
|
||||
App::PropertyBool ShowInTree;
|
||||
App::PropertyEnumeration OnTopWhenSelected;
|
||||
App::PropertyEnumeration SelectionStyle;
|
||||
|
||||
virtual void attach(App::DocumentObject *pcObject);
|
||||
virtual void reattach(App::DocumentObject *);
|
||||
|
||||
@@ -103,10 +103,6 @@ ViewProviderGeometryObject::ViewProviderGeometryObject()
|
||||
ADD_PROPERTY(BoundingBox,(false));
|
||||
ADD_PROPERTY(Selectable,(true));
|
||||
|
||||
ADD_PROPERTY(SelectionStyle,((long)0));
|
||||
static const char *SelectionStyleEnum[] = {"Shape","BoundBox",0};
|
||||
SelectionStyle.setEnums(SelectionStyleEnum);
|
||||
|
||||
bool enableSel = hGrp->GetBool("EnableSelection", true);
|
||||
Selectable.setValue(enableSel);
|
||||
|
||||
|
||||
@@ -363,6 +363,7 @@ public:
|
||||
pcSnapshot = new SoFCSelectionRoot;
|
||||
else
|
||||
pcSnapshot = new SoSeparator;
|
||||
pcSnapshot->boundingBoxCaching = SoSeparator::OFF;
|
||||
pcSnapshot->renderCaching = SoSeparator::OFF;
|
||||
std::ostringstream ss;
|
||||
ss << pcLinked->getObject()->getNameInDocument()
|
||||
|
||||
@@ -315,7 +315,7 @@ ViewProviderMesh::ViewProviderMesh() : pcOpenEdge(0)
|
||||
}
|
||||
|
||||
if (hGrp->GetBool("ShowBoundingBox", false))
|
||||
pcHighlight->style = Gui::SoFCSelection::BOX;
|
||||
SelectionStyle.setValue(1);
|
||||
|
||||
Coloring.setStatus(App::Property::Hidden, true);
|
||||
}
|
||||
@@ -370,6 +370,10 @@ void ViewProviderMesh::onChanged(const App::Property* prop)
|
||||
else if (prop == &Coloring) {
|
||||
tryColorPerVertexOrFace(Coloring.getValue());
|
||||
}
|
||||
else if (prop == &SelectionStyle) {
|
||||
pcHighlight->style = SelectionStyle.getValue()
|
||||
?Gui::SoFCSelection::BOX:Gui::SoFCSelection::EMISSIVE;
|
||||
}
|
||||
else {
|
||||
// Set the inverse color for open edges
|
||||
if (prop == &ShapeColor) {
|
||||
|
||||
@@ -164,6 +164,41 @@ void SoBrepEdgeSet::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
inherited::GLRenderBelowPath(action);
|
||||
}
|
||||
|
||||
void SoBrepEdgeSet::getBoundingBox(SoGetBoundingBoxAction * action) {
|
||||
|
||||
SelContextPtr ctx2 = Gui::SoFCSelectionRoot::getSecondaryActionContext<SelContext>(action,this);
|
||||
if(!ctx2 || (ctx2->sl.size()==1 && ctx2->sl[0]<0)) {
|
||||
inherited::getBoundingBox(action);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx2->sl.empty())
|
||||
return;
|
||||
|
||||
auto state = action->getState();
|
||||
auto coords = SoCoordinateElement::getInstance(state);
|
||||
const SbVec3f *coords3d = coords->getArrayPtr3();
|
||||
|
||||
if(!validIndexes(coords,ctx2->sl))
|
||||
return;
|
||||
|
||||
SbBox3f bbox;
|
||||
|
||||
int32_t i;
|
||||
const int32_t *cindices = &ctx2->sl[0];
|
||||
const int32_t *end = cindices + ctx2->sl.size();
|
||||
while (cindices < end) {
|
||||
bbox.extendBy(coords3d[*cindices++]);
|
||||
i = (cindices < end) ? *cindices++ : -1;
|
||||
while (i >= 0) {
|
||||
bbox.extendBy(coords3d[i]);
|
||||
i = cindices < end ? *cindices++ : -1;
|
||||
}
|
||||
}
|
||||
if(!bbox.isEmpty())
|
||||
action->extendBy(bbox);
|
||||
}
|
||||
|
||||
void SoBrepEdgeSet::renderShape(const SoGLCoordinateElement * const coords,
|
||||
const int32_t *cindices, int numindices)
|
||||
{
|
||||
|
||||
@@ -60,6 +60,9 @@ protected:
|
||||
const SoPrimitiveVertex *v1,
|
||||
const SoPrimitiveVertex *v2,
|
||||
SoPickedPoint *pp);
|
||||
|
||||
virtual void getBoundingBox(SoGetBoundingBoxAction * action);
|
||||
|
||||
private:
|
||||
struct SelContext;
|
||||
typedef std::shared_ptr<SelContext> SelContextPtr;
|
||||
|
||||
@@ -890,6 +890,53 @@ void SoBrepFaceSet::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
inherited::GLRenderBelowPath(action);
|
||||
}
|
||||
|
||||
void SoBrepFaceSet::getBoundingBox(SoGetBoundingBoxAction * action) {
|
||||
|
||||
if (this->coordIndex.getNum() < 3)
|
||||
return;
|
||||
|
||||
SelContextPtr ctx2 = Gui::SoFCSelectionRoot::getSecondaryActionContext<SelContext>(action,this);
|
||||
if(!ctx2 || ctx2->isSelectAll()) {
|
||||
inherited::getBoundingBox(action);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx2->selectionIndex.empty())
|
||||
return;
|
||||
|
||||
auto state = action->getState();
|
||||
auto coords = SoCoordinateElement::getInstance(state);
|
||||
const SbVec3f *coords3d = static_cast<const SoGLCoordinateElement*>(coords)->getArrayPtr3();
|
||||
const int32_t *cindices = this->coordIndex.getValues(0);
|
||||
const int32_t *pindices = this->partIndex.getValues(0);
|
||||
int numparts = this->partIndex.getNum();
|
||||
|
||||
SbBox3f bbox;
|
||||
for(auto id : ctx2->selectionIndex) {
|
||||
if (id<0 || id >= numparts)
|
||||
break;
|
||||
// coords
|
||||
int length=0;
|
||||
int start=0;
|
||||
length = (int)pindices[id]*4;
|
||||
for (int j=0;j<id;j++)
|
||||
start+=(int)pindices[j];
|
||||
start *= 4;
|
||||
|
||||
auto viptr = &cindices[start];
|
||||
auto viendptr = viptr + length;
|
||||
while (viptr + 2 < viendptr) {
|
||||
bbox.extendBy(coords3d[*viptr++]);
|
||||
bbox.extendBy(coords3d[*viptr++]);
|
||||
bbox.extendBy(coords3d[*viptr++]);
|
||||
++viptr;
|
||||
}
|
||||
}
|
||||
|
||||
if(!bbox.isEmpty())
|
||||
action->extendBy(bbox);
|
||||
}
|
||||
|
||||
// this macro actually makes the code below more readable :-)
|
||||
#define DO_VERTEX(idx) \
|
||||
if (mbind == PER_VERTEX) { \
|
||||
|
||||
@@ -98,6 +98,7 @@ protected:
|
||||
const SoPrimitiveVertex * v3,
|
||||
SoPickedPoint * pp);
|
||||
virtual void generatePrimitives(SoAction * action);
|
||||
virtual void getBoundingBox(SoGetBoundingBoxAction * action);
|
||||
|
||||
private:
|
||||
enum Binding {
|
||||
|
||||
@@ -154,6 +154,33 @@ void SoBrepPointSet::GLRenderBelowPath(SoGLRenderAction * action)
|
||||
inherited::GLRenderBelowPath(action);
|
||||
}
|
||||
|
||||
void SoBrepPointSet::getBoundingBox(SoGetBoundingBoxAction * action) {
|
||||
|
||||
SelContextPtr ctx2 = Gui::SoFCSelectionRoot::getSecondaryActionContext<SelContext>(action,this);
|
||||
if(!ctx2 || ctx2->isSelectAll()) {
|
||||
inherited::getBoundingBox(action);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx2->selectionIndex.empty())
|
||||
return;
|
||||
|
||||
auto state = action->getState();
|
||||
auto coords = SoCoordinateElement::getInstance(state);
|
||||
const SbVec3f *coords3d = coords->getArrayPtr3();
|
||||
int numverts = coords->getNum();
|
||||
int startIndex = this->startIndex.getValue();
|
||||
|
||||
SbBox3f bbox;
|
||||
for(auto idx : ctx2->selectionIndex) {
|
||||
if(idx >= startIndex && idx < numverts)
|
||||
bbox.extendBy(coords3d[idx]);
|
||||
}
|
||||
|
||||
if(!bbox.isEmpty())
|
||||
action->extendBy(bbox);
|
||||
}
|
||||
|
||||
void SoBrepPointSet::renderHighlight(SoGLRenderAction *action, SelContextPtr ctx)
|
||||
{
|
||||
if(!ctx || ctx->highlightIndex<0)
|
||||
|
||||
@@ -56,6 +56,8 @@ protected:
|
||||
virtual void GLRenderBelowPath(SoGLRenderAction * action);
|
||||
virtual void doAction(SoAction* action);
|
||||
|
||||
virtual void getBoundingBox(SoGetBoundingBoxAction * action);
|
||||
|
||||
private:
|
||||
typedef Gui::SoFCSelectionContext SelContext;
|
||||
typedef Gui::SoFCSelectionContextPtr SelContextPtr;
|
||||
|
||||
@@ -493,6 +493,12 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat)
|
||||
pcPointsRoot->renderCaching =
|
||||
wireframe->renderCaching = SoSeparator::OFF;
|
||||
|
||||
pcNormalRoot->boundingBoxCaching =
|
||||
pcFlatRoot->boundingBoxCaching =
|
||||
pcWireframeRoot->boundingBoxCaching =
|
||||
pcPointsRoot->boundingBoxCaching =
|
||||
wireframe->boundingBoxCaching = SoSeparator::OFF;
|
||||
|
||||
// enable two-side rendering
|
||||
pShapeHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
|
||||
pShapeHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
|
||||
|
||||
Reference in New Issue
Block a user