chiark / gitweb /
viewdims variable
[moebius2.git] / view.c
diff --git a/view.c b/view.c
index 712623c02f6667694c760b65e37cd6306f41ede8..cc86803594841154686a48adb5c77aff1bb5b316 100644 (file)
--- a/view.c
+++ b/view.c
@@ -25,6 +25,7 @@ static GSL_MATRIX(transform);
 static FILE *input_f;
 static struct stat input_stab;
 static const char *input_filename;
+static int pause_updates;
 
 static void read_input(void) {
   int r;
@@ -54,6 +55,8 @@ static void transform_coordinates(void) {
   }
 }
 
+static int vertex_in_triangles[N], vertex_in_triangles_checked;
+
 static void addtriangle(int va, int vb, int vc) {
   Triangle *t= &trisbuffer[ntris];
   int k;
@@ -64,30 +67,51 @@ static void addtriangle(int va, int vb, int vc) {
     t->vertex[1][k]= conformation[vb][k];
     t->vertex[2][k]= conformation[vc][k];
   }
+  if (!vertex_in_triangles_checked) {
+    vertex_in_triangles[va]++;
+    vertex_in_triangles[vb]++;
+    vertex_in_triangles[vc]++;
+  }
   displaylist[ntris++]= t;
 }
 
 static void generate_display_list(void) {
-  int vb, ve[3], e;
+  int vb, ve[V6], e;
 
   ntris= 0;
   FOR_VERTEX(vb) {
-    /* We use the two triangles in the parallelogram vb, vb+e0, vb+e1, vb+e2.
+    /* 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).
+     * orientable so it shouldn't matter).  Picking the parallelogram
+     * to our right avoids getting it wrong at the join.
      */
-    for (e=0; e<3; e++) ve[e]= EDGE_END2(vb,e);
-    if (ve[1]>=0) {
-      if (ve[0]>=0) addtriangle(vb,ve[0],ve[1]);
-      if (ve[2]>=0) addtriangle(vb,ve[1],ve[2]);
+//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) {
+      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();
+      }
     }
+    vertex_in_triangles_checked= 1;
   }
 }    
 
 static int dl_compare(const void *tav, const void *tbv) {
   int i;
   const Triangle *const *tap= tav, *ta= *tap;
-  const Triangle *const *tbp= tbp, *tb= *tbp;
+  const Triangle *const *tbp= tbv, *tb= *tbp;
   double za=0, zb=0;
   for (i=0; i<3; i++) {
     za += ta->vertex[i][2];
@@ -114,7 +138,7 @@ static Window window;
 static DrawingMode dmred, dmblue, dmwhite;
 static const DrawingMode *dmcurrent;
 static int wwidth=WSZ, wheight=WSZ, wmindim=WSZ, wmaxdim=WSZ;
-static int ncut, currentbuffer, x11depth, x11screen;
+static int ncut, currentbuffer, x11depth, x11screen, wireframe;
 XVisualInfo visinfo;
 
 static double sizeadj_scale= 0.3, eyes_apart, scale_wmindim;
@@ -128,7 +152,7 @@ static void drawtriangle(const Triangle *t) {
   int i;
 
   for (i=0; i<3; i++) {
-    double *v= t->vertex[i];
+    const double *v= t->vertex[i];
     double x= v[0];
     double y= v[1];
     double z= v[2];
@@ -141,15 +165,16 @@ static void drawtriangle(const Triangle *t) {
   }
   points[3]= points[0];
 
-  XA( XFillPolygon(display,pixmap, dmcurrent->fillgc,
-                  points,3,Convex,CoordModeOrigin) );
+  if (!wireframe)
+    XA( XFillPolygon(display,pixmap, dmcurrent->fillgc,
+                    points,3,Convex,CoordModeOrigin) );
   XA( XDrawLines(display,pixmap, dmcurrent->linegc,
                 points, 4,CoordModeOrigin) );
 }
 
 static const unsigned long core_event_mask=
   ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask|
-  KeyPressMask;
+  KeyPressMask|SubstructureNotifyMask;
 
 static void mkpixmaps(void) {
   for (currentbuffer=0; currentbuffer<2; currentbuffer++) {
@@ -249,7 +274,7 @@ static void show(void) {
 
 typedef struct {
   const char *name;
-  void (*start)(void);
+  void (*start)(const XButtonEvent *e);
   void (*delta)(double dx, double dy);
   void (*conclude)(void);
   void (*abandon)(void);
@@ -261,10 +286,11 @@ typedef struct {
     drag_##x##_conclude, drag_##x##_abandon    \
   }
 
-#define DRAG_SAVING(x, thing)                          \
+#define DRAG_SAVING(x, thing, hook)                    \
   static typeof(thing) original_##thing;               \
-  static void drag_##x##_start(void) {                 \
+  static void drag_##x##_start(const XButtonEvent *e) {        \
     memcpy(&original_##thing, &thing, sizeof(thing));  \
+    hook;                                              \
   }                                                    \
   static void drag_##x##_conclude(void) { }            \
   static void drag_##x##_abandon(void) {               \
@@ -273,7 +299,7 @@ typedef struct {
   }                                                    \
   DRAG(x)
 
-static void drag_none_start(void) { }
+static void drag_none_start(const XButtonEvent *e) { }
 static void drag_none_delta(double dx, double dy) { }
 static void drag_none_conclude(void) { }
 static void drag_none_abandon(void) { }
@@ -296,6 +322,25 @@ static void pmatrix(const char *n, double m[D3][D3]) {
 }
 #define PMATRIX(x) pmatrix(#x,x);
 
+static double drag_transform_conv_x_z= 0;
+static double drag_transform_conv_y_z= 0;
+
+static void drag_transform_prep(const XButtonEvent *e) {
+  static const double factor= 2.5;
+  drag_transform_conv_x_z= MAX( MIN(e->y * factor / wheight - (factor/2),
+                                   1.0), -1.0);
+  drag_transform_conv_y_z= MAX( MIN(e->x * factor / wwidth  - (factor/2),
+                                   1.0), -1.0);
+  printf("drag_transform_conv_{x,y}_z = %g,%g\n",
+        drag_transform_conv_x_z, drag_transform_conv_y_z);
+}
+
+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:
    *
@@ -310,31 +355,56 @@ static void drag_rotate_delta(double dx, double dy) {
    * we make cy and sy be cos() and sin(hypot(x,y)) and use
    * with cr,sr as cos() and sin(atan2(y,y)):
    *
-   * Ie we would do  T' = R^T X R T   where
-   *             or  T' =    C    T   where  C = R^T X R  and
+   * Ie we would do  T' = R^T X R T   where
+   *             or  T' =    C    T   where  C = R^T X R  and
    *
    *  adjustment R = [  cr  sr  0 ]
    *                 [ -sr  cr  0 ]
-   *                 [  0    0  1 ]
+   *                 [  0    0  1 ]    or make_z_rotation(cr,sr)
+   *
+   *  rotation Z   = [  cz  sz  0 ]
+   *                 [ -sz  cz  0 ]
+   *                 [  0    0  1 ]    or make_z_rotation(cz,sz)
    */
 
-  double rotx[D3][D3], adjr[D3][D3];
+  double rotx[D3][D3], adjr[D3][D3], rotz[D3][D3];
   GSL_MATRIX(rotx);
   GSL_MATRIX(adjr);
+  GSL_MATRIX(rotz);
 
   static double temp[D3][D3], change[D3][D3];
   static GSL_MATRIX(temp);
   static GSL_MATRIX(change);
 
+  printf("\nTRANSFORM %g, %g\n", dx,dy);
+
+  double dz= -drag_transform_conv_x_z * dx +
+              drag_transform_conv_y_z * dy;
+         
+  dx *= (1 - fabs(drag_transform_conv_x_z));
+  dy *= (1 - fabs(drag_transform_conv_y_z));
+
   double d= hypot(dx,dy);
-  if (d < 1e-6) return;
+
+  printf(" dx,dy,dz = %g, %g, %g    d = %g\n", dx,dy,dz, d);
+
+  if (hypot(d,dz) < 1e-6) return;
+
+  printf(" no xy rotation\n");
 
   double ang= d*2.0;
   
   double cy= cos(ang);
   double sy= sin(ang);
-  double cr= -dy / d;
-  double sr=  dx / d;
+
+  double cr, sr;
+  if (d > 1e-6) {
+    cr= -dy / d;
+    sr=  dx / d;
+  } else {
+    cr= 1;
+    sr= 0;
+  }
   printf("\n d=%g cy,sy=%g,%g cr,sr=%g,%g\n\n", d,cy,sy,cr,sr);
   
   rotx[0][0]=   1;    rotx[0][1]=   0;     rotx[0][2]=  0;
@@ -342,26 +412,33 @@ static void drag_rotate_delta(double dx, double dy) {
   rotx[2][0]=   0;    rotx[2][1]= -sy;     rotx[2][2]= cy;
   PMATRIX(rotx);
 
-  adjr[0][0]=  cr;    adjr[0][1]=  sr;     adjr[0][2]=  0;
-  adjr[1][0]= -sr;    adjr[1][1]=  cr;     adjr[1][2]=  0;
-  adjr[2][0]=   0;    adjr[2][1]=   0;     adjr[2][2]=  1;
+  make_z_rotation(adjr,cr,sr);
   PMATRIX(adjr);
 
   GA( gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0,
                     &rotx_gsl,&adjr_gsl,
                     0.0, &temp_gsl) );
-  PMATRIX(temp);
+  pmatrix("X R", temp);
   
   GA( gsl_blas_dgemm(CblasTrans,CblasNoTrans, 1.0,
                     &adjr_gsl,&temp_gsl,
                     0.0, &change_gsl) );
   PMATRIX(change);
 
+  double angz= dz*2.0;
+  make_z_rotation(rotz,cos(angz),sin(angz));
+  PMATRIX(rotz);
+
+  GA( gsl_blas_dgemm(CblasTrans,CblasNoTrans, 1.0,
+                    &rotz_gsl,&change_gsl,
+                    0.0, &temp_gsl) );
+  pmatrix("Z C", temp);
+
   static double skew[D3][D3];
   static GSL_MATRIX(skew);
   
   GA( gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0,
-                    &change_gsl,&transform_gsl,
+                    &temp_gsl, &transform_gsl,
                     0.0, &skew_gsl) );
   PMATRIX(skew);
 
@@ -403,13 +480,13 @@ static void drag_rotate_delta(double dx, double dy) {
   printf("drag_rotate_delta...\n");
   show();
 }
-DRAG_SAVING(rotate, transform);
+DRAG_SAVING(rotate, transform, drag_transform_prep(e));
 
 static void drag_sizeadj_delta(double dx, double dy) {
   sizeadj_scale *= pow(3.0, -dy);
   show();
 }
-DRAG_SAVING(sizeadj, sizeadj_scale);
+DRAG_SAVING(sizeadj, sizeadj_scale);
 
 static void drag_3d_delta(double dx, double dy) {
   eyes_apart += dx * 0.1;
@@ -417,7 +494,7 @@ static void drag_3d_delta(double dx, double dy) {
   printf("sizeadj eyes_apart %g\n", eyes_apart);
   show();
 }
-DRAG_SAVING(3d, eyes_apart);
+DRAG_SAVING(3d, eyes_apart);
 
 static const Drag *drag= &drag_none;
 
@@ -450,7 +527,7 @@ static void event_button(XButtonEvent *e) {
           drag->name, (unsigned long)e->button, e->x, e->y);
     drag_last_x= e->x;
     drag_last_y= e->y;
-    drag->start();
+    drag->start(e);
   }
   if (e->type == ButtonRelease) {
     printf("drag=%s release %d,%d\n", drag->name, e->x, e->y);
@@ -477,11 +554,22 @@ static void event_key(XKeyEvent *e) {
     return;
   }
 
-  if (!strcmp(buf,"q")) exit(0);
-  if (!strcmp(buf,"d")) {
+  if (!strcmp(buf,"q"))
+    exit(0);
+  else if (!strcmp(buf,"p"))
+    pause_updates= !pause_updates;
+  else if (!strcmp(buf,"w")) {
+    wireframe= !wireframe;
+    show();
+    return;
+  } else if (!strcmp(buf,"d")) {
     eyes_apart= eyes_apart>0 ? eyes_apart_min : eyes_apart_preferred;
     show();
     return;
+  } else {
+    printf("unknown key keycode=%d state=0x%x char=%c 0x%02x\n",
+          e->keycode, e->state, buf[0]>' ' && buf[0]<127 ? buf[0] : '?',
+          buf[0]);
   }
 }
 
@@ -520,6 +608,23 @@ static void check_input(void) {
   show();
 }
 
+static void topocheck(void) {
+  int v1,e,v2,eprime,v1prime, count;
+  FOR_EDGE(v1,e,v2) {
+    count= 0;
+    FOR_VEDGE(v2,eprime,v1prime)
+      if (v1prime==v1) count++;
+    if (count!=1) {
+      fprintf(stderr,"%02x -%d-> %02x  reverse edge count = %d!\n",
+             v1,e,v2, count);
+      FOR_VEDGE(v2,eprime,v1prime)
+       fprintf(stderr,"%02x -%d-> %02x -> %d -> %02x\n",
+               v1,e,v2,eprime,v1prime);
+      exit(-1);
+    }
+  }
+}
+
 int main(int argc, const char *const *argv) {
   static const int wantedevents= POLLIN|POLLPRI|POLLERR|POLLHUP;
 
@@ -527,6 +632,9 @@ int main(int argc, const char *const *argv) {
   int k, i, r, *xfds, nxfds, polls_alloc=0;
   struct pollfd *polls=0;
   int motion_deferred=0, motion_x=-1, motion_y=-1;
+
+  topocheck();
+  if (argc==1) { printf("topology self-consistent, ok\n"); exit(0); }
   
   if (argc != 2 || argv[1][0]=='-') {
     fputs("need filename\n",stderr); exit(8);
@@ -557,8 +665,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)
@@ -570,7 +681,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;
     }