Rename some stuff in the IdList again. Rough in the file save

stuff, though no file load stuff, and perhaps this can all be made
to work from a table somehow. Move the quaternion stuff into its
own class, and add a fancy animated view when you orient onto a
csys.

[git-p4: depot-paths = "//depot/solvespace/": change = 1672]
solver
Jonathan Westhues 2008-04-18 03:11:48 -08:00
parent c097fea4f3
commit 0d3217c0df
13 changed files with 403 additions and 88 deletions

View File

@ -19,6 +19,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \
$(OBJDIR)\expr.obj \
$(OBJDIR)\constraint.obj \
$(OBJDIR)\drawconstraint.obj \
$(OBJDIR)\file.obj \
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib

54
dsc.h
View File

@ -5,6 +5,28 @@
typedef unsigned long DWORD;
typedef unsigned char BYTE;
class Vector;
class Quaternion {
public:
// a + bi + cj + dk
double a, b, c, d;
static Quaternion MakeFrom(double a, double b, double c, double d);
static Quaternion MakeFrom(Vector u, Vector v);
Quaternion Plus(Quaternion y);
Quaternion Minus(Quaternion y);
Quaternion ScaledBy(double s);
double Magnitude(void);
Quaternion WithMagnitude(double s);
// Call a rotation matrix [ u' v' n' ]'; this returns the first and
// second rows, where that matrix is generated by this quaternion
Vector RotationU(void);
Vector RotationV(void);
};
class Vector {
public:
double x, y, z;
@ -21,12 +43,6 @@ public:
double Magnitude(void);
Vector WithMagnitude(double s);
Vector ScaledBy(double s);
// Call a rotation matrix [ u' v' n' ]'; this returns the first and
// second rows, where that matrix is generated by the given quaternion
// a + bi + cj + dk
static Vector RotationU(double a, double b, double c, double d);
static Vector RotationV(double a, double b, double c, double d);
};
class Point2d {
@ -44,14 +60,14 @@ template <class T, class H>
class IdList {
public:
T *elem;
int elems;
int n;
int elemsAllocated;
H AddAndAssignId(T *t) {
int i;
DWORD id = 0;
for(i = 0; i < elems; i++) {
for(i = 0; i < n; i++) {
id = max(id, elem[i].h.v);
}
@ -62,20 +78,20 @@ public:
}
void Add(T *t) {
if(elems >= elemsAllocated) {
if(n >= elemsAllocated) {
elemsAllocated = (elemsAllocated + 32)*2;
elem = (T *)MemRealloc(elem, elemsAllocated*sizeof(elem[0]));
if(!elem) oops();
}
elem[elems] = *t;
elems++;
elem[n] = *t;
n++;
}
T *FindById(H h) {
T *t = FindByIdNoOops(h);
if(!t) {
dbp("failed to look up item %16lx, searched %d items", h.v, elems);
dbp("failed to look up item %16lx, searched %d items", h.v, n);
oops();
}
return t;
@ -83,7 +99,7 @@ public:
T *FindByIdNoOops(H h) {
int i;
for(i = 0; i < elems; i++) {
for(i = 0; i < n; i++) {
if(elem[i].h.v == h.v) {
return &(elem[i]);
}
@ -93,14 +109,14 @@ public:
void ClearTags(void) {
int i;
for(i = 0; i < elems; i++) {
for(i = 0; i < n; i++) {
elem[i].tag = 0;
}
}
void Tag(H h, int tag) {
int i;
for(i = 0; i < elems; i++) {
for(i = 0; i < n; i++) {
if(elem[i].h.v == h.v) {
elem[i].tag = tag;
}
@ -110,7 +126,7 @@ public:
void RemoveTagged(void) {
int src, dest;
dest = 0;
for(src = 0; src < elems; src++) {
for(src = 0; src < n; src++) {
if(elem[src].tag) {
// this item should be deleted
} else {
@ -120,18 +136,18 @@ public:
dest++;
}
}
elems = dest;
n = dest;
// and elemsAllocated is untouched, because we didn't resize
}
void MoveSelfInto(IdList<T,H> *l) {
memcpy(l, this, sizeof(*this));
elemsAllocated = elems = 0;
elemsAllocated = n = 0;
elem = NULL;
}
void Clear(void) {
elemsAllocated = elems = 0;
elemsAllocated = n = 0;
if(elem) free(elem);
elem = NULL;
}

View File

@ -10,9 +10,10 @@ void Entity::Get2dCsysBasisVectors(Vector *u, Vector *v) {
for(int i = 0; i < 4; i++) {
q[i] = SS.param.FindById(param(i))->val;
}
Quaternion quat = Quaternion::MakeFrom(q[0], q[1], q[2], q[3]);
*u = Vector::RotationU(q[0], q[1], q[2], q[3]);
*v = Vector::RotationV(q[0], q[1], q[2], q[3]);
*u = quat.RotationU();
*v = quat.RotationV();
}
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {

View File

@ -130,6 +130,8 @@ void Expr::App(char *s, ...) {
vsprintf(StringBuffer+strlen(StringBuffer), s, f);
}
char *Expr::Print(void) {
if(!this) return "0";
StringBuffer[0] = '\0';
PrintW();
return StringBuffer;
@ -356,6 +358,7 @@ void Expr::Lex(char *in) {
Expr *Expr::FromString(char *in) {
UnparsedCnt = 0;
UnparsedP = 0;
OperandsP = 0;
OperatorsP = 0;

84
file.cpp Normal file
View File

@ -0,0 +1,84 @@
#include "solvespace.h"
bool SolveSpace::SaveToFile(char *filename) {
fh = fopen(filename, "w");
if(!fh) {
Error("Couldn't write to file '%s'", fh);
return false;
}
fprintf(fh, "!!SolveSpaceREVa\n\n\n");
int i;
for(i = 0; i < group.n; i++) {
Group *g = &(group.elem[i]);
fprintf(fh, "Group.h.v=%08x\n", g->h.v);
fprintf(fh, "Group.name=%s\n", g->name.str);
fprintf(fh, "AddGroup\n\n");
}
for(i = 0; i < param.n; i++) {
Param *p = &(param.elem[i]);
fprintf(fh, "Param.h.v=%08x\n", p->h.v);
fprintf(fh, "Param.val=%.20f\n", p->val);
fprintf(fh, "AddParam\n\n");
}
for(i = 0; i < request.n; i++) {
Request *r = &(request.elem[i]);
fprintf(fh, "Request.h.v=%08x\n", r->h.v);
fprintf(fh, "Request.type=%d\n", r->type);
fprintf(fh, "Request.csys.v=%08x\n", r->csys.v);
fprintf(fh, "Request.group.v=%08x\n", r->group.v);
fprintf(fh, "Request.name=%s\n", r->name.str);
fprintf(fh, "AddRequest\n\n");
}
for(i = 0; i < entity.n; i++) {
Entity *e = &(entity.elem[i]);
fprintf(fh, "Entity.h.v=%08x\n", e->h.v);
fprintf(fh, "Entity.type=%d\n", e->type);
fprintf(fh, "AddEntity\n\n");
}
for(i = 0; i < point.n; i++) {
Point *p = &(point.elem[i]);
fprintf(fh, "Point.h.v=%08x\n", p->h.v);
fprintf(fh, "Point.type=%d\n", p->type);
fprintf(fh, "Point.csys.v=%08x\n", p->csys.v);
fprintf(fh, "AddPoint\n\n");
}
for(i = 0; i < constraint.n; i++) {
Constraint *c = &(constraint.elem[i]);
fprintf(fh, "Constraint.h.v=%08x\n", c->h.v);
fprintf(fh, "Constraint.type=%d\n", c->type);
fprintf(fh, "Constraint.group.v=%08x\n", c->group);
fprintf(fh, "Constraint.exprA=%s\n", c->exprA->Print());
fprintf(fh, "Constraint.exprB=%s\n", c->exprB->Print());
fprintf(fh, "Constraint.ptA.v=%08x\n", c->ptA.v);
fprintf(fh, "Constraint.ptB.v=%08x\n", c->ptB.v);
fprintf(fh, "Constraint.ptC.v=%08x\n", c->ptC.v);
fprintf(fh, "Constraint.entityA.v=%08x\n", c->entityA.v);
fprintf(fh, "Constraint.entityB.v=%08x\n", c->entityB.v);
fprintf(fh, "Constraint.disp.offset.x=%.20f\n", c->disp.offset.x);
fprintf(fh, "Constraint.disp.offset.y=%.20f\n", c->disp.offset.y);
fprintf(fh, "Constraint.disp.offset.z=%.20f\n", c->disp.offset.z);
fprintf(fh, "AddConstraint\n\n");
}
fclose(fh);
return true;
}
bool SolveSpace::LoadFromFile(char *filename) {
fh = fopen(filename, "r");
if(!fh) {
Error("Couldn't read from file '%s'", fh);
return false;
}
return true;
}

View File

@ -6,15 +6,17 @@
#define mEdit (&GraphicsWindow::MenuEdit)
#define mReq (&GraphicsWindow::MenuRequest)
#define mCon (&Constraint::MenuConstrain)
#define mFile (&SolveSpace::MenuFile)
#define S 0x100
#define C 0x200
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 0, "&File", 0, NULL },
{ 1, "&New\tCtrl+N", 0, NULL },
{ 1, "&Open...\tCtrl+O", 0, NULL },
{ 1, "&Save\tCtrl+S", 0, NULL },
{ 1, "Save &As...", 0, NULL },
{ 1, NULL, 0, NULL },
{ 1, "E&xit", 0, NULL },
{ 1, "&New\tCtrl+N", MNU_NEW, 'N'|C, mFile },
{ 1, "&Open...\tCtrl+O", MNU_OPEN, 'O'|C, mFile },
{ 1, "&Save\tCtrl+S", MNU_SAVE, 'S'|C, mFile },
{ 1, "Save &As...", MNU_SAVE_AS, 0, mFile },
{ 1, NULL, 0, 0, NULL },
{ 1, "E&xit", MNU_EXIT, 0, mFile },
{ 0, "&Edit", 0, NULL },
{ 1, "&Undo\tCtrl+Z", 0, NULL },
@ -37,7 +39,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 0, "&Request", 0, NULL },
{ 1, "Dra&w in 2d Coordinate System\tW", MNU_SEL_CSYS, 'W', mReq },
{ 1, "Draw Anywhere in 3d\tF", MNU_NO_CSYS, 'Q', mReq },
{ 1, "Draw Anywhere in 3d\tQ", MNU_NO_CSYS, 'Q', mReq },
{ 1, NULL, 0, NULL },
{ 1, "Datum &Point\tP", MNU_DATUM_POINT, 'P', mReq },
{ 1, "Datum A&xis\tX", 0, 'X', mReq },
@ -132,18 +134,63 @@ void GraphicsWindow::MenuView(int id) {
CheckMenuById(MNU_LOCK_VIEW, SS.GW.viewLocked);
break;
case MNU_ORIENT_ONTO:
case MNU_ORIENT_ONTO: {
SS.GW.GroupSelection();
Entity *e = NULL;
if(SS.GW.gs.n == 1 && SS.GW.gs.csyss == 1) {
Entity *e = SS.entity.FindById(SS.GW.gs.entity[0]);
e->Get2dCsysBasisVectors( &(SS.GW.projRight), &(SS.GW.projUp));
SS.GW.offset = SS.point.FindById(e->point(16))->GetCoords();
e = SS.entity.FindById(SS.GW.gs.entity[0]);
} else if(SS.GW.activeCsys.v != Entity::NO_CSYS.v) {
e = SS.entity.FindById(SS.GW.activeCsys);
}
if(e) {
// A quaternion with our original rotation
Quaternion quat0 = Quaternion::MakeFrom(
SS.GW.projRight, SS.GW.projUp);
// And with our final rotation
Vector pr, pu;
e->Get2dCsysBasisVectors(&pr, &pu);
Quaternion quatf = Quaternion::MakeFrom(pr, pu);
// Make sure we take the shorter of the two possible paths.
double mp = (quatf.Minus(quat0)).Magnitude();
double mm = (quatf.Plus(quat0)).Magnitude();
if(mp > mm) {
quatf = quatf.ScaledBy(-1);
mp = mm;
}
// And also get the offsets.
Vector offset0 = SS.GW.offset;
Vector offsetf = SS.point.FindById(e->point(16))->GetCoords();
// Animate transition, unless it's a tiny move.
SDWORD dt = (mp < 0.01) ? (-20) : (SDWORD)(100 + 1000*mp);
SDWORD tn, t0 = GetMilliseconds();
double s = 0;
do {
SS.GW.offset =
(offset0.ScaledBy(1 - s)).Plus(offsetf.ScaledBy(s));
Quaternion quat =
(quat0.ScaledBy(1 - s)).Plus(quatf.ScaledBy(s));
quat = quat.WithMagnitude(1);
SS.GW.projRight = quat.RotationU();
SS.GW.projUp = quat.RotationV();
PaintGraphics();
tn = GetMilliseconds();
s = (tn - t0)/((double)dt);
} while((tn - t0) < dt);
SS.GW.projRight = pr;
SS.GW.projUp = pu;
SS.GW.offset = offsetf;
SS.GW.hover.Clear();
SS.GW.ClearSelection();
InvalidateGraphics();
} else {
Error("Select plane or coordinate system before orienting.");
}
break;
}
default: oops();
}
@ -156,12 +203,12 @@ void GraphicsWindow::EnsureValidActives(void) {
Group *g = SS.group.FindByIdNoOops(activeGroup);
if((!g) || (g->h.v == Group::HGROUP_REFERENCES.v)) {
int i;
for(i = 0; i < SS.group.elems; i++) {
for(i = 0; i < SS.group.n; i++) {
if(SS.group.elem[i].h.v != Group::HGROUP_REFERENCES.v) {
break;
}
}
if(i >= SS.group.elems) oops();
if(i >= SS.group.n) oops();
activeGroup = SS.group.elem[i].h;
change = true;
}
@ -174,6 +221,8 @@ void GraphicsWindow::EnsureValidActives(void) {
change = true;
}
if(change) SS.TW.Show();
EnableMenuById(MNU_NO_CSYS, (activeCsys.v != Entity::NO_CSYS.v));
}
void GraphicsWindow::MenuEdit(int id) {
@ -362,7 +411,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
memset(dest, 0, sizeof(*dest));
// Do the points
for(i = 0; i < SS.entity.elems; i++) {
for(i = 0; i < SS.entity.n; i++) {
d = SS.entity.elem[i].GetDistance(mp);
if(d < 10 && d < dmin) {
memset(dest, 0, sizeof(*dest));
@ -371,7 +420,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
}
// Entities
for(i = 0; i < SS.point.elems; i++) {
for(i = 0; i < SS.point.n; i++) {
d = SS.point.elem[i].GetDistance(mp);
if(d < 10 && d < dmin) {
memset(dest, 0, sizeof(*dest));
@ -380,7 +429,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp, Selection *dest) {
}
// Constraints
for(i = 0; i < SS.constraint.elems; i++) {
for(i = 0; i < SS.constraint.n; i++) {
d = SS.constraint.elem[i].GetDistance(mp);
if(d < 10 && d < dmin) {
memset(dest, 0, sizeof(*dest));
@ -581,15 +630,15 @@ void GraphicsWindow::Paint(int w, int h) {
// First, draw the entire scene.
glColor3f(1, 1, 1);
for(i = 0; i < SS.entity.elems; i++) {
for(i = 0; i < SS.entity.n; i++) {
SS.entity.elem[i].Draw();
}
glColor3f(0, 0.8f, 0);
for(i = 0; i < SS.point.elems; i++) {
for(i = 0; i < SS.point.n; i++) {
SS.point.elem[i].Draw();
}
glColor3f(1.0f, 0, 1.0f);
for(i = 0; i < SS.constraint.elems; i++) {
for(i = 0; i < SS.constraint.n; i++) {
SS.constraint.elem[i].Draw();
}

View File

@ -82,9 +82,9 @@ public:
hRequest h;
// Types of requests
static const int CSYS_2D = 10;
static const int DATUM_POINT = 11;
static const int LINE_SEGMENT = 20;
static const int CSYS_2D = 100;
static const int DATUM_POINT = 101;
static const int LINE_SEGMENT = 200;
int type;
@ -107,6 +107,9 @@ public:
class Entity {
public:
int tag;
hEntity h;
static const hEntity NO_CSYS;
static const int CSYS_2D = 1000;
@ -114,11 +117,6 @@ public:
static const int LINE_SEGMENT = 1010;
int type;
int tag;
hEntity h;
Expr *expr[16];
inline hRequest request(void)
{ hRequest r; r.v = (this->h.v >> 10); return r; }
inline hParam param(int i)
@ -161,7 +159,6 @@ public:
int type;
static const int IN_FREE_SPACE = 0; // three params, x y z
static const int IN_2D_CSYS = 1; // two params, u v, plus csys
static const int BY_EXPR = 2; // three Expr *, could be anything
hEntity csys;
@ -234,9 +231,7 @@ public:
// These define how the constraint is drawn on-screen.
struct {
hEntity csys;
Vector offset;
Vector u, v;
} disp;
static hConstraint AddConstraint(Constraint *c);

View File

@ -58,11 +58,11 @@ void SolveSpace::GenerateAll(void) {
entity.Clear();
point.Clear();
for(i = 0; i < request.elems; i++) {
for(i = 0; i < request.n; i++) {
request.elem[i].Generate(&entity, &point, &param);
}
for(i = 0; i < param.elems; i++) {
for(i = 0; i < param.n; i++) {
Param *p = prev.FindByIdNoOops(param.elem[i].h);
if(p) {
param.elem[i].val = p->val;
@ -80,8 +80,8 @@ void SolveSpace::ForceReferences(void) {
double a, b, c, d;
} Quat[] = {
{ Request::HREQUEST_REFERENCE_XY, 1, 0, 0, 0, },
{ Request::HREQUEST_REFERENCE_YZ, 0.5, -0.5, -0.5, -0.5, },
{ Request::HREQUEST_REFERENCE_ZX, 0.5, 0.5, 0.5, 0.5, },
{ Request::HREQUEST_REFERENCE_YZ, 0.5, 0.5, 0.5, 0.5, },
{ Request::HREQUEST_REFERENCE_ZX, 0.5, -0.5, -0.5, -0.5, },
};
for(int i = 0; i < 3; i++) {
hEntity he;
@ -101,3 +101,21 @@ void SolveSpace::ForceReferences(void) {
void SolveSpace::Solve(void) {
}
void SolveSpace::MenuFile(int id) {
switch(id) {
case GraphicsWindow::MNU_NEW:
case GraphicsWindow::MNU_OPEN:
case GraphicsWindow::MNU_SAVE:
SS.SaveToFile("t.slv");
break;
case GraphicsWindow::MNU_SAVE_AS:
break;
case GraphicsWindow::MNU_EXIT:
break;
default: oops();
}
}

View File

@ -14,6 +14,8 @@
#define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#')
typedef signed long SDWORD;
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
@ -26,12 +28,21 @@
class Expr;
// From the platform-specific code.
int SaveFileYesNoCancel(void);
BOOL GetSaveFile(char *file, char *defExtension, char *selPattern);
BOOL GetOpenFile(char *file, char *defExtension, char *selPattern);
void CheckMenuById(int id, BOOL checked);
void EnableMenuById(int id, BOOL checked);
void InvalidateGraphics(void);
void InvalidateText(void);
SDWORD GetMilliseconds(void);
void PaintGraphics(void);
void dbp(char *str, ...);
void Error(char *str, ...);
Expr *AllocExpr(void);
void FreeAllExprs(void);
void *MemRealloc(void *p, int n);
@ -82,13 +93,19 @@ public:
inline Param *GetParam (hParam h) { return param. FindById(h); }
inline Point *GetPoint (hPoint h) { return point. FindById(h); }
hGroup activeGroup;
hGroup activeGroup;
FILE *fh;
void GenerateAll(void);
void ForceReferences(void);
void Init(void);
void Solve(void);
static void MenuFile(int id);
bool SaveToFile(char *filename);
bool LoadFromFile(char *filename);
};
extern SolveSpace SS;

View File

@ -254,10 +254,10 @@ void TextWindow::ShowHeader(void) {
void TextWindow::ShowAllGroups(void) {
Printf("%C8[[all groups in sketch follow]]%E");
int i;
for(i = 0; i <= SS.group.elems; i++) {
for(i = 0; i <= SS.group.n; i++) {
DWORD v;
char *s;
if(i == SS.group.elems) {
if(i == SS.group.n) {
s = "all requests from all groups";
v = 0;
} else {
@ -293,7 +293,7 @@ void TextWindow::ShowRequestsInGroup(void) {
}
int i;
for(i = 0; i < SS.request.elems; i++) {
for(i = 0; i < SS.request.n; i++) {
Request *r = &(SS.request.elem[i]);
if(r->group.v == shown->group.v || shown->group.v == 0) {

8
ui.h
View File

@ -74,8 +74,14 @@ public:
// This table describes the top-level menus in the graphics winodw.
typedef enum {
// File
MNU_NEW = 100,
MNU_OPEN,
MNU_SAVE,
MNU_SAVE_AS,
MNU_EXIT,
// View
MNU_ZOOM_IN = 100,
MNU_ZOOM_IN,
MNU_ZOOM_OUT,
MNU_ZOOM_TO_FIT,
MNU_ORIENT_ONTO,

View File

@ -23,27 +23,85 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
mat[15] = a44;
}
Quaternion Quaternion::MakeFrom(double a, double b, double c, double d) {
Quaternion q;
q.a = a;
q.b = b;
q.c = c;
q.d = d;
return q;
}
Quaternion Quaternion::MakeFrom(Vector u, Vector v)
{
Vector n = u.Cross(v);
Quaternion q;
q.a = 0.5*sqrt(1 + u.x + v.y + n.z);
q.b = (1/(4*(q.a)))*(v.z - n.y);
q.c = (1/(4*(q.a)))*(n.x - u.z);
q.d = (1/(4*(q.a)))*(u.y - v.x);
return q;
}
Quaternion Quaternion::Plus(Quaternion y) {
Quaternion q;
q.a = a + y.a;
q.b = b + y.b;
q.c = c + y.c;
q.d = d + y.d;
return q;
}
Quaternion Quaternion::Minus(Quaternion y) {
Quaternion q;
q.a = a - y.a;
q.b = b - y.b;
q.c = c - y.c;
q.d = d - y.d;
return q;
}
Quaternion Quaternion::ScaledBy(double s) {
Quaternion q;
q.a = a*s;
q.b = b*s;
q.c = c*s;
q.d = d*s;
return q;
}
double Quaternion::Magnitude(void) {
return sqrt(a*a + b*b + c*c + d*d);
}
Quaternion Quaternion::WithMagnitude(double s) {
return ScaledBy(s/Magnitude());
}
Vector Quaternion::RotationU(void) {
Vector v;
v.x = a*a + b*b - c*c - d*d;
v.y = 2*a*d + 2*b*c;
v.z = 2*b*d - 2*a*c;
return v;
}
Vector Quaternion::RotationV(void) {
Vector v;
v.x = 2*b*c - 2*a*d;
v.y = a*a - b*b + c*c - d*d;
v.z = 2*a*b + 2*c*d;
return v;
}
Vector Vector::MakeFrom(double x, double y, double z) {
Vector v;
v.x = x; v.y = y; v.z = z;
return v;
}
Vector Vector::RotationU(double a, double b, double c, double d) {
Vector v;
v.x = a*a + b*b - c*c - d*d;
v.y = 2*b*c - 2*a*d;
v.z = 2*a*c + 2*b*d;
return v;
}
Vector Vector::RotationV(double a, double b, double c, double d) {
Vector v;
v.x = 2*a*d + 2*b*c;
v.y = a*a - b*b + c*c - d*d;
v.z = 2*c*d - 2*a*b;
return v;
}
Vector Vector::Plus(Vector b) {
Vector r;

View File

@ -1,5 +1,6 @@
#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <stdarg.h>
@ -349,6 +350,32 @@ void InvalidateGraphics(void)
{
InvalidateRect(GraphicsWnd, NULL, FALSE);
}
static void PaintGraphicsWithHdc(HDC hdc)
{
HGLRC hgrc = CreateGlContext(hdc);
RECT r;
GetClientRect(GraphicsWnd, &r);
int w = r.right - r.left;
int h = r.bottom - r.top;
SS.GW.Paint(w, h);
SwapBuffers(hdc);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hgrc);
}
void PaintGraphics(void)
{
HDC hdc = GetDC(GraphicsWnd);
PaintGraphicsWithHdc(hdc);
}
SDWORD GetMilliseconds(void)
{
return (SDWORD)GetTickCount();
}
void InvalidateText(void)
{
InvalidateRect(TextWnd, NULL, FALSE);
@ -370,19 +397,7 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HGLRC hgrc = CreateGlContext(hdc);
RECT r;
GetClientRect(GraphicsWnd, &r);
int w = r.right - r.left;
int h = r.bottom - r.top;
SS.GW.Paint(w, h);
SwapBuffers(hdc);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hgrc);
PaintGraphicsWithHdc(hdc);
EndPaint(hwnd, &ps);
break;
@ -446,6 +461,58 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
return 1;
}
//-----------------------------------------------------------------------------
// Common dialog routines, to open or save a file.
//-----------------------------------------------------------------------------
BOOL GetOpenFile(char *file, char *defExtension, char *selPattern)
{
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hInstance = Instance;
ofn.hwndOwner = GraphicsWnd;
ofn.lpstrFilter = selPattern;
ofn.lpstrDefExt = defExtension;
ofn.lpstrFile = file;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
EnableWindow(GraphicsWnd, FALSE);
BOOL r = GetOpenFileName(&ofn);
EnableWindow(GraphicsWnd, TRUE);
SetForegroundWindow(GraphicsWnd);
return r;
}
BOOL GetSaveFile(char *file, char *defExtension, char *selPattern)
{
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hInstance = Instance;
ofn.hwndOwner = GraphicsWnd;
ofn.lpstrFilter = selPattern;
ofn.lpstrDefExt = defExtension;
ofn.lpstrFile = file;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
EnableWindow(GraphicsWnd, FALSE);
BOOL r = GetSaveFileName(&ofn);
EnableWindow(GraphicsWnd, TRUE);
SetForegroundWindow(GraphicsWnd);
return r;
}
int SaveFileYesNoCancel(void)
{
return MessageBox(GraphicsWnd,
"The program has changed since it was last saved.\r\n\r\n"
"Do you want to save the changes?", "SolveSpace",
MB_YESNOCANCEL | MB_ICONWARNING);
}
static void MenuById(int id, BOOL yes, BOOL check)
{
int i;