Make the extrude command do a bit more; now I generate all the

faces of the polyhedron. And shade the faces when I draw them, and
fix up our projection matrix so that the depth testing works
properly.

[git-p4: depot-paths = "//depot/solvespace/": change = 1703]
This commit is contained in:
Jonathan Westhues 2008-05-02 02:54:22 -08:00
parent 658b7df50f
commit 30636a6f29
10 changed files with 202 additions and 51 deletions

View File

@ -234,9 +234,14 @@ void Entity::PointGetExprsInWorkplane(hEntity wrkpl, Expr **u, Expr **v) {
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
if(dogd.drawing) {
// This fudge guarantees that the line will get drawn in front of
// anything else at the "same" depth in the z-buffer, so that it
// goes in front of the shaded stuff.
Vector n = SS.GW.projRight.Cross(SS.GW.projUp);
n = n.WithMagnitude(1.2/SS.GW.scale);
glBegin(GL_LINE_STRIP);
glxVertex3v(a);
glxVertex3v(b);
glxVertex3v(a.Plus(n));
glxVertex3v(b.Plus(n));
glEnd();
} else {
Point2d ap = SS.GW.ProjectPoint(a);

View File

@ -133,6 +133,9 @@ void glxFillPolygon(SPolygon *p)
gluTessCallback(gt, GLU_TESS_COMBINE, (cf *)Combine);
gluTessProperty(gt, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
Vector normal = p->Normal();
glNormal3d(normal.x, normal.y, normal.z);
gluTessBeginPolygon(gt, NULL);
for(i = 0; i < p->l.n; i++) {
SContour *sc = &(p->l.elem[i]);

View File

@ -108,8 +108,10 @@ void GraphicsWindow::Init(void) {
showWorkplanes = true;
showAxes = true;
showPoints = true;
showAllGroups = true;
showConstraints = true;
showSolids = true;
showHdnLines = false;
showSolids = true;
solving = SOLVE_ALWAYS;
@ -443,6 +445,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
if(pendingOperation == DRAGGING_NEW_POINT ||
pendingOperation == DRAGGING_NEW_LINE_POINT)
{
SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
UpdateDraggedEntity(pendingPoint, x, y);
HitTestMakeSelection(mp);
} else if(pendingOperation == DRAGGING_NEW_CUBIC_POINT) {
@ -690,6 +693,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
break;
}
}
SS.GenerateAll(SS.GW.solving == SOLVE_ALWAYS);
SS.TW.Show();
InvalidateGraphics();
@ -777,6 +781,15 @@ void GraphicsWindow::ToggleAnyDatumShown(int link, DWORD v) {
SS.TW.Show();
}
Vector GraphicsWindow::VectorFromProjs(double right, double up, double fwd) {
Vector n = projRight.Cross(projUp);
Vector r = offset.ScaledBy(-1);
r = r.Plus(projRight.ScaledBy(right));
r = r.Plus(projUp.ScaledBy(up));
r = r.Plus(n.ScaledBy(fwd));
return r;
}
void GraphicsWindow::Paint(int w, int h) {
havePainted = true;
width = w; height = h;
@ -786,57 +799,73 @@ void GraphicsWindow::Paint(int w, int h) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScaled(scale*2.0/w, scale*2.0/h, 0);
glScaled(scale*2.0/w, scale*2.0/h, scale*2.0/w);
double tx = projRight.Dot(offset);
double ty = projUp.Dot(offset);
Vector n = projUp.Cross(projRight);
double tz = n.Dot(offset);
double mat[16];
MakeMatrix(mat, projRight.x, projRight.y, projRight.z, tx,
projUp.x, projUp.y, projUp.z, ty,
0, 0, 0, 0,
n.x, n.y, n.z, tz,
0, 0, 0, 1);
glMultMatrixd(mat);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glShadeModel(GL_SMOOTH);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_DEPTH_TEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_NORMALIZE);
glClearIndex((GLfloat)0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Vector light = VectorFromProjs(-0.49*w/scale, 0.49*h/scale, 0);
GLfloat lightPos[4] =
{ (GLfloat)light.x, (GLfloat)light.y, (GLfloat)light.z, 0 };
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glEnable(GL_LIGHT0);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1);
GLfloat ambient[4] = { 0.4f, 0.4f, 0.4f, 1.0f };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
glxUnlockColor();
int i, a;
// Draw the groups; this fills the polygons, if requested.
if(showSolids) {
for(i = 0; i < SS.group.n; i++) {
SS.group.elem[i].Draw();
}
}
// First, draw the entire scene. We don't necessarily want to draw
// things with normal z-buffering behaviour; e.g. we always want to
// draw a line segment in front of a reference. So we have three draw
// levels, and only the first gets normal depth testing.
glxUnlockColor();
for(a = 0; a <= 2; a++) {
// Three levels: 0 least prominent (e.g. a reference workplane), 1 is
// middle (e.g. line segment), 2 is always in front (e.g. point).
if(a == 1) glDisable(GL_DEPTH_TEST);
if(a >= 1 && showHdnLines) glDisable(GL_DEPTH_TEST);
for(i = 0; i < SS.entity.n; i++) {
SS.entity.elem[i].Draw(a);
}
}
glDisable(GL_DEPTH_TEST);
// Draw the constraints
for(i = 0; i < SS.constraint.n; i++) {
SS.constraint.elem[i].Draw();
}
// Draw the groups; this fills the polygons, if requested.
for(i = 0; i < SS.group.n; i++) {
SS.group.elem[i].Draw();
}
// Then redraw whatever the mouse is hovering over, highlighted.
glDisable(GL_DEPTH_TEST);
glxLockColorTo(1, 1, 0);

View File

@ -76,3 +76,45 @@ void SPolygon::AddPoint(Vector p) {
(l.elem[l.n-1]).l.Add(&sp);
}
void SPolygon::MakeEdgesInto(SEdgeList *el) {
int i;
for(i = 0; i < l.n; i++) {
(l.elem[i]).MakeEdgesInto(el);
}
}
Vector SPolygon::Normal(void) {
if(l.n < 1) return Vector::MakeFrom(0, 0, 0);
return (l.elem[0]).Normal();
}
void SContour::MakeEdgesInto(SEdgeList *el) {
int i;
for(i = 0; i < (l.n-1); i++) {
SEdge e;
e.a = l.elem[i].p;
e.b = l.elem[i+1].p;
el->l.Add(&e);
}
}
Vector SContour::Normal(void) {
if(l.n < 3) return Vector::MakeFrom(0, 0, 0);
Vector u = (l.elem[0].p).Minus(l.elem[1].p);
Vector v;
double dot = 2;
// Find the edge in the contour that's closest to perpendicular to the
// first edge, since that will give best numerical stability.
for(int i = 1; i < (l.n-1); i++) {
Vector vt = (l.elem[i].p).Minus(l.elem[i+1].p);
double dott = fabs(vt.Dot(u)/(u.Magnitude()*vt.Magnitude()));
if(dott < dot) {
dot = dott;
v = vt;
}
}
return (u.Cross(v)).WithMagnitude(1);
}

View File

@ -55,14 +55,19 @@ public:
class SContour {
public:
SList<SPoint> l;
void MakeEdgesInto(SEdgeList *el);
Vector Normal(void);
};
class SPolygon {
public:
SList<SContour> l;
Vector Normal(void);
void AddEmptyContour(void);
void AddPoint(Vector p);
void MakeEdgesInto(SEdgeList *el);
void Clear(void);
};

View File

@ -134,39 +134,98 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz) {
SS.entity.Add(&en);
}
void Group::MakePolygons(void) {
faces.Clear();
if(type == DRAWING) {
edges.l.Clear();
int i;
for(i = 0; i < SS.entity.n; i++) {
Entity *e = &(SS.entity.elem[i]);
if(e->group.v != h.v) continue;
e->GenerateEdges(&edges);
}
SPolygon poly;
memset(&poly, 0, sizeof(poly));
SEdge error;
if(edges.AssemblePolygon(&poly, &error)) {
polyError.yes = false;
faces.Add(&poly);
} else {
polyError.yes = true;
polyError.notClosedAt = error;
poly.Clear();
}
} else if(type == EXTRUDE) {
Vector translate;
translate.x = SS.GetParam(h.param(0))->val;
translate.y = SS.GetParam(h.param(1))->val;
translate.z = SS.GetParam(h.param(2))->val;
edges.l.Clear();
Group *src = SS.GetGroup(opA);
if(src->faces.n != 1) return;
(src->faces.elem[0]).MakeEdgesInto(&edges);
SPolygon poly;
SEdge error;
// The bottom
memset(&poly, 0, sizeof(poly));
if(!edges.AssemblePolygon(&poly, &error)) oops();
faces.Add(&poly);
// The sides
int i;
for(i = 0; i < edges.l.n; i++) {
SEdge *edge = &(edges.l.elem[i]);
memset(&poly, 0, sizeof(poly));
poly.AddEmptyContour();
poly.AddPoint(edge->a);
poly.AddPoint(edge->b);
poly.AddPoint((edge->b).Plus(translate));
poly.AddPoint((edge->a).Plus(translate));
poly.AddPoint(edge->a);
faces.Add(&poly);
edge->a = (edge->a).Plus(translate);
edge->b = (edge->b).Plus(translate);
}
// The top
memset(&poly, 0, sizeof(poly));
if(!edges.AssemblePolygon(&poly, &error)) oops();
faces.Add(&poly);
}
}
void Group::Draw(void) {
if(!visible) return;
edges.l.Clear();
int i;
for(i = 0; i < SS.entity.n; i++) {
Entity *e = &(SS.entity.elem[i]);
if(e->group.v != h.v) continue;
e->GenerateEdges(&edges);
}
SPolygon poly;
memset(&poly, 0, sizeof(poly));
SEdge error;
if(edges.AssemblePolygon(&poly, &error)) {
glxColor4d(0, 0, 1, 0.1);
glxFillPolygon(&poly);
} else {
if(polyError.yes) {
glxColor4d(1, 0, 0, 0.2);
glLineWidth(10);
glBegin(GL_LINES);
glxVertex3v(error.a);
glxVertex3v(error.b);
glxVertex3v(polyError.notClosedAt.a);
glxVertex3v(polyError.notClosedAt.b);
glEnd();
glLineWidth(1);
glxColor3d(1, 0, 0);
glPushMatrix();
glxTranslatev(error.b);
glxTranslatev(polyError.notClosedAt.b);
glxOntoWorkplane(SS.GW.projRight, SS.GW.projUp);
glxWriteText("not closed contour!");
glPopMatrix();
} else {
int i;
glEnable(GL_LIGHTING);
GLfloat vec[] = { 0, 0, 0.5, 1.0 };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec);
for(i = 0; i < faces.n; i++) {
glxFillPolygon(&(faces.elem[i]));
}
glDisable(GL_LIGHTING);
}
poly.Clear();
}
hParam Request::AddParam(IdList<Param,hParam> *param, hParam hp) {

View File

@ -85,8 +85,12 @@ public:
hGroup opB;
bool visible;
SEdgeList edges;
SPolygon poly;
SEdgeList edges;
SList<SPolygon> faces;
struct {
SEdge notClosedAt;
bool yes;
} polyError;
NameStr name;
char *DescriptionString(void);
@ -101,6 +105,7 @@ public:
hEntity Remap(hEntity in, int copyNumber);
void CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz);
void MakePolygons(void);
void Draw(void);
SPolygon GetPolygon(void);

View File

@ -60,6 +60,8 @@ void SolveSpace::GenerateAll(bool andSolve) {
// Solve this group.
if(andSolve) SolveGroup(g->h);
}
g->MakePolygons();
}
prev.Clear();

View File

@ -217,17 +217,14 @@ void TextWindow::ShowHeader(void) {
SS.GW.EnsureValidActives();
char *cd = (SS.GW.activeWorkplane.v == Entity::FREE_IN_3D.v) ?
"free in 3d" :
SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString();
// Navigation buttons
if(SS.GW.pendingDescription) {
Printf(false, " %Bt%Ft group:%s",
SS.group.FindById(SS.GW.activeGroup)->DescriptionString());
Printf(false, " %Bt%Ft workplane:%Fd %s", cd);
} else {
// Navigation buttons
char *cd;
if(SS.GW.activeWorkplane.v == Entity::FREE_IN_3D.v) {
cd = "free in 3d";
} else {
cd = SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString();
}
Printf(false, " %Lb%f<<%E %Lh%fhome%E %Bt%Ft workplane:%Fd %s",
(&TextWindow::ScreenNavigation),
(&TextWindow::ScreenNavigation),
@ -255,10 +252,12 @@ void TextWindow::ShowHeader(void) {
datumColor, &(SS.GW.ToggleAnyDatumShown)
);
Printf(false, "%Bt%Ft "
"%Fp%Ll%D%fall-groups%E "
"%Fp%Ll%D%fconstraints%E",
hs(SS.GW.showAllGroups), (DWORD)(&SS.GW.showAllGroups), &(SS.GW.ToggleBool),
hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), &(SS.GW.ToggleBool)
"%Fp%Ll%D%fconstraints%E "
"%Fp%Ll%D%fsolids%E "
"%Fp%Ll%D%fhidden-lines%E",
hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), &(SS.GW.ToggleBool),
hs(SS.GW.showSolids), (DWORD)(&SS.GW.showSolids), &(SS.GW.ToggleBool),
hs(SS.GW.showHdnLines), (DWORD)(&SS.GW.showHdnLines), &(SS.GW.ToggleBool)
);
}

4
ui.h
View File

@ -155,6 +155,7 @@ public:
void NormalizeProjectionVectors(void);
Point2d ProjectPoint(Vector p);
void AnimateOnto(Quaternion quatf, Vector offsetf);
Vector VectorFromProjs(double right, double up, double forward);
typedef enum {
UNIT_MM = 0,
@ -215,9 +216,10 @@ public:
bool showWorkplanes;
bool showAxes;
bool showPoints;
bool showAllGroups;
bool showConstraints;
bool showTextWindow;
bool showSolids;
bool showHdnLines;
static void ToggleBool(int link, DWORD v);
static void ToggleAnyDatumShown(int link, DWORD v);