diff --git a/game.cpp b/game.cpp index eea5ba27..1ecc9d6e 100644 --- a/game.cpp +++ b/game.cpp @@ -145,6 +145,10 @@ int hrand(int i) { return r() % i; } +ld hrandf() { + return (r() & HRANDMAX) / (HRANDMAX + 1.0); + } + void initcell(cell *c) { c->mpdist = INFD; // minimum distance from the player, ever c->cpdist = INFD; // current distance from the player diff --git a/graph.cpp b/graph.cpp index 4d3ea0b3..b09cd2c9 100644 --- a/graph.cpp +++ b/graph.cpp @@ -4855,6 +4855,12 @@ bool allowIncreasedSight() { purehookset hooks_drawmap; +transmatrix cview() { + sphereflip = Id; + if(sphereflipped()) sphereflip[2][2] = -1; + return ypush(vid.yshift) * sphereflip * View; + } + void drawthemap() { callhooks(hooks_drawmap); @@ -4924,12 +4930,10 @@ void drawthemap() { arrowtraps.clear(); - sphereflip = Id; profile_start(1); if(euclid) drawEuclidean(); else { - if(sphereflipped()) sphereflip[2][2] = -1; int sr = max(sightrange, ambush_distance); maxreclevel = conformal::on ? sr + 2: @@ -4937,9 +4941,7 @@ void drawthemap() { if(S3>3) maxreclevel+=2; - drawrec(viewctr, - maxreclevel, - hsOrigin, ypush(vid.yshift) * sphereflip * View); + drawrec(viewctr, maxreclevel, hsOrigin, cview()); } drawBlizzards(); drawArrowTraps(); diff --git a/hyper.h b/hyper.h index bf7c5ec3..be5d8b3a 100644 --- a/hyper.h +++ b/hyper.h @@ -2397,3 +2397,6 @@ inline hyperpoint tC0(const transmatrix &T) { z[0] = T[0][2]; z[1] = T[1][2]; z[2] = T[2][2]; return z; } + +transmatrix actualV(const heptspin& hs, const transmatrix& V); +transmatrix cview(); diff --git a/hypgraph.cpp b/hypgraph.cpp index 995a56ef..02f2f70b 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -329,6 +329,10 @@ bool confusingGeometry() { return elliptic || quotient == 1 || torus; } +transmatrix actualV(const heptspin& hs, const transmatrix& V) { + return (hs.spin || nontruncated) ? V * spin(hs.spin*2*M_PI/S7 + (nontruncated ? M_PI:0)) : V; + } + void drawrec(const heptspin& hs, int lev, hstate s, const transmatrix& V) { // shmup::calc_relative_matrix(cwt.c, hs.h); @@ -340,8 +344,7 @@ void drawrec(const heptspin& hs, int lev, hstate s, const transmatrix& V) { if(dodrawcell(c)) { reclevel = maxreclevel - lev; - drawcell(c, (hs.spin || nontruncated) ? V1 * spin(hs.spin*2*M_PI/S7 + (nontruncated ? M_PI:0)) : V1, 0, - hs.mirrored); + drawcell(c, actualV(hs, V1), 0, hs.mirrored); } if(lev <= 0) return; diff --git a/shmup.cpp b/shmup.cpp index c8876a3a..0c64a2c0 100644 --- a/shmup.cpp +++ b/shmup.cpp @@ -3276,6 +3276,16 @@ void destroyBoats(cell *c) { } transmatrix calc_relative_matrix(cell *c, heptagon *h1) { + + if(sphere) { + if(gmatrix0.count(c) && gmatrix0.count(h1->c7)) + return inverse(gmatrix0[h1->c7]) * gmatrix0[c]; + else { + printf("error: gmatrix0 not known\n"); + exit(1); + } + } + transmatrix gm = Id; heptagon *h2 = c->master; transmatrix where = Id; @@ -3316,13 +3326,7 @@ transmatrix calc_relative_matrix(cell *c, heptagon *h1) { transmatrix &ggmatrix(cell *c) { transmatrix& t = gmatrix[c]; if(t[2][2] == 0) { - if(sphere && gmatrix0.count(c)) - t = gmatrix[cwt.c] * inverse(gmatrix0[cwt.c]) * gmatrix0[c]; - else if(sphere) { - printf("error: gmatrix0 not known\n"); - exit(1); - } - else if(torus) { + if(torus) { forCellIdEx(c2, i, c) if(celldistance(c2, centerover) < celldistance(c, centerover)) t = ggmatrix(c2) * eumovedir(3+i); @@ -3338,11 +3342,8 @@ transmatrix &ggmatrix(cell *c) { printf("gmatrix0 = \n"); display(gmatrix0[c]); */ } - else { - t = - View * spin(viewctr.spin * 2 * M_PI / S7) * calc_relative_matrix(c, viewctr.h); - if(nontruncated) t = t * pispin; - } + else + t = actualV(viewctr, cview()) * calc_relative_matrix(c, viewctr.h); } return t; } diff --git a/textures.cpp b/textures.cpp index b12e245e..8aa95ecc 100644 --- a/textures.cpp +++ b/textures.cpp @@ -171,14 +171,13 @@ void mapTexture(cell *c, textureinfo& mi, patterns::patterninfo &si, const trans ld z = ctof(c) ? rhexf : hexvdist; - int sym = si.symmetries; + // int sym = si.symmetries; for(int i=0; itype; i++) { - int is = i % sym; hyperpoint h1 = spin(M_PI + M_PI * (2*i +1) / c->type) * xpush(z) * C0; hyperpoint h2 = spin(M_PI + M_PI * (2*i -1) / c->type) * xpush(z) * C0; - hyperpoint hm1 = spin(M_PI + M_PI * (2*is+1) / c->type) * xpush(z) * C0; - hyperpoint hm2 = spin(M_PI + M_PI * (2*is-1) / c->type) * xpush(z) * C0; + hyperpoint hm1 = spin(M_PI + M_PI * (2*i +1) / c->type) * xpush(z) * C0; + hyperpoint hm2 = spin(M_PI + M_PI * (2*i -1) / c->type) * xpush(z) * C0; mapTextureTriangle(mi, {C0, h1, h2}, {C0, hm1, hm2}); } } @@ -272,7 +271,7 @@ void perform_mapping() { if(!texture_map.count(si.id)) replace = true; - else if(hdist0(p.second*C0) < hdist0(texture_map[si.id].M * C0)) + else if(hdist0(p.second*sphereflip * C0) < hdist0(texture_map[si.id].M * sphereflip * C0)) replace = true; if(replace) { @@ -342,7 +341,82 @@ void drawRawTexture() { glDisable(GL_TEXTURE_2D); } -enum eTexturePanstate {tpsModel, tpsMove, tpsScale, tpsAffine, tpsZoom, tpsProjection}; +struct magicmapper_point { + cell *c; + hyperpoint cell_relative; + hyperpoint texture_coords; + }; + +vector amp; + +struct magic_param { + bool do_spin; + ld spinangle, scale, proj, moveangle, shift; + + void shuffle() { + do_spin = hrand(2); + spinangle = hrandf() - hrandf(); + moveangle = hrandf() * 2 * M_PI; + shift = hrandf() - hrandf(); + scale = hrandf() - hrandf(); + proj = hrandf() - hrandf(); + } + + void apply(ld delta) { + vid.alpha *= exp(delta * proj); + vid.scale *= exp(delta * scale); + + if(do_spin) + View = spin(delta * spinangle) * View; + else + View = spin(moveangle) * xpush(delta*shift) * spin(-moveangle) * View; + + fixmatrix(View); + } + }; + +ld magic_quality() { + gmatrix.clear(); + calcparam(); + + ld q = 0; + for(auto& p: amp) { + hyperpoint inmodel; + applymodel(shmup::ggmatrix(p.c) * p.cell_relative, inmodel); + inmodel[0] *= vid.radius * 1. / vid.scrsize; + inmodel[1] *= vid.radius * 1. / vid.scrsize; + q += intvalxy(inmodel, p.texture_coords); + } + return q; + } + +void applyMagic() { + ld cq = magic_quality(); + + int last_success = 0; + + for(int s=0; s<50000 && s 1e-9; delta *= (failed ? -.7 : 1.2)) { + p.apply(delta); + ld nq = magic_quality(); + if(nq < cq) { + cq = nq; + last_success = s; + } + else { + p.apply(-delta); + failed = true; + } + } + } + } + +enum eTexturePanstate {tpsModel, tpsMove, tpsScale, tpsAffine, tpsZoom, tpsProjection, tpsMagic}; eTexturePanstate panstate; void mousemovement() { @@ -385,7 +459,7 @@ void mousemovement() { case tpsZoom: { // do not zoom in portrait! if(nonzero && !newmove) { - View = View * inverse(spintox(mouseeu)) * spintox(lastmouse); + View = inverse(spintox(mouseeu)) * spintox(lastmouse) * View; vid.scale = vid.scale * sqrt(intvalxy(C0, mouseeu)) / sqrt(intvalxy(C0, lastmouse)); } if(nonzero) lastmouse = mouseeu; @@ -401,6 +475,18 @@ void mousemovement() { newmove = false; } + case tpsMagic: { + if(!mouseover) return; + if(newmove) { + magicmapper_point newpoint; + newpoint.c = mouseover; + newpoint.cell_relative = inverse(gmatrix[mouseover]) * mouseh; + amp.push_back(newpoint); + newmove = false; + } + amp.back().texture_coords = mouseeu; + } + default: break; } } @@ -490,6 +576,7 @@ bool load_textureconfig() { } if(!readtexture()) return false; + calcparam(); drawthemap(); perform_mapping(); tstate = tstate_max = tsActive; @@ -523,6 +610,13 @@ void showMenu() { dialog::addBoolItem(XLAT("zoom/scale the model"), panstate == tpsZoom, 'z'); dialog::addBoolItem(XLAT("projection"), panstate == tpsProjection, 'p'); dialog::addBoolItem(XLAT("affine transformations"), panstate == tpsAffine, 'y'); + dialog::addBoolItem(XLAT("magic"), panstate == tpsMagic, 'A'); + + if(panstate == tpsMagic) { + dialog::addSelItem(XLAT("delete markers"), its(size(amp)), 'D'); + dialog::addSelItem(XLAT("perform auto-adjustment"), "...", 'R'); + } + dialog::addSelItem(XLAT("precision"), its(gsplits), 'p'); } @@ -546,6 +640,33 @@ void showMenu() { dialog::display(); + if(tstate == tsAdjusting) { + initquickqueue(); + char letter = 'A'; + for(auto& am: amp) { + hyperpoint h = shmup::ggmatrix(am.c) * am.cell_relative; + display(h); + queuechr(h, vid.fsize, letter, 0xC00000, 1); + + hyperpoint inmodel; + applymodel(h, inmodel); + inmodel[0] *= vid.radius * 1. / vid.scrsize; + inmodel[1] *= vid.radius * 1. / vid.scrsize; + queuechr( + vid.xcenter + vid.scrsize * inmodel[0], + vid.ycenter + vid.scrsize * inmodel[1], + 0, vid.fsize/2, letter, 0xC0C0C0, 1); + + queuechr( + vid.xcenter + vid.scrsize * am.texture_coords[0], + vid.ycenter + vid.scrsize * am.texture_coords[1], + 0, vid.fsize, letter, 0x00C000, 1); + + letter++; + } + quickqueue(); + } + if(holdmouse) mousemovement(); keyhandler = [] (int sym, int uni) { @@ -565,7 +686,10 @@ void showMenu() { else if(uni == 'y' && tstate == tsAdjusting) panstate = tpsAffine; else if(uni == 'z' && tstate == tsAdjusting) panstate = tpsZoom; else if(uni == 'p' && tstate == tsAdjusting) panstate = tpsProjection; - + else if(uni == 'A' && tstate == tsAdjusting) panstate = tpsMagic; + else if(uni == 'D' && tstate == tsAdjusting) amp.clear(); + else if(uni == 'R' && tstate == tsAdjusting) applyMagic(); + else if(uni == 's' && tstate == tsActive) dialog::openFileDialog(configname, XLAT("texture config to save:"), ".txc", [] () {