/* version 2007.09.24, D. J. Bernstein; public domain */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "font.h" #define WINDOWWIDTH 1024 #define WINDOWHEIGHT 768 int zoom = 0; double scale = 1; double invscale = 1; double xmiddle = 0; double ymiddle = 0; long long edgethickness = 0; long long linearedges = 0; typedef unsigned int uint32; uint32 bitmap[WINDOWHEIGHT][WINDOWWIDTH]; char *title = "draw"; int bitmapchanged; uint32 drawstring_color[256]; void drawstring(int x,int y,uint32 color,const char *string) { char c; int f; int i; int j; int pos; int colorblue = color & 255; int colorgreen = (color >> 8) & 255; int colorred = (color >> 16) & 255; for (i = 0;i < 256;++i) { drawstring_color[i] = ((i + (colorblue * (255 - i)) / 255) << 0) + ((i + (colorgreen * (255 - i)) / 255) << 8) + ((i + (colorred * (255 - i)) / 255) << 16) ; } for (;;) { c = *string; if (!c) return; for (f = 0;font_char[f];++f) if (font_char[f] == c) { pos = font_start[f] * FONT_HEIGHT; for (i = 0;i < font_width[f];++i,++x) { if (x >= WINDOWWIDTH) return; for (j = 0;j < FONT_HEIGHT;++j,++pos) if (x >= 0 && y + j >= 0 && y + j < WINDOWHEIGHT) bitmap[y + j][x] = drawstring_color[(uint32) font_pixels[pos]]; } break; } ++string; } } struct vertex { unsigned long long value; int numinputs; unsigned long long input[3]; char *label; double x; double y; } *vertices = 0; long long verticesnum = 0; long long verticesalloc = 0; struct edge { long long from; long long to; long long flipped; } *edges = 0; long long edgesnum = 0; long long edgesalloc = 0; void ensurevertex(long long v) { long long i; if (v < 0) exit(111); if (v >= verticesalloc) { struct vertex *newvertices; verticesalloc = v + (v >> 3) + 1; newvertices = malloc(verticesalloc * sizeof(*newvertices)); if (!newvertices) exit(111); for (i = 0;i < verticesnum;++i) newvertices[i] = vertices[i]; if (vertices) free(vertices); vertices = newvertices; } while (v >= verticesnum) { vertices[verticesnum].label = 0; vertices[verticesnum].x = 0; vertices[verticesnum].y = 0; vertices[verticesnum].value = 0; ++verticesnum; } } char line[65536]; char label[65536]; void readdata(void) { long long i; long long v1; long long v2; double d; long long flipped; while (fgets(line,sizeof line,stdin)) { if (sscanf(line,"edge:%lld:%lld:%lld:",&v1,&v2,&flipped) == 3) { if (edgesnum >= edgesalloc) { struct edge *newedges; edgesalloc = edgesnum + (edgesnum >> 3) + 1; newedges = malloc(edgesalloc * sizeof(*newedges)); if (!newedges) exit(111); for (i = 0;i < edgesnum;++i) newedges[i] = edges[i]; if (edges) free(edges); edges = newedges; } edges[edgesnum].from = v1; edges[edgesnum].to = v2; edges[edgesnum].flipped = flipped; ++edgesnum; continue; } if (sscanf(line,"vertex:%lld:label:%1000[^:\n]",&v1,label) == 2) { ensurevertex(v1); vertices[v1].label = strdup(label); continue; } if (sscanf(line,"vertex:%lld:x:%lf",&v1,&d) == 2) { ensurevertex(v1); vertices[v1].x = d; continue; } if (sscanf(line,"vertex:%lld:y:%lf",&v1,&d) == 2) { ensurevertex(v1); vertices[v1].y = -d; continue; } } if (ferror(stdin)) exit(111); } void reinitialize(void) { long long i; for (i = 0;i < verticesnum;++i) { vertices[i].numinputs = 0; if (vertices[i].label) if (vertices[i].label[0] == 'k' || vertices[i].label[0] == 'i') vertices[i].value ^= (-(long long) (random() & 1)); } } void recalculate(void) { long long i; long long to; for (i = 0;i < edgesnum;++i) { to = edges[i].to; if (!vertices[to].label) continue; if (edges[i].flipped) vertices[to].input[vertices[to].numinputs++] = ~vertices[edges[i].from].value; else vertices[to].input[vertices[to].numinputs++] = vertices[edges[i].from].value; if (!strcmp(vertices[to].label,"&")) { if (vertices[to].numinputs == 2) { vertices[to].value = vertices[to].input[0] & vertices[to].input[1]; vertices[to].numinputs = 0; } } else if (!strcmp(vertices[to].label,"^")) { if (vertices[to].numinputs == 2) { vertices[to].value = vertices[to].input[0] ^ vertices[to].input[1]; vertices[to].numinputs = 0; } } else if (!strcmp(vertices[to].label,"maj")) { if (vertices[to].numinputs == 3) { vertices[to].value = (vertices[to].input[0] & vertices[to].input[1]) | (vertices[to].input[0] & vertices[to].input[2]) | (vertices[to].input[1] & vertices[to].input[2]); vertices[to].numinputs = 0; } } else if (!strcmp(vertices[to].label,"^^")) { if (vertices[to].numinputs == 3) { vertices[to].value = vertices[to].input[0] ^ vertices[to].input[1] ^ vertices[to].input[2]; vertices[to].numinputs = 0; } } else if (!strcmp(vertices[to].label,"=")) { if (vertices[to].numinputs == 1) { vertices[to].value = vertices[to].input[0]; vertices[to].numinputs = 0; } } else if (vertices[to].label[0] == 'o') { if (vertices[to].numinputs == 1) { vertices[to].value = vertices[to].input[0]; vertices[to].numinputs = 0; } } } } long long xchunk = 64; long long ychunk = 64; int perscale(void) { static double leftover = 0; leftover += 1; if (leftover >= scale) { leftover -= scale; return 1; } return 0; } long long pointedvertex = -1; void redraw(void) { long long i; long long j; long long k; int x; int y; double x1; double y1; double x2; double y2; int s; int color; int loop; unsigned char *ram; double slope; int flaglinear; bitmapchanged = 1; for (y = 0;y < WINDOWHEIGHT;++y) for (x = 0;x < WINDOWWIDTH;++x) bitmap[y][x] = 0xffffff; #define ON 0xff5050 #define OFF 0x00ff00 #define MIXED 0x800000 for (i = 0;i < verticesnum;++i) { if (vertices[i].label && vertices[i].label[0] == '=') continue; if (((vertices[i].x - xmiddle) * xchunk) * invscale + WINDOWWIDTH / 2 >= WINDOWWIDTH) continue; if (((vertices[i].x - xmiddle + 1) * xchunk) * invscale + WINDOWWIDTH / 2 < 0) continue; if (((vertices[i].y - ymiddle) * ychunk) * invscale + WINDOWHEIGHT / 2 >= WINDOWHEIGHT) continue; if (((vertices[i].y - ymiddle + 1) * ychunk) * invscale + WINDOWHEIGHT / 2 < 0) continue; for (k = 0;k < ychunk;k += scale) { y = ((vertices[i].y - ymiddle) * ychunk + k) * invscale + WINDOWHEIGHT / 2; if (y < 0) continue; if (y >= WINDOWHEIGHT) break; for (j = 0;j < xchunk;j += scale) { x = ((vertices[i].x - xmiddle) * xchunk + j) * invscale + WINDOWWIDTH / 2; if (x < 0) continue; if (x >= WINDOWWIDTH) break; if (zoom == 0) { if ((vertices[i].value >> j) & 1) bitmap[y][x] = ON; else bitmap[y][x] = OFF; } else { if (vertices[i].value == -1) bitmap[y][x] = ON; else if (vertices[i].value == 0) bitmap[y][x] = OFF; else bitmap[y][x] = MIXED; } if (vertices[i].label && vertices[i].label[0] == 'o') bitmap[y][x] ^= 0xffffff; } } } if (edgethickness > 0) { int linearnow; for (linearnow = linearedges;linearnow >= 0;--linearnow) for (i = 0;i < edgesnum;++i) { flaglinear = 0; if (vertices[edges[i].to].label && vertices[edges[i].to].label[0] == '^') flaglinear = 1; if (vertices[edges[i].to].label && vertices[edges[i].to].label[0] == 'o') flaglinear = 1; if (vertices[edges[i].to].label && vertices[edges[i].to].label[0] == '=') flaglinear = 1; if (flaglinear && !linearnow) continue; if (((vertices[edges[i].to].y - ymiddle + 0.5) * ychunk) * invscale + WINDOWHEIGHT / 2 < 0) continue; if (((vertices[edges[i].from].y - ymiddle + 0.5) * ychunk) * invscale + WINDOWHEIGHT / 2 >= WINDOWHEIGHT) continue; for (j = (xchunk - edgethickness) / 2;j < (xchunk + edgethickness) / 2;++j) { x1 = ((vertices[edges[i].from].x - xmiddle) * xchunk + j) * invscale + WINDOWWIDTH / 2; y1 = ((vertices[edges[i].from].y - ymiddle + 0.5) * ychunk) * invscale + WINDOWHEIGHT / 2; x2 = ((vertices[edges[i].to].x - xmiddle) * xchunk + j) * invscale + WINDOWWIDTH / 2; y2 = ((vertices[edges[i].to].y - ymiddle + 0.5) * ychunk) * invscale + WINDOWHEIGHT / 2; if (y2 <= y1) continue; if (y1 >= WINDOWHEIGHT) continue; if (y2 < 0) continue; slope = (x2 - x1) / (y2 - y1); for (y = ceil(y1);y <= floor(y2);y += 1) if (perscale()) { if (y < 0) continue; if (y >= WINDOWHEIGHT) break; x = x1 + (y - y1) * slope; if (x < 0) continue; if (x >= WINDOWWIDTH) continue; if (flaglinear) bitmap[y][x] = 0x0000ff; else bitmap[y][x] = 0; } } } } if (pointedvertex >= 0 && pointedvertex < verticesnum) { i = pointedvertex; for (j = 0;j < xchunk;j += 1) for (k = 0;k < ychunk;k += 1) { if (j > 0 && j < xchunk - 1 && k > 0 && k < ychunk - 1) continue; y = ((vertices[i].y - ymiddle) * ychunk + k) * invscale + WINDOWHEIGHT / 2; x = ((vertices[i].x - xmiddle) * xchunk + j) * invscale + WINDOWWIDTH / 2; if (y < 0) continue; if (y >= WINDOWHEIGHT) break; if (x < 0) continue; if (x >= WINDOWWIDTH) break; bitmap[y][x] = 0; } sprintf(line,"%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld (%lld %.0lf %.0lf) %.1000s" ,vertices[pointedvertex].value & 3 ,(vertices[pointedvertex].value >> 2) & 3 ,(vertices[pointedvertex].value >> 4) & 3 ,(vertices[pointedvertex].value >> 6) & 3 ,(vertices[pointedvertex].value >> 8) & 3 ,(vertices[pointedvertex].value >> 10) & 3 ,(vertices[pointedvertex].value >> 12) & 3 ,(vertices[pointedvertex].value >> 14) & 3 ,(vertices[pointedvertex].value >> 16) & 3 ,(vertices[pointedvertex].value >> 18) & 3 ,(vertices[pointedvertex].value >> 20) & 3 ,(vertices[pointedvertex].value >> 22) & 3 ,(vertices[pointedvertex].value >> 24) & 3 ,(vertices[pointedvertex].value >> 26) & 3 ,(vertices[pointedvertex].value >> 28) & 3 ,(vertices[pointedvertex].value >> 30) & 3 ,(vertices[pointedvertex].value >> 32) & 3 ,(vertices[pointedvertex].value >> 34) & 3 ,(vertices[pointedvertex].value >> 36) & 3 ,(vertices[pointedvertex].value >> 38) & 3 ,(vertices[pointedvertex].value >> 40) & 3 ,(vertices[pointedvertex].value >> 42) & 3 ,(vertices[pointedvertex].value >> 44) & 3 ,(vertices[pointedvertex].value >> 46) & 3 ,(vertices[pointedvertex].value >> 48) & 3 ,(vertices[pointedvertex].value >> 50) & 3 ,(vertices[pointedvertex].value >> 52) & 3 ,(vertices[pointedvertex].value >> 54) & 3 ,(vertices[pointedvertex].value >> 56) & 3 ,(vertices[pointedvertex].value >> 58) & 3 ,(vertices[pointedvertex].value >> 60) & 3 ,(vertices[pointedvertex].value >> 62) & 3 ,pointedvertex ,vertices[pointedvertex].y ,vertices[pointedvertex].x ,vertices[pointedvertex].label ? vertices[pointedvertex].label : "unnamed"); drawstring(40,10,0,line); } } void pointnode(int xmouse,int ymouse) { double x; double y; double dist; long long i; long long besti; double bestdist = 0; for (i = 0;i < verticesnum;++i) { x = ((vertices[i].x - xmiddle + 0.5) * xchunk) * invscale + WINDOWWIDTH / 2; y = ((vertices[i].y - ymiddle + 0.5) * ychunk) * invscale + WINDOWHEIGHT / 2; dist = (xmouse - x) * (xmouse - x) + (ymouse - y) * (ymouse - y); if (i == 0 || dist < bestdist) { bestdist = dist; besti = i; } } if (verticesnum > 0) pointedvertex = besti; redraw(); } #define ZOOMS 25 double zoomscale[ZOOMS] = { 1.000000000000000000000000000 , 1.122462048309372981433533049 , 1.259921049894873164767210607 , 1.414213562373095048801688724 , 1.587401051968199474751705639 , 1.781797436280678609480452411 , 2.000000000000000000000000000 , 2.244924096618745962867066099 , 2.519842099789746329534421214 , 2.828427124746190097603377448 , 3.174802103936398949503411278 , 3.563594872561357218960904822 , 4.000000000000000000000000000 , 4.489848193237491925734132198 , 5.039684199579492659068842429 , 5.656854249492380195206754896 , 6.349604207872797899006822557 , 7.127189745122714437921809644 , 8.000000000000000000000000000 , 8.979696386474983851468264397 , 10.07936839915898531813768485 , 11.31370849898476039041350979 , 12.69920841574559579801364511 , 14.25437949024542887584361928 , 16 } ; void selectychunk(int c) { if (c < 4) return; if (c > 64) return; if (c == ychunk) return; ychunk = c; redraw(); } void selectzoom(int n) { if (n < 0) return; if (n >= ZOOMS) return; if (n == zoom) return; zoom = n; scale = zoomscale[zoom]; invscale = 1 / scale; redraw(); } void selectxmiddle(long long x) { xmiddle = x; redraw(); } void selectymiddle(long long y) { ymiddle = y; redraw(); } void selectedges(long long e) { if (e < 0) return; if (e > 20) return; if (e == edgethickness) return; edgethickness = e; redraw(); } void selectbit(long long b) { unsigned long long x; if (pointedvertex < 0) return; if (pointedvertex >= verticesnum) return; x = vertices[pointedvertex].value; x = -(x & 1); switch(b) { case 0: x ^= 0xaaaaaaaaaaaaaaaa; break; case 1: x ^= 0xcccccccccccccccc; break; case 2: x ^= 0xf0f0f0f0f0f0f0f0; break; case 3: x ^= 0xff00ff00ff00ff00; break; case 4: x ^= 0xffff0000ffff0000; break; case 5: x ^= 0xffffffff00000000; break; case 6: x ^= 0xffffffffffffffff; break; } vertices[pointedvertex].value = x; recalculate(); redraw(); } int button1pressed = 0; int button3pressed = 0; int main(int argc,char **argv) { Display *display; int screen; int depth; XImage *image; Window window; GC gc; XSetWindowAttributes attrib; XTextProperty titleprop; XEvent event; static char keybuf[64]; KeySym keysym; Font font; display = XOpenDisplay(0); if (!display) return 111; screen = DefaultScreen(display); depth = DefaultDepth(display,screen); attrib.border_pixel = WhitePixel(display,screen); attrib.background_pixel = WhitePixel(display,screen); attrib.override_redirect = 0; window = XCreateWindow(display,DefaultRootWindow(display),0,0,WINDOWWIDTH,WINDOWHEIGHT,0,depth,InputOutput,CopyFromParent,CWBackPixel | CWBorderPixel,&attrib); if (!window) return 111; if (XStringListToTextProperty(&title,1,&titleprop) == 0) return 111; XSetTextProperty(display,window,&titleprop,XA_WM_NAME); gc = XCreateGC(display,window,0,0); if (!gc) return 111; font = XLoadFont(display,"-adobe-helvetica-bold-r-normal--25-180-100-100-p-138-iso8859-1"); XSetFont(display,gc,font); XMapRaised(display,window); XSelectInput(display,window,ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask); image = XCreateImage(display,CopyFromParent,depth,ZPixmap,0,(char *) bitmap,WINDOWWIDTH,WINDOWHEIGHT,32,0); if (!image) return 111; XInitImage(image); image->byte_order = LSBFirst; image->bitmap_bit_order = MSBFirst; selectzoom(0); readdata(); reinitialize(); recalculate(); redraw(); for (;;) { if (bitmapchanged) { XPutImage(display,window,gc,image,0,0,0,0,WINDOWWIDTH,WINDOWHEIGHT); bitmapchanged = 0; } XNextEvent(display,&event); switch(event.type) { case ButtonPress: pointnode(event.xbutton.x,event.xbutton.y); /* * if (event.xbutton.button == Button3) selectnode(pointednode); */ if (event.xbutton.button == Button1) button1pressed = 1; if (event.xbutton.button == Button3) button3pressed = 1; break; case ButtonRelease: if (event.xbutton.button == Button1) button1pressed = 0; if (event.xbutton.button == Button3) button3pressed = 0; break; case Expose: bitmapchanged = 1; break; case KeyPress: XLookupString(&event.xkey,keybuf,(sizeof keybuf) - 1,&keysym,0); if (keysym == XK_q) return 0; else if (keysym == XK_0) selectbit(0); else if (keysym == XK_1) selectbit(1); else if (keysym == XK_2) selectbit(2); else if (keysym == XK_3) selectbit(3); else if (keysym == XK_4) selectbit(4); else if (keysym == XK_5) selectbit(5); else if (keysym == XK_6) selectbit(6); else if (keysym == XK_7) selectbit(7); else if (keysym == XK_e) selectedges(edgethickness + 1); else if (keysym == XK_E) selectedges(edgethickness - 1); else if (keysym == XK_w) { linearedges = !linearedges; redraw(); } else if (keysym == XK_r) { reinitialize(); recalculate(); redraw(); } else if (keysym == XK_h) selectxmiddle(xmiddle - scale); else if (keysym == XK_l) selectxmiddle(xmiddle + scale); else if (keysym == XK_j) selectymiddle(ymiddle + (scale * xchunk) / ychunk); else if (keysym == XK_k) selectymiddle(ymiddle - (scale * xchunk) / ychunk); else if (keysym == XK_a) selectzoom(zoom + 1); else if (keysym == XK_z) selectzoom(zoom - 1); else if (keysym == XK_Y) selectychunk(ychunk - 1); else if (keysym == XK_y) selectychunk(ychunk + 1); } } }