Styles
A style is a collection of attributes that is applied to a segment as a set. In complex segment trees, you may have segments that are not related hierarchically, but nonetheless share common attributes. You could set attributes for each segment individually. However, that is not only inefficient, but also inconvenient, especially when the modifications involve a large number of segments. Instead, defining and using a style provides a convenient way to take a set of attributes and apply them to many segments. Any attribute that can be set on a segment can also be set in a style.
Named Styles
The recommended way to create a style is by creating and using a HPS::NamedStyleDefinition
. Named styles are those which are referenced by a name you assign to them. Attributes are set on the style object itself. In this example, a green wireframe style is applied to the style definition:
HPS::NamedStyleDefinition wire_style = myPortfolio.DefineNamedStyle("green wireframe", HPS::Database::CreateRootSegment());
wire_style.GetSource().GetVisibilityControl().SetFaces(false).SetEdges(true);
wire_style.GetSource().GetMaterialMappingControl().SetEdgeColor(RGBColor(0.0f, 1.0f, 0.0f));
mySegmentKey.GetPortfolioControl().Push(myPortfolio);
mySegmentKey.GetStyleControl().PushNamed("green wireframe");
HPS.NamedStyleDefinition wire_style = myPortfolio.DefineNamedStyle("green wireframe", HPS.Database.CreateRootSegment());
wire_style.GetSource().GetVisibilityControl().SetFaces(false).SetEdges(true);
wire_style.GetSource().GetMaterialMappingControl().SetEdgeColor(new HPS.RGBAColor(0.0f, 1.0f, 0.0f));
mySegmentKey.GetPortfolioControl().Push(myPortfolio);
mySegmentKey.GetStyleControl().PushNamed("green wireframe");
Style Segments
A style can also be defined by setting attributes on a style segment. A style segment is a segment with attributes that are used as the source of the style. The segment does not have to be part of the scene hierarchy. If you have many styles, you may want to consider creating a style library. A style library is an informal collection of segments which hold no geometry and are used only as a source of styles.
Code for creating and using a style is shown below. The concept is the same as using a named style, but instead of setting attributes on the style definition object, you style the segment directly:
HPS::SegmentKey styleSegment = HPS::Database::CreateRootSegment();
// setup the attributes on 'styleSegment'
styleSegment.GetVisibilityControl().SetFaces(false).SetEdges(true);
styleSegment.GetMaterialMappingControl().SetEdgeColor(RGBAColor(0, 1, 0));
// 'anotherSegment' uses the style from 'styleSegment'
anotherSegment.GetStyleControl().PushSegment(styleSegment);
HPS.SegmentKey styleSegment = HPS.Database.CreateRootSegment();
// setup the attributes on 'styleSegment'
styleSegment.GetVisibilityControl().SetFaces(false).SetEdges(true);
styleSegment.GetMaterialMappingControl().SetEdgeColor(new HPS.RGBAColor(0, 1, 0));
// 'anotherSegment' uses the style from 'styleSegment'
anotherSegment.GetStyleControl().PushSegment(styleSegment);
Each segment has an associated style stack which allows a segment to have more than one style applied to it. In this case, the style settings at the top of the stack overrides any conflicting style information that may be present below. You can unset a style by using one of the following:
// pops a style off the stack
mySegmentKey.GetStyleControl().Pop();
// removes the style stack and replaces it with the new style
mySegmentKey.GetStyleControl().SetNamed("newStyle");
// unsets all styles on this segment
mySegmentKey.GetStyleControl().UnsetEverything();
// pops a style off the stack
mySegmentKey.GetStyleControl().Pop();
// removes the style stack and replaces it with the new style
mySegmentKey.GetStyleControl().SetNamed("newStyle");
// unsets all styles on this segment
mySegmentKey.GetStyleControl().UnsetEverything();
Using Conditional Styles
A conditional style is a style that is automatically applied to a segment when a set of conditions are met. The “condition” is merely a set of flags that is set on on a segment. The flags themselves are strings.
HPS::ConditionalExpression condition1("c1");
// will be applied only if condition1 is satisfied
mySegmentKey.GetStyleControl().SetNamed("glossy red", condition1);
// setting the "c1" condition will enable this segment's style
mySegmentKey.SetCondition("c1");
HPS.ConditionalExpression condition1 = new HPS.ConditionalExpression("c1");
// will be applied only if condition1 is satisfied
mySegmentKey.GetStyleControl().SetNamed("glossy red", condition1);
// setting the "c1" condition will enable this segment's style
mySegmentKey.SetCondition("c1");
While the basic example above is too simple to warrant setting up the condition mechanism, the benefit of using conditions becomes more apparent when applied to multiple segments. For instance, imagine you have a model with many different parts, some of which are supposed to become invisible when the scene is rotated in a certain way. Since conditions inherit down the tree like other attributes, this means you need only set the condition at the root segment for all subsegments with that conditional style to be made invisible.
Complex Conditional Styles
Segments can be marked with more than one condition at a time.
HPS::UTF8Array conditionArray;
conditionArray.push_back("c1");
conditionArray.push_back("c3");
mySegmentKey.SetConditions(conditionArray); // sets "c1" and "c3"
String[] conditionArray = new String[2];
conditionArray[0] = "c1";
conditionArray[1] = "c3";
mySegmentKey.SetConditions(conditionArray); // sets "c1" and "c3"
Visualize can also interpret basic conditional operators using HPS::OR
and HPS::AND
. To create one of these complex conditions, they must be combined into a single condition. For example, if you want a condition of ("c1" OR "c2") AND "c3"
, you could construct it as demonstrated below:
HPS::ConditionalExpression condition1("c1");
HPS::ConditionalExpression condition2("c2");
HPS::ConditionalExpression complexOR = HPS::ConditionalExpression::OR(condition1, condition2);
HPS::ConditionalExpression condition3("c3");
HPS::ConditionalExpression complexAND = HPS::ConditionalExpression::AND(complexOR, condition3);
mySegmentKey.GetStyleControl().SetNamed("myStyle", complexAND);
HPS.ConditionalExpression condition1 = new HPS.ConditionalExpression("c1");
HPS.ConditionalExpression condition2 = new HPS.ConditionalExpression("c2");
HPS.ConditionalExpression complexOR = HPS.ConditionalExpression.OR(condition1, condition2);
HPS.ConditionalExpression condition3 = new HPS.ConditionalExpression("c3");
HPS.ConditionalExpression complexAND = HPS.ConditionalExpression.AND(complexOR, condition3);
mySegmentKey.GetStyleControl().SetNamed("myStyle", complexAND);
Visualize also supports XOR
and NOT
operators. Up to 10 conditions are supported for a single conditional operator. However, you can construct an arbitrarily large conditions [the presence of AND
and OR
constructors which take multiple arguments is to make it more convenient to do things like AND(c1, c2, c3)
instead of having to do AND(AND(c1, c2), c3)
].
Using Multiple Styles With the Style Stack
Visualize uses a stack to manage styles. Each segment either has its own stack or inherits one from a parent. Anytime you set a style, you are implicitly using the style stack. If you are using only one style per segment, the style stack is transparent because you are only working with the top element. However, to enable multiple styles on the same segment, instead of setting the style, you must push the style onto the segment’s style stack. To do this, simply call PushStyle
:
mySegmentKey.GetStyleControl().PushNamed("myStyle");
mySegmentKey.GetStyleControl().PushNamed("myStyle");
When rendering, Visualize will examine the style stack and apply the styles individually. In the case that styles have overlapping attributes, the attributes of the most recently pushed style will take precedence over styles further down in the stack.
It is possible to edit the style stack by getting an array of the current styles and then modifying that array. So, for example, to remove a style from the middle of a stack of three styles:
HPS::UTF8Array styleNames(3);
HPS::ConditionalExpressionArray conditions;
mySegmentKey.GetStyleControl().ShowAllNamed(styleNames, conditions);
styleNames.erase(styleNames.begin() + 1);
mySegmentKey.GetStyleControl().UnsetEverything();
for (size_t i = 0; i < styleNames.size(); ++i)
mySegmentKey.GetStyleControl().PushNamed(styleNames[i], conditions[i]);
String[] styleNames = new String[3];
HPS.ConditionalExpression[] conditions = new HPS.ConditionalExpression[3];
mySegmentKey.GetStyleControl().ShowAllNamed(out styleNames, out conditions);
String[] newStyleNames = new String[2];
newStyleNames[0] = styleNames[0];
newStyleNames[1] = styleNames[2];
HPS.Style.Type[] styleTypesArray = new HPS.Style.Type[2];
styleTypesArray[0] = HPS.Style.Type.Named;
styleTypesArray[1] = HPS.Style.Type.Named;
HPS.SegmentKey[] segmentKeyArray = new HPS.SegmentKey[2];
HPS.PortfolioKey[] portfolioKeyArray = new HPS.PortfolioKey[2];
mySegmentKey.GetStyleControl().Set(styleTypesArray, segmentKeyArray, newStyleNames, conditions);