Allow rendering hidden solid edges using a distinct style.
Before this change, the two buttons "Show/hide shaded model" (S) and "Show/hide hidden lines" (H) resulted in drawing the following elements in the following styles: Button | Non-occluded | Non-occluded | Occluded | Occluded state | solid edges | entities | solid edges | entities --------+--------------+--------------+-------------+-------------- !S !H | | | solid-edge | entity style --------+ | +-------------+-------------- S !H | | | invisible --------+ solid-edge | entity style +-------------+-------------- !S H | | | | --------+ | | solid-edge | entity style S H | | | | --------+--------------+--------------+-------------+-------------- After this change, they are drawn as follows: Button | Non-occluded | Non-occluded | Occluded | Occluded state | solid edges | entities | solid edges | entities --------+--------------+--------------+-------------+-------------- !S !H | | | solid-edge | entity style --------+ | +-------------+-------------- S !H | | | invisible --------+ solid-edge | entity style +-------------+-------------- !S H | | | | --------+ | | hidden-edge | stippled¹ S H | | | | --------+--------------+--------------+-------------+-------------- ¹ entity style, but the stipple parameters taken from hidden-edge In SolveSpace's true WYSIWYG tradition, the 2d view export follows the rendered view exactly. Also, it is now possible to edit the stipple parameters of built-in styles, so that by changing the hidden-edge style to non-stippled it is possible to regain the old behavior.
This commit is contained in:
parent
d55300232f
commit
d1a2eb6d18
18
src/draw.cpp
18
src/draw.cpp
|
@ -34,7 +34,7 @@ void GraphicsWindow::Selection::Draw(void) {
|
|||
Vector refp = Vector::From(0, 0, 0);
|
||||
if(entity.v) {
|
||||
Entity *e = SK.GetEntity(entity);
|
||||
e->Draw();
|
||||
e->Draw(/*drawAsHidden=*/false);
|
||||
if(emphasized) refp = e->GetReferencePos();
|
||||
}
|
||||
if(constraint.v) {
|
||||
|
@ -686,9 +686,15 @@ nogrid:;
|
|||
// Draw the active group; this does stuff like the mesh and edges.
|
||||
(SK.GetGroup(activeGroup))->Draw();
|
||||
|
||||
// Now draw the entities
|
||||
if(showHdnLines) glDisable(GL_DEPTH_TEST);
|
||||
Entity::DrawAll();
|
||||
// Now draw the entities.
|
||||
if(SS.GW.showHdnLines) {
|
||||
ssglDepthRangeOffset(2);
|
||||
glDepthFunc(GL_GREATER);
|
||||
Entity::DrawAll(/*drawAsHidden=*/true);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
}
|
||||
ssglDepthRangeOffset(0);
|
||||
Entity::DrawAll(/*drawAsHidden=*/false);
|
||||
|
||||
// Draw filled paths in all groups, when those filled paths were requested
|
||||
// specially by assigning a style with a fill color, or when the filled
|
||||
|
@ -737,9 +743,7 @@ nogrid:;
|
|||
glEnd();
|
||||
|
||||
// And the naked edges, if the user did Analyze -> Show Naked Edges.
|
||||
ssglLineWidth(Style::Width(Style::DRAW_ERROR));
|
||||
ssglColorRGB(Style::Color(Style::DRAW_ERROR));
|
||||
ssglDrawEdges(&(SS.nakedEdges), true);
|
||||
ssglDrawEdges(&(SS.nakedEdges), true, { Style::DRAW_ERROR });
|
||||
|
||||
// Then redraw whatever the mouse is hovering over, highlighted.
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
|
|
@ -40,10 +40,9 @@ void Entity::LineDrawOrGetDistance(Vector a, Vector b, bool maybeFat, int data)
|
|||
dogd.refp = (a.Plus(b)).ScaledBy(0.5);
|
||||
}
|
||||
|
||||
void Entity::DrawAll(void) {
|
||||
// This handles points and line segments as a special case, because I
|
||||
// seem to be able to get a huge speedup that way, by consolidating
|
||||
// stuff to gl.
|
||||
void Entity::DrawAll(bool drawAsHidden) {
|
||||
// This handles points as a special case, because I seem to be able
|
||||
// to get a huge speedup that way, by consolidating stuff to gl.
|
||||
int i;
|
||||
if(SS.GW.showPoints) {
|
||||
double s = 3.5/SS.GW.scale;
|
||||
|
@ -98,19 +97,23 @@ void Entity::DrawAll(void) {
|
|||
|
||||
for(i = 0; i < SK.entity.n; i++) {
|
||||
Entity *e = &(SK.entity.elem[i]);
|
||||
if(e->IsPoint())
|
||||
{
|
||||
if(e->IsPoint()) {
|
||||
continue; // already handled
|
||||
}
|
||||
e->Draw();
|
||||
e->Draw(drawAsHidden);
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::Draw(void) {
|
||||
void Entity::Draw(bool drawAsHidden) {
|
||||
hStyle hs = Style::ForEntity(h);
|
||||
dogd.lineWidth = Style::Width(hs);
|
||||
dogd.stippleType = Style::PatternType(hs);
|
||||
dogd.stippleScale = Style::StippleScaleMm(hs);
|
||||
if(drawAsHidden) {
|
||||
dogd.stippleType = Style::PatternType({ Style::HIDDEN_EDGE });
|
||||
dogd.stippleScale = Style::StippleScaleMm({ Style::HIDDEN_EDGE });
|
||||
} else {
|
||||
dogd.stippleType = Style::PatternType(hs);
|
||||
dogd.stippleScale = Style::StippleScaleMm(hs);
|
||||
}
|
||||
ssglLineWidth((float)dogd.lineWidth);
|
||||
ssglColorRGB(Style::Color(hs));
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ void SolveSpaceUI::ExportViewOrWireframeTo(const std::string &filename, bool wir
|
|||
GenerateAll(GENERATE_ALL);
|
||||
|
||||
SMesh *sm = NULL;
|
||||
if(SS.GW.showShaded) {
|
||||
if(SS.GW.showShaded || SS.GW.showHdnLines) {
|
||||
Group *g = SK.GetGroup(SS.GW.activeGroup);
|
||||
g->GenerateDisplayItems();
|
||||
sm = &(g->displayMesh);
|
||||
|
@ -136,8 +136,7 @@ void SolveSpaceUI::ExportViewOrWireframeTo(const std::string &filename, bool wir
|
|||
if(!e->IsVisible()) continue;
|
||||
if(e->construction) continue;
|
||||
|
||||
if(SS.exportPwlCurves || (sm && !SS.GW.showHdnLines) ||
|
||||
fabs(SS.exportOffset) > LENGTH_EPS)
|
||||
if(SS.exportPwlCurves || sm || fabs(SS.exportOffset) > LENGTH_EPS)
|
||||
{
|
||||
// We will be doing hidden line removal, which we can't do on
|
||||
// exact curves; so we need things broken down to pwls. Same
|
||||
|
@ -322,7 +321,7 @@ void SolveSpaceUI::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *s
|
|||
|
||||
// And now we perform hidden line removal if requested
|
||||
SEdgeList hlrd = {};
|
||||
if(sm && !SS.GW.showHdnLines) {
|
||||
if(sm) {
|
||||
SKdNode *root = SKdNode::From(&smp);
|
||||
|
||||
// Generate the edges where a curved surface turns from front-facing
|
||||
|
@ -344,19 +343,19 @@ void SolveSpaceUI::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *s
|
|||
continue;
|
||||
}
|
||||
|
||||
SEdgeList out = {};
|
||||
SEdgeList edges = {};
|
||||
// Split the original edge against the mesh
|
||||
out.AddEdge(se->a, se->b, se->auxA);
|
||||
root->OcclusionTestLine(*se, &out, cnt);
|
||||
edges.AddEdge(se->a, se->b, se->auxA);
|
||||
root->OcclusionTestLine(*se, &edges, cnt, /*removeHidden=*/!SS.GW.showHdnLines);
|
||||
// the occlusion test splits unnecessarily; so fix those
|
||||
out.MergeCollinearSegments(se->a, se->b);
|
||||
edges.MergeCollinearSegments(se->a, se->b);
|
||||
cnt++;
|
||||
// And add the results to our output
|
||||
SEdge *sen;
|
||||
for(sen = out.l.First(); sen; sen = out.l.NextAfter(sen)) {
|
||||
for(sen = edges.l.First(); sen; sen = edges.l.NextAfter(sen)) {
|
||||
hlrd.AddEdge(sen->a, sen->b, sen->auxA);
|
||||
}
|
||||
out.Clear();
|
||||
edges.Clear();
|
||||
}
|
||||
|
||||
sel = &hlrd;
|
||||
|
@ -516,6 +515,12 @@ void SolveSpaceUI::ExportLinesAndMesh(SEdgeList *sel, SBezierList *sbl, SMesh *s
|
|||
sblss.AddOpenPath(b);
|
||||
}
|
||||
|
||||
// We need the mesh for occlusion testing, but if we don't export it,
|
||||
// erase it now.
|
||||
if(!SS.GW.showShaded) {
|
||||
sms.Clear();
|
||||
}
|
||||
|
||||
// Now write the lines and triangles to the output file
|
||||
out->OutputLinesAndMesh(&sblss, &sms);
|
||||
|
||||
|
|
|
@ -562,15 +562,19 @@ void ssglDebugPolygon(SPolygon *p)
|
|||
}
|
||||
}
|
||||
|
||||
void ssglDrawEdges(SEdgeList *el, bool endpointsToo)
|
||||
void ssglDrawEdges(SEdgeList *el, bool endpointsToo, hStyle hs)
|
||||
{
|
||||
double lineWidth = Style::Width(hs);
|
||||
int stippleType = Style::PatternType(hs);
|
||||
double stippleScale = Style::StippleScaleMm(hs);
|
||||
ssglLineWidth(float(lineWidth));
|
||||
ssglColorRGB(Style::Color(hs));
|
||||
|
||||
SEdge *se;
|
||||
glBegin(GL_LINES);
|
||||
for(se = el->l.First(); se; se = el->l.NextAfter(se)) {
|
||||
ssglVertex3v(se->a);
|
||||
ssglVertex3v(se->b);
|
||||
ssglStippledLine(se->a, se->b, lineWidth, stippleType, stippleScale,
|
||||
/*maybeFat=*/true);
|
||||
}
|
||||
glEnd();
|
||||
|
||||
if(endpointsToo) {
|
||||
glPointSize(12);
|
||||
|
|
|
@ -476,7 +476,7 @@ void Group::DrawDisplayItems(int t) {
|
|||
if(gs.faces > 0) ms1 = gs.face[0].v;
|
||||
if(gs.faces > 1) ms2 = gs.face[1].v;
|
||||
|
||||
if(SS.GW.showShaded) {
|
||||
if(SS.GW.showShaded || SS.GW.showHdnLines) {
|
||||
if(SS.drawBackFaces && !displayMesh.isTransparent) {
|
||||
// For debugging, draw the backs of the triangles in red, so that we
|
||||
// notice when a shell is open
|
||||
|
@ -485,16 +485,26 @@ void Group::DrawDisplayItems(int t) {
|
|||
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
|
||||
}
|
||||
|
||||
// Draw the shaded solid into the depth buffer for hidden line removal,
|
||||
// and if we're actually going to display it, to the color buffer too.
|
||||
glEnable(GL_LIGHTING);
|
||||
if(!SS.GW.showShaded) glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||
ssglFillMesh(useSpecColor, specColor, &displayMesh, mh, ms1, ms2);
|
||||
if(!SS.GW.showShaded) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
if(SS.GW.showEdges) {
|
||||
glDepthMask(GL_FALSE);
|
||||
if(SS.GW.showHdnLines) {
|
||||
ssglDepthRangeOffset(0);
|
||||
glDepthFunc(GL_GREATER);
|
||||
ssglDrawEdges(&displayEdges, false, { Style::HIDDEN_EDGE });
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
}
|
||||
ssglDepthRangeOffset(2);
|
||||
ssglColorRGB(Style::Color(Style::SOLID_EDGE));
|
||||
ssglLineWidth(Style::Width(Style::SOLID_EDGE));
|
||||
ssglDrawEdges(&displayEdges, false);
|
||||
ssglDrawEdges(&displayEdges, false, { Style::SOLID_EDGE });
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
if(SS.GW.showMesh) ssglDebugMesh(&displayMesh);
|
||||
|
|
Binary file not shown.
Before ![]() (image error) Size: 26 KiB After ![]() (image error) Size: 544 B ![]() ![]() |
15
src/mesh.cpp
15
src/mesh.cpp
|
@ -653,7 +653,7 @@ void SKdNode::SnapToMesh(SMesh *m) {
|
|||
// them for occlusion. Keep only the visible segments. sel is both our input
|
||||
// and our output.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SKdNode::SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr) {
|
||||
void SKdNode::SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr, bool removeHidden) {
|
||||
SEdgeList seln = {};
|
||||
|
||||
Vector tn = tr->Normal().WithMagnitude(1);
|
||||
|
@ -754,8 +754,11 @@ void SKdNode::SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr) {
|
|||
if(n[i].Dot(pt) - d[i] > LENGTH_EPS) se->tag = 0;
|
||||
}
|
||||
}
|
||||
if(!removeHidden && se->tag == 1)
|
||||
se->auxA = Style::HIDDEN_EDGE;
|
||||
}
|
||||
sel->l.RemoveTagged();
|
||||
if(removeHidden)
|
||||
sel->l.RemoveTagged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -763,7 +766,7 @@ void SKdNode::SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr) {
|
|||
// Given an edge orig, occlusion test it against our mesh. We output an edge
|
||||
// list in sel, containing the visible portions of that edge.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SKdNode::OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt) {
|
||||
void SKdNode::OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt, bool removeHidden) {
|
||||
if(gt && lt) {
|
||||
double ac = (orig.a).Element(which),
|
||||
bc = (orig.b).Element(which);
|
||||
|
@ -773,13 +776,13 @@ void SKdNode::OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt) {
|
|||
bc < c + KDTREE_EPS ||
|
||||
which == 2)
|
||||
{
|
||||
lt->OcclusionTestLine(orig, sel, cnt);
|
||||
lt->OcclusionTestLine(orig, sel, cnt, removeHidden);
|
||||
}
|
||||
if(ac > c - KDTREE_EPS ||
|
||||
bc > c - KDTREE_EPS ||
|
||||
which == 2)
|
||||
{
|
||||
gt->OcclusionTestLine(orig, sel, cnt);
|
||||
gt->OcclusionTestLine(orig, sel, cnt, removeHidden);
|
||||
}
|
||||
} else {
|
||||
STriangleLl *ll;
|
||||
|
@ -788,7 +791,7 @@ void SKdNode::OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt) {
|
|||
|
||||
if(tr->tag == cnt) continue;
|
||||
|
||||
SplitLinesAgainstTriangle(sel, tr);
|
||||
SplitLinesAgainstTriangle(sel, tr, removeHidden);
|
||||
tr->tag = cnt;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -453,7 +453,7 @@ void SEdgeList::MergeCollinearSegments(Vector a, Vector b) {
|
|||
SEdge *prev = &(l.elem[i-1]),
|
||||
*now = &(l.elem[i]);
|
||||
|
||||
if((prev->b).Equals(now->a)) {
|
||||
if((prev->b).Equals(now->a) && prev->auxA == now->auxA) {
|
||||
// The previous segment joins up to us; so merge it into us.
|
||||
prev->tag = 1;
|
||||
now->a = prev->a;
|
||||
|
|
|
@ -306,8 +306,8 @@ public:
|
|||
void MakeCertainEdgesInto(SEdgeList *sel, int how, bool coplanarIsInter,
|
||||
bool *inter, bool *leaky);
|
||||
|
||||
void OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt);
|
||||
void SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr);
|
||||
void OcclusionTestLine(SEdge orig, SEdgeList *sel, int cnt, bool removeHidden);
|
||||
void SplitLinesAgainstTriangle(SEdgeList *sel, STriangle *tr, bool removeHidden);
|
||||
|
||||
void SnapToMesh(SMesh *m);
|
||||
void SnapToVertex(Vector v, SMesh *extras);
|
||||
|
|
|
@ -505,8 +505,8 @@ public:
|
|||
void GenerateBezierCurves(SBezierList *sbl);
|
||||
void GenerateEdges(SEdgeList *el, bool includingConstruction=false);
|
||||
|
||||
static void DrawAll(void);
|
||||
void Draw(void);
|
||||
static void DrawAll(bool drawAsHidden);
|
||||
void Draw(bool drawAsHidden);
|
||||
double GetDistance(Point2d mp);
|
||||
Vector GetReferencePos(void);
|
||||
|
||||
|
@ -767,6 +767,7 @@ public:
|
|||
ANALYZE = 11,
|
||||
DRAW_ERROR = 12,
|
||||
DIM_SOLID = 13,
|
||||
HIDDEN_EDGE = 14,
|
||||
|
||||
FIRST_CUSTOM = 0x100
|
||||
};
|
||||
|
|
|
@ -345,7 +345,7 @@ void ssglFillPolygon(SPolygon *p);
|
|||
void ssglFillMesh(bool useSpecColor, RgbaColor color,
|
||||
SMesh *m, uint32_t h, uint32_t s1, uint32_t s2);
|
||||
void ssglDebugPolygon(SPolygon *p);
|
||||
void ssglDrawEdges(SEdgeList *l, bool endpointsToo);
|
||||
void ssglDrawEdges(SEdgeList *l, bool endpointsToo, hStyle hs);
|
||||
void ssglDebugMesh(SMesh *m);
|
||||
void ssglMarkPolygonNormal(SPolygon *p);
|
||||
typedef void ssglLineFn(void *data, Vector a, Vector b);
|
||||
|
|
|
@ -24,6 +24,7 @@ const Style::Default Style::Defaults[] = {
|
|||
{ { ANALYZE }, "Analyze", RGBf(0.0, 1.0, 1.0), 1.0, 0 },
|
||||
{ { DRAW_ERROR }, "DrawError", RGBf(1.0, 0.0, 0.0), 8.0, 0 },
|
||||
{ { DIM_SOLID }, "DimSolid", RGBf(0.1, 0.1, 0.1), 1.0, 0 },
|
||||
{ { HIDDEN_EDGE }, "HiddenEdge", RGBf(0.8, 0.8, 0.8), 2.0, 1 },
|
||||
{ { 0 }, NULL, RGBf(0.0, 0.0, 0.0), 0.0, 0 }
|
||||
};
|
||||
|
||||
|
@ -94,7 +95,8 @@ void Style::FillDefaultStyle(Style *s, const Default *d) {
|
|||
s->exportable = true;
|
||||
s->filled = false;
|
||||
s->fillColor = RGBf(0.3, 0.3, 0.3);
|
||||
s->stippleType = Style::STIPPLE_CONTINUOUS;
|
||||
s->stippleType = (d->h.v == Style::HIDDEN_EDGE) ? Style::STIPPLE_DASH
|
||||
: Style::STIPPLE_CONTINUOUS;
|
||||
s->stippleScale = 15.0;
|
||||
s->zIndex = d->zIndex;
|
||||
}
|
||||
|
@ -828,43 +830,41 @@ void TextWindow::ShowStyleInfo(void) {
|
|||
SS.UnitName());
|
||||
}
|
||||
|
||||
if(s->h.v >= Style::FIRST_CUSTOM) {
|
||||
Printf(false,"%Ba %Ftstipple type:%E");
|
||||
Printf(false,"%Ba %Ftstipple type:%E");
|
||||
|
||||
const size_t patternCount = Style::LAST_STIPPLE + 1;
|
||||
const char *patternsSource[patternCount] = {
|
||||
"___________",
|
||||
"- - - - - -",
|
||||
"__ __ __ __",
|
||||
"-.-.-.-.-.-",
|
||||
"..-..-..-..",
|
||||
"...........",
|
||||
"~~~~~~~~~~~",
|
||||
"__~__~__~__"
|
||||
};
|
||||
std::string patterns[patternCount];
|
||||
const size_t patternCount = Style::LAST_STIPPLE + 1;
|
||||
const char *patternsSource[patternCount] = {
|
||||
"___________",
|
||||
"- - - - - -",
|
||||
"__ __ __ __",
|
||||
"-.-.-.-.-.-",
|
||||
"..-..-..-..",
|
||||
"...........",
|
||||
"~~~~~~~~~~~",
|
||||
"__~__~__~__"
|
||||
};
|
||||
std::string patterns[patternCount];
|
||||
|
||||
for(int i = 0; i <= Style::LAST_STIPPLE; i++) {
|
||||
const char *str = patternsSource[i];
|
||||
do {
|
||||
switch(*str) {
|
||||
case ' ': patterns[i] += " "; break;
|
||||
case '.': patterns[i] += "\xEE\x80\x84"; break;
|
||||
case '_': patterns[i] += "\xEE\x80\x85"; break;
|
||||
case '-': patterns[i] += "\xEE\x80\x86"; break;
|
||||
case '~': patterns[i] += "\xEE\x80\x87"; break;
|
||||
default: oops();
|
||||
}
|
||||
} while(*(++str));
|
||||
}
|
||||
for(int i = 0; i <= Style::LAST_STIPPLE; i++) {
|
||||
const char *str = patternsSource[i];
|
||||
do {
|
||||
switch(*str) {
|
||||
case ' ': patterns[i] += " "; break;
|
||||
case '.': patterns[i] += "\xEE\x80\x84"; break;
|
||||
case '_': patterns[i] += "\xEE\x80\x85"; break;
|
||||
case '-': patterns[i] += "\xEE\x80\x86"; break;
|
||||
case '~': patterns[i] += "\xEE\x80\x87"; break;
|
||||
default: oops();
|
||||
}
|
||||
} while(*(++str));
|
||||
}
|
||||
|
||||
for(int i = 0; i <= Style::LAST_STIPPLE; i++) {
|
||||
const char *radio = s->stippleType == i ? RADIO_TRUE : RADIO_FALSE;
|
||||
Printf(false, "%Bp %D%f%Lp%s %s%E",
|
||||
(i % 2 == 0) ? 'd' : 'a',
|
||||
s->h.v, &ScreenChangeStylePatternType,
|
||||
i + 1, radio, patterns[i].c_str());
|
||||
}
|
||||
for(int i = 0; i <= Style::LAST_STIPPLE; i++) {
|
||||
const char *radio = s->stippleType == i ? RADIO_TRUE : RADIO_FALSE;
|
||||
Printf(false, "%Bp %D%f%Lp%s %s%E",
|
||||
(i % 2 == 0) ? 'd' : 'a',
|
||||
s->h.v, &ScreenChangeStylePatternType,
|
||||
i + 1, radio, patterns[i].c_str());
|
||||
}
|
||||
|
||||
if(s->h.v >= Style::FIRST_CUSTOM) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user