// HyperRogue paper model generator // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details #if CAP_MODEL namespace netgen { // We need a two-dimensional vector class for this. struct vec { double x, y; vec(double _x, double _y) : x(_x), y(_y) { } vec() : x(0), y(0) {} }; vec& operator += (vec& a, const vec b) { a.x += b.x; a.y += b.y; return a; } vec& operator -= (vec& a, const vec b) { a.x -= b.x; a.y -= b.y; return a; } // coordinatewise multiplication and division vec& operator *= (vec& a, const vec b) { a.x *= b.x; a.y *= b.y; return a; } vec& operator *= (vec& a, double scalar) { a.x *= scalar; a.y *= scalar; return a; } vec& operator /= (vec& a, const vec b) { a.x /= b.x; a.y /= b.y; return a; } vec& operator /= (vec& a, double scalar) { a.x /= scalar; a.y /= scalar; return a; } vec operator + (vec a, const vec b) { return a+=b; } vec operator - (vec a, const vec b) { return a-=b; } vec operator * (vec a, const vec b) { return a*=b; } vec operator / (vec a, const vec b) { return a/=b; } vec operator * (vec a, double scalar) { return a*=scalar; } vec operator * (double scalar, vec a) { return a*=scalar; } vec operator / (vec a, double scalar) { return a/=scalar; } vec operator / (double scalar, vec a) { return a/=scalar; } vec ang(double f) { return vec(cos(f), sin(f)); } double norm(vec v) { return v.x*v.x+v.y*v.y; } // the parameters. bool loaded; int SCALE, PX, PY, BASE, SX, SY, CELLS, fontsize, created; double el; #define MAXCELLS 1000 // All the datatables stored in the net files. int ct[MAXCELLS]; double vx[MAXCELLS][16]; vec center[MAXCELLS]; double rot[MAXCELLS]; int glued[MAXCELLS]; int nei[MAXCELLS][MAX_EDGE]; // auxiliary data double raylen[MAXCELLS]; double edgist[MAXCELLS]; char patek[MAXCELLS][MAX_EDGE]; // data generated by HyperRogue hyperpoint hcenter[MAXCELLS][9]; // Functions handling the data. //============================== // Use HyperRogue to generate the data (ct, vx, nei). int mode = 0; void buildVertexInfo(cell *c, transmatrix V) { if(mode == 1) for(int ii=0; ii<CELLS; ii++) if(dcal[ii] == c) { hcenter[ii][MAX_EDGE] = V * C0; if(c->type == 7) { for(int i=0; i<c->type; i++) { int hdir = displaydir(c, i) + 6; transmatrix V2 = V * spin(hdir * M_PI / 42) * xpush(hexf); hcenter[ii][i] = V2 * C0; } } if(c->type == 6) { for(int i=0; i<c->type; i++) { int hdir = displaydir(c, i); transmatrix V2 = V * spin(hdir * M_PI / 42) * xpush(crossf) * spin(M_PI*8/7) * xpush(hexf); hcenter[ii][i] = V2 * C0; } } } } void dataFromHR() { mode = 1; drawthemap(); mode = 0; for(int i=0; i<CELLS; i++) { ct[i] = dcal[i]->type; for(int k=0; k<8; k++) vx[i][2*k] = hcenter[i][k][0], vx[i][2*k+1] = hcenter[i][k][1]; for(int k=0; k<ct[i]; k++) nei[i][k] = -1; for(int j=0; j<CELLS; j++) { cell *c1 = dcal[i]; cell *c2 = dcal[j]; for(int k=0; k<c1->type; k++) if(c1->mov[k] == c2) nei[i][k] = j; } } for(int i=0; i<CELLS; i++) { center[i] = vec(SX/2, SY/2); rot[i] = 0; glued[i] = -1; for(int e=0; e<ct[i]; e++) if(nei[i][e] < i && nei[i][e] != -1 && (glued[i] == -1 || nei[i][e] < glued[i])) { glued[i] = nei[i][e]; } } } void loadData() { FILE *f = fopen("papermodeldata.txt", "rt"); if(!f) return; int err = fscanf(f, "%d %d %d %d %d %d %d %lf %d\n\n", &CELLS, &SX, &SY, &PX, &PY, &SCALE, &BASE, &el, &created); if(err != 9) { fclose(f); return; } loaded = true; if(!created) { fclose(f); return; } for(int i=0; i<CELLS; i++) err = fscanf(f, "%d", &ct[i]); for(int i=0; i<CELLS; i++) for(int j=0; j<16; j++) err = fscanf(f, "%lf" ,&vx[i][j]); for(int i=0; i<CELLS; i++) for(int j=0; j<7; j++) nei[i][j] = -1; while(true) { int a, b, c; err = fscanf(f, "%d%d%d", &a, &b, &c); if(a < 0) break; else nei[a][c] = b; } for(int i=0; i<CELLS; i++) { double dx, dy, dr; int g; err = fscanf(f, "%lf%lf%lf%d\n", &dx, &dy, &dr, &g); center[i] = vec(dx, dy); rot[i] = dr; glued[i] = g; } fclose(f); } void saveData() { // global parameters FILE *f = fopen("papermodeldata2.txt", "wt"); if(!f) { addMessage("Could not save the paper model data"); return; } fprintf(f, "%d %d %d %d %d %d %d %lf %d\n\n", CELLS, SX, SY, PX, PY, SCALE, BASE, el, created); // net parameters: cell types for(int i=0; i<CELLS; i++) fprintf(f, "%d ", ct[i]); fprintf(f, "\n"); // net parameters: hcenters for(int i=0; i<CELLS; i++) { for(int k=0; k<16; k++) fprintf(f, "%9.6lf ", vx[i][k]); fprintf(f, "\n"); } fprintf(f, "\n\n"); // create netgen for(int i=0; i<CELLS; i++) for(int j=0; j<CELLS; j++) { for(int k=0; k<ct[i]; k++) if(nei[i][k] == j) fprintf(f, "%d %d %d ", i, j, k); } fprintf(f, "-1 -1 -1\n\n"); // graphics for(int i=0; i<CELLS; i++) fprintf(f, "%12.7lf %12.7lf %10.7lf %d\n", center[i].x, center[i].y, rot[i], glued[i] ); fclose(f); } // Simple graphical functions //============================ void blackline(vec v1, vec v2, int col = 0x000000FF) { #if CAP_SDLGFX==1 aalineColor(s, int(v1.x), int(v1.y), int(v2.x), int(v2.y), col); #endif } void drawtriangle(vec v1, vec v2, vec v3, int col) { #if CAP_SDLGFX==1 polyx[0] = int(v1.x); polyx[1] = int(v2.x); polyx[2] = int(v3.x); polyy[0] = int(v1.y); polyy[1] = int(v2.y); polyy[2] = int(v3.y); filledPolygonColorI(s, polyx, polyy, 3, col); #endif } void blackcircle(vec v, int r, int col = 0x000000FF) { #if CAP_SDLGFX aacircleColor(s, int(v.x), int(v.y), r, col); #endif } void blacktext(vec v, char c) { char str[2]; str[0] = c; str[1] = 0; int tsize = int(el * 12/27); displaystr(int(v.x), int(v.y), 0, tsize, str, 0, 8); } hyperpoint hvec(int i, int e) { return hpxy(vx[i][2*e], vx[i][2*e+1]); } bool wellspread(double d1, double d2, double d3, int &co) { int id1 = int(d1); int id2 = int(d2); int id3 = int(d3); co = min(min(id1,id2),id3); return (id1 <= co+1 && id2 <= co+1 && id3 <= co+1); } SDL_Surface *net, *hqsurface; int& hqpixel(hyperpoint h) { int hx, hy, hs; getcoord0(h, hx, hy, hs); return qpixel(hqsurface, hx, hy); } void copyhypertriangle( vec g1, vec g2, vec g3, hyperpoint h1, hyperpoint h2, hyperpoint h3) { int ix, iy; if(wellspread(g1.x,g2.x,g3.x,ix) && wellspread(g1.y,g2.y,g3.y,iy)) qpixel(net,ix,iy) = hqpixel(h1); else { vec g4 = (g2+g3)/2; vec g5 = (g3+g1)/2; vec g6 = (g1+g2)/2; hyperpoint h4 = mid(h2,h3); hyperpoint h5 = mid(h3,h1); hyperpoint h6 = mid(h1,h2); copyhypertriangle(g1,g5,g6, h1,h5,h6); copyhypertriangle(g5,g3,g4, h5,h3,h4); copyhypertriangle(g6,g4,g2, h6,h4,h2); copyhypertriangle(g4,g6,g5, h4,h6,h5); } } void setRaylen() { for(int i=0; i<CELLS; i++) { raylen[i] = el / sin(M_PI / ct[i]); edgist[i] = raylen[i] * cos(M_PI / ct[i]); } } // draw the model void createPapermodel() { #if !CAP_SDLGFX addMessage(XLAT("High quality shots not available on this platform")); return; #endif loadData(); SDL_Surface *sav = s; s = hqsurface = SDL_CreateRGBSurface(SDL_SWSURFACE,BASE,BASE,32,0,0,0,0); videopar vid2 = vid; vid.xres = vid.yres = 2000; vid.scale = 0.99; vid.usingGL = false; int sch = cheater; cheater = 0; calcparam(); mode = 2; darken = 0; SDL_FillRect(s, NULL, 0); drawfullmap(); mode = 0; /* for(int i=0; i<CELLS; i++) { int t = ct[i]; for(int e=0; e<t; e++) drawline(hvec(i,e), hvec(i,(e+1)%t), 0x80808080); for(int e=0; e<7; e++) drawline(hvec(i,e), hvec(i,7), 0x80808080); } */ s = net = SDL_CreateRGBSurface(SDL_SWSURFACE,SX*SCALE,SY*SCALE,32,0,0,0,0); SDL_FillRect(net, NULL, 0xFFFFFF); int pateks = 0; int zeroi = nei[0][0]; int zeroe = 0; for(int e=0; e<6; e++) if(nei[zeroi][e] == 0) zeroe = e; el *= SCALE; setRaylen(); for(int faza=0; faza<2; faza++) for(int i=0; i<CELLS; i++) { int t = ct[i]; printf("faza %d cell %d\n", faza, i); for(int e=0; e<t; e++) { vec v1 = center[i] * SCALE + raylen[i] * ang(rot[i] + 2*M_PI*e/t); vec v2 = center[i] * SCALE + raylen[i] * ang(rot[i] + 2*M_PI*(e+1)/t); vec v3 = (v1+v2)/2; if(faza == 1) blackline(v1, v2); int ofs = t == 7 ? 0 : 5; // 0,2,0 ~ 2,0,0 if(0) if((i==0 && e == 0) || (i == zeroi && e == zeroe)) { for(int ofs=0; ofs<t; ofs++) { printf("OFS %d: %s", ofs, display(hvec(i, (e+ofs)%t))); printf(" %s\n", display(hvec(i, (e+1+ofs)%t))); } } if(faza == 0) copyhypertriangle( center[i] * SCALE, v1, v2, hvec(i,7), hvec(i, (e+ofs)%t), hvec(i, (e+1+ofs)%t) ); if(faza == 1) if(nei[i][e] != -1 && nei[i][e] != glued[i] && glued[nei[i][e]] != i) { vec vd = v2-v1; swap(vd.x, vd.y); vd.x = -vd.x; double factor = -sqrt(3)/6; vd.x *= factor; vd.y *= factor; vec v4 = v3 + vd; vec v5 = v3 + vd/2; if(!patek[i][e]) { int i2 = nei[i][e]; for(int e2=0; e2<ct[nei[i][e]]; e2++) if(nei[i2][e2] == i) patek[i][e] = patek[i2][e2] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "!@#$%^&*+=~:;<>?/|\"., [{(\\]})" [(pateks++) % 85]; } int col = 0xFFFFFFFF; int p = patek[i][e]; col -= 0x8000 * (p&1); p /= 2; col -= 0x800000 * (p&1); p /= 2; col -= 0x80000000 * (p&1); p /= 2; col -= 0x4000 * (p&1); p /= 2; col -= 0x400000 * (p&1); p /= 2; col -= 0x40000000 * (p&1); p /= 2; col -= 0x2000 * (p&1); p /= 2; col -= 0x200000 * (p&1); p /= 2; col -= 0x20000000 * (p&1); p /= 2; drawtriangle(v1,v2,v4, col); blacktext(v5, patek[i][e]); blackline(v1, v4); blackline(v2, v4); } } } printf("pateks = %d\n", pateks); IMAGESAVE(net, "papermodel-all" IMAGEEXT); IMAGESAVE(hqsurface, "papermodel-source" IMAGEEXT); int qx = SX*SCALE/PX; int qy = SY*SCALE/PY; SDL_Surface *quarter = SDL_CreateRGBSurface(SDL_SWSURFACE,qx,qy,32,0,0,0,0); for(int iy=0; iy<PY; iy++) for(int ix=0; ix<PX; ix++) { for(int y=0; y<qy; y++) for(int x=0; x<qx; x++) qpixel(quarter,x,y) = qpixel(net, x+qx*ix, y+qy*iy); char buf[64]; sprintf(buf, "papermodel-page%d%d" IMAGEEXT, iy, ix); IMAGESAVE(quarter, buf); } SDL_FreeSurface(net); SDL_FreeSurface(hqsurface); SDL_FreeSurface(quarter); s = sav; vid = vid2; cheater = sch; } vec mousepos, rel; int bei = 0, bee = 0, whichcell = 0; double cedist; bool dragging = false; int glueroot(int i) { if(glued[i] == -1) return i; return glueroot(glued[i]); } void clicked(int x, int y, int b) { mousepos = vec(x, y); if(b == 1) rel = center[glueroot(whichcell)] - mousepos, dragging = true; if(b == 17) dragging = false; if(b == 32 && dragging) center[glueroot(whichcell)] = rel + mousepos; } void applyGlue(int i) { int j = glued[i]; int it = ct[i]; int jt = ct[j]; int ie = 0, je = 0; for(int e=0; e<it; e++) if(nei[i][e] == j) ie = e; for(int e=0; e<jt; e++) if(nei[j][e] == i) je = e; rot[i] = rot[j] + 2*M_PI*(je+.5)/jt - 2*M_PI*(ie+.5)/it + M_PI; center[i] = center[j] + (edgist[i]+edgist[j]) * ang(rot[j] + 2*M_PI*(je+.5)/jt); } void displaynets() { SDL_LockSurface(s); setRaylen(); for(int uy=SY-1; uy>=0; uy--) for(int ux=SX-1; ux>=0; ux--) { qpixel(s, ux, uy) = 0; } for(int y=1; y<PY; y++) blackline(vec(0,SY*y/PY), vec(SX,SY*y/PY), 0x404080FF); for(int x=1; x<PX; x++) blackline(vec(SX*x/PX,0), vec(SX*x/PX,SY), 0x404080FF); for(int i=0; i<CELLS; i++) { if(norm(center[i]-mousepos) < norm(center[whichcell]-mousepos)) whichcell = i; int t = ct[i]; if(i == whichcell) blackcircle(center[i], 10, 0x40FF40FF); if(i == bei || i == nei[bei][bee]) blackcircle(center[i], 5, 0x40FF40FF); if(glued[i] == -1) blackcircle(center[i], 7, 0xFF4040FF); if(glued[i] != -1) applyGlue(i); for(int e=0; e<t; e++) { vec v1 = center[i] + raylen[i] * ang(rot[i] + 2*M_PI*e/t); vec v2 = center[i] + raylen[i] * ang(rot[i] + 2*M_PI*(e+1)/t); vec v3 = (v1+v2)/2; if(nei[i][e] >= 0 && !dragging) { if(norm(v3-mousepos) < cedist) bei = i, bee = e; if(i == bei && e == bee) cedist = norm(v3-mousepos); } int col = i == bei && e == bee ? 0x40FF40FF: i == nei[bei][bee] && nei[i][e] == bei ? 0x40FF40FF : nei[i][e] == glued[i] ? 0x303030FF : glued[nei[i][e]] == i ? 0x303030FF : nei[i][e] >= 0 ? 0xC0C0C0FF : 0x808080FF; blackline(v1, v2, col); if(nei[i][e] != -1 && nei[i][e] != glued[i] && glued[nei[i][e]] != i) { vec vd = v2-v1; swap(vd.x, vd.y); vd.x = -vd.x; double factor = -sqrt(3)/6; vd.x *= factor; vd.y *= factor; vec v4 = v3 + vd; blackline(v1, v4, 0xFFC0C0C0); blackline(v2, v4, 0xFFC0C0C0); } } } SDL_UnlockSurface(s); SDL_UpdateRect(s, 0, 0, 0, 0); } double rs, rz; void addglue() { int i = bei; int j = nei[bei][bee]; if(glued[i] == j) glued[i] = -1; else if(glued[j] == i) glued[j] = -1; else if(glueroot(i) == glueroot(j)) ; else if(glued[j] == -1) glued[j] = i; } int nti; void smooth() { int ti = SDL_GetTicks(); rot[whichcell] += rs * (nti - ti) / 1000.0; el += rz * (nti - ti) / 1000.0; nti = ti; } void netgen_loop() { nti = SDL_GetTicks(); while(true) { smooth(); displaynets(); SDL_Event event; while(SDL_PollEvent(&event)) switch (event.type) { case SDL_QUIT: exit(1); return; case SDL_MOUSEBUTTONDOWN: { clicked(event.button.x, event.button.y, event.button.button); break; } case SDL_MOUSEBUTTONUP: { clicked(event.button.x, event.button.y, 16+event.button.button); break; } case SDL_MOUSEMOTION: { clicked(event.motion.x, event.motion.y, 32); break; } case SDL_KEYDOWN: { int key = event.key.keysym.sym; int uni = event.key.keysym.unicode; if(uni == 'q' || key == SDLK_ESCAPE || key == SDLK_F10) return; if(key == SDLK_PAGEUP) rs = 3; if(key == SDLK_PAGEDOWN) rs = -3; if(uni == 'z') rz = 1; if(uni == 'x') rz = -1; if(uni == 'g') addglue(); break; } case SDL_KEYUP: { rs = 0; rz = 0; break; } } } } void designNet() { s = SDL_SetVideoMode(SX, SY, 32, 0); netgen_loop(); saveData(); setvideomode(); } void show() { cmode = sm::SIDE; gamescreen(0); if(true) { for(int i=0; i<CELLS; i++) { int t = ct[i]; int ofs = t == 7 ? 0 : 5; for(int e=0; e<t; e++) { int col = nei[i][e] == glued[i] && glued[i] >= 0 ? 0x303030 : nei[i][e] >= 0 && glued[nei[i][e]] == i ? 0x303030 : nei[i][e] >= 0 ? 0x808080 : 0xC0C0C0; prettyline(hvec(i, (e+ofs)%t), hvec(i, (e+1+ofs)%t), (col << 8) + 0xFF, 3); } } } if(mode != 2) { dialog::init("paper model creator"); dialog::addItem(XLAT("synchronize net and map"), 's'); dialog::addItem(XLAT("display the scope"), 't'); dialog::addItem(XLAT("create the model"), 'c'); dialog::addItem(XLAT("back to HyperRogue"), 'q'); dialog::addItem(XLAT("design the net"), 'd'); dialog::display(); } keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); if(!loaded) { loadData(); if(!loaded) { addMessage(XLAT("Failed to load the file 'papermodeldata.txt'")); popScreen(); return; } if(!created) { View = Id; if(centerover) viewctr.h = centerover->master; else viewctr.h = cwt.c->master; playermoved = false; dataFromHR(); designNet(); created = 1; return; } } if(mode == 2 && uni != 0) { mode = 0; return; } if(uni == 's') { View = Id; if(centerover) viewctr.h = centerover->master; else viewctr.h = cwt.c->master; playermoved = false; } else if(uni == 'c') { createPapermodel(); addMessage(XLAT("The paper model created as papermodel-*.bmp")); } else if(uni == 'd') designNet(); else if(uni == 't') mode = 2; else if(doexiton(sym, uni)) popScreen(); }; } void run() { if(euclid) addMessage("Useless in Euclidean geometry."); else if(sphere) addMessage("Not implemented for spherical geometry. Please tell me if you really want this."); else pushScreen(show); } } #endif