2 * Displays a conformation
12 typedef struct { double vertex[3][D3]; } Triangle;
14 static Triangle trisbuffer[MAXTRIS], *displaylist[MAXTRIS];
16 static Vertices conformation;
18 #define STATIC_MATRIX(x) \
19 static double x[D3][D3]; \
20 static gsl_matrix x##_gsl= { D3,D3,D3,&x[0][0] };
22 STATIC_MATRIX(transform);
24 const char *input_filename;
26 static void read_input(void) {
30 f= fopen(input_filename, "rb"); if (!f) diee("input file");
32 r= fread(&conformation,sizeof(conformation),1,f); if (r!=1) diee("fread");
36 static void transform_coordinates(void) {
43 static void addtriangle(int va, int vb, int vc) {
44 Triangle *t= &trisbuffer[ntris];
47 assert(ntris < MAXTRIS);
49 t->vertex[0][k]= conformation[va][k];
50 t->vertex[1][k]= conformation[vb][k];
51 t->vertex[2][k]= conformation[vc][k];
53 displaylist[ntris++]= t;
56 static void generate_display_list(void) {
61 /* We use the two triangles in the parallelogram vb, vb+e1, vb+e0, vb+e2.
62 * We go round each triangle clockwise (although our surface is non-
63 * orientable so it shouldn't matter).
65 for (e=0; e<3; e++) ve[e]= EDGE_END2(vb,e);
67 if (ve[1]>=0) addtriangle(vb,ve[0],ve[1]);
68 if (ve[2]>=0) addtriangle(vb,ve[2],ve[0]);
73 static int dl_compare(const void *tav, const void *tbv) {
74 const Triangle *const *tap= tav, *ta= *tap;
75 const Triangle *const *tbp= tbp, *tb= *tbp;
76 double za= ta->vertex[0][2];
77 double zb= tb->vertex[0][2];
82 static void sort_display_list(void) {
83 qsort(displaylist, ntris, sizeof(*displaylist), dl_compare);
86 /*---------- X stuff ----------*/
90 static Display *display;
91 static Pixmap pixmap, doublebuffers[2];
93 static GC linegc, fillgc;
94 static int wwidth=WSZ, wheight=WSZ, wmaxdim=WSZ, currentbuffer;
97 static double scale= WSZ * 0.3;
98 static double eye_z= -10, eye_x= 0;
99 static double cut_z= -9;
101 static void xdie(int l, const char *str) {
102 fprintf(stderr,"X library call failed, line %d: %s\n", l, str);
105 #define XA(w) ((w) ? (void)0 : xdie(__LINE__, #w))
107 static void drawtriangle(const Triangle *t) {
111 for (i=0; i<3; i++) {
112 double *v= t->vertex[i];
117 if (z < cut_z) { ncut++; return; }
119 double zezezp= eye_z / (eye_z - z);
120 points[i].x= scale * (zezezp * (x - eye_x) + eye_x) + WSZ/2;
121 points[i].y= scale * (zezezp * y ) + WSZ/2;
123 points[3]= points[0];
125 XA( XFillPolygon(display,pixmap,fillgc, points,3,Convex,CoordModeOrigin) );
126 XA( XDrawLines(display,pixmap,linegc,points, 4,CoordModeOrigin) );
129 static const unsigned long core_event_mask=
130 ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask;
132 static void display_prepare(void) {
134 XSetWindowAttributes wa;
139 XA( display= XOpenDisplay(0) );
140 screen= DefaultScreen(display);
141 depth= DefaultDepth(display,screen);
142 XA( XMatchVisualInfo(display,screen,depth, TrueColor,&vinfo) );
144 wa.event_mask= core_event_mask;
145 XA( window= XCreateWindow(display, DefaultRootWindow(display),
146 0,0, wwidth,wheight, 0,depth,
147 InputOutput, vinfo.visual,
150 hints.flags= USPosition;
153 XSetWMNormalHints(display,window,&hints);
155 for (currentbuffer=0; currentbuffer<2; currentbuffer++) {
156 XA( pixmap= XCreatePixmap(display,window,wwidth,wheight,depth) );
157 doublebuffers[currentbuffer]= pixmap;
160 gcv.function= GXcopy;
161 gcv.plane_mask= ~0UL;
162 gcv.foreground= WhitePixel(display,screen);
163 linegc= XCreateGC(display,pixmap, GCFunction|GCPlaneMask|GCForeground, &gcv);
165 gcv.function= GXclear;
166 gcv.plane_mask= ~0UL;
167 fillgc= XCreateGC(display,pixmap, GCFunction|GCPlaneMask, &gcv);
172 static void display_conformation(void) {
176 pixmap= doublebuffers[currentbuffer];
177 XA( XFillRectangle(display,pixmap,fillgc,0,0,wwidth,wheight) );
178 for (i=0, t=displaylist, ncut=0; i<ntris; i++, t++)
180 printf("shown, %d/%d triangles cut\n", ncut, ntris);
182 XA( XSetWindowBackgroundPixmap(display,window,pixmap) );
183 XA( XClearWindow(display,window) );
184 currentbuffer= !currentbuffer;
187 static void show(void) {
189 transform_coordinates();
190 generate_display_list();
192 display_conformation();
198 void (*delta)(double dx, double dy);
199 void (*conclude)(void);
200 void (*abandon)(void);
204 static const Drag drag_##x= { \
205 #x, drag_##x##_start, drag_##x##_delta, \
206 drag_##x##_conclude, drag_##x##_abandon \
209 #define DRAG_SAVING(x, thing) \
210 static typeof(thing) original_##thing; \
211 static void drag_##x##_start(void) { \
212 memcpy(&original_##thing, &thing, sizeof(thing)); \
214 static void drag_##x##_conclude(void) { } \
215 static void drag_##x##_abandon(void) { \
216 memcpy(&thing, &original_##thing, sizeof(thing)); \
221 static void drag_none_start(void) { }
222 static void drag_none_delta(double dx, double dy) { }
223 static void drag_none_conclude(void) { }
224 static void drag_none_abandon(void) { }
227 static void drag_rotate_delta(double dx, double dy) {
228 /* We multiple our transformation matrix by this matrix:
232 * and then renormalise.
235 STATIC_MATRIX(rotateby);
237 static double tau[D3];
238 static gsl_vector tau_gsl= { D3,1,&tau[0] };
246 gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0,
247 &rotateby_gsl,&transform_gsl, 0.0,&qr_gsl);
248 gsl_linalg_QR_decomp(&qr_gsl, &tau_gsl);
249 gsl_linalg_QR_unpack(&qr_gsl, &tau_gsl,
250 &transform_gsl, &rotateby_gsl /*dummy*/);
252 printf("drag_rotate_delta...\n");
255 DRAG_SAVING(rotate, transform);
257 static void drag_scale_delta(double dx, double dy) {
258 scale *= pow(3.0, dy);
261 DRAG_SAVING(scale, scale);
263 static const Drag *drag= &drag_none;
265 static int drag_last_x, drag_last_y;
267 static void drag_position(int x, int y) {
268 drag->delta((x - drag_last_x) * 1.0 / wmaxdim,
269 (y - drag_last_y) * 1.0 / wmaxdim);
274 static void event_button(XButtonEvent *e) {
275 if (e->window != window || !e->same_screen) return;
276 if (e->type == ButtonPress) {
277 if (e->state || drag != &drag_none) {
278 printf("drag=%s press state=0x%lx abandon\n",
279 drag->name, (unsigned long)e->state);
285 case Button1: drag= &drag_rotate; break;
286 case Button2: drag= &drag_scale; break;
287 default: printf("unknown drag start %d\n", e->button);
289 printf("drag=%s press button=%lu start %d,%d\n",
290 drag->name, (unsigned long)e->button, e->x, e->y);
295 if (e->type == ButtonRelease) {
296 printf("drag=%s release %d,%d\n", drag->name, e->x, e->y);
297 drag_position(e->x, e->y);
303 static void event_motion(int x, int y) {
304 printf("drag=%s motion %d,%d\n", drag->name, x, y);
308 static void event_config(XConfigureEvent *e) { printf("configure\n"); }
310 int main(int argc, const char *const *argv) {
312 int motion_deferred=0, motion_x=-1, motion_y=-1;
314 if (argc != 2 || argv[1][0]=='-') {
315 fputs("need filename\n",stderr); exit(8);
317 input_filename= argv[1];
323 XMapWindow(display,window);
325 if (motion_deferred) {
326 int r= XCheckMaskEvent(display,~0UL,&event);
328 event_motion(motion_x, motion_y);
333 XNextEvent(display,&event);
335 switch (event.type) {
338 case ButtonRelease: event_button(&event.xbutton); break;
340 case ConfigureNotify: event_config(&event.xconfigure); break;
343 motion_x= event.xmotion.x;
344 motion_y= event.xmotion.y;
349 printf("unknown event type %u 0x%x\n", event.type,event.type);