diff --git a/Makefile b/Makefile index 0d9bf706..004eb426 100644 --- a/Makefile +++ b/Makefile @@ -156,7 +156,7 @@ makeh$(EXE_EXTENSION): makeh.cpp $(CXX) -O2 makeh.cpp -o $@ autohdr.h: makeh$(EXE_EXTENSION) language-data.cpp *.cpp - ./makeh classes.cpp locations.cpp colors.cpp hyperpoint.cpp geometry.cpp goldberg.cpp init.cpp floorshapes.cpp cell.cpp multi.cpp shmup.cpp pattern2.cpp mapeditor.cpp graph.cpp textures.cpp hprint.cpp language.cpp util.cpp complex.cpp *.cpp > autohdr.h + ./makeh classes.cpp locations.cpp colors.cpp hyperpoint.cpp geometry.cpp goldberg.cpp init.cpp floorshapes.cpp cell.cpp multi.cpp shmup.cpp pattern2.cpp mapeditor.cpp graph.cpp textures.cpp hprint.cpp language.cpp util.cpp complex.cpp multigame.cpp *.cpp > autohdr.h language-data.cpp: langen$(EXE_EXTENSION) ./langen > language-data.cpp diff --git a/cell.cpp b/cell.cpp index b5206338..c93dc500 100644 --- a/cell.cpp +++ b/cell.cpp @@ -1450,7 +1450,7 @@ EX int valence() { /** portalspaces are not defined outside of a boundary */ EX bool is_boundary(cell *c) { if(c == &out_of_bounds) return true; - return (cgflags & qPORTALSPACE) && isWall(c->wall); + return ((cgflags & qPORTALSPACE) || intra::in) && isWall(c->wall); } /** compute the distlimit for a tessellation automatically */ diff --git a/geometry.cpp b/geometry.cpp index 49019560..95d3ca18 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -1196,7 +1196,7 @@ EX void check_cgi() { if(fake::in()) fake::underlying_cgip->timestamp = ntimestamp; if(arcm::alt_cgip) arcm::alt_cgip->timestamp = ntimestamp; - if(isize(cgis) > 4) { + if(isize(cgis) > 4 && !intra::in) { vector> timestamps; for(auto& t: cgis) timestamps.emplace_back(-t.second.timestamp, t.first); sort(timestamps.begin(), timestamps.end()); diff --git a/graph.cpp b/graph.cpp index 2a82b320..4002fc52 100644 --- a/graph.cpp +++ b/graph.cpp @@ -4014,6 +4014,11 @@ EX subcellshape& generate_subcellshape_if_needed(cell *c, int id) { ss.walltester.push_back(w); } + if(hybri || WDIM == 2) { + ss.walltester.push_back(C0); + ss.walltester.push_back(C0); + } + for(int i=0; itype; i++) ss.faces.push_back({hybrid::get_corner(c1, i, 0, -1), hybrid::get_corner(c1, i, 0, +1), hybrid::get_corner(c1, i, 1, +1), hybrid::get_corner(c1, i, 1, -1)}); diff --git a/hyper.cpp b/hyper.cpp index 81ff951f..5184ce25 100644 --- a/hyper.cpp +++ b/hyper.cpp @@ -123,6 +123,7 @@ #include "inforder.cpp" #include "dpgen.cpp" #include "vr.cpp" +#include "intra.cpp" #if CAP_ROGUEVIZ #include "rogueviz/rogueviz-all.cpp" diff --git a/hypgraph.cpp b/hypgraph.cpp index d619484e..421a82cf 100644 --- a/hypgraph.cpp +++ b/hypgraph.cpp @@ -2902,6 +2902,17 @@ EX transmatrix get_shift_view_of(const hyperpoint H, const transmatrix V) { /** shift the view according to the given tangent vector */ EX void shift_view(hyperpoint H) { if(callhandlers(false, hooks_shift_view, H)) return; + static bool recursive = false; + if(!recursive && intra::in) { + H /= 10; + recursive = true; + for(int i=0; i<10; i++) { + shift_view(H); + intra::check_portal_movement(); + } + recursive = false; + return; + } auto oView = View; View = get_shift_view_of(H, View); auto& wc = current_display->which_copy; diff --git a/intra.cpp b/intra.cpp new file mode 100644 index 00000000..93cd1455 --- /dev/null +++ b/intra.cpp @@ -0,0 +1,297 @@ +#include "hyper.h" + +namespace hr { + +EX namespace intra { + +EX bool in; + +#if HDR +/** information per every space connected with intra-portals */ +struct intra_data { + gamedata gd; + geometryinfo gi; + int wallindex; + }; +#endif + +EX vector data; + +/** index of the space we are currently in */ +EX int intra_current; + +/** map cells to their intra spaces */ +EX map intra_id; + +#if HDR +/** information about portal (one side) */ +struct portal_data { + int kind; + hyperpoint v0; + ld d; + transmatrix T; + transmatrix iT; + hyperpoint co0; + hyperpoint co1; + ld scale; + /* convert h to portal coordinates ('poco') to usual coordinates */ + hyperpoint to_poco(hyperpoint h) const; + /* convert h from portal coordinates ('poco') to usual coordinates */ + hyperpoint from_poco(hyperpoint h) const; + }; +#endif + +hyperpoint portal_data::to_poco(hyperpoint h) const { + if(prod && kind == 1) { + auto dec = product_decompose(h); + h = dec.second; + h[0] /= h[2]; + h[1] /= h[2]; + h[2] = dec.first - d; + h[3] = 1; + return h; + } + else if(prod && kind == 0) { + h = T * h; + ld z = product_decompose(h).first; + h /= exp(z); + auto h1 = h; + h[0] = asin_auto(h1[1]); + h[1] = z; + h[2] = asin_auto_clamp(h1[0] / cos_auto(h[0])); + h[3] = 1; + return h; + } + else { + h = T * h; + h /= h[3]; + return h; + } + } + +hyperpoint portal_data::from_poco(hyperpoint h) const { + if(prod && kind == 1) { + ld d = h[2]; + h[2] = 1; + auto z = product_decompose(h).first; + return h * exp(d+d-z); + } + else if(prod && kind == 0) { + auto h0 = h; + h[0] = sin_auto(h0[2]) * cos_auto(h0[0]); + h[1] = sin_auto(h0[0]); + h[2] = cos_auto(h0[0]) * cos_auto(h0[2]); + h[3] = 1; + return iT * h * exp(h0[1]); + } + else { + h[3] = 1; + return normalize(iT * h); + } + } + +EX portal_data make_portal(cellwalker cw) { + auto& ss = currentmap->get_cellshape(cw.at); + auto& fac = ss.faces[cw.spin]; + portal_data id; + id.scale = 1; + if(prod && cw.spin == cw.at->type - 1) { + id.kind = 1; + id.d = product_decompose(fac[0]).first; + id.v0 = C0 * exp(id.d); + } + else if(prod && cw.spin == cw.at->type - 2) { + throw hr_exception("cannot construct a portal in this direction"); + } + else if(prod) { + id.kind = 0; + id.v0 = Hypc; + id.scale = cgi.plevel; + for(auto p: fac) id.v0 += p; + id.v0 /= sqrt(abs(intval(id.v0, Hypc))); + id.T = cpush(0, -hdist0(id.v0)) * spintox(id.v0); + for(int i=0; i<3; i++) id.T[3][i] = id.T[i][3] = i==3; + if(debugflags & DF_GEOM) + for(int a=0; a<4; a++) { + hyperpoint h = fac[a]; + println(hlog, kz(h), " -> ", kz(spintox(id.v0)*h), " -> ", kz(cpush(0, -hdist0(id.v0))) * kz(spintox(id.v0) * h), " -> ", kz(id.to_poco(h))); + } + } + else { + id.kind = 0; + id.v0 = Hypc; + for(auto p: fac) id.v0 += p; + id.v0 = normalize(id.v0); + id.T = cpush(2, -hdist0(id.v0)) * cspin(2, 0, 90*degree) * spintox(id.v0); + } + id.iT = inverse(id.T); + if(MDIM == 3) for(int i=0; i<4; i++) id.iT[3][i] = id.iT[i][3] = i==3; + id.co0 = id.to_poco(fac[(in_s2xe() || sphere) ? 2 : 0]); + id.co1 = id.to_poco(fac[1]); + return id; + } + +#if HDR +/** information about connection (portal-to-portal) */ +struct connection_data { + int source_world; + int target_world; + cellwalker scw, tcw; + portal_data id1; + portal_data id2; + transmatrix T; + }; +#endif + +EX map connections; + +EX connection_data* find_connection(int a, int b) { + for(auto& p: connections) + if(intra_id[p.first.at] == a && p.second.target_world == b) + return &p.second; + return nullptr; + } + +EX void switch_to(int id) { + if(intra_current == id) return; + data[intra_current].gd.storegame(); + intra_current = id; + ginf[gProduct] = data[intra_current].gi; + data[intra_current].gd.restoregame(); + } + +void connect_portal_1(cellwalker cw1, cellwalker cw2) { + auto& p = connections[cw1]; + p.source_world = intra_id[cw1.at]; + p.target_world = intra_id[cw2.at]; + p.scw = cw1; + p.tcw = cw2; + switch_to(intra_id[cw1.at]); + p.id1 = make_portal(cw1); + switch_to(intra_id[cw2.at]); + p.id2 = make_portal(cw2); + + if(1) { + dynamicval g(geometry, gCubeTiling); + transmatrix T1; + set_column(T1, 0, p.id1.co0); + set_column(T1, 1, p.id1.co1); + set_column(T1, 2, hyperpoint(0,0,p.id1.scale,0)); + set_column(T1, 3, C03); + transmatrix T2; + set_column(T2, 0, p.id2.co0); + set_column(T2, 1, p.id2.co1); + set_column(T2, 2, hyperpoint(0,0,-p.id2.scale,0)); + set_column(T2, 3, C03); + if(debugflags & DF_GEOM) for(int i=0; i<4; i++) + println(hlog, "mapping ", get_column(T1, i), " to ", get_column(T2, i)); + p.T = T2 * inverse(T1); + } + } + +EX vector> full_sample_list; + +EX void connect_portal(cellwalker cw1, cellwalker cw2) { + connect_portal_1(cw1, cw2); + connect_portal_1(cw2, cw1); + } + +/** make currentmap into one of the spaces in intra */ +EX void become() { + auto& ac = currentmap->allcells(); + for(cell *c: ac) + intra_id[c] = intra_current; + for(cell *c: ac) + currentmap->wall_offset(c); + for(cell *c: ac) c->item = itNone; + data.emplace_back(); + data.back().gd.storegame(); + data.back().gi = ginf[gProduct]; + + auto v = hybrid::gen_sample_list(); + int gi = 0; + if(full_sample_list.size()) { + gi = full_sample_list.back().first; + full_sample_list.pop_back(); + } + data.back().wallindex = gi; + for(auto x: v) + full_sample_list.emplace_back(x.first + gi, x.second); + sightranges[geometry] = 10; + } + +/** after called become() on some spaces, actually start intra */ +EX void start(int id IS(0)) { + in = true; + intra_current = id; + data[intra_current].gd.restoregame(); + ginf[gProduct] = data[intra_current].gi; + } + +#if HDR +/** a convenience struct to switch back after a temporary switch_to */ +struct resetter { + int ic; + resetter() { ic = intra::intra_current; } + ~resetter() { if(intra::in) switch_to(ic); } + }; +#endif + +EX void may_switch_to(cell *c) { + if(in) switch_to(intra_id[c]); + } + +EX int full_wall_offset(cell *c) { + int wo = currentmap->wall_offset(c); + if(in) wo += data[intra_id[c]].wallindex; + return wo; + } + +EX void check_portal_movement() { + transmatrix iView = view_inverse(View); + ld dist = hdist0(iView * C0); + int nei = -1; + for(int i=0; itype; i++) { + ld dist1 = hdist0(currentmap->ray_iadj(centerover, i) * iView * C0); + if(dist1 < dist) nei = i, dist = dist1; + } + + auto cw1 = cellwalker(centerover, nei); + ld c = camera_speed; + auto p = at_or_null(connections, cw1); + if(p) { + ld eps = 1e-3; + c /= p->id1.scale; + anims::cycle_length /= p->id1.scale; + + array ds; /* camera, forward, upward */ + ds[0] = inverse(View) * C0; + ds[1] = inverse(get_shift_view_of(ctangent(2, -eps), View)) * C0; + ds[2] = inverse(get_shift_view_of(ctangent(1, +eps), View)) * C0; + + for(auto& h: ds) h = p->id1.to_poco(h); + + /* reset the original */ + View = Id; NLP = Id; + + switch_to(p->target_world); + centerover = p->tcw.at; + + if(1) { + dynamicval g(geometry, gCubeTiling); + for(auto& h: ds) h = p->T * h; + } + + for(auto& h: ds) h = p->id2.from_poco(h); + + set_view(ds[0], ds[1], ds[2]); + + c *= p->id2.scale; + anims::cycle_length *= p->id2.scale; + camera_speed = c; + } + } + +EX } + +} \ No newline at end of file diff --git a/multigame.cpp b/multigame.cpp index ec737784..7becd272 100644 --- a/multigame.cpp +++ b/multigame.cpp @@ -61,6 +61,8 @@ void gamedata_all(gamedata& gd) { gd.store(land_structure); gd.store(*current_display); gd.store(cgip); + gd.store(hybrid::underlying); + gd.store(hybrid::underlying_cgip); gd.store_ptr(vid); gd.store(sightrange_bonus); gd.store(genrange_bonus); diff --git a/nonisotropic.cpp b/nonisotropic.cpp index a0be2f24..529c32b6 100644 --- a/nonisotropic.cpp +++ b/nonisotropic.cpp @@ -1410,7 +1410,7 @@ EX namespace hybrid { vector> result; for(auto& v: cgi.walloffsets) if(v.first >= 0) result.push_back(v); sort(result.begin(), result.end()); - result.emplace_back(isize(cgi.wallstart), nullptr); + result.emplace_back(isize(cgi.wallstart)-1, nullptr); return result; } diff --git a/raycaster.cpp b/raycaster.cpp index 64eb126b..6ffaa818 100644 --- a/raycaster.cpp +++ b/raycaster.cpp @@ -57,11 +57,13 @@ EX int max_cells = 2048; EX bool rays_generate = true; EX ld& exp_decay_current() { + if(intra::in) return exp_decay_exp; if(fake::in()) return *FPIU(&exp_decay_current()); return (sn::in() || hyperbolic || sl2) ? exp_decay_exp : exp_decay_poly; } EX int& max_iter_current() { + if(intra::in) return max_iter_iso; if(nonisotropic || stretch::in()) return max_iter_sol; else if(is_eyes()) return max_iter_eyes; else return max_iter_iso; @@ -93,6 +95,7 @@ ld& maxstep_current() { eGeometry last_geometry; vector> used_sample_list() { + if(intra::in) return intra::full_sample_list; return hybrid::gen_sample_list(); } @@ -322,7 +325,8 @@ struct raygen { void compute_which_and_dist(); void apply_reflect(); void move_forward(); - void emit_iterate(); + void emit_intra_portal(int gid1, int gid2); + void emit_iterate(int gid1); void create(); }; @@ -336,7 +340,7 @@ void raygen::compute_which_and_dist() { fmain += " if(which == -1) {\n"; - fmain += "for(int i="+its(flat1)+"; i<"+(prod ? "sides-2" : (WDIM == 2 || is_subcube_based(variation)) ? "sides" : its(flat2))+"; i++) {\n"; + fmain += "for(int i="+its(flat1)+"; i<"+(prod ? "sides-2" : (WDIM == 2 || is_subcube_based(variation) || intra::in) ? "sides" : its(flat2))+"; i++) {\n"; // fmain += "int woi = walloffset+i;\n"; @@ -961,15 +965,132 @@ void raygen::apply_reflect() { } } -void raygen::emit_iterate() { +void raygen::emit_intra_portal(int gid1, int gid2) { + + int they_curvature = false; + if(1) { + intra::resetter ir; + intra::switch_to(gid2); + they_curvature = hyperbolic ? -1 : sphere ? 1 : 0; + /* product also has 0 */ + } + + if(prod && they_curvature) { + string fn = in_h2xe() ? "to_poco_h2xr_h" : "to_poco_s2xr_s"; + fmain += + " mediump vec4 nposition = position + tangent * xspeed * 1e-3;\n" + " position = "+fn+"(position);\n" + " position.z = 0.;\n" // zpos - uPLevel;\n" + " nposition = "+fn+"(nposition);\n" + " nposition.z = zspeed * 1e-3;\n"; + } + else if(prod) { + string fn = in_h2xe() ? "to_poco_h2xr_e" : "to_poco_s2xr_e"; + fmain += + " mediump vec4 nposition = position + tangent * xspeed * 1e-3;\n" + " mediump mat4 tkt = " + getM("mid+1") + ";\n" + " position = "+fn+"(tkt * position);\n" + " position.y = zpos;\n" + " nposition = "+fn+"(tkt * nposition);\n" + " nposition.y = zpos + zspeed * 1e-3;\n"; + } + else { + fmain += + " mediump vec4 nposition = position + tangent * 1e-3;\n" + " mediump mat4 tkt = " + getM("mid+1") + ";\n"; + if(hyperbolic) fmain += + " position = to_poco_h3(tkt * position);\n" + " nposition = to_poco_h3(tkt * nposition);\n"; + else if(sphere) fmain += + " position = to_poco_s3(tkt * position);\n" + " nposition = to_poco_s3(tkt * nposition);\n"; + else fmain += + " position = tkt * position;\n" + " nposition = tkt * nposition;\n"; + } + + fmain += + " mediump mat4 m = " + getM("mid") + ";\n" + " position = m * position;\n" + " nposition = m * nposition;\n"; + + int we_curvature = hyperbolic ? -1 : sphere ? 1 : 0; + + intra::resetter ir; + intra::switch_to(gid2); + + if(prod && we_curvature) { + string sgn = in_h2xe() ? "-" : "+"; + string fn = in_h2xe() ? "from_poco_h2xr_h" : "from_poco_s2xr_s"; + ld their_plevel = cgi.plevel / 2; + fmain += + " zspeed = (nposition.z - position.z) * 1e3;\n" + " zpos = position.z + " + glhr::to_glsl(their_plevel) + ";\n" + " position = "+fn+"(position);\n" + " nposition = "+fn+"(nposition);\n" + " tangent = (nposition - position) * 1e3;\n" + " mediump float pnorm = tangent.z * position.z "+sgn+" tangent.x * position.x "+sgn+" tangent.y * position.y;\n" + " tangent -= position * pnorm;\n" + " xspeed = sqrt(tangent.x * tangent.x + tangent.y * tangent.y "+sgn+" tangent.z * tangent.z);\n" + " tangent /= xspeed;\n"; + } + else if(prod) { + string sgn = in_h2xe() ? "-" : "+"; + string fn = in_h2xe() ? "from_poco_h2xr_e" : "from_poco_s2xr_e"; + fmain += + " mediump mat4 itkt = " + getM("mid+2") + ";\n"; + fmain += + " zpos = position.y;\n" + " zspeed = (nposition.y - zpos) * 1e3;\n" + " position = itkt * "+fn+"(position);\n" + " nposition = itkt * "+fn+"(nposition);\n" + " tangent = (nposition - position) * 1e3;\n" + " mediump float pnorm = tangent.z * position.z "+sgn+" dot(position.xy, tangent.xy);\n" + " tangent -= position * pnorm;\n" + " xspeed = sqrt(dot(tangent.xy, tangent.xy) "+sgn+" tangent.z * tangent.z);\n" + " tangent /= xspeed;\n" + " mediump float l = xspeed*xspeed+zspeed*zspeed;\n" + " xspeed /= sqrt(l); zspeed /= sqrt(l);\n"; + } + else { + string sgn = hyperbolic ? "-" : "+"; + string he = hyperbolic ? "from_poco_h3" : "from_poco_s3"; + fmain += + " mediump mat4 itkt = " + getM("mid+2") + ";\n"; + + if(hyperbolic || sphere) fmain += + " position = itkt * "+he+"(position);\n" + " nposition = itkt * "+he+"(nposition);\n" + " tangent = (nposition - position) * 1e3;\n" + " mediump float pnorm = position.w * position.w "+sgn+" dot(position.xyz, position.xyz);\n" + " position /= sqrt(pnorm);\n" + " pnorm = tangent.w * position.w "+sgn+" dot(position.xyz, tangent.xyz);\n" + " tangent -= position * pnorm;\n" + " mediump float xspeed = sqrt(dot(tangent.xyz, tangent.xyz) "+sgn+" tangent.w * tangent.w);\n" + " tangent /= xspeed;\n"; + + else fmain += + " position = itkt * position;\n" + " nposition = itkt * nposition;\n" + " tangent = (nposition - position) * 1e3;\n" + " tangent /= dot(tangent.xyz, tangent.xyz);\n"; + } + } + +void raygen::emit_iterate(int gid1) { using glhr::to_glsl; + if(intra::in && prod) + fmain += " const mediump float uPLevel = " + to_glsl(cgi.plevel/2) + ";\n"; + fmain += " mediump float dist = 100.;\n"; fmain += " int which = -1;\n"; + if(hyperbolic && intra::in) fmain += "iter +=8;\n"; + if(in_e2xe() && !eyes) fmain += "tangent.w = position.w = 0.;\n"; if(IN_ODS) fmain += @@ -1183,7 +1304,111 @@ void raygen::emit_iterate() { " m[0][1] = -m[0][1]; m[1][0] = -m[1][0];\n" // inverse " toOrig = toOrig * m;\n"; - fmain += no_intra_portal; + if(!intra::in) fmain += no_intra_portal; + else { + + if(hyperbolic) { + fsh += + "mediump vec4 to_poco_h3(mediump vec4 pos) {\n" + " return pos / pos[3];\n" + " }\n\n"; + + fsh += + "mediump vec4 from_poco_h3(mediump vec4 pos) {\n" + " float s = 1. - dot(pos.xyz, pos.xyz);\n" + " return pos / sqrt(s);\n" + " }\n\n"; + } + + if(sphere) { + fsh += + "mediump vec4 to_poco_s3(mediump vec4 pos) {\n" + " return pos / pos[3];\n" + " }\n\n"; + + fsh += + "mediump vec4 from_poco_s3(mediump vec4 pos) {\n" + " float s = 1. + dot(pos.xyz, pos.xyz);\n" + " return pos / sqrt(s);\n" + " }\n\n"; + } + + if(prod) { + if(in_h2xe()) { + fsh += + "mediump vec4 from_poco_h2xr_h(mediump vec4 pos) {\n" + " float s = 1. - pos.x*pos.x - pos.y * pos.y;\n" + " pos.z = 1.;\n" + " return pos / sqrt(s);\n" + " }\n\n"; + + fsh += + "mediump vec4 to_poco_h2xr_h(mediump vec4 pos) {\n" + " pos /= pos[2];\n" + " pos.w = 1.;\n" + " return pos;\n" + " }\n\n"; + + fsh += + "mediump vec4 from_poco_h2xr_e(mediump vec4 pos) {\n" + " return vec4(sinh(pos[2]) * cosh(pos[0]), sinh(pos[0]), cosh(pos[0]) * cosh(pos[2]), 0);\n" + " }\n\n"; + + fsh += + "mediump vec4 to_poco_h2xr_e(mediump vec4 pos) {\n" + " mediump float x = asinh(pos[1]);\n" + " return vec4(x, 0, asinh(pos[0] / cosh(x)), 1);\n" + " }\n\n"; + } + else { + fsh += + "mediump vec4 from_poco_s2xr_s(mediump vec4 pos) {\n" + " float s = 1. + pos.x*pos.x + pos.y * pos.y;\n" + " pos.z = 1.;\n" + " return pos / sqrt(s);\n" + " }\n\n"; + + fsh += + "mediump vec4 to_poco_s2xr_s(mediump vec4 pos) {\n" + " pos /= pos[2];\n" + " pos.w = 1.;\n" + " return pos;\n" + " }\n\n"; + + fsh += + "mediump vec4 from_poco_s2xr_e(mediump vec4 pos) {\n" + " return vec4(sin(pos[2]) * cos(pos[0]), sin(pos[0]), cos(pos[0]) * cos(pos[2]), 0);\n" + " }\n\n"; + + fsh += + "mediump vec4 to_poco_s2xr_e(mediump vec4 pos) {\n" + " mediump float x = asin_clamp(pos[1]);\n" + " return vec4(x, 0, asin_clamp(pos[0] / cos(x)), 1);\n" + " }\n\n"; + } + } + + if(intra::in) { + int q = isize(intra::data); + for(int gid2=0; gid2type; j++) ms[id+j] = protect_prod(currentmap->ray_iadj(c, j)); @@ -1667,6 +1926,7 @@ struct raycast_map { int id = p.first; cell *c = p.second; if(!c) continue; + intra::may_switch_to(c); for(int j=0; jtype; j++) ms[mirror_shift+id+j] = protect_prod(mirrorize(ms[id+j])); if(WDIM == 2) for(int a: {0, 1}) { @@ -1680,12 +1940,14 @@ struct raycast_map { } } - if(prod) { - for(auto p: sa) { - int id =p.first; - if(id == 0) continue; - ms[id-2] = Id; - ms[id-1] = Id; + for(auto p: sa) { + cell *c = p.second; + if(!c) continue; + intra::may_switch_to(c); + int id =p.first; + if(prod) { + ms[id+c->type-2] = Id; + ms[id+c->type-1] = Id; } } } @@ -1694,13 +1956,22 @@ struct raycast_map { manual_celllister cl; cl.add(cs); bool optimize = !isWall3(cs); + intra::resetter ir; // vector legaldir = { -1 }; for(int i=0; i 0 && c->wall == waBarrier) continue; if(optimize && isWall3(c)) continue; forCellIdCM(c2, d, c) { // if(reflect_val == 0 && !((1<tcw.at; + } + if(rays_generate) setdist(c2, 7, c); /* if(!cl.listed(c2)) legaldir.push_back(legaldir[i] &~ (1<<((d+3)%6)) ); */ @@ -1722,6 +1993,7 @@ struct raycast_map { } void generate_connections(cell *c, int id) { + intra::may_switch_to(c); auto& vmap = volumetric::vmap; if(volumetric::on) { celldrawer dd; @@ -1735,7 +2007,14 @@ struct raycast_map { vcolor = (backcolor << 8); volumetric[u] = glhr::acolor(vcolor); } - forCellIdEx(c1, i, c) { + forCellIdEx(c1_real, i, c) { + cell *c1 = c1_real; + const intra::connection_data *p = nullptr; + if(intra::in) { + cellwalker cw(c, i); + p = at_or_null(intra::connections, cw); + if(p) c1 = p->tcw.at; + } int u = (id/per_row*length) + (id%per_row * deg) + i; if(!ids.count(c1)) { wallcolor[u] = glhr::acolor(color_out_of_range | 0xFF); @@ -1775,23 +2054,36 @@ struct raycast_map { } } - int wo = currentmap->wall_offset(c); + int wo = intra::full_wall_offset(c); if(wo >= our_raygen.irays) { println(hlog, "wo=", wo, " irays = ", our_raygen.irays); reset_raycaster(); return; } - transmatrix T = currentmap->iadj(c, i) * inverse(ms[wo + i]); - if(in_e2xe() && i >= c->type-2) - T = Id; - T = protect_prod(T); - for(int k=0; k<=isize(ms); k++) { - if(k < isize(ms) && !eqmatrix(ms[k], T, 1e-5)) continue; - if(k == isize(ms)) ms.push_back(T); + if(p) { + int k = isize(ms); + auto bak = geometry; + ms.push_back(p->T); + geometry = bak; + ms.push_back(p->id1.T); + ms.push_back(p->id2.iT); connections[u][2] = (k+.5) / 1024.; - break; } - auto wo1 = currentmap->wall_offset(c1); + else { + transmatrix T = currentmap->iadj(c, i) * inverse(ms[wo + i]); + if(in_e2xe() && i >= c->type-2) + T = Id; + T = protect_prod(T); + for(int k=0; k<=isize(ms); k++) { + if(k < isize(ms) && !eqmatrix(ms[k], T, 1e-5)) continue; + if(k == isize(ms)) ms.push_back(T); + connections[u][2] = (k+.5) / 1024.; + break; + } + } + intra::resetter ir; + intra::may_switch_to(c1); + int wo1 = intra::full_wall_offset(c1); if(wo1 >= max_wall_offset) println(hlog, "error: wall_offset ", wo1, " exceeds ", max_wall_offset); if(c1->type >= max_celltype) @@ -1815,6 +2107,7 @@ struct raycast_map { void generate_connections() { int id = 0; + intra::resetter ir; for(cell* c: lst) if(!reset_rmap) generate_connections(c, id++); } @@ -2012,14 +2305,22 @@ EX void cast() { } if(o->uWallOffset != -1) { - glUniform1i(o->uWallOffset, currentmap->wall_offset(cs)); + glUniform1i(o->uWallOffset, intra::full_wall_offset(cs)); glUniform1i(o->uSides, cs->type + (WDIM == 2 ? 2 : 0)); } vector wallx, wally; vector wallstart; - load_walls(wallx, wally, wallstart); + if(intra::in) { + intra::resetter ir; + for(int i=0; i& what IS(default_screenshot_co #if CAP_WRL wrl::take(fname); #endif - return; + break; case screenshot_format::svg: #if CAP_SVG svg::render(fname, what); #endif - return; + break; case screenshot_format::png: case screenshot_format::rawfile: #if CAP_PNG render_png(fname, what); #endif - return; + break; } + + v.backup.plevel_factor = vid.plevel_factor; } #if CAP_COMMANDLINE diff --git a/shaders.cpp b/shaders.cpp index 63f350e9..18dbe621 100644 --- a/shaders.cpp +++ b/shaders.cpp @@ -751,6 +751,7 @@ EX void add_fixed_functions(string& shader) { add_if(shader, "tanh", "mediump float tanh(mediump float x) { return sinh(x) / cosh(x); }\n"); add_if(shader, "sinh", "mediump float sinh(mediump float x) { return (exp(x) - exp(-x)) / 2.0; }\n"); + add_if(shader, "asin_clamp", "mediump float asin_clamp(mediump float x) { return x > 1. ? PI/2. : x < -1. ? -PI/2. : asin(x); }\n"); add_if(shader, "cosh", "mediump float cosh(mediump float x) { return (exp(x) + exp(-x)) / 2.0; }\n"); add_if(shader, "asinh", "mediump float asinh(mediump float x) { return log(sqrt(x*x + 1.0) + x); }\n"); add_if(shader, "acosh", "mediump float acosh(mediump float x) { return log(sqrt(x*x - 1.0) + x); }\n");