From 3caec11dfa6b7d47c46122e89f02e49476ce0b7f Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Thu, 12 Sep 2019 23:14:37 +0200 Subject: [PATCH] added some devmods --- devmods/README.md | 4 + devmods/edit-shaders.cpp | 72 ++++++++ devmods/manual-animation.cpp | 241 +++++++++++++++++++++++++ devmods/solv-table.cpp | 336 +++++++++++++++++++++++++++++++++++ language-pl.cpp | 2 +- 5 files changed, 654 insertions(+), 1 deletion(-) create mode 100644 devmods/README.md create mode 100644 devmods/edit-shaders.cpp create mode 100644 devmods/manual-animation.cpp create mode 100644 devmods/solv-table.cpp diff --git a/devmods/README.md b/devmods/README.md new file mode 100644 index 00000000..ee363cff --- /dev/null +++ b/devmods/README.md @@ -0,0 +1,4 @@ +This subdirectory contains various extra modules which are useful in development, +but are not a part of standard HyperRogue build nor RogueViz. + +They can be added to a HyperRogue build e.g. with `mymake devmods/edit-shaders`. diff --git a/devmods/edit-shaders.cpp b/devmods/edit-shaders.cpp new file mode 100644 index 00000000..afe48376 --- /dev/null +++ b/devmods/edit-shaders.cpp @@ -0,0 +1,72 @@ +// This addon is useful when debugging or tuning shaders. +// Press F2, edit the shader files, then press F3 to see them in action. + +// F2: write the currently used shaders to files +// F3: replace the currently used shaders with the content of the files + +// Might need some editing. + +#include "../hyper.h" + +namespace hr { + +string load_whole(const char *fname) { + char buf[1000000]; + FILE *f = fopen(fname, "rb"); + int n = fread(buf, 1, 1000000, f); + buf[n] = 0; + return buf; + } + +void print_shader(const char *fname, string s) { + FILE *f = fopen(fname, "wb"); + int indent = 0; + bool linestart = true; + for(char c: s) { + if(c == ' ' && linestart) continue; + if(c == '\n' && linestart) continue; + linestart = false; + fputc(c, f); + if(c == '{') indent += 2; + if(c == '}') indent -= 2; + if(c == ';' || c == '}' || c == '{') { + fputc('\n', f); + for(int i=0; iset_all(0); + auto p = glhr::get_shaders(); + print_shader("addons/current.vsh", p.first); + print_shader("addons/current.fsh", p.second); + addMessage("shaders saved"); + return true; + } + + if(sym == SDLK_F3) { + glhr::be_textured(); + current_display->set_all(0); + string vsh = load_whole("addons/current.vsh"); + string fsh = load_whole("addons/current.fsh"); + println(hlog, "loaded vsh:\n", vsh); + glhr::install_shaders(vsh, fsh); + glhr::be_textured(); + current_display->set_all(0); + return true; + } + + return false; + } + +auto hook = + addHook(hooks_handleKey, 100, trailer_handleKey) ++ 0; + +} diff --git a/devmods/manual-animation.cpp b/devmods/manual-animation.cpp new file mode 100644 index 00000000..983ffd84 --- /dev/null +++ b/devmods/manual-animation.cpp @@ -0,0 +1,241 @@ +#include "../hyper.h" + +// A tool to create smooth manually controlled movement animations in 3D geometries. + +// Press 'f' to start controlling + +// 'qweasdzxc' will move the camera and additionally rotate the view a bit (except 's') + +// 'b' goes back 1 frame, 'e' undoes 30 frames + +// 'r' starts recording + +// 1234 change movement speed (see console for details) +// 67890 change rotation speed (see console for details) + +namespace hr { + +bool saving_positions; + +int next_pos_tick; + +vector > saved; + +bool trailer_turn(int delta) { + if(saving_positions) + View = cpush(2, -delta/8000.) * cspin(0, 2, (mousex - current_display->xcenter) * delta / -1000000.) * cspin(1, 2, (mousey - current_display->ycenter) * delta / -1000000.) * View; + return true; + } + +bool recording; + +void trailer_frame() { + // if(saving_positions || !isize(saved)) + if(!recording) queuechr(current_display->xcenter, current_display->ycenter, 0, 16, '+', 0xFFFFFFFF); + + if(saving_positions && ticks > next_pos_tick) { + next_pos_tick += 66; + saved.emplace_back(View, nisot::local_perspective, hybrid::current_view_level, viewctr); + println(hlog, "frames = ", isize(saved)); + } + } + +bool keys_on = false; + +ld stepdist = 0.02; + +ld stepang = 0.01; + +bool move_camera(transmatrix T) { + for(int it=0; it<5; it++) { + saved.emplace_back(View, nisot::local_perspective, hybrid::current_view_level, viewctr); + println(hlog, "frames = ", isize(saved)); + shift_view(ztangent(-stepdist)); + rotate_view(T); + } + playermoved = false; + return true; + } + +namespace solv { pair getcoord(heptagon *h); } + +bignum bdiff(heptagon *h1, heptagon *h2) { + if(h1 == h2) return 0; + auto p = bdiff(h1->move(3), h2->move(3)); + int d = h1->c.spin(3) - h2->c.spin(3); + println(hlog, "d=", d, " p = ", p.get_str(10000)); + return p + p + bignum(d); + } + +#define BASE 10 + +/* +void o_addmul(bignum& b0, const bignum& b, int factor) { + int K = isize(b.digits); + if(K > isize(b0.digits)) b0.digits.resize(K); + int carry = 0; + for(int i=0; ; i++) { + bool cnt = (i 0 && carry < -1) || (carry == -1 && i < isize(b0.digits))); + println(hlog, "cnt = ", cnt, " carry = ", carry + if(!cnt) break; + println(hlog, "i=", i, " carry start=", carry); + if(i >= isize(b0.digits)) b0.digits.push_back(0); + long long l = b0.digits[i]; + l += carry; + if(i < K) l += b.digits[i] * factor; + carry = 0; + if(l >= BASE) carry = l / BASE; + if(l < 0) carry = -(BASE-1-l) / BASE; + l -= carry * BASE; + b0.digits[i] = l; + println(hlog, "carry=", carry); + } + println(hlog, "carry end=", carry); + if(carry < 0) b0.digits.back() -= BASE; + while(isize(b0.digits) && b0.digits.back() == 0) b0.digits.pop_back(); + } */ + +void get_b4_distance() { + heptagon *h1 = currentmap->gamestart()->master; + heptagon *h2 = viewctr.at; + if(h1->distance != h2->distance) + println(hlog, "Z difference: ", h2->distance - h1->distance); + else { + auto c1 = solv::getcoord(h1); + auto c2 = solv::getcoord(h2); + println(hlog, "X difference: ", bdiff(c1.first, c2.first).get_str(10000)); + println(hlog, "Y difference: ", bdiff(c1.second, c2.second).get_str(10000)); + println(hlog, "X difference> ", bdiff(c2.first, c1.first).get_str(10000)); + println(hlog, "Y difference> ", bdiff(c2.second, c1.second).get_str(10000)); + } + } + +bool trailer_handleKey(int sym, int uni) { + + if(sym == 'f') { + keys_on = !keys_on; + println(hlog, "keys_on = ", keys_on); + return true; + } + + // println(hlog, "cells_drawn = ", cells_drawn, " cells_generated = ", cells_generated); + + if(keys_on) { + + if(sym == 't') { + if(!saved.empty()) { + println(hlog, "frames = ", isize(saved)); + saved.pop_back(); + } + if(!saved.empty()) { + tie(View, nisot::local_perspective, hybrid::current_view_level, viewctr) = saved.back(); + } + return true; + } + + /* if(sym == 'e') { + dialog::editNumber(stepdist, 0, 1, 0.1, 0.1, "", ""); + dialog::scaleLog(); + } */ + + if(sym == 's') return move_camera(Id); + + if(sym == 'a') return move_camera(cspin(0, 2, stepang)); + + if(sym == 'd') return move_camera(cspin(0, 2, -stepang)); + + if(sym == 'q') return move_camera(cspin(0, 2, stepang) * cspin(1, 2, stepang)); + if(sym == 'w') return move_camera(cspin(1, 2, stepang)); + if(sym == 'e') return move_camera(cspin(0, 2, -stepang) * cspin(1, 2, stepang)); + + if(sym == 'z') return move_camera(cspin(0, 2, stepang) * cspin(1, 2, -stepang)); + if(sym == 'x') return move_camera(cspin(1, 2, -stepang)); + if(sym == 'c') return move_camera(cspin(0, 2, -stepang) * cspin(1, 2, -stepang)); + + + if(sym == '1') { stepdist = 0; println(hlog, stepdist); return true; } + if(sym == '2') { stepdist = 0.01; println(hlog, stepdist); return true; } + if(sym == '3') { stepdist = 0.02; println(hlog, stepdist); return true; } + if(sym == '4') { stepdist = 0.05; println(hlog, stepdist); return true; } + + if(sym == '6') { stepang = 0.001; println(hlog, stepang); return true; } + if(sym == '7') { stepang = 0.003; println(hlog, stepang); return true; } + if(sym == '8') { stepang = 0.01; println(hlog, stepang); return true; } + if(sym == '9') { stepang = 0.03; println(hlog, stepang); return true; } + if(sym == '0') { stepang = 0.1; println(hlog, stepang); return true; } + + if(sym == 'p') { get_b4_distance(); return true; } + + if(sym == SDLK_F4) { + saving_positions = !saving_positions; + next_pos_tick = ticks; + println(hlog, "saving_positions = ", saving_positions); + return true; + } + + if(sym == 'b') { + saved.pop_back(); + tie(View, nisot::local_perspective, hybrid::current_view_level, viewctr) = saved.back(); + return true; + } + + if(sym == 'u' && isize(saved) > 40) { + for(int i=0; i<30; i++) saved.pop_back(); + tie(View, nisot::local_perspective, hybrid::current_view_level, viewctr) = saved.back(); + return true; + } + + if(sym == 'r') { + recording = true; + if(mouseaim_sensitivity) { + mouseaim_sensitivity = 0; + return true; + } + if(musicvolume) { + musicvolume = 0; + Mix_VolumeMusic(0); + return true; + } + saving_positions = false; +// vid.cells_drawn_limit = 1000000; + int i = 0; + shot::take("anim/start.png"); + shot::transparent = false; +// shot::shotx = 1920; +// shot::shoty = 1080; + shot::shot_aa = 2; + solv::solrange_xy = 30; + solv::solrange_z = 6; + vid.cells_drawn_limit = 100000; + vid.cells_generated_limit = 1000; +// sightranges[geometry] = 4; + static int lasti = 0; + + for(auto& p: saved) { + // sightranges[geometry] = 4 + i * 2. / isize(saved); + tie(View, nisot::local_perspective, hybrid::current_view_level, viewctr) = p; + ticks = i * 1000 / 30; + if(i < lasti) continue; + + system("mkdir addons/possaver/"); + + shot::take(format("extra/possaver/%05d.png", i)); + println(hlog, "frame ", i); + i++; + } + + lasti = i; + recording = false; + } + } + + return false; + } + +auto hook = + addHook(hooks_handleKey, 100, trailer_handleKey) ++ addHook(hooks_drawmap, 100, trailer_frame) ++ addHook(shmup::hooks_turn, 100, trailer_turn) ++ 0; + +} diff --git a/devmods/solv-table.cpp b/devmods/solv-table.cpp new file mode 100644 index 00000000..6c238740 --- /dev/null +++ b/devmods/solv-table.cpp @@ -0,0 +1,336 @@ +// This generates the 'solv-geodesics.dat' file. +// You may change the _PREC* values for more precise geodesics. + +#include "../hyper.h" + +#include +#include + +namespace hr { + +const int _PRECX = 64; +const int _PRECY = 64; +const int _PRECZ = 64; + +transmatrix parabolic1(ld u); + +namespace solv { + +typedef hyperpoint pt; +typedef array ptlow; + +ptlow be_low(pt x) { return ptlow({float(x[0]), float(x[1]), float(x[2])}); } + +template void parallelize(int threads, int Nmin, int Nmax, T action) { + std::vector v; + for(int k=0; k&) v; + if(x == 0 && z == 0) return C0; + hyperpoint h = parabolic1(x) * xpush(-z) * C0; + ld d = acosh(h[2]) / sqrt(h[0] * h[0] + h[1] * h[1]); + return hyperpoint({h[1]*d, 0, -h[0]*d,1}); + } + +hyperpoint sol2(pt v) { + auto [x,y,z,t] = (array&) v; + if(y == 0 && z == 0) return C0; + hyperpoint h = parabolic1(y) * xpush(z) * C0; + ld d = acosh(h[2]) / sqrt(h[0] * h[0] + h[1] * h[1]); + return hyperpoint({0, h[1]*d, +h[0]*d,1}); + } + +ld x_to_ix(ld u); + +ld solerror(pt ok, pt chk) { + auto zok = point3( x_to_ix(ok[0]), x_to_ix(ok[1]), tanh(ok[2]) ); + auto zchk = point3( x_to_ix(chk[0]), x_to_ix(chk[1]), tanh(chk[2]) ); + return hypot_d(3, zok - zchk); + } + +ld eucerror(pt ok, pt chk) { + return pow(ok[0]-chk[0], 2) + pow(ok[1]-chk[1], 2) + pow(ok[2]-chk[2], 2); + } + +pt iterative_solve(pt xp, pt candidate, int prec, ld minerr, bool debug = false) { + + transmatrix T = Id; T[0][1] = 8; T[2][2] = 5; + + auto f = [&] (hyperpoint x) { return nisot::numerical_exp(x, prec); }; // T * x; }; + + auto ver = f(candidate); + ld err = solerror(xp, ver); + auto at = candidate; + + ld eps = 1e-6; + + pt c[3]; + for(int a=0; a<3; a++) c[a] = point3(a==0, a==1, a==2); + + while(err > minerr) { + if(debug) println(hlog, "\n\nf(", at, "?) = ", ver, " (error ", err, ")"); + array pnear; + for(int a=0; a<3; a++) { + auto x = at + c[a] * eps; + if(debug) println(hlog, "f(", x, ") = ", f(x), " = y + ", f(x)-ver ); + pnear[a] = (f(x) - ver) / eps; // (direct_exp(at + c[a] * eps, prec) - ver) / eps; + } + + transmatrix U = Id; + for(int a=0; a<3; a++) + for(int b=0; b<3; b++) + U[a][b] = pnear[b][a]; + + hyperpoint diff = (xp - ver); + + hyperpoint bonus = inverse(U) * diff; + + if(hypot_d(3, bonus) > 0.1) bonus = bonus * 0.1 / hypot_d(3, bonus); + + int fixes = 0; + + if(debug) + println(hlog, "\nU = ", U, "\ndiff = ", diff, "\nbonus = ", bonus, "\n"); + + nextfix: + hyperpoint next = at + bonus; + hyperpoint nextver = f(next); + ld nexterr = solerror(xp, nextver); + if(debug) println(hlog, "f(", next, ") = ", nextver, ", error = ", nexterr); + + if(nexterr < err) { + // println(hlog, "reduced error ", err, " to ", nexterr); + at = next; + ver = nextver; + err = nexterr; + continue; + } + else { + bonus /= 2; + fixes++; + if(fixes > 10) { + if(err > 999) { + for(ld s = 1; abs(s) > 1e-9; s *= 0.5) + for(int k=0; k<27; k++) { + int kk = k; + next = at; + for(int i=0; i<3; i++) { if(kk%3 == 1) next[i] += s; if(kk%3 == 2) next[i] -= s; kk /= 3; } + // next = at + c[k] * s; + nextver = f(next); + nexterr = solerror(xp, nextver); + // println(hlog, "f(", next, ") = ", nextver, ", error = ", nexterr); + if(nexterr < err) { at = next; ver = nextver; err = nexterr; goto nextiter; } + } + println(hlog, "cannot improve error ", err); + exit(1); + } + break; + } + goto nextfix; + } + + nextiter: ; + } + + return at; + } + +ptlow solution[_PRECZ][_PRECY][_PRECX]; + +ptlow mlow(ld x, ld y, ld z) { return ptlow({float(x), float(y), float(z)}); } + +pt atxyz(ld x, ld y, ld z) { return hyperpoint({x, y, z, 1}); } + +ptlow operator +(ptlow a, ptlow b) { return mlow(a[0]+b[0], a[1]+b[1], a[2]+b[2]); } +ptlow operator -(ptlow a, ptlow b) { return mlow(a[0]-b[0], a[1]-b[1], a[2]-b[2]); } +ptlow operator *(ptlow a, ld x) { return mlow(a[0]*x, a[1]*x, a[2]*x); } + +ptlow can(pt x) { + // azimuthal equidistant to Klein + ld r = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); + if(r == 0) return mlow(0,0,0); + ld make_r = tanh(r); + ld d = make_r / r; + return mlow(x[0]*d, x[1]*d, x[2]*d); + } + +pt uncan(ptlow x) { + ld r = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); + if(r == 0) return atxyz(0,0,0); + ld make_r = atanh(r); + if(r == 1) make_r = 30; + ld d = make_r / r; + return atxyz(x[0]*d, x[1]*d, x[2]*d); + } + +pt uncan_info(ptlow x) { + ld r = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); + println(hlog, "r = ", r); + if(r == 0) return atxyz(0,0,0); + ld make_r = atanh(r); + println(hlog, "make_r = ", make_r); + ld d = make_r / r; + println(hlog, "d = ", d); + return atxyz(x[0]*d, x[1]*d, x[2]*d); + } + +void fint(FILE *f, int x) { fwrite(&x, sizeof(x), 1, f); } +void ffloat(FILE *f, float x) { fwrite(&x, sizeof(x), 1, f); } + +void write_table(const char *fname) { + FILE *f = fopen(fname, "wb"); + fint(f, _PRECX); + fint(f, _PRECY); + fint(f, _PRECZ); + fwrite(solution, sizeof(solution), 1, f); + fclose(f); + } + +void load_table(const char *fname) { + int s; + FILE *f = fopen(fname, "rb"); + fread(&s, 4, 1, f); + fread(&s, 4, 1, f); + fread(&s, 4, 1, f); + fread(solution, sizeof(solution), 1, f); + fclose(f); + } + +ld ix_to_x(ld ix) { + ld minx = 0, maxx = 1; + for(int it=0; it<100; it++) { + ld x = (minx + maxx) / 2; + if(x_to_ix(atanh(x)) < ix) minx = x; + else maxx = x; + } + return atanh(minx); + } + +ld iz_to_z(ld z) { + return atanh(z); // atanh(z * 2 - 1); + } + +ld z_to_iz(ld z) { + return tanh(z); // (tanh(z) + 1) / 2; + } + +int last_x = _PRECX-1, last_y = _PRECY-1, last_z = _PRECZ-1; + +ld ptd(ptlow p) { + return p[0]*p[0] + p[1]*p[1] + p[2] * p[2]; + } + +ptlow zflip(ptlow x) { return mlow(x[1], x[0], -x[2]); } + +void build_sols() { + std::mutex file_mutex; + ld max_err = 0; + auto act = [&] (int tid, int iz) { + + auto solve_at = [&] (int ix, int iy) { + ld x = ix_to_x(ix / (_PRECX-1.)); + ld y = ix_to_x(iy / (_PRECY-1.)); + ld z = iz_to_z(iz / (_PRECZ-1.)); + + auto v = hyperpoint ({x,y,z,1}); + + vector candidates; + pt cand; + + candidates.push_back(atxyz(0,0,0)); + + static constexpr int prec = 100; + + // sort(candidates.begin(), candidates.end(), [&] (pt a, pt b) { return solerror(v, direct_exp(a, prec)) > solerror(v, direct_exp(b, prec)); }); + + // cand_best = candidates.back(); + + vector solved_candidates; + + for(auto c: candidates) { + auto solt = iterative_solve(v, c, prec, 1e-6); + solved_candidates.push_back(solt); + if(solerror(v, nisot::numerical_exp(solt, prec)) < 1e-9) break; + } + + sort(solved_candidates.begin(), solved_candidates.end(), [&] (pt a, pt b) { return solerror(v, nisot::numerical_exp(a, prec)) > solerror(v, nisot::numerical_exp(b, prec)); }); + + cand = solved_candidates.back(); + + auto xerr = solerror(v, nisot::numerical_exp(cand, prec)); + + if(xerr > 1e-3) { + println(hlog, format("[%2d %2d %2d] ", iz, iy, ix)); + println(hlog, "f(?) = ", v); + println(hlog, "f(", cand, ") = ", nisot::numerical_exp(cand, prec)); + println(hlog, "error = ", xerr); + println(hlog, "canned = ", can(cand)); + max_err = xerr; + hyperpoint h1 = uncan(solution[iz][iy-1][ix]); + hyperpoint h2 = uncan(solution[iz][iy][ix-1]); + hyperpoint h3 = uncan(solution[iz][iy-1][ix-1]); + hyperpoint h4 = h1 + h2 - h3; + solution[iz][iy][ix] = can(h4); + return; + } + + solution[iz][iy][ix] = can(cand); + + for(int z=0; z<3; z++) if(isnan(solution[iz][iy][ix][z]) || isinf(solution[iz][iy][ix][z])) { + println(hlog, cand, "canned to ", solution[iz][iy][ix]); + exit(4); + } + }; + + for(int it=0; it fm(file_mutex); + println(hlog, format("%2d: %2d", iz, it)); + } + }; + + parallelize(last_z, 0, last_z, act); + + for(int x=0; x