X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=moebius2.git;a=blobdiff_plain;f=view.c;h=cc86803594841154686a48adb5c77aff1bb5b316;hp=abecc7ca4d5fc206532f00d3f7c33dfe41281b78;hb=3c0d58c901fd6f8265dad93f096d2ae03866fc6e;hpb=134d36d51a86567bba2a9cfe1b209c4bc7d1a7f0 diff --git a/view.c b/view.c index abecc7c..cc86803 100644 --- 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=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,19 +138,21 @@ 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; static double eye_z= -10, eye_x=0; static double cut_z= -9; +static const double eyes_apart_preferred=0.05, eyes_apart_min= -0.02; + static void drawtriangle(const Triangle *t) { XPoint points[4]; 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]; @@ -139,14 +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; + ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask| + KeyPressMask|SubstructureNotifyMask; static void mkpixmaps(void) { for (currentbuffer=0; currentbuffer<2; currentbuffer++) { @@ -214,11 +242,13 @@ static void display_conformation(void) { XA( XFillRectangle(display,pixmap,dmwhite.fillgc,0,0,wwidth,wheight) ); if (eyes_apart > 0) { - const double preferred=0.05, beyond=0.07; + const double stationary= 0.07; - eye_x= eyes_apart < preferred ? eyes_apart : - eyes_apart < beyond ? preferred : - eyes_apart - (beyond - preferred); + eye_x= eyes_apart < eyes_apart_preferred + ? eyes_apart : + eyes_apart < (eyes_apart_preferred + stationary) + ? eyes_apart_preferred + : eyes_apart - stationary; eye_x /= sizeadj_scale; drawtriangles(&dmblue); eye_x= -eye_x; @@ -244,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); @@ -256,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) { \ @@ -268,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) { } @@ -291,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: * @@ -305,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' = Z R^T X R T where + * or T' = Z 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; @@ -337,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); @@ -398,22 +480,21 @@ 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) { - const double min_eyes_apart= -0.02; eyes_apart += dx * 0.1; - if (eyes_apart < min_eyes_apart) eyes_apart= min_eyes_apart; + if (eyes_apart < eyes_apart_min) eyes_apart= eyes_apart_min; 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; @@ -446,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); @@ -461,6 +542,37 @@ static void event_motion(int x, int y) { drag_position(x,y); } +static void event_key(XKeyEvent *e) { + KeySym ks; + char buf[10]; + int r; + + r= XLookupString(e,buf,sizeof(buf)-1,&ks,0); + if (!r) { + printf("XLookupString keycode=%u state=0x%x gave %d\n", + e->keycode, e->state, r); + return; + } + + 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]); + } +} + static void event_config(XConfigureEvent *e) { if (e->width == wwidth && e->height == wheight) return; @@ -496,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; @@ -503,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); @@ -533,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