static int ntris;
static Vertices conformation;
+static double transform[D3][D3]= {{1,0,0}, {0,1,0}, {0,0,1}};
+STATIC_GSL_MATRIX(transform);
+
const char *input_filename;
static void read_input(void) {
f= fopen(input_filename, "rb"); if (!f) diee("input file");
errno= 0;
- r= fread(&conformation,1,sizeof(conformation),f); if (r!=1) diee("fread");
+ r= fread(&conformation,sizeof(conformation),1,f); if (r!=1) diee("fread");
fclose(f);
}
static void transform_coordinates(void) {
+ /*
+ static double result[D3];
+ static const gsl_vector result_gsl= { D3,1,&result[0]; }
+
int v;
+
FOR_VERTEX(v) {
- }
+ GA( gsl_blas_dgemv(CblasNoTrans,
+ }*/
}
static void addtriangle(int va, int vb, int vc) {
static void generate_display_list(void) {
int vb, ve[3], e;
-
+
+ ntris= 0;
FOR_VERTEX(vb) {
/* We use the two triangles in the parallelogram vb, vb+e1, vb+e0, vb+e2.
* We go round each triangle clockwise (although our surface is non-
const Triangle *const *tbp= tbp, *tb= *tbp;
double za= ta->vertex[0][2];
double zb= tb->vertex[0][2];
- return za > zb ? +1 :
- za < zb ? -1 : 0;
+ return za > zb ? -1 :
+ za < zb ? +1 : 0;
}
static void sort_display_list(void) {
static Pixmap pixmap, doublebuffers[2];
static Window window;
static GC linegc, fillgc;
-static int wwidth=WSZ, wheight=WSZ, currentbuffer;
+static int wwidth=WSZ, wheight=WSZ, wmindim=WSZ, wmaxdim=WSZ;
+static int ncut, currentbuffer, x11depth, x11screen;
-static double scale= WSZ * 0.3;
+static double scale= 0.3;
static double eye_z= -10, eye_x= 0;
static double cut_z= -9;
-static void xdie(int l, const char *str) {
- fprintf(stderr,"X library call failed, line %d: %s\n", l, str);
-}
-
-#define XA(w) ((w) ? (void)0 : xdie(__LINE__, #w))
-
static void drawtriangle(const Triangle *t) {
XPoint points[4];
int i;
double x= v[0];
double y= v[1];
double z= v[2];
- if (z < cut_z) return;
+
+ if (z < cut_z) { ncut++; return; }
+
double zezezp= eye_z / (eye_z - z);
- points[i].x= scale * (zezezp * (x - eye_x) + eye_x);
- points[i].y= scale * (zezezp * y );
+ points[i].x= scale * wmindim * (zezezp * (x - eye_x) + eye_x) + wwidth/2;
+ points[i].y= scale * wmindim * (zezezp * y ) + wheight/2;
}
points[3]= points[0];
-
- XA(! XFillPolygon(display,pixmap,fillgc, points,3,Convex,CoordModeOrigin) );
- XA(! XDrawLines(display,pixmap,linegc,points, 4,CoordModeOrigin) );
+
+ XA( XFillPolygon(display,pixmap,fillgc, points,3,Convex,CoordModeOrigin) );
+ XA( XDrawLines(display,pixmap,linegc,points, 4,CoordModeOrigin) );
+}
+
+static const unsigned long core_event_mask=
+ ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask;
+
+static void mkpixmaps(void) {
+ for (currentbuffer=0; currentbuffer<2; currentbuffer++) {
+ XA( pixmap= XCreatePixmap(display,window,wwidth,wheight,x11depth) );
+ doublebuffers[currentbuffer]= pixmap;
+ }
+ currentbuffer= 0;
}
static void display_prepare(void) {
XGCValues gcv;
XSetWindowAttributes wa;
- int screen, depth;
XVisualInfo vinfo;
+ XSizeHints hints;
XA( display= XOpenDisplay(0) );
- screen= DefaultScreen(display);
- depth= DefaultDepth(display,screen);
- XA(! XMatchVisualInfo(display,screen,depth, TrueColor,&vinfo) );
+ x11screen= DefaultScreen(display);
+ x11depth= DefaultDepth(display,x11screen);
+ XA( XMatchVisualInfo(display,x11screen,x11depth, TrueColor,&vinfo) );
- wa.event_mask= ButtonPress|ConfigureNotify;
+ wa.event_mask= core_event_mask;
XA( window= XCreateWindow(display, DefaultRootWindow(display),
- 10,10, wwidth,wheight, 0,depth,
+ 0,0, wwidth,wheight, 0,x11depth,
InputOutput, vinfo.visual,
CWEventMask, &wa) );
- for (currentbuffer=0; currentbuffer<2; currentbuffer++) {
- XA( pixmap= XCreatePixmap(display,window,wwidth,wheight,depth) );
- doublebuffers[currentbuffer]= pixmap;
- }
+ hints.flags= USPosition;
+ hints.x= 10;
+ hints.y= 10;
+ XSetWMNormalHints(display,window,&hints);
+
+ mkpixmaps();
gcv.function= GXcopy;
gcv.plane_mask= ~0UL;
- gcv.foreground= WhitePixel(display,screen);
+ gcv.foreground= WhitePixel(display,x11screen);
linegc= XCreateGC(display,pixmap, GCFunction|GCPlaneMask|GCForeground, &gcv);
gcv.function= GXclear;
gcv.plane_mask= ~0UL;
fillgc= XCreateGC(display,pixmap, GCFunction|GCPlaneMask, &gcv);
-
- currentbuffer= 0;
}
static void display_conformation(void) {
int i;
pixmap= doublebuffers[currentbuffer];
- XA(! XFillRectangle(display,pixmap,fillgc,0,0,wwidth,wheight) );
- for (i=0, t=displaylist; i<ntris; i++, t++)
+ XA( XFillRectangle(display,pixmap,fillgc,0,0,wwidth,wheight) );
+ for (i=0, t=displaylist, ncut=0; i<ntris; i++, t++)
drawtriangle(*t);
- XA(! XSetWindowBackgroundPixmap(display,window,pixmap) );
- XA(! XClearWindow(display,window) );
+ printf("shown, %d/%d triangles cut\n", ncut, ntris);
+
+ XA( XSetWindowBackgroundPixmap(display,window,pixmap) );
+ XA( XClearWindow(display,window) );
currentbuffer= !currentbuffer;
}
display_conformation();
}
+typedef struct {
+ const char *name;
+ void (*start)(void);
+ void (*delta)(double dx, double dy);
+ void (*conclude)(void);
+ void (*abandon)(void);
+} Drag;
+
+#define DRAG(x) \
+ static const Drag drag_##x= { \
+ #x, drag_##x##_start, drag_##x##_delta, \
+ drag_##x##_conclude, drag_##x##_abandon \
+ }
+
+#define DRAG_SAVING(x, thing) \
+ static typeof(thing) original_##thing; \
+ static void drag_##x##_start(void) { \
+ memcpy(&original_##thing, &thing, sizeof(thing)); \
+ } \
+ static void drag_##x##_conclude(void) { } \
+ static void drag_##x##_abandon(void) { \
+ memcpy(&thing, &original_##thing, sizeof(thing)); \
+ show(); \
+ } \
+ DRAG(x)
+
+static void drag_none_start(void) { }
+static void drag_none_delta(double dx, double dy) { }
+static void drag_none_conclude(void) { }
+static void drag_none_abandon(void) { }
+DRAG(none);
+
+static void drag_rotate_delta(double dx, double dy) {
+ /* We multiple our transformation matrix by this matrix:
+ * [ 1 0 0 ]
+ * [ 0 1 0 ]
+ * [ dx dy 1 ]
+ * and then renormalise.
+ */
+
+ static double rotateby[D3][D3]= {{1,0,0},{0,1,0},{-20,-20,1}};
+ STATIC_GSL_MATRIX(rotateby);
+
+ static double qr[D3][D3];
+ STATIC_GSL_MATRIX(qr);
+
+ static double tau[D3];
+ STATIC_GSL_VECTOR(tau);
+
+ int k;
+
+ K rotateby[k][k]= 1;
+ rotateby[0][2]= dx;
+ rotateby[1][2]= dy;
+
+ GA( gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0,
+ &rotateby_gsl,&transform_gsl, 0.0,&qr_gsl) );
+ GA( gsl_linalg_QR_decomp(&qr_gsl, &tau_gsl) );
+ GA( gsl_linalg_QR_unpack(&qr_gsl, &tau_gsl,
+ &transform_gsl, &rotateby_gsl /*dummy*/) );
+
+ printf("drag_rotate_delta...\n");
+ show();
+}
+DRAG_SAVING(rotate, transform);
+
+static void drag_scale_delta(double dx, double dy) {
+ scale *= pow(3.0, dy);
+ show();
+}
+DRAG_SAVING(scale, scale);
+
+static const Drag *drag= &drag_none;
+
+static int drag_last_x, drag_last_y;
+
+static void drag_position(int x, int y) {
+ drag->delta((x - drag_last_x) * 1.0 / wmaxdim,
+ (y - drag_last_y) * 1.0 / wmaxdim);
+ drag_last_x= x;
+ drag_last_y= y;
+}
+
+static void event_button(XButtonEvent *e) {
+ if (e->window != window || !e->same_screen) return;
+ if (e->type == ButtonPress) {
+ if (e->state || drag != &drag_none) {
+ printf("drag=%s press state=0x%lx abandon\n",
+ drag->name, (unsigned long)e->state);
+ drag->abandon();
+ drag= &drag_none;
+ return;
+ }
+ switch (e->button) {
+ case Button1: drag= &drag_rotate; break;
+ case Button2: drag= &drag_scale; break;
+ default: printf("unknown drag start %d\n", e->button);
+ }
+ printf("drag=%s press button=%lu start %d,%d\n",
+ drag->name, (unsigned long)e->button, e->x, e->y);
+ drag_last_x= e->x;
+ drag_last_y= e->y;
+ drag->start();
+ }
+ if (e->type == ButtonRelease) {
+ printf("drag=%s release %d,%d\n", drag->name, e->x, e->y);
+ drag_position(e->x, e->y);
+ drag->conclude();
+ drag= &drag_none;
+ }
+}
+
+static void event_motion(int x, int y) {
+ printf("drag=%s motion %d,%d\n", drag->name, x, y);
+ drag_position(x,y);
+}
+
+static void event_config(XConfigureEvent *e) {
+ if (e->width == wwidth && e->height == wheight)
+ return;
+
+ wwidth= e->width; wheight= e->height;
+ wmaxdim= wwidth > wheight ? wwidth : wheight;
+ wmindim= wwidth < wheight ? wwidth : wheight;
+ XA( XSetWindowBackground(display,window,BlackPixel(display,x11screen)) );
+ for (currentbuffer=0; currentbuffer<2; currentbuffer++)
+ XA( XFreePixmap(display, doublebuffers[currentbuffer]) );
+
+ mkpixmaps();
+ show();
+}
+
int main(int argc, const char *const *argv) {
+ XEvent event;
+ int k;
+ int motion_deferred=0, motion_x=-1, motion_y=-1;
+
if (argc != 2 || argv[1][0]=='-') {
fputs("need filename\n",stderr); exit(8);
}
input_filename= argv[1];
read_input();
+ K transform[k][k]= 1.0;
display_prepare();
show();
- XSync(display,0);
- for (;;);
+
+ XMapWindow(display,window);
+ for (;;) {
+ if (motion_deferred) {
+ int r= XCheckMaskEvent(display,~0UL,&event);
+ if (!r) {
+ event_motion(motion_x, motion_y);
+ motion_deferred=0;
+ continue;
+ }
+ } else {
+ XNextEvent(display,&event);
+ }
+ switch (event.type) {
+
+ case ButtonPress:
+ case ButtonRelease: event_button(&event.xbutton); break;
+
+ case ConfigureNotify: event_config(&event.xconfigure); break;
+
+ case MotionNotify:
+ motion_x= event.xmotion.x;
+ motion_y= event.xmotion.y;
+ motion_deferred= 1;
+ continue;
+
+ default:
+ printf("unknown event type %u 0x%x\n", event.type,event.type);
+ }
+ }
}