chiark / gitweb /
0921edfb52291b4c0f8addb866e920b026bf6b8c
[moebius2.git] / project.c
1 /*
2  * Displays a conformation
3  */
4
5 #include <X11/Xlib.h>
6 #include <X11/Xutil.h>
7
8 #include "mgraph.h"
9
10 #define MAXTRIS (N*2)
11
12 typedef struct { double vertex[3][D3]; } Triangle;
13
14 static Triangle trisbuffer[MAXTRIS], *displaylist[MAXTRIS];
15 static int ntris;
16 static Vertices conformation;
17
18 #define STATIC_MATRIX(x)                                        \
19   static double x[D3][D3];                                      \
20   static gsl_matrix x##_gsl= { D3,D3,D3,&x[0][0] };
21
22 STATIC_MATRIX(transform);
23
24 const char *input_filename;
25
26 static void read_input(void) {
27   FILE *f;
28   int r;
29   
30   f= fopen(input_filename, "rb");  if (!f) diee("input file");
31   errno= 0;
32   r= fread(&conformation,sizeof(conformation),1,f);  if (r!=1) diee("fread");
33   fclose(f);
34 }
35
36 static void transform_coordinates(void) {
37   int v;
38
39   FOR_VERTEX(v) {
40   }
41 }
42
43 static void addtriangle(int va, int vb, int vc) {
44   Triangle *t= &trisbuffer[ntris];
45   int k;
46   
47   assert(ntris < MAXTRIS);
48   K {
49     t->vertex[0][k]= conformation[va][k];
50     t->vertex[1][k]= conformation[vb][k];
51     t->vertex[2][k]= conformation[vc][k];
52   }
53   displaylist[ntris++]= t;
54 }
55
56 static void generate_display_list(void) {
57   int vb, ve[3], e;
58
59   ntris= 0;
60   FOR_VERTEX(vb) {
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).
64      */
65     for (e=0; e<3; e++) ve[e]= EDGE_END2(vb,e);
66     if (ve[0]>=0) {
67       if (ve[1]>=0) addtriangle(vb,ve[0],ve[1]);
68       if (ve[2]>=0) addtriangle(vb,ve[2],ve[0]);
69     }
70   }
71 }    
72
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];
78   return za > zb ? -1 :
79          za < zb ? +1 : 0;
80 }
81
82 static void sort_display_list(void) {
83   qsort(displaylist, ntris, sizeof(*displaylist), dl_compare);
84 }
85
86 /*---------- X stuff ----------*/
87
88 #define WSZ 400
89
90 static Display *display;
91 static Pixmap pixmap, doublebuffers[2];
92 static Window window;
93 static GC linegc, fillgc;
94 static int wwidth=WSZ, wheight=WSZ, wmaxdim=WSZ, currentbuffer;
95 static int ncut;
96
97 static double scale= WSZ * 0.3;
98 static double eye_z= -10, eye_x= 0;
99 static double cut_z= -9;
100
101 static void xdie(int l, const char *str) {
102   fprintf(stderr,"X library call failed, line %d: %s\n", l, str);
103 }
104
105 #define XA(w) ((w) ? (void)0 : xdie(__LINE__, #w))
106
107 static void drawtriangle(const Triangle *t) {
108   XPoint points[4];
109   int i;
110
111   for (i=0; i<3; i++) {
112     double *v= t->vertex[i];
113     double x= v[0];
114     double y= v[1];
115     double z= v[2];
116
117     if (z < cut_z) { ncut++; return; }
118     
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;
122   }
123   points[3]= points[0];
124
125   XA( XFillPolygon(display,pixmap,fillgc, points,3,Convex,CoordModeOrigin) );
126   XA( XDrawLines(display,pixmap,linegc,points, 4,CoordModeOrigin) );
127 }
128
129 static const unsigned long core_event_mask=
130   ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask;
131
132 static void display_prepare(void) {
133   XGCValues gcv;
134   XSetWindowAttributes wa;
135   int screen, depth;
136   XVisualInfo vinfo;
137   XSizeHints hints;
138   
139   XA( display= XOpenDisplay(0) );
140   screen= DefaultScreen(display);
141   depth= DefaultDepth(display,screen);
142   XA( XMatchVisualInfo(display,screen,depth, TrueColor,&vinfo) );
143   
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,
148                             CWEventMask, &wa) );
149
150   hints.flags= USPosition;
151   hints.x= 10;
152   hints.y= 10;
153   XSetWMNormalHints(display,window,&hints);
154   
155   for (currentbuffer=0; currentbuffer<2; currentbuffer++) {
156     XA( pixmap= XCreatePixmap(display,window,wwidth,wheight,depth) );
157     doublebuffers[currentbuffer]= pixmap;
158   }
159
160   gcv.function= GXcopy;
161   gcv.plane_mask= ~0UL;
162   gcv.foreground= WhitePixel(display,screen);
163   linegc= XCreateGC(display,pixmap, GCFunction|GCPlaneMask|GCForeground, &gcv);
164   
165   gcv.function= GXclear;
166   gcv.plane_mask= ~0UL;
167   fillgc= XCreateGC(display,pixmap, GCFunction|GCPlaneMask, &gcv);
168
169   currentbuffer= 0;
170 }
171
172 static void display_conformation(void) {
173   Triangle *const *t;
174   int i;
175   
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++)
179     drawtriangle(*t);
180   printf("shown, %d/%d triangles cut\n", ncut, ntris);
181   
182   XA( XSetWindowBackgroundPixmap(display,window,pixmap) );
183   XA( XClearWindow(display,window) );
184   currentbuffer= !currentbuffer;
185 }
186
187 static void show(void) {
188   read_input();
189   transform_coordinates();
190   generate_display_list();
191   sort_display_list();
192   display_conformation();
193 }
194
195 typedef struct {
196   const char *name;
197   void (*start)(void);
198   void (*delta)(double dx, double dy);
199   void (*conclude)(void);
200   void (*abandon)(void);
201 } Drag;
202
203 #define DRAG(x)                                 \
204   static const Drag drag_##x= {                 \
205     #x, drag_##x##_start, drag_##x##_delta,     \
206     drag_##x##_conclude, drag_##x##_abandon     \
207   }
208
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));   \
213   }                                                     \
214   static void drag_##x##_conclude(void) { }             \
215   static void drag_##x##_abandon(void) {                \
216     memcpy(&thing, &original_##thing, sizeof(thing));   \
217     show();                                             \
218   }                                                     \
219   DRAG(x)
220
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) { }
225 DRAG(none);
226
227 static void drag_rotate_delta(double dx, double dy) {
228   /* We multiple our transformation matrix by this matrix:
229    *     [  1   0   0 ]
230    *     [  0   1   0 ]
231    *     [ dx  dy   1 ]
232    * and then renormalise.
233    */
234
235   STATIC_MATRIX(rotateby);
236   STATIC_MATRIX(qr);
237   static double tau[D3];
238   static gsl_vector tau_gsl= { D3,1,&tau[0] };
239   
240   int k;
241   
242   K rotateby[k][k]= 1;
243   rotateby[0][2]= dx;
244   rotateby[1][2]= dy;
245   
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*/);
251
252   printf("drag_rotate_delta...\n");
253   show();
254 }
255 DRAG_SAVING(rotate, transform);
256
257 static void drag_scale_delta(double dx, double dy) {
258   scale *= pow(3.0, dy);
259   show();
260 }
261 DRAG_SAVING(scale, scale);
262
263 static const Drag *drag= &drag_none;
264
265 static int drag_last_x, drag_last_y;
266
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);
270   drag_last_x= x;
271   drag_last_y= y;
272 }
273
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);
280       drag->abandon();
281       drag= &drag_none;
282       return;
283     }
284     switch (e->button) {
285     case Button1: drag= &drag_rotate;  break;
286     case Button2: drag= &drag_scale;   break;
287     default: printf("unknown drag start %d\n", e->button);
288     }
289     printf("drag=%s press button=%lu start %d,%d\n",
290            drag->name, (unsigned long)e->button, e->x, e->y);
291     drag_last_x= e->x;
292     drag_last_y= e->y;
293     drag->start();
294   }
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);
298     drag->conclude();
299     drag= &drag_none;
300   }
301 }
302
303 static void event_motion(int x, int y) {
304   printf("drag=%s motion %d,%d\n", drag->name, x, y);
305   drag_position(x,y);
306 }
307
308 static void event_config(XConfigureEvent *e) { printf("configure\n"); }
309
310 int main(int argc, const char *const *argv) {
311   XEvent event;
312   int motion_deferred=0, motion_x=-1, motion_y=-1;
313   
314   if (argc != 2 || argv[1][0]=='-') {
315     fputs("need filename\n",stderr); exit(8);
316   }
317   input_filename= argv[1];
318
319   read_input();
320   display_prepare();
321   show();
322
323   XMapWindow(display,window);
324   for (;;) {
325     if (motion_deferred) {
326       int r= XCheckMaskEvent(display,~0UL,&event);
327       if (!r) {
328         event_motion(motion_x, motion_y);
329         motion_deferred=0;
330         continue;
331       }
332     } else {
333       XNextEvent(display,&event);
334     }
335     switch (event.type) {
336
337     case ButtonPress:
338     case ButtonRelease:     event_button(&event.xbutton);     break;
339       
340     case ConfigureNotify:   event_config(&event.xconfigure);  break;
341
342     case MotionNotify:
343       motion_x= event.xmotion.x;
344       motion_y= event.xmotion.y;
345       motion_deferred= 1;
346       continue;
347       
348     default:
349       printf("unknown event type %u 0x%x\n", event.type,event.type);
350     }
351   }
352 }
353