chiark / gitweb /
better with more bendingness costs
[moebius2.git] / view.c
diff --git a/view.c b/view.c
index 742db8075e6d3e9df854397fd4441079673d5d79..36b85b58ecd1a4fa08394f221cb46ccafdd59d81 100644 (file)
--- a/view.c
+++ b/view.c
@@ -5,8 +5,6 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/poll.h>
 
 #include "mgraph.h"
@@ -25,12 +23,46 @@ static GSL_MATRIX(transform);
 static FILE *input_f;
 static struct stat input_stab;
 static const char *input_filename;
+static int pause_updates;
+
+#define TITLE_MAX 100
+static char title[TITLE_MAX+1];
 
 static void read_input(void) {
-  int r;
+  int r, last_readlink_r, last_readlink_errno=0;
+  char symlink_check[sizeof(title)];
+
+  last_readlink_r= -2;
   
-  if (input_f) fclose(input_f);
-  input_f= fopen(input_filename, "rb");  if (!input_f) diee("input file");
+  for (;;) {
+    r= readlink(input_filename, symlink_check, TITLE_MAX);
+    assert(r<=TITLE_MAX);
+    assert(r!=-2);
+
+    if (r>=0) symlink_check[r]= 0;
+    else symlink_check[0]= 0;
+
+    if (r == last_readlink_r &&
+       (r<0
+        ? (errno==last_readlink_errno)
+        : !strcmp(symlink_check, title))) {
+      assert(input_f);
+      if (r<0) {
+       if (last_readlink_errno==EINVAL)
+         snprintf(title,sizeof(title),"%s",input_filename);
+       else
+         snprintf(title,sizeof(title),"? %s",strerror(last_readlink_errno));
+      }
+      break;
+    }
+    
+    strcpy(title, symlink_check);
+    last_readlink_r= r;
+    last_readlink_errno= errno;
+
+    if (input_f) fclose(input_f);
+    input_f= fopen(input_filename, "rb");  if (!input_f) diee("input file");
+  }
 
   if (fstat(fileno(input_f), &input_stab)) diee("fstat input file");
 
@@ -46,7 +78,7 @@ static void transform_coordinates(void) {
 
   int v, k;
   
-  FOR_VERTEX(v) {
+  FOR_VERTEX(v,INNER) {
     input_gsl.data= &conformation[v][0];
     GA( gsl_blas_dgemv(CblasNoTrans, 1.0,&transform_gsl, &input_gsl,
                       0.0, &result_gsl) );
@@ -78,26 +110,29 @@ static void generate_display_list(void) {
   int vb, ve[V6], e;
 
   ntris= 0;
-  FOR_VERTEX(vb) {
+  FOR_VERTEX(vb,INNER) {
     /* We use the two triangles in the parallelogram vb, vb+e5, vb+e0, vb+e1.
      * We go round each triangle clockwise (although our surface is non-
      * orientable so it shouldn't matter).  Picking the parallelogram
      * to our right avoids getting it wrong at the join.
      */
+//if ((vb & YMASK) > Y1) continue;
+//if ((vb & XMASK) > 2) continue; 
     for (e=0; e<V6; e++) ve[e]= EDGE_END2(vb,e);
     assert(ve[0]>=0);
     if (ve[5]>=0) addtriangle(vb,ve[0],ve[5]);
+//continue;
     if (ve[1]>=0) addtriangle(vb,ve[1],ve[0]);
   }
 
   if (!vertex_in_triangles_checked) {
     int v, expd;
-    FOR_VERTEX(v) {
+    FOR_VERTEX(v,INNER) {
       expd= RIM_VERTEX_P(v) ? 3 : 6;
       if (vertex_in_triangles[v] != expd) {
        fprintf(stderr,"vertex %02x used for %d triangles, expected %d\n",
                v, vertex_in_triangles[v], expd);
-       abort();
+//     abort();
       }
     }
     vertex_in_triangles_checked= 1;
@@ -170,7 +205,7 @@ static void drawtriangle(const Triangle *t) {
 
 static const unsigned long core_event_mask=
   ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask|
-  KeyPressMask;
+  KeyPressMask|SubstructureNotifyMask;
 
 static void mkpixmaps(void) {
   for (currentbuffer=0; currentbuffer<2; currentbuffer++) {
@@ -253,7 +288,8 @@ static void display_conformation(void) {
     drawtriangles(&dmwhite);
     printf("shown, %d/%d triangles cut\n", ncut, ntris);
   }
-  
+
+  XA( XStoreName(display,window,title) );
   XA( XSetWindowBackgroundPixmap(display,window,pixmap) );
   XA( XClearWindow(display,window) );
   currentbuffer= !currentbuffer;
@@ -335,7 +371,7 @@ static void make_z_rotation(double rotz[D3][D3], double cz, double sz) {
   rotz[0][0]=  cz;    rotz[0][1]=  sz;     rotz[0][2]=  0;
   rotz[1][0]= -sz;    rotz[1][1]=  cz;     rotz[1][2]=  0;
   rotz[2][0]=   0;    rotz[2][1]=   0;     rotz[2][2]=  1;
-}  
+}
 
 static void drag_rotate_delta(double dx, double dy) {
   /* We multiple our transformation matrix by a matrix:
@@ -538,10 +574,38 @@ static void event_motion(int x, int y) {
   drag_position(x,y);
 }
 
+static void transform_preset_record(const char *fn, const char *fn_new) {
+  FILE *f;
+  f= fopen(fn_new,"wb");
+  if (!f) diee("open new transform");
+  if (fwrite(transform,sizeof(transform),1,f) != 1) diee("write transform");
+  if (fclose(f)) diee("fclose new transform");
+  if (rename(fn_new,fn)) diee("install transform");
+}
+
+static void transform_preset_playback(const char *fn) {
+  FILE *f;
+  f= fopen(fn,"rb");
+  if (!f && errno==ENOENT) {
+    fprintf(stderr,"no preset %s\n",fn);
+    XBell(display,100);
+    return;
+  }
+  errno= 0;
+  if (fread(transform,sizeof(transform),1,f) != 1) {
+    perror("read preset!");
+    XBell(display,100);
+    return;
+  }
+  fclose(f);
+  show();
+}
+
 static void event_key(XKeyEvent *e) {
   KeySym ks;
-  char buf[10];
-  int r;
+  XKeyEvent e_nomod;
+  char buf[10], buf_nomod[10];
+  int r, r_nomod;
 
   r= XLookupString(e,buf,sizeof(buf)-1,&ks,0);
   if (!r) {
@@ -550,17 +614,43 @@ static void event_key(XKeyEvent *e) {
     return;
   }
 
-  if (!strcmp(buf,"q")) exit(0);
-  if (!strcmp(buf,"w")) {
+  if (!strcmp(buf,"q"))
+    exit(0);
+  else if (!strcmp(buf,"p"))
+    pause_updates= !pause_updates;
+  else if (!strcmp(buf,"w")) {
     wireframe= !wireframe;
     show();
     return;
-  }
-  if (!strcmp(buf,"d")) {
+  } else if (!strcmp(buf,"d")) {
     eyes_apart= eyes_apart>0 ? eyes_apart_min : eyes_apart_preferred;
     show();
     return;
   }
+
+  e_nomod= *e;
+  e_nomod.state= 0;
+  buf_nomod[0]= 0;
+  r_nomod= XLookupString(&e_nomod,buf_nomod,sizeof(buf_nomod)-1,&ks,0);
+  if (r_nomod && !buf_nomod[1] && buf_nomod[0]>='0' && buf_nomod[0]<='9') {
+    char filename[20], filename_new[25];
+    snprintf(filename,sizeof(filename)-1,".view-preset-%s",buf_nomod);
+    snprintf(filename_new,sizeof(filename_new)-1,"%s.new",filename);
+    printf("transform preset %d %s\n", e->state, filename);
+    if (e->state) transform_preset_record(filename,filename_new);
+    else transform_preset_playback(filename);
+    return;
+  }
+
+  printf("unknown key keycode=%d state=0x%x char=%c 0x%02x "
+        "[rnm=%d bnm[0,1]=0x%02x,%02x]\n",
+        e->keycode, e->state, buf[0]>' ' && buf[0]<127 ? buf[0] : '?',
+        buf[0], r_nomod, buf_nomod[0], buf_nomod[1]);
+  printf("%d %d %d %d\n",
+        r_nomod,
+        !buf_nomod[1],
+        buf_nomod[0]>='0',
+        buf_nomod[0]<='9');
 }
 
 static void event_config(XConfigureEvent *e) {
@@ -600,7 +690,7 @@ static void check_input(void) {
 
 static void topocheck(void) {
   int v1,e,v2,eprime,v1prime, count;
-  FOR_EDGE(v1,e,v2) {
+  FOR_EDGE(v1,e,v2, INNER) {
     count= 0;
     FOR_VEDGE(v2,eprime,v1prime)
       if (v1prime==v1) count++;
@@ -623,6 +713,7 @@ int main(int argc, const char *const *argv) {
   struct pollfd *polls=0;
   int motion_deferred=0, motion_x=-1, motion_y=-1;
 
+  mgraph_prepare();
   topocheck();
   if (argc==1) { printf("topology self-consistent, ok\n"); exit(0); }
   
@@ -655,8 +746,11 @@ int main(int argc, const char *const *argv) {
     polls[i].fd= ConnectionNumber(display);
     polls[i].events= wantedevents;
 
-    r= poll(polls, nxfds+1, motion_deferred ? 0 : 200);
-    if (r<0) diee("poll");
+    r= poll(polls, nxfds+1, motion_deferred ? 0 : pause_updates ? -1 : 200);
+    if (r<0) {
+      if (errno==EINTR) continue;
+      diee("poll");
+    }
 
     for (i=0; i<nxfds; i++)
       if (polls[i].revents)
@@ -668,7 +762,8 @@ int main(int argc, const char *const *argv) {
        event_motion(motion_x, motion_y);
        motion_deferred=0;
       }
-      check_input();
+      if (!pause_updates)
+       check_input();
       continue;
     }