1 // compile with:
2 // ./mymake -O3 inner-maps
3 // used in: https://twitter.com/zenorogue/status/1212408644941295619
4 
5 // run with:
6 // ./hyper -innner-map -noscr -canvas r -canvas i -wsh 0 -smart 4 -shott 0 -alpha 1
7 
8 #include "rogueviz.h"
9 
10 namespace hr {
11 
12 namespace inner {
13 
14 bool out = true;
15 
16 EX struct renderbuffer *buf1, *buf2;
17 
18 map<cell*, basic_textureinfo> lti;
19 
20 ld mdist;
21 
22 bool for_klein = false;
23 
24 ld alpha = -.7;
25 
26 cell *rendercenter;
27 shiftmatrix rendercenterV;
28 
29 bool auto_move = false;
30 
31 ld texture_alpha = 1;
32 ld inner_alpha = 1;
33 bool dense = false;
34 
35 // should do 30x -- temporarily disabled
36 
37 ld iterations = 1;
38 
39 ld iterations_bank;
40 
gentexture()41 void gentexture() {
42   if(out) iterations_bank += iterations;
43   while(iterations_bank >= 1) {
44     iterations_bank -= 1;
45     println(hlog, "# = ", isize(lti));
46     dynamicval<bool> b(out, false);
47     dynamicval<ld> va(pconf.alpha, texture_alpha);
48     if(!buf1) {
49       buf1 = new renderbuffer(rug::texturesize, rug::texturesize, true);
50       buf2 = new renderbuffer(rug::texturesize, rug::texturesize, true);
51       }
52     resetbuffer rb;
53     rug::calcparam_rug();
54     models::configure();
55 
56     buf1->enable();
57     buf1->clear(0);
58     buf2->use_as_texture();
59 
60     draw_boundary(0);
61     draw_boundary(1);
62 
63     draw_model_elements();
64     drawthemap();
65     drawqueue();
66     calcparam();
67 
68     rb.reset();
69 
70     swap(buf1, buf2);
71 
72     rendercenter = centerover;
73     rendercenterV = gmatrix[centerover];
74 
75     }
76   }
77 
frame()78 void frame() {
79   gentexture();
80   if(auto_move) {
81     color_t col = minf[moReptile].color;
82     drawMonsterType(moReptile, NULL, shiftless(spin(alpha)), col, mdist, col);
83     mapeditor::drawplayer = false;
84     }
85   }
86 
87 bool done;
88 
89 hpcshape edgeshape;
90 
91 hpcshape circ;
92 
93 ld crad = dense ? .5 : 1.82;
94 ld ceps = .02;
95 
96 ld crad_p;
97 
need_redo()98 void need_redo() {
99   done = false;
100   }
101 
make_shape()102 void make_shape() {
103   if(done) return;
104   done = true;
105   cgi.bshape(circ, PPR::WALL);
106   circ.flags |= POLY_TRIANGLES;
107   int k = for_klein ? 1 : 2;
108   int maxz = for_klein ? 120 : 30;
109   for(int z=0; z<maxz; z++) {
110     ld ra = (z+0.)/maxz * crad, rb = (z+1.)/maxz * crad;
111     for(int i=0; i<360; i+=k) {
112       ld a = i * degree;
113       ld b = (i+k) * degree;
114 
115       cgi.hpcpush(xspinpush0(a, ra));
116       cgi.hpcpush(xspinpush0(a, rb));
117       cgi.hpcpush(xspinpush0(b, rb));
118 
119       if(z) {
120         cgi.hpcpush(xspinpush0(a, ra));
121         cgi.hpcpush(xspinpush0(b, ra));
122         cgi.hpcpush(xspinpush0(b, rb));
123         }
124       }
125     }
126   cgi.finishshape();
127   println(hlog, "circ vertices = ", circ.e - circ.s);
128 
129   cgi.bshape(edgeshape, PPR::WALL);
130   for(int i=0; i<=360; i+=k) {
131     ld a = i * degree;
132     cgi.hpcpush(xspinpush0(a, crad - ceps));
133     }
134   for(int i=0; i<=360; i+=k) {
135     ld a = i * degree;
136     cgi.hpcpush(xspinpush0(a, crad + ceps));
137     }
138   cgi.finishshape();
139 
140   cgi.extra_vertices();
141 
142   hyperpoint ph = xspinpush0(0, crad);
143   ph /= (inner_alpha+ph[2]);
144   crad_p = ph[0];
145   }
146 
147 set<cell*> gs;
148 
render(cell * c,const shiftmatrix & V)149 bool render(cell *c, const shiftmatrix& V) {
150   if(!buf1 || !buf2 || !rendercenter) return false;
151   make_shape();
152   if(false && !gs.count(c)) {
153     gs.insert(c);
154     c->mondir = hrand(c->type);
155     dont_face_pc = true;
156     switch(hrand(100)) {
157       case 0:
158         c->monst = moOrangeDog;
159         break;
160       case 1:
161         c->item = itHell;
162         break;
163       case 2:
164         c->monst = moSalamander;
165         break;
166       case 3:
167         c->monst = moButterfly;
168         break;
169       case 4:
170         c->monst = moSparrowhawk;
171         break;
172       }
173     }
174   if(dense ? pseudohept(c) : cdist50(c) == 0) {
175     dynamicval<color_t> po(poly_outline, 0x000000FF);
176     auto& p = lti[c];
177     p.texture_id = buf2->renderedTexture;
178     p.tvertices.clear();
179 
180   /*inner_alpha = anyshiftclick ? 1 : 0;
181   hyperpoint ph = xspinpush0(0, crad);
182   ph /= (inner_alpha+ph[2]);
183   crad_p = ph[0];
184   */
185 
186     for(int i=circ.s; i<circ.e; i++) {
187       hyperpoint h = cgi.hpc[i];
188       // hyperboloid to Poincare
189       h /= (inner_alpha + h[2]);
190       // scale up
191       h /= crad_p;
192       h *= .99999999;
193       // Poincare to hyperboloid
194 
195       h = perspective_to_space(h, inner_alpha, cgclass);
196 
197       /*
198       ld hr = sqhypot_d(2, h);
199       ld hz = (1 + hr) / (1 - hr);
200       h[0] *= (hz+1);
201       h[1] *= (hz+1);
202       h[2] = hz;
203       */
204 
205       // move according to V
206       h = rendercenterV.T * inverse(ggmatrix(rendercenter).T) * V.T * h;
207       // texture coordinates
208       // hyperpoint scr;
209       // dynamicval<ld> b(pconf.alpha, anyshiftclick ? pconf.alpha : texture_alpha);
210       // applymodel(h, scr);
211       hyperpoint scr = h / (texture_alpha + h[2]);
212       p.tvertices.push_back(glhr::makevertex(.5 + .5 * scr[0], .5 - .5 * scr[1], 0));
213       }
214     queuepoly(V, circ, 0xFFFFFFFF).tinf = &p;
215     queuepoly(V, edgeshape, darkena(c->landparam, 0, 0xFF));
216     }
217   return false;
218   }
219 
shift()220 void shift() {
221   if(auto_move) {
222     centerover = currentmap->gamestart();
223     mdist = (ticks % 10000) * 6 / 10000.;
224     View = spin(alpha) * xpush(-mdist) * spin(-alpha);
225     anims::moved();
226     centerover->monst = moNone;
227     forCellEx(c1, centerover) c1->monst = moNone;
228     }
229   }
230 
show()231 void show() {
232   cmode = sm::SIDE | sm::MAYDARK;
233   gamescreen(0);
234   dialog::init(XLAT("inner maps"), 0xFFFFFFFF, 150, 0);
235   add_edit(texture_alpha);
236   add_edit(inner_alpha);
237   add_edit(dense);
238   add_edit(crad);
239   add_edit(ceps);
240   add_edit(auto_move);
241   add_edit(iterations);
242   dialog::addBack();
243   dialog::display();
244   }
245 
enable()246 void enable() {
247   using rogueviz::rv_hook;
248   rv_hook(hooks_frame, 100, frame);
249   rv_hook(hooks_drawcell, 100, render);
250   rv_hook(anims::hooks_anim, 100, shift);
251   rv_hook(hooks_o_key, 80, [] (o_funcs& v) { v.push_back(named_dialog("inner maps", show)); });
252   }
253 
254 auto hook = arg::add3("-inner-map", enable)
__anonae1ccc810202null255   + addHook(hooks_configfile, 100, [] {
256     param_f(texture_alpha, "inner_talpha")
257     ->editable(0, 5, .1, "texture projection distance", "", 't');
258     param_f(inner_alpha, "inner_ialpha")
259     ->editable(0, 5, .1, "inner projection distance", "", 'i')
260     ->set_reaction(need_redo);
261     param_b(dense, "inner_dense")
262     ->editable("densely packed maps", 'd');
263     param_f(crad, "inner_crad")
264     ->editable(0, 10, .1, "radii of the inner maps", "", 'r')
265     ->set_reaction(need_redo);
266     param_f(ceps, "inner_ceps")
267     ->editable(0, 0.1, .001, "map frame size", "", 'f')
268     ->set_reaction(need_redo);
269     param_b(auto_move, "auto_move")
270     ->editable("animate", 'a');
271     param_f(iterations, "inner_iterations")
272     ->editable(0, 30, 0.2, "iterations per frame",
273       "How many times per frame should we re-render the map",
274       'i')
275     ->set_reaction(need_redo);
276     })
__anonae1ccc810302(string s, vector<tour::slide>& v) 277   + addHook_rvslides(52, [] (string s, vector<tour::slide>& v) {
278       if(s != "projections") return;
279       using namespace tour;
280 
281       v.push_back(slide{
282         "projections/hyperbolic to hyperbolic", 10, LEGAL::NONE | QUICKGEO,
283 
284         "We can also project a hyperbolic plane to a hyperbolic plane of different curvature.\n\n"
285         "Creatures living in the hyperbolic world may use the native Poincaré model to get conformal, circular, and totally useless maps of their whole world.\n\n"
286 
287         "Press 'o' to change the settings."
288         ,
289         [] (presmode mode) {
290           slide_url(mode, 't', "Twitter link (with description)", "https://twitter.com/zenorogue/status/1212408644941295619");
291           setCanvas(mode, 'r');
292 
293           if(mode == pmStart) {
294             if(!shmup::on) restart_game(rg::shmup);
295             slide_backup(mapeditor::drawplayer, true);
296             enable();
297             start_game();
298             }
299           }});
300       });
301 
302 }
303 }
304