Move colors and line widths for almost everything to the styles

mechanism. This gets filled in from some defaults, and stored in
the registry. The default styles do not get saved in the file, but
user-created styles (which aren't supported yet) do.

[git-p4: depot-paths = "//depot/solvespace/": change = 2028]
This commit is contained in:
Jonathan Westhues 2009-09-16 23:32:36 -08:00
parent e989c86a38
commit ce99217bbb
14 changed files with 347 additions and 119 deletions

View File

@ -1,7 +1,7 @@
DEFINES = /D_WIN32_WINNT=0x500 /DISOLATION_AWARE_ENABLED /D_WIN32_IE=0x500 /DWIN32_LEAN_AND_MEAN /DWIN32
# Use the multi-threaded static libc because libpng and zlib do; not sure if anything bad
# happens if those mix, but don't want to risk it.
CFLAGS = /W3 /nologo -MT -Iextlib -I..\common\win32 /D_DEBUG /D_CRT_SECURE_NO_WARNINGS /I. /Zi /EHs /O2
CFLAGS = /W3 /nologo -MT -Iextlib -I..\common\win32 /D_DEBUG /D_CRT_SECURE_NO_WARNINGS /I. /Zi /EHs # /O2
HEADERS = ..\common\win32\freeze.h ui.h solvespace.h dsc.h sketch.h expr.h polygon.h srf\surface.h
@ -61,7 +61,7 @@ LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib shell32.lib opengl32.lib g
all: $(OBJDIR)/solvespace.exe
@cp $(OBJDIR)/solvespace.exe .
solvespace fail.slvs
solvespace t8.slvs
clean:
rm -f obj/*

View File

@ -798,11 +798,9 @@ void GraphicsWindow::Selection::Clear(void) {
void GraphicsWindow::Selection::Draw(void) {
Vector refp;
if(entity.v) {
glLineWidth(1.5);
Entity *e = SK.GetEntity(entity);
e->Draw();
if(emphasized) refp = e->GetReferencePos();
glLineWidth(1);
}
if(constraint.v) {
Constraint *c = SK.GetConstraint(constraint);
@ -810,13 +808,17 @@ void GraphicsWindow::Selection::Draw(void) {
if(emphasized) refp = c->GetReferencePos();
}
if(emphasized && (constraint.v || entity.v)) {
// We want to emphasize this constraint or entity, by drawing a thick
// line from the top left corner of the screen to the reference point
// of that entity or constraint.
double s = 0.501/SS.GW.scale;
Vector topLeft = SS.GW.projRight.ScaledBy(-SS.GW.width*s);
topLeft = topLeft.Plus(SS.GW.projUp.ScaledBy(SS.GW.height*s));
topLeft = topLeft.Minus(SS.GW.offset);
glLineWidth(40);
glColor4d(1.0, 1.0, 0, 0.2);
DWORD rgb = Style::Color(Style::HOVERED);
glColor4d(REDf(rgb), GREENf(rgb), BLUEf(rgb), 0.2);
glBegin(GL_LINES);
glxVertex3v(topLeft);
glxVertex3v(refp);
@ -1018,8 +1020,9 @@ void GraphicsWindow::Paint(int w, int h) {
if(SS.AllGroupsOkay()) {
glClearColor(0, 0, 0, 1.0f);
} else {
// Draw a red background whenever we're having solve problems.
glClearColor(0.4f, 0, 0, 1.0f);
// Draw a different background whenever we're having solve problems.
DWORD rgb = Style::Color(Style::DRAW_ERROR);
glClearColor(0.4f*REDf(rgb), 0.4f*GREENf(rgb), 0.4f*BLUEf(rgb), 1.0f);
// And show the text window, which has info to debug it
ForceTextWindowShown();
}
@ -1085,8 +1088,8 @@ void GraphicsWindow::Paint(int w, int h) {
}
// Draw the traced path, if one exists
glLineWidth(1);
glColor3d(0, 1, 1);
glLineWidth(Style::Width(Style::ANALYZE));
glxColorRGB(Style::Color(Style::ANALYZE));
SContour *sc = &(SS.traced.path);
glBegin(GL_LINE_STRIP);
for(i = 0; i < sc->l.n; i++) {
@ -1095,21 +1098,23 @@ void GraphicsWindow::Paint(int w, int h) {
glEnd();
// And the naked edges, if the user did Analyze -> Show Naked Edges.
glLineWidth(7);
glColor3d(1, 0, 0);
glLineWidth(Style::Width(Style::DRAW_ERROR));
glxColorRGB(Style::Color(Style::DRAW_ERROR));
glxDrawEdges(&(SS.nakedEdges), true);
// Then redraw whatever the mouse is hovering over, highlighted.
glDisable(GL_DEPTH_TEST);
glxLockColorTo(1, 1, 0);
glxLockColorTo(Style::Color(Style::HOVERED));
hover.Draw();
// And finally draw the selection, same mechanism.
glxLockColorTo(1, 0, 0);
glxLockColorTo(Style::Color(Style::SELECTED));
for(i = 0; i < MAX_SELECTED; i++) {
selection[i].Draw();
}
glxUnlockColor();
// And finally the toolbar.
if(SS.showToolbar) {
ToolbarDraw();

View File

@ -350,7 +350,6 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
Vector gu = SS.GW.projUp.ScaledBy(1/SS.GW.scale);
Vector gn = (gr.Cross(gu)).WithMagnitude(1/SS.GW.scale);
glxColor3d(1, 0.1, 1);
switch(type) {
case PT_PT_DISTANCE: {
Vector ap = SK.GetEntity(ptA)->PointGetNum();
@ -465,12 +464,25 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
break;
}
// Let's adjust the color of this constraint to have the same
// rough luma as the point color, so that the constraint does not
// stand out in an ugly way.
DWORD cd = Style::Color(Style::DATUM),
cc = Style::Color(Style::CONSTRAINT);
// convert from 8-bit color to a vector
Vector vd = Vector::From(REDf(cd), GREENf(cd), BLUEf(cd)),
vc = Vector::From(REDf(cc), GREENf(cc), BLUEf(cc));
// and scale the constraint color to have the same magnitude as
// the datum color, maybe a bit dimmer
vc = vc.WithMagnitude(vd.Magnitude()*0.9);
// and set the color to that.
glxColorRGB(RGBf(vc.x, vc.y, vc.z));
for(int a = 0; a < 2; a++) {
Vector r = SS.GW.projRight.ScaledBy((a+1)/SS.GW.scale);
Vector d = SS.GW.projUp.ScaledBy((2-a)/SS.GW.scale);
for(int i = 0; i < 2; i++) {
Vector p = SK.GetEntity(i == 0 ? ptA : ptB)-> PointGetNum();
glxColor3d(0.4, 0, 0.4);
glBegin(GL_QUADS);
glxVertex3v(p.Plus (r).Plus (d));
glxVertex3v(p.Plus (r).Minus(d));
@ -878,7 +890,10 @@ s:
void Constraint::Draw(void) {
dogd.drawing = true;
dogd.sel = NULL;
glLineWidth(1);
glLineWidth(Style::Width(Style::CONSTRAINT));
glxColorRGB(Style::Color(Style::CONSTRAINT));
DrawOrGetDistance(NULL);
}

View File

@ -40,7 +40,7 @@ void Entity::DrawAll(void) {
double s = 3.5/SS.GW.scale;
Vector r = SS.GW.projRight.ScaledBy(s);
Vector d = SS.GW.projUp.ScaledBy(s);
glxColor3d(0, 0.8, 0);
glxColorRGB(Style::Color(Style::DATUM));
glxDepthRangeOffset(6);
glBegin(GL_QUADS);
for(i = 0; i < SK.entity.n; i++) {
@ -52,6 +52,9 @@ void Entity::DrawAll(void) {
Vector v = e->PointGetNum();
// If we're analyzing the sketch to show the degrees of freedom,
// then we draw big colored squares over the points that are
// free to move.
bool free = false;
if(e->type == POINT_IN_3D) {
Param *px = SK.GetParam(e->param[0]),
@ -68,12 +71,12 @@ void Entity::DrawAll(void) {
if(free) {
Vector re = r.ScaledBy(2.5), de = d.ScaledBy(2.5);
glxColor3d(0, 1.0, 1.0);
glxColorRGB(Style::Color(Style::ANALYZE));
glxVertex3v(v.Plus (re).Plus (de));
glxVertex3v(v.Plus (re).Minus(de));
glxVertex3v(v.Minus(re).Minus(de));
glxVertex3v(v.Minus(re).Plus (de));
glxColor3d(0, 0.8, 0);
glxColorRGB(Style::Color(Style::DATUM));
}
glxVertex3v(v.Plus (r).Plus (d));
@ -85,7 +88,6 @@ void Entity::DrawAll(void) {
glxDepthRangeOffset(0);
}
glLineWidth(1.5);
for(i = 0; i < SK.entity.n; i++) {
Entity *e = &(SK.entity.elem[i]);
if(e->IsPoint())
@ -94,10 +96,13 @@ void Entity::DrawAll(void) {
}
e->Draw();
}
glLineWidth(1);
}
void Entity::Draw(void) {
hStyle hs = Style::ForEntity(h);
glLineWidth(Style::Width(hs));
glxColorRGB(Style::Color(hs));
dogd.drawing = true;
DrawOrGetDistance();
}
@ -302,14 +307,6 @@ void Entity::DrawOrGetDistance(void) {
Group *g = SK.GetGroup(group);
if(group.v != SS.GW.activeGroup.v) {
glxColor3d(0.5, 0.3, 0.0);
} else if(construction) {
glxColor3d(0.1, 0.7, 0.1);
} else {
glxColor3d(1, 1, 1);
}
switch(type) {
case POINT_N_COPY:
case POINT_N_TRANS:
@ -325,7 +322,7 @@ void Entity::DrawOrGetDistance(void) {
Vector r = SS.GW.projRight.ScaledBy(s/SS.GW.scale);
Vector d = SS.GW.projUp.ScaledBy(s/SS.GW.scale);
glxColor3d(0, 0.8, 0);
glxColorRGB(Style::Color(Style::DATUM));
glxDepthRangeOffset(6);
glBegin(GL_QUADS);
glxVertex3v(v.Plus (r).Plus (d));
@ -356,15 +353,18 @@ void Entity::DrawOrGetDistance(void) {
}
hRequest hr = h.request();
double f = (i == 0 ? 0.4 : 1);
// Always draw the x, y, and z axes in red, green, and blue;
// brighter for the ones at the bottom left of the screen,
// dimmer for the ones at the model origin.
int f = (i == 0 ? 100 : 255);
if(hr.v == Request::HREQUEST_REFERENCE_XY.v) {
glxColor3d(0, 0, f);
glxColorRGB(RGB(0, 0, f));
} else if(hr.v == Request::HREQUEST_REFERENCE_YZ.v) {
glxColor3d(f, 0, 0);
glxColorRGB(RGB(f, 0, 0));
} else if(hr.v == Request::HREQUEST_REFERENCE_ZX.v) {
glxColor3d(0, f, 0);
glxColorRGB(RGB(0, f, 0));
} else {
glxColor3d(0, 0.4, 0.4);
glxColorRGB(Style::Color(Style::NORMALS));
if(i > 0) break;
}
@ -396,7 +396,6 @@ void Entity::DrawOrGetDistance(void) {
LineDrawOrGetDistance(tip,tip.Minus(v.RotatedAbout(axis,-0.6)));
}
glxDepthRangeLockToFront(false);
glLineWidth(1.5);
break;
}
@ -423,7 +422,7 @@ void Entity::DrawOrGetDistance(void) {
Vector mp = p.Minus(us).Plus (vs);
glLineWidth(1);
glxColor3d(0, 0.3, 0.3);
glxColorRGB(Style::Color(Style::NORMALS));
glEnable(GL_LINE_STIPPLE);
glLineStipple(3, 0x1111);
if(!h.isFromRequest()) {
@ -436,7 +435,6 @@ void Entity::DrawOrGetDistance(void) {
LineDrawOrGetDistance(mm, mp);
LineDrawOrGetDistance(mp, pp);
glDisable(GL_LINE_STIPPLE);
glLineWidth(1.5);
char *str = DescriptionString()+5;
if(dogd.drawing) {

View File

@ -30,6 +30,7 @@ void SolveSpace::NewFile(void) {
SK.constraint.Clear();
SK.request.Clear();
SK.group.Clear();
SK.style.Clear();
SK.entity.Clear();
SK.param.Clear();
@ -150,6 +151,13 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z) },
{ 'c', "Constraint.disp.style", 'x', &(SS.sv.c.disp.style) },
{ 's', "Style.h.v", 'x', &(SS.sv.s.h.v) },
{ 's', "Style.width", 'f', &(SS.sv.s.width) },
{ 's', "Style.widthHow", 'd', &(SS.sv.s.widthHow) },
{ 's', "Style.color", 'x', &(SS.sv.s.color) },
{ 's', "Style.visible", 'b', &(SS.sv.s.visible) },
{ 's', "Style.exportable", 'b', &(SS.sv.s.exportable) },
{ 0, NULL, NULL, NULL },
};
@ -239,6 +247,14 @@ bool SolveSpace::SaveToFile(char *filename) {
fprintf(fh, "AddConstraint\n\n");
}
for(i = 0; i < SK.style.n; i++) {
sv.s = SK.style.elem[i];
if(sv.s.h.v >= Style::FIRST_CUSTOM) {
SaveUsingTable('s');
fprintf(fh, "AddStyle\n\n");
}
}
// A group will have either a mesh or a shell, but not both; but the code
// to print either of those just does nothing if the mesh/shell is empty.
@ -363,6 +379,7 @@ bool SolveSpace::LoadFromFile(char *filename) {
SK.group.Clear();
SK.entity.Clear();
SK.param.Clear();
SK.style.Clear();
memset(&sv, 0, sizeof(sv));
char line[1024];
@ -383,20 +400,23 @@ bool SolveSpace::LoadFromFile(char *filename) {
LoadUsingTable(key, val);
} else if(strcmp(line, "AddGroup")==0) {
SK.group.Add(&(sv.g));
memset(&(sv.g), 0, sizeof(sv.g));
ZERO(&(sv.g));
} else if(strcmp(line, "AddParam")==0) {
// params are regenerated, but we want to preload the values
// for initial guesses
SK.param.Add(&(sv.p));
memset(&(sv.p), 0, sizeof(sv.p));
ZERO(&(sv.p));
} else if(strcmp(line, "AddEntity")==0) {
// entities are regenerated
} else if(strcmp(line, "AddRequest")==0) {
SK.request.Add(&(sv.r));
memset(&(sv.r), 0, sizeof(sv.r));
ZERO(&(sv.r));
} else if(strcmp(line, "AddConstraint")==0) {
SK.constraint.Add(&(sv.c));
memset(&(sv.c), 0, sizeof(sv.c));
ZERO(&(sv.c));
} else if(strcmp(line, "AddStyle")==0) {
SK.style.Add(&(sv.s));
ZERO(&(sv.s));
} else if(strcmp(line, VERSION_STRING)==0) {
// do nothing, version string
} else if(StrStartsWith(line, "Triangle ") ||

View File

@ -44,6 +44,7 @@ void glxWriteTextRefCenter(char *str, Vector t, Vector u, Vector v,
static void LineDrawCallback(void *fndata, Vector a, Vector b)
{
glLineWidth(1);
glBegin(GL_LINES);
glxVertex3v(a);
glxVertex3v(b);
@ -95,26 +96,28 @@ void glxVertex3v(Vector u)
glVertex3f((GLfloat)u.x, (GLfloat)u.y, (GLfloat)u.z);
}
void glxLockColorTo(double r, double g, double b)
void glxLockColorTo(DWORD rgb)
{
ColorLocked = false;
glxColor3d(r, g, b);
ColorLocked = false;
glColor3d(REDf(rgb), GREENf(rgb), BLUEf(rgb));
ColorLocked = true;
}
void glxUnlockColor(void)
{
ColorLocked = false;
ColorLocked = false;
}
void glxColor3d(double r, double g, double b)
void glxColorRGB(DWORD rgb)
{
if(!ColorLocked) glColor3d(r, g, b);
// Is there a bug in some graphics drivers where this is not equivalent
// to glColor3d? There seems to be...
glxColorRGBa(rgb, 1.0);
}
void glxColor4d(double r, double g, double b, double a)
void glxColorRGBa(DWORD rgb, double a)
{
if(!ColorLocked) glColor4d(r, g, b, a);
if(!ColorLocked) glColor4d(REDf(rgb), GREENf(rgb), BLUEf(rgb), a);
}
static void Stipple(BOOL forSel)
@ -148,11 +151,11 @@ static void Stipple(BOOL forSel)
}
}
static void StippleTriangle(STriangle *tr, BOOL s, double r, double g, double b)
static void StippleTriangle(STriangle *tr, BOOL s, DWORD rgb)
{
glEnd();
glDisable(GL_LIGHTING);
glColor3d(r, g, b);
glxColorRGB(rgb);
Stipple(s);
glBegin(GL_TRIANGLES);
glxVertex3v(tr->a);
@ -166,6 +169,9 @@ static void StippleTriangle(STriangle *tr, BOOL s, double r, double g, double b)
void glxFillMesh(int specColor, SMesh *m, DWORD h, DWORD s1, DWORD s2)
{
DWORD rgbHovered = Style::Color(Style::HOVERED),
rgbSelected = Style::Color(Style::SELECTED);
glEnable(GL_NORMALIZE);
int prevColor = -1;
glBegin(GL_TRIANGLES);
@ -208,10 +214,10 @@ void glxFillMesh(int specColor, SMesh *m, DWORD h, DWORD s1, DWORD s2)
if((s1 != 0 && tr->meta.face == s1) ||
(s2 != 0 && tr->meta.face == s2))
{
StippleTriangle(tr, TRUE, 1, 0, 0);
StippleTriangle(tr, TRUE, rgbSelected);
}
if(h != 0 && tr->meta.face == h) {
StippleTriangle(tr, FALSE, 1, 1, 0);
StippleTriangle(tr, FALSE, rgbHovered);
}
}
glEnd();
@ -283,13 +289,13 @@ void glxDebugPolygon(SPolygon *p)
Vector a = (sc->l.elem[j]).p;
Vector b = (sc->l.elem[j+1]).p;
glxLockColorTo(0, 0, 1);
glxLockColorTo(RGB(0, 0, 255));
Vector d = (a.Minus(b)).WithMagnitude(-0);
glBegin(GL_LINES);
glxVertex3v(a.Plus(d));
glxVertex3v(b.Minus(d));
glEnd();
glxLockColorTo(1, 0, 0);
glxLockColorTo(RGB(255, 0, 0));
glBegin(GL_POINTS);
glxVertex3v(a.Plus(d));
glxVertex3v(b.Minus(d));
@ -327,7 +333,7 @@ void glxDebugMesh(SMesh *m)
glxDepthRangeOffset(1);
glxUnlockColor();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glxColor4d(0, 1, 0, 1.0);
glxColorRGBa(RGB(0, 255, 0), 1.0);
glBegin(GL_TRIANGLES);
for(i = 0; i < m->l.n; i++) {
STriangle *t = &(m->l.elem[i]);

View File

@ -356,7 +356,8 @@ Group *Group::RunningMeshGroup(void) {
void Group::DrawDisplayItems(int t) {
int specColor;
if(t == DRAWING_3D || t == DRAWING_WORKPLANE) {
specColor = RGB(25, 25, 25); // force the color to something dim
// force the color to something dim
specColor = Style::Color(Style::DIM_SOLID);
} else {
specColor = -1; // use the model color
}
@ -382,11 +383,9 @@ void Group::DrawDisplayItems(int t) {
glDisable(GL_LIGHTING);
}
if(SS.GW.showEdges) {
glLineWidth(1);
glxDepthRangeOffset(2);
glxColor3d(REDf (SS.edgeColor),
GREENf(SS.edgeColor),
BLUEf (SS.edgeColor));
glxColorRGB(Style::Color(Style::SOLID_EDGE));
glLineWidth(Style::Width(Style::SOLID_EDGE));
glxDrawEdges(&displayEdges, false);
}
@ -418,14 +417,13 @@ void Group::Draw(void) {
// it's just a nuisance.
if(type == DRAWING_WORKPLANE) {
glDisable(GL_DEPTH_TEST);
glxColor4d(1, 0, 0, 0.2);
glLineWidth(10);
glxColorRGBa(Style::Color(Style::DRAW_ERROR), 0.2);
glLineWidth (Style::Width(Style::DRAW_ERROR));
glBegin(GL_LINES);
glxVertex3v(polyError.notClosedAt.a);
glxVertex3v(polyError.notClosedAt.b);
glEnd();
glLineWidth(1);
glxColor3d(1, 0, 0);
glxColorRGB(Style::Color(Style::DRAW_ERROR));
glxWriteText("not closed contour!",
polyError.notClosedAt.b, SS.GW.projRight, SS.GW.projUp,
NULL, NULL);
@ -437,7 +435,7 @@ void Group::Draw(void) {
// These errors occur at points, not lines
if(type == DRAWING_WORKPLANE) {
glDisable(GL_DEPTH_TEST);
glxColor3d(1, 0, 0);
glxColorRGB(Style::Color(Style::DRAW_ERROR));
char *msg = (polyError.how == POLY_NOT_COPLANAR) ?
"points not all coplanar!" :
"contour is self-intersecting!";
@ -447,7 +445,7 @@ void Group::Draw(void) {
glEnable(GL_DEPTH_TEST);
}
} else {
glxColor4d(0, 0.1, 0.1, 0.5);
glxColorRGBa(Style::Color(Style::CONTOUR_FILL), 0.5);
glxDepthRangeOffset(1);
glxFillPolygon(&poly);
glxDepthRangeOffset(0);

View File

@ -597,28 +597,64 @@ public:
class Style {
public:
int tag;
hStyle h;
static const int ACTIVE = 1;
// If an entity has no style, then it will be colored according to
// whether the group that it's in is active or not, whether it's
// construction or not, and so on.
static const int NO_STYLE = 0;
static const int ACTIVE_GRP = 1;
static const int CONSTRUCTION = 2;
static const int INACTIVE = 3;
static const int INACTIVE_GRP = 3;
static const int DATUM = 4;
static const int SOLID_EDGE = 5;
static const int CONSTRAINT = 6;
static const int SELECTED = 7;
static const int HOVERED = 8;
static const int CONTOUR_FILL = 9;
static const int NORMALS = 10;
static const int ANALYZE = 11;
static const int DRAW_ERROR = 12;
static const int DIM_SOLID = 13;
static const int FIRST_CUSTOM = 0x1000;
static const int WIDTH_ABSOLUTE = 0;
static const int WIDTH_RELATIVE = 1;
static const int WIDTH_PIXELS = 2;
NameStr name;
static const int WIDTH_MM = 0;
static const int WIDTH_PIXELS = 1;
double width;
int widthHow;
DWORD color;
bool visible;
bool exportable;
// The default styles, for entities that don't have a style assigned yet,
// and for datums and such.
typedef struct {
hStyle h;
char *cnfPrefix;
DWORD color;
double width;
} Default;
static const Default Defaults[];
static char *CnfColor(char *prefix);
static char *CnfWidth(char *prefix);
static char *CnfPrefixToName(char *prefix);
static void CreateDefaultStyle(hStyle h);
static void FreezeDefaultStyles(void);
static void LoadFactoryDefaults(void);
static Style *Get(hStyle hs);
static DWORD Color(hStyle hs, bool forExport=false);
static float Width(hStyle hs);
static DWORD Color(int hs, bool forExport=false);
static float Width(int hs);
static hStyle ForEntity(hEntity he);
};

View File

@ -64,8 +64,6 @@ void SolveSpace::Init(char *cmdLine) {
viewUnits = (Unit)CnfThawDWORD((DWORD)UNIT_MM, "ViewUnits");
// Camera tangent (determines perspective)
cameraTangent = CnfThawFloat(0.0f, "CameraTangent");
// Color for edges (drawn as lines for emphasis)
edgeColor = CnfThawDWORD(RGB(200, 200, 200), "EdgeColor");
// Export scale factor
exportScale = CnfThawFloat(1.0f, "ExportScale");
// Export offset (cutter radius comp)
@ -99,6 +97,10 @@ void SolveSpace::Init(char *cmdLine) {
}
RefreshRecentMenus();
// The default styles (colors, line widths, etc.) are also stored in the
// configuration file, but we will automatically load those as we need
// them.
// Start with either an empty file, or the file specified on the
// command line.
NewFile();
@ -144,8 +146,6 @@ void SolveSpace::Exit(void) {
CnfFreezeDWORD((DWORD)viewUnits, "ViewUnits");
// Camera tangent (determines perspective)
CnfFreezeFloat((float)cameraTangent, "CameraTangent");
// Color for edges (drawn as lines for emphasis)
CnfFreezeDWORD(edgeColor, "EdgeColor");
// Export scale (a float, stored as a DWORD)
CnfFreezeFloat(exportScale, "ExportScale");
// Export offset (cutter radius comp)
@ -171,6 +171,9 @@ void SolveSpace::Exit(void) {
// Show toolbar in the graphics window
CnfFreezeDWORD(showToolbar, "ShowToolbar");
// And the default styles, colors and line widths and such.
Style::FreezeDefaultStyles();
ExitNow();
}

View File

@ -191,10 +191,10 @@ void glxWriteTextRefCenter(char *str, Vector t, Vector u, Vector v,
glxLineFn *fn, void *fndata);
double glxStrWidth(char *str);
double glxStrHeight(void);
void glxLockColorTo(double r, double g, double b);
void glxLockColorTo(DWORD rgb);
void glxUnlockColor(void);
void glxColor3d(double r, double g, double b);
void glxColor4d(double r, double g, double b, double a);
void glxColorRGB(DWORD rgb);
void glxColorRGBa(DWORD rgb, double a);
void glxDepthRangeOffset(int units);
void glxDepthRangeLockToFront(bool yes);
@ -470,6 +470,7 @@ public:
IdList<Group,hGroup> group;
IdList<CONSTRAINT,hConstraint> constraint;
IdList<Request,hRequest> request;
IdList<Style,hStyle> style;
// These are generated from the above.
IdList<ENTITY,hEntity> entity;
@ -481,7 +482,10 @@ public:
inline Param *GetParam (hParam h) { return param. FindById(h); }
inline Request *GetRequest(hRequest h) { return request.FindById(h); }
inline Group *GetGroup (hGroup h) { return group. FindById(h); }
// Styles are handled a bit differently.
};
#undef ENTITY
#undef CONSTRAINT
class SolveSpace {
public:
@ -494,6 +498,7 @@ public:
IdList<Request,hRequest> request;
IdList<Constraint,hConstraint> constraint;
IdList<Param,hParam> param;
IdList<Style,hStyle> style;
hGroup activeGroup;
} UndoState;
static const int MAX_UNDO = 16;
@ -522,7 +527,6 @@ public:
double chordTol;
int maxSegments;
double cameraTangent;
DWORD edgeColor;
float exportScale;
float exportOffset;
int drawBackFaces;
@ -582,6 +586,7 @@ public:
Entity e;
Param p;
Constraint c;
Style s;
} sv;
static void MenuFile(int id);
bool GetFilenameAndSave(bool saveAs);

166
style.cpp
View File

@ -1,5 +1,167 @@
#include "solvespace.h"
//DWORD Style::Color(hStyle h) {
//}
const Style::Default Style::Defaults[] = {
{ ACTIVE_GRP, "ActiveGrp", RGBf(1.0, 1.0, 1.0), 1.5, },
{ CONSTRUCTION, "Construction", RGBf(0.1, 0.7, 0.1), 1.5, },
{ INACTIVE_GRP, "InactiveGrp", RGBf(0.5, 0.3, 0.0), 1.5, },
{ DATUM, "Datum", RGBf(0.0, 0.8, 0.0), 1.5, },
{ SOLID_EDGE, "SolidEdge", RGBf(0.8, 0.8, 0.8), 1.0, },
{ CONSTRAINT, "Constraint", RGBf(1.0, 0.1, 1.0), 1.0, },
{ SELECTED, "Selected", RGBf(1.0, 0.0, 0.0), 1.5, },
{ HOVERED, "Hovered", RGBf(1.0, 1.0, 0.0), 1.5, },
{ CONTOUR_FILL, "ContourFill", RGBf(0.0, 0.1, 0.1), 1.0, },
{ NORMALS, "Normals", RGBf(0.0, 0.4, 0.4), 1.0, },
{ ANALYZE, "Analyze", RGBf(0.0, 1.0, 1.0), 1.0, },
{ DRAW_ERROR, "DrawError", RGBf(1.0, 0.0, 0.0), 8.0, },
{ DIM_SOLID, "DimSolid", RGBf(0.1, 0.1, 0.1), 1.0, },
{ 0, NULL, 0, 0.0, },
};
char *Style::CnfColor(char *prefix) {
static char name[100];
sprintf(name, "Style_%s_Color", prefix);
return name;
}
char *Style::CnfWidth(char *prefix) {
static char name[100];
sprintf(name, "Style_%s_Width", prefix);
return name;
}
char *Style::CnfPrefixToName(char *prefix) {
static char name[100];
int i = 0, j = 0;
while(prefix[i] && j < 90) {
if(isupper(prefix[i]) && i != 0) {
name[j++] = '-';
}
name[j++] = tolower(prefix[i]);
i++;
}
name[j++] = '\0';
return name;
}
void Style::CreateDefaultStyle(hStyle h) {
const Default *d;
for(d = &(Defaults[0]); d->h.v; d++) {
if(d->h.v == h.v) break;
}
if(!d->h.v) {
// Not a default style; so just create it the same as our default
// active group entity style.
d = &(Defaults[0]);
}
Style ns;
ZERO(&ns);
ns.color = CnfThawDWORD(d->color, CnfColor(d->cnfPrefix));
ns.width = CnfThawFloat((float)(d->width), CnfWidth(d->cnfPrefix));
ns.widthHow = WIDTH_PIXELS;
ns.visible = true;
ns.exportable = true;
ns.name.strcpy(CnfPrefixToName(d->cnfPrefix));
ns.h = h;
SK.style.Add(&ns);
}
void Style::LoadFactoryDefaults(void) {
const Default *d;
for(d = &(Defaults[0]); d->h.v; d++) {
Style *s = Get(d->h);
s->color = d->color;
s->width = d->width;
s->widthHow = WIDTH_PIXELS;
s->visible = true;
s->exportable = true;
s->name.strcpy(CnfPrefixToName(d->cnfPrefix));
}
}
void Style::FreezeDefaultStyles(void) {
const Default *d;
for(d = &(Defaults[0]); d->h.v; d++) {
CnfFreezeDWORD(Color(d->h), CnfColor(d->cnfPrefix));
CnfFreezeFloat((float)Width(d->h), CnfWidth(d->cnfPrefix));
}
}
//-----------------------------------------------------------------------------
// Look up a style by its handle. If that style does not exist, then create
// the style, according to our table of default styles.
//-----------------------------------------------------------------------------
Style *Style::Get(hStyle h) {
Style *s = SK.style.FindByIdNoOops(h);
if(s) {
// It exists, good.
return s;
} else {
// It doesn't exist; so we should create it and then return that.
CreateDefaultStyle(h);
return SK.style.FindById(h);
}
}
//-----------------------------------------------------------------------------
// A couple of wrappers, so that I can call these functions with either an
// hStyle or with the integer corresponding to that hStyle.v.
//-----------------------------------------------------------------------------
DWORD Style::Color(int s, bool forExport) {
hStyle hs = { s };
return Color(hs, forExport);
}
float Style::Width(int s) {
hStyle hs = { s };
return Width(hs);
}
//-----------------------------------------------------------------------------
// Return the color associated with our style as 8-bit RGB.
//-----------------------------------------------------------------------------
DWORD Style::Color(hStyle h, bool forExport) {
Style *s = Get(h);
return s->color;
}
//-----------------------------------------------------------------------------
// Return the width associated with our style in pixels..
//-----------------------------------------------------------------------------
float Style::Width(hStyle h) {
double r = 1.0;
Style *s = Get(h);
if(s->widthHow == WIDTH_MM) {
r = s->width * SS.GW.scale;
} else if(s->widthHow == WIDTH_PIXELS) {
r = s->width;
}
// This returns a float because glLineWidth expects a float, avoid casts.
return (float)r;
}
//-----------------------------------------------------------------------------
// Return the appropriate style for our entity. If the entity has a style
// explicitly assigned, then it's that style. Otherwise it's the appropriate
// default style.
//-----------------------------------------------------------------------------
hStyle Style::ForEntity(hEntity he) {
Entity *e = SK.GetEntity(he);
// If the entity has a special style, use that. If that style doesn't
// exist yet, then it will get created automatically later.
if(e->style.v != 0) {
return e->style;
}
// Otherwise, we use the default rules.
hStyle hs;
if(e->group.v != SS.GW.activeGroup.v) {
hs.v = INACTIVE_GRP;
} else if(e->construction) {
hs.v = CONSTRUCTION;
} else {
hs.v = ACTIVE_GRP;
}
return hs;
}

View File

@ -606,41 +606,33 @@ void TextWindow::ScreenChangeColor(int link, DWORD v) {
SS.TW.edit.meaning = EDIT_COLOR;
SS.TW.edit.i = v;
}
void TextWindow::ScreenChangeEdgeColor(int link, DWORD v) {
char str[1024];
sprintf(str, "%.3f, %.3f, %.3f",
REDf(SS.edgeColor), GREENf(SS.edgeColor), BLUEf(SS.edgeColor));
ShowTextEditControl(37, 3, str);
SS.TW.edit.meaning = EDIT_EDGE_COLOR;
}
void TextWindow::ScreenChangeChordTolerance(int link, DWORD v) {
char str[1024];
sprintf(str, "%.2f", SS.chordTol);
ShowTextEditControl(43, 3, str);
ShowTextEditControl(37, 3, str);
SS.TW.edit.meaning = EDIT_CHORD_TOLERANCE;
}
void TextWindow::ScreenChangeMaxSegments(int link, DWORD v) {
char str[1024];
sprintf(str, "%d", SS.maxSegments);
ShowTextEditControl(47, 3, str);
ShowTextEditControl(41, 3, str);
SS.TW.edit.meaning = EDIT_MAX_SEGMENTS;
}
void TextWindow::ScreenChangeCameraTangent(int link, DWORD v) {
char str[1024];
sprintf(str, "%.3f", 1000*SS.cameraTangent);
ShowTextEditControl(53, 3, str);
ShowTextEditControl(47, 3, str);
SS.TW.edit.meaning = EDIT_CAMERA_TANGENT;
}
void TextWindow::ScreenChangeExportScale(int link, DWORD v) {
char str[1024];
sprintf(str, "%.3f", (double)SS.exportScale);
ShowTextEditControl(59, 3, str);
ShowTextEditControl(53, 3, str);
SS.TW.edit.meaning = EDIT_EXPORT_SCALE;
}
void TextWindow::ScreenChangeExportOffset(int link, DWORD v) {
ShowTextEditControl(63, 3, SS.MmToString(SS.exportOffset));
ShowTextEditControl(57, 3, SS.MmToString(SS.exportOffset));
SS.TW.edit.meaning = EDIT_EXPORT_OFFSET;
}
void TextWindow::ScreenChangeBackFaces(int link, DWORD v) {
@ -674,7 +666,7 @@ void TextWindow::ScreenChangeCanvasSize(int link, DWORD v) {
default: return;
}
int row = 77, col;
int row = 71, col;
if(v < 10) {
row += v*2;
col = 11;
@ -711,12 +703,6 @@ void TextWindow::ShowConfiguration(void) {
SS.lightIntensity[i], i, &ScreenChangeLightIntensity);
}
Printf(false, "");
Printf(false, "%Ft edge color r,g,b%E");
Printf(false, "%Ba %@, %@, %@ %Fl%Ll%f%D[change]%E",
REDf(SS.edgeColor), GREENf(SS.edgeColor), BLUEf(SS.edgeColor),
&ScreenChangeEdgeColor, 0);
Printf(false, "");
Printf(false, "%Ft chord tolerance (in screen pixels)%E");
Printf(false, "%Ba %2 %Fl%Ll%f%D[change]%E; now %d triangles",
@ -997,16 +983,6 @@ void TextWindow::EditControlDone(char *s) {
InvalidateGraphics();
break;
}
case EDIT_EDGE_COLOR: {
double r, g, b;
if(sscanf(s, "%lf, %lf, %lf", &r, &g, &b)==3) {
SS.edgeColor = RGB(r*255, g*255, b*255);
} else {
Error("Bad format: specify color as r, g, b");
}
SS.GenerateAll(0, INT_MAX);
break;
}
case EDIT_EXPORT_SCALE: {
Expr *e = Expr::From(s);
if(e) {

8
ui.h
View File

@ -77,10 +77,9 @@ public:
static const int EDIT_CHORD_TOLERANCE = 13;
static const int EDIT_MAX_SEGMENTS = 14;
static const int EDIT_CAMERA_TANGENT = 15;
static const int EDIT_EDGE_COLOR = 16;
static const int EDIT_EXPORT_SCALE = 17;
static const int EDIT_EXPORT_OFFSET = 18;
static const int EDIT_CANVAS_SIZE = 19;
static const int EDIT_EXPORT_SCALE = 16;
static const int EDIT_EXPORT_OFFSET = 17;
static const int EDIT_CANVAS_SIZE = 18;
// For the helical sweep
static const int EDIT_HELIX_TURNS = 20;
static const int EDIT_HELIX_PITCH = 21;
@ -167,7 +166,6 @@ public:
static void ScreenChangeChordTolerance(int link, DWORD v);
static void ScreenChangeMaxSegments(int link, DWORD v);
static void ScreenChangeCameraTangent(int link, DWORD v);
static void ScreenChangeEdgeColor(int link, DWORD v);
static void ScreenChangeExportScale(int link, DWORD v);
static void ScreenChangeExportOffset(int link, DWORD v);

View File

@ -77,6 +77,9 @@ void SolveSpace::PushFromCurrentOnto(UndoStack *uk) {
for(i = 0; i < SK.param.n; i++) {
ut->param.Add(&(SK.param.elem[i]));
}
for(i = 0; i < SK.style.n; i++) {
ut->style.Add(&(SK.style.elem[i]));
}
ut->activeGroup = SS.GW.activeGroup;
uk->write = WRAP(uk->write + 1, MAX_UNDO);
@ -110,12 +113,14 @@ void SolveSpace::PopOntoCurrentFrom(UndoStack *uk) {
SK.request.Clear();
SK.constraint.Clear();
SK.param.Clear();
SK.style.Clear();
// And then do a shallow copy of the state from the undo list
ut->group.MoveSelfInto(&(SK.group));
ut->request.MoveSelfInto(&(SK.request));
ut->constraint.MoveSelfInto(&(SK.constraint));
ut->param.MoveSelfInto(&(SK.param));
ut->style.MoveSelfInto(&(SK.style));
SS.GW.activeGroup = ut->activeGroup;
// No need to free it, since a shallow copy was made above
@ -150,6 +155,7 @@ void SolveSpace::UndoClearState(UndoState *ut) {
ut->request.Clear();
ut->constraint.Clear();
ut->param.Clear();
ut->style.Clear();
ZERO(ut);
}