Overriding Visual Styles of Elements in Teigha BIM

Evgeny Tikhonov

March 16, 2018

It is well known that materials applied to elements are different in shading and realistic modes. However, this rule does not apply for some elements.

Let’s look at the OdBmImposterLight element. The picture below shows an imposter light placed on an extrusion. Both the light and extrusion have the same material, which has a red color for shading mode and a grey color for realistic mode.

image1

Imposter light placed on an extrusion

To achieve this behavior for a desired element, just implement a descendant of the OdBmOverriddenVisualStyle and OdBmOverriddenVisualStyleImpl classes.

Here is the declaration:

class TB_DB_EXPORT OdBmOverriddenVisualStyleForImposterLight : public OdBmOverriddenVisualStyle {
  ODBM_DECLARE_CUSTOM_CLASS_MEMBERS(OdBmOverriddenVisualStyleForImposterLight);
public:
  virtual void overrideByDbView(const OdBmDBViewPtr&);
};

class TB_DB_EXPORT OdBmOverriddenVisualStyleForImposterLightImpl 
	: public OdBmOverriddenVisualStyleImpl {
  ODBM_DECLARE_CUSTOM_CLASS_IMPL_MEMBERS(OdBmOverriddenVisualStyleForImposterLight);
public:
  OdBmOverriddenVisualStyleForImposterLightImpl();
  virtual ~OdBmOverriddenVisualStyleForImposterLightImpl(){};
  virtual void overrideByDbView(const OdBmDBViewPtr&);
};

And the definition:

#define NEW_CONSTR2(CLASS) OdRxObjectImpl<OdBmOverriddenVisualStyleForImposterLight>::createObject()
ODTF_DEFINE_MEMBERS2(OdBmOverriddenVisualStyleForImposterLight, OdBmOverriddenVisualStyle, NULL, NULL, OdBmOverriddenVisualStyleForImposterLight::pseudoConstructor, 
                     OD_T("OdBmOverriddenVisualStyleForImposterLight"))
ODRX_DEFINE_PSEUDOCONSTRUCTOR(OdBmOverriddenVisualStyleForImposterLight, NEW_CONSTR2)


OdBmOverriddenVisualStyleForImposterLight::OdBmOverriddenVisualStyleForImposterLight(
  OdBmOverriddenVisualStyleForImposterLightImpl* pImpl) : OdBmOverriddenVisualStyle(pImpl) {
}

OdBmOverriddenVisualStyleForImposterLight::OdBmOverriddenVisualStyleForImposterLight() : 
  OdBmOverriddenVisualStyle(new OdBmOverriddenVisualStyleForImposterLightImpl) {
}

void OdBmOverriddenVisualStyleForImposterLight::overrideByDbView(const OdBmDBViewPtr& view) {
  getImpl()->overrideByDbView(view);
}

OdBmOverriddenVisualStyleForImposterLightImpl::OdBmOverriddenVisualStyleForImposterLightImpl(): OdBmOverriddenVisualStyleImpl() {
}

void OdBmOverriddenVisualStyleForImposterLightImpl::overrideByDbView(const OdBmDBViewPtr& view) {
  OdBmDBViewImpl* pView = OdBmSystemInternals::getImpl(view);
  if (pView) {
    OdGiVisualStyle& viewStyle = pView->getVisualStyle();
    (OdGiVisualStyle&)m_visualStyle = viewStyle;
    // disable textures for imposter light - will use shaded colors in realistic mode
    m_visualStyle.displayStyle().setDisplaySettingsFlag(OdGiDisplayStyle::kTextures, false);
  }
}

OdUInt32 OdBmOverriddenVisualStyleImpl::subSetAttributes(OdGiDrawableTraits* traits) const
{
  OdGiVisualStyleTraitsPtr pVsTraits = OdGiVisualStyleTraits::cast(traits);
  if (pVsTraits.get())
    pVsTraits->setOdGiVisualStyle(m_visualStyle);
 
  return OdBmObjectImpl::subSetAttributes(traits) | OdGiDrawable::kDrawableUsesNesting; //It is container;
}

Notice that you need to register the overridden visual style in the database, as required by GI:

OdBmSystemInternals::getImpl(pDb)->addElement(
OdBmOverriddenVisualStyleForImposterLight::createObject(),
    OdBm::OverriddenVisualStyles::ImposterLight, OdBmObjectId::kNull, false);

This code, for example, can be placed inside the OdBmMaterialTableNewImpl:: setDocument() method.

Also you need to implement the subViewportDraw() method for the desired class.

void OdBmImposterLightImpl::subViewportDraw(OdGiViewportDraw *pVd) const {
  OdBmViewportPtr pViewport = OdBmObjectId(pVd->viewportObjectId()).safeOpenObject();
  OdBmDBViewPtr pView = pViewport->getDbViewId().safeOpenObject();

  OdBmDatabase* pDb = static_cast<OdBmDatabase*>(pVd->context()->database());
  OdDbStub* pVisualStyle = 
pDb->getObjectId(OdBm::OverriddenVisualStyles::ImposterLight);
  if (pVisualStyle) {
    OdBmOverriddenVisualStylePtr pStyle = OdBmObjectId(pVisualStyle).openObject();
    pStyle->overrideByDbView(pView);
    pVd->subEntityTraits().setVisualStyle(pVisualStyle);
  }
  OdBmImposterLightInternalImpl::subViewportDraw(pVd);
}

Done.