X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=moebius2.git;a=blobdiff_plain;f=project.c;h=266237f90b222be270b723c5845007ff85330e36;hp=2d24f0868d67e1e1d205390f5133169fcfea7f94;hb=456ce271eea85ff5acfe6a4416fa6c085d998c64;hpb=4e53c82487592a5a490e3ac6daaae979e9812338 diff --git a/project.c b/project.c index 2d24f08..266237f 100644 --- a/project.c +++ b/project.c @@ -15,6 +15,9 @@ static Triangle trisbuffer[MAXTRIS], *displaylist[MAXTRIS]; static int ntris; static Vertices conformation; +static double transform[D3][D3]= {{1,0,0}, {0,1,0}, {0,0,1}}; +static GSL_MATRIX(transform); + const char *input_filename; static void read_input(void) { @@ -23,14 +26,22 @@ static void read_input(void) { f= fopen(input_filename, "rb"); if (!f) diee("input file"); errno= 0; - r= fread(&conformation,1,sizeof(conformation),f); if (r!=1) diee("fread"); + r= fread(&conformation,sizeof(conformation),1,f); if (r!=1) diee("fread"); fclose(f); } static void transform_coordinates(void) { - int v; + double result[D3]; + GSL_VECTOR(result); + gsl_vector input_gsl= { D3,1 }; + int v, k; + FOR_VERTEX(v) { + input_gsl.data= &conformation[v][0]; + GA( gsl_blas_dgemv(CblasNoTrans, 1.0,&transform_gsl, &input_gsl, + 0.0, &result_gsl) ); + K conformation[v][k]= result[k]; } } @@ -49,7 +60,8 @@ static void addtriangle(int va, int vb, int vc) { static void generate_display_list(void) { int vb, ve[3], e; - + + ntris= 0; FOR_VERTEX(vb) { /* We use the two triangles in the parallelogram vb, vb+e1, vb+e0, vb+e2. * We go round each triangle clockwise (although our surface is non- @@ -64,12 +76,16 @@ static void generate_display_list(void) { } 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; - double za= ta->vertex[0][2]; - double zb= tb->vertex[0][2]; - return za > zb ? +1 : - za < zb ? -1 : 0; + double za=0, zb=0; + for (i=0; i<3; i++) { + za += ta->vertex[i][2]; + zb += tb->vertex[i][2]; + } + return za > zb ? -1 : + za < zb ? +1 : 0; } static void sort_display_list(void) { @@ -80,21 +96,21 @@ static void sort_display_list(void) { #define WSZ 400 +typedef struct { GC fillgc, linegc; } DrawingMode; + static Display *display; static Pixmap pixmap, doublebuffers[2]; static Window window; -static GC linegc, fillgc; -static int wwidth=WSZ, wheight=WSZ, currentbuffer; -static double scale= WSZ * 0.3; -static double eye_z= -10, eye_x= 0; -static double cut_z= -9; - -static void xdie(int l, const char *str) { - fprintf(stderr,"X library call failed, line %d: %s\n", l, str); -} +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; +XVisualInfo visinfo; -#define XA(w) ((w) ? (void)0 : xdie(__LINE__, #w)) +static double sizeadj_scale= 0.3, eyes_apart, scale_wmindim; +static double eye_z= -10, eye_x=0; +static double cut_z= -9; static void drawtriangle(const Triangle *t) { XPoint points[4]; @@ -105,65 +121,111 @@ static void drawtriangle(const Triangle *t) { double x= v[0]; double y= v[1]; double z= v[2]; - if (z < cut_z) return; + + if (z < cut_z) { ncut++; return; } + double zezezp= eye_z / (eye_z - z); - points[i].x= scale * (zezezp * (x - eye_x) + eye_x); - points[i].y= scale * (zezezp * y ); + points[i].x= scale_wmindim * (zezezp * (x - eye_x) + eye_x) + wwidth/2; + points[i].y= scale_wmindim * (zezezp * y ) + wheight/2; } points[3]= points[0]; - - XA(! XFillPolygon(display,pixmap,fillgc, points,3,Convex,CoordModeOrigin) ); - XA(! XDrawLines(display,pixmap,linegc,points, 4,CoordModeOrigin) ); + + XA( XFillPolygon(display,pixmap, dmcurrent->fillgc, + points,3,Convex,CoordModeOrigin) ); + XA( XDrawLines(display,pixmap, dmcurrent->linegc, + points, 4,CoordModeOrigin) ); } -static void display_prepare(void) { +static const unsigned long core_event_mask= + ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask; + +static void mkpixmaps(void) { + for (currentbuffer=0; currentbuffer<2; currentbuffer++) { + XA( pixmap= XCreatePixmap(display,window,wwidth,wheight,x11depth) ); + doublebuffers[currentbuffer]= pixmap; + } + currentbuffer= 0; +} + +static void mkgcs(DrawingMode *dm, unsigned long planes) { XGCValues gcv; + + gcv.function= GXcopy; + gcv.foreground= WhitePixel(display,x11screen); + gcv.plane_mask= planes; + dm->linegc= XCreateGC(display,pixmap, + GCFunction|GCForeground|GCPlaneMask, + &gcv); + + gcv.function= GXclear; + dm->fillgc= XCreateGC(display,pixmap, + GCFunction|GCPlaneMask, + &gcv); +} + +static void display_prepare(void) { XSetWindowAttributes wa; - int screen, depth; - XVisualInfo vinfo; + XSizeHints hints; XA( display= XOpenDisplay(0) ); - screen= DefaultScreen(display); - depth= DefaultDepth(display,screen); - XA(! XMatchVisualInfo(display,screen,depth, TrueColor,&vinfo) ); + x11screen= DefaultScreen(display); + x11depth= DefaultDepth(display,x11screen); + XA( XMatchVisualInfo(display,x11screen,x11depth, TrueColor,&visinfo) ); - wa.event_mask= ButtonPress|ConfigureNotify; + wa.event_mask= core_event_mask; XA( window= XCreateWindow(display, DefaultRootWindow(display), - 10,10, wwidth,wheight, 0,depth, - InputOutput, vinfo.visual, + 0,0, wwidth,wheight, 0,x11depth, + InputOutput, visinfo.visual, CWEventMask, &wa) ); - for (currentbuffer=0; currentbuffer<2; currentbuffer++) { - XA( pixmap= XCreatePixmap(display,window,wwidth,wheight,depth) ); - doublebuffers[currentbuffer]= pixmap; - } + hints.flags= USPosition; + hints.x= 10; + hints.y= 10; + XSetWMNormalHints(display,window,&hints); - gcv.function= GXcopy; - gcv.plane_mask= ~0UL; - gcv.foreground= WhitePixel(display,screen); - linegc= XCreateGC(display,pixmap, GCFunction|GCPlaneMask|GCForeground, &gcv); - - gcv.function= GXclear; - gcv.plane_mask= ~0UL; - fillgc= XCreateGC(display,pixmap, GCFunction|GCPlaneMask, &gcv); + mkpixmaps(); - currentbuffer= 0; + mkgcs(&dmwhite, AllPlanes); + mkgcs(&dmblue, visinfo.blue_mask); + mkgcs(&dmred, visinfo.red_mask); } -static void display_conformation(void) { +static void drawtriangles(const DrawingMode *dm) { Triangle *const *t; int i; - - pixmap= doublebuffers[currentbuffer]; - XA(! XFillRectangle(display,pixmap,fillgc,0,0,wwidth,wheight) ); - for (i=0, t=displaylist; i 0) { + const double preferred=0.05, beyond=0.07; + + eye_x= eyes_apart < preferred ? eyes_apart : + eyes_apart < beyond ? preferred : + eyes_apart - (beyond - preferred); + eye_x /= sizeadj_scale; + drawtriangles(&dmblue); + eye_x= -eye_x; + drawtriangles(&dmred); + } else { + drawtriangles(&dmwhite); + printf("shown, %d/%d triangles cut\n", ncut, ntris); + } + + XA( XSetWindowBackgroundPixmap(display,window,pixmap) ); + XA( XClearWindow(display,window) ); currentbuffer= !currentbuffer; } static void show(void) { + scale_wmindim= sizeadj_scale * wmindim; read_input(); transform_coordinates(); generate_display_list(); @@ -171,17 +233,284 @@ static void show(void) { display_conformation(); } +typedef struct { + const char *name; + void (*start)(void); + void (*delta)(double dx, double dy); + void (*conclude)(void); + void (*abandon)(void); +} Drag; + +#define DRAG(x) \ + static const Drag drag_##x= { \ + #x, drag_##x##_start, drag_##x##_delta, \ + drag_##x##_conclude, drag_##x##_abandon \ + } + +#define DRAG_SAVING(x, thing) \ + static typeof(thing) original_##thing; \ + static void drag_##x##_start(void) { \ + memcpy(&original_##thing, &thing, sizeof(thing)); \ + } \ + static void drag_##x##_conclude(void) { } \ + static void drag_##x##_abandon(void) { \ + memcpy(&thing, &original_##thing, sizeof(thing)); \ + show(); \ + } \ + DRAG(x) + +static void drag_none_start(void) { } +static void drag_none_delta(double dx, double dy) { } +static void drag_none_conclude(void) { } +static void drag_none_abandon(void) { } +DRAG(none); + +static void pvectorcore(const char *n, double v[D3]) { + int k; + printf("%10s [ ",n); + K printf("%# 10.10f ",v[k]); + printf("]\n"); +} +static void pvector(const char *n, double v[D3]) { + pvectorcore(n,v); + putchar('\n'); +} +static void pmatrix(const char *n, double m[D3][D3]) { + int j; + for (j=0; jdelta((x - drag_last_x) * 1.0 / wmaxdim, + (y - drag_last_y) * 1.0 / wmaxdim); + drag_last_x= x; + drag_last_y= y; +} + +static void event_button(XButtonEvent *e) { + if (e->window != window || !e->same_screen) return; + if (e->type == ButtonPress) { + if (e->state || drag != &drag_none) { + printf("drag=%s press state=0x%lx abandon\n", + drag->name, (unsigned long)e->state); + drag->abandon(); + drag= &drag_none; + return; + } + switch (e->button) { + case Button1: drag= &drag_rotate; break; + case Button2: drag= &drag_sizeadj; break; + case Button3: drag= &drag_3d; break; + default: printf("unknown drag start %d\n", e->button); + } + printf("drag=%s press button=%lu start %d,%d\n", + drag->name, (unsigned long)e->button, e->x, e->y); + drag_last_x= e->x; + drag_last_y= e->y; + drag->start(); + } + if (e->type == ButtonRelease) { + printf("drag=%s release %d,%d\n", drag->name, e->x, e->y); + drag_position(e->x, e->y); + drag->conclude(); + drag= &drag_none; + } +} + +static void event_motion(int x, int y) { + printf("drag=%s motion %d,%d\n", drag->name, x, y); + drag_position(x,y); +} + +static void event_config(XConfigureEvent *e) { + if (e->width == wwidth && e->height == wheight) + return; + + wwidth= e->width; wheight= e->height; + wmaxdim= wwidth > wheight ? wwidth : wheight; + wmindim= wwidth < wheight ? wwidth : wheight; + + XA( XSetWindowBackground(display,window,BlackPixel(display,x11screen)) ); + for (currentbuffer=0; currentbuffer<2; currentbuffer++) + XA( XFreePixmap(display, doublebuffers[currentbuffer]) ); + + mkpixmaps(); + show(); +} + int main(int argc, const char *const *argv) { + XEvent event; + int k; + int motion_deferred=0, motion_x=-1, motion_y=-1; + if (argc != 2 || argv[1][0]=='-') { fputs("need filename\n",stderr); exit(8); } input_filename= argv[1]; read_input(); + K transform[k][k]= 1.0; display_prepare(); show(); - XSync(display,0); - for (;;); + + XMapWindow(display,window); + for (;;) { + if (motion_deferred) { + int r= XCheckMaskEvent(display,~0UL,&event); + if (!r) { + event_motion(motion_x, motion_y); + motion_deferred=0; + continue; + } + } else { + XNextEvent(display,&event); + } + switch (event.type) { + + case ButtonPress: + case ButtonRelease: event_button(&event.xbutton); break; + + case ConfigureNotify: event_config(&event.xconfigure); break; + + case MotionNotify: + motion_x= event.xmotion.x; + motion_y= event.xmotion.y; + motion_deferred= 1; + continue; + + default: + printf("unknown event type %u 0x%x\n", event.type,event.type); + } + } }