1 // Hyperbolic Rogue - Floor Shapes
2 
3 // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
4 
5 /** \file floorshapes.cpp
6  *  \brief Adjusting the floor shapes to various geometries.
7  */
8 
9 #include "hyper.h"
10 namespace hr {
11 #if CAP_SHAPES
12 
13 #if HDR
14 struct qfloorinfo {
15   transmatrix spin;
16   const struct hpcshape *shape;
17   floorshape *fshape;
18   struct textureinfo *tinf;
19   int usershape;
20   };
21 
22 extern qfloorinfo qfi;
23 #endif
24 
25 EX vector<basic_textureinfo> floor_texture_vertices;
26 EX vector<glvertex> floor_texture_map;
27 EX struct renderbuffer *floor_textures;
28 
init_floorshapes()29 void geometry_information::init_floorshapes() {
30   all_escher_floorshapes.clear();
31   all_plain_floorshapes = {
32     &shFloor, &shMFloor, &shMFloor2, &shMFloor3, &shMFloor4,
33     &shFullFloor, &shBigTriangle, &shTriheptaFloor, &shBigHepta
34     };
35 
36   for(auto s: all_plain_floorshapes) s->is_plain = true;
37 
38   auto init_escher = [this] (escher_floorshape& sh, int s0, int s1, int noft, int s2) {
39     sh.shapeid0 = s0;
40     sh.shapeid1 = s1;
41     sh.noftype = noft;
42     sh.shapeid2 = s2;
43     sh.scale = 1;
44     sh.is_plain = false;
45     all_escher_floorshapes.push_back(&sh);
46     };
47 
48   init_escher(shStarFloor, 1, 2, 0, 0);
49   init_escher(shCloudFloor, 3, 4, 0, 0);
50   init_escher(shCrossFloor, 5, 6, 2, 54);
51   init_escher(shChargedFloor, 7, 385, 1, 10);
52   init_escher(shSStarFloor, 11, 12, 0, 0);
53   init_escher(shOverFloor, 13, 15, 1, 14);
54   init_escher(shTriFloor, 17, 18, 0, 385);
55   init_escher(shFeatherFloor, 19, 21, 1, 20);
56   init_escher(shBarrowFloor, 23, 24, 1, 25);
57   init_escher(shNewFloor, 26, 27, 2, 54);
58   init_escher(shTrollFloor, 28, 29, 0, 0);
59   init_escher(shButterflyFloor, 325, 326, 1, 178);
60   init_escher(shLavaFloor, 359, 360, 1, 178);
61   init_escher(shLavaSeabed, 386, 387, 1, 178);
62   init_escher(shSeabed, 334, 335, 0, 0);
63   init_escher(shCloudSeabed, 336, 337, 0, 0);
64   init_escher(shCaveSeabed, 338, 339, 2, 54);
65   init_escher(shPalaceFloor, 45, 46, 0, 385);
66   init_escher(shDemonFloor, 51, 50, 1, 178);
67   init_escher(shCaveFloor, 52, 53, 2, 54);
68   init_escher(shDesertFloor, 55, 56, 0, 4);
69   init_escher(shPowerFloor, 57, 58, 0, 12); /* dragon */
70   init_escher(shRoseFloor, 174, 175, 1, 173);
71   init_escher(shSwitchFloor, 377, 378, 1, 379);
72   init_escher(shTurtleFloor, 176, 177, 1, 178);
73   for(int i: {0,1,2})
74     init_escher(shRedRockFloor[i], 55, 56, 0, 0);
75   init_escher(shDragonFloor, 181, 182, 2, 183); /* dragon */
76 
77   int ids = 0;
78   for(auto sh: all_plain_floorshapes) sh->id = ids++;
79   for(auto sh: all_escher_floorshapes) sh->id = ids++;
80   }
81 
82 typedef pair<transmatrix, vector<transmatrix>> matrixitem;
83 
84 struct mesher {
85   eGeometry g;
86   int sym;
87   ld bspi;
88   hyperpoint lcorner, rcorner, mfar[2], vfar[4];
89   };
90 
msh(eGeometry g,int sym,ld main,ld v0,ld v1,ld bspi,ld scale)91 mesher msh(eGeometry g, int sym, ld main, ld v0, ld v1, ld bspi, ld scale) {
92   main *= scale; v0 *= scale; v1 *= scale;
93   mesher m;
94   m.sym = sym;
95   m.bspi = bspi;
96   dynamicval<eGeometry> dg(geometry, g);
97 
98   hyperpoint rot = xpush(v0) * xspinpush0(M_PI - M_PI/sym, main);
99   hyperpoint bnlfar = xpush(v0) * spin(M_PI) * rspintox(rot) * rspintox(rot) * rspintox(rot) * xpush0(hdist0(rot));
100   hyperpoint bnrfar = xpush(v0) * spin(M_PI) * spintox(rot) * spintox(rot) * spintox(rot) * xpush0(hdist0(rot));
101 
102   m.lcorner = xspinpush0 (bspi-M_PI/sym, main);
103   m.rcorner = xspinpush0 (bspi+M_PI/sym, main);
104   m.mfar[0] = xspinpush0 (bspi, v0);
105   m.mfar[1] = xspinpush0 (bspi, v1);
106   m.vfar[0] = spin(bspi) * bnlfar;
107   m.vfar[2] = spin(bspi) * bnrfar;
108   m.vfar[1] = spin(-2*M_PI/sym) * m.vfar[2];
109   m.vfar[3] = spin(+2*M_PI/sym) * m.vfar[0];
110 
111   return m;
112   }
113 
114 struct matrixlist {
115   mesher o, n;
116   vector<matrixitem> v;
117   };
118 
genitem(const transmatrix & m1,const transmatrix & m2,int nsym)119 matrixitem genitem(const transmatrix& m1, const transmatrix& m2, int nsym) {
120   matrixitem mi;
121   mi.first = m1;
122   mi.second.resize(nsym);
123   for(int i=0; i<nsym; i++)
124     mi.second[i] = spin(2*M_PI*i/nsym) * m2;
125   return mi;
126   }
127 
do_kleinize()128 bool do_kleinize() { return S3 >= OINF; }
129 
kleinize(hyperpoint h)130 EX hyperpoint kleinize(hyperpoint h) {
131   if(GDIM == 2) return point3(h[0]/h[2], h[1]/h[2], 1);
132   else return point31(h[0]/h[3], h[1]/h[3], h[2]/h[3]);
133   }
134 
may_kleinize(hyperpoint h)135 EX hyperpoint may_kleinize(hyperpoint h) {
136   if(do_kleinize()) return kleinize(h);
137   else return h;
138   }
139 
addmatrix(matrixlist & matrices,hyperpoint o0,hyperpoint o1,hyperpoint o2,hyperpoint n0,hyperpoint n1,hyperpoint n2,int d,int osym,int nsym)140 void addmatrix(matrixlist& matrices, hyperpoint o0, hyperpoint o1, hyperpoint o2, hyperpoint n0, hyperpoint n1, hyperpoint n2, int d, int osym, int nsym) {
141   if(do_kleinize()) o0 = kleinize(o0), o1 = kleinize(o1), o2 = kleinize(o2), n0 = kleinize(n0), n1 = kleinize(n1), n2 = kleinize(n2);
142   matrices.v.push_back(genitem(inverse(spin(2*M_PI*d/osym)*build_matrix(o0, o1, o2,C02)), spin(2*M_PI*d/nsym)*build_matrix(n0, n1, n2,C02), nsym));
143   }
144 
145 matrixlist hex_matrices, hept_matrices;
146 
generate_matrices(matrixlist & matrices,const mesher & o,const mesher & n)147 void generate_matrices(matrixlist& matrices, const mesher& o, const mesher& n) {
148   matrices.v.clear();
149   matrices.o = o;
150   matrices.n = n;
151 
152   for(int d=0; d<o.sym; d++) {
153     hyperpoint center = hpxy(0,0);
154     int d1 = d&1;
155     addmatrix(matrices, center, o.lcorner, o.rcorner, center, n.lcorner, n.rcorner, d, o.sym, n.sym);
156     addmatrix(matrices, o.mfar[d1], o.lcorner, o.rcorner, n.mfar[d1], n.lcorner, n.rcorner, d, o.sym, n.sym);
157     addmatrix(matrices, o.mfar[d1], o.lcorner, o.vfar[d1], n.mfar[d1], n.lcorner, n.vfar[d1], d, o.sym, n.sym);
158     addmatrix(matrices, o.mfar[d1], o.rcorner, o.vfar[d1+2], n.mfar[d1], n.rcorner, n.vfar[d1+2], d, o.sym, n.sym);
159     }
160   }
161 
162 int nsym0;
163 
generate_matrices_scale(ld scale,int noft)164 void generate_matrices_scale(ld scale, int noft) {
165   mesher ohex = msh(gNormal, 6, 0.329036, 0.566256, 0.620672, 0, 1);
166   mesher ohept = msh(gNormal, 7, hexf7, hcrossf7, hcrossf7, M_PI/7, 1);
167   if(!BITRUNCATED) {
168     mesher nall = msh(geometry, S7, cgi.rhexf, cgi.tessf, cgi.tessf, -M_PI, scale);
169     bool use = geosupport_football() < 2;
170     if(use && noft == 1) {
171       mesher opure = msh(gNormal, 7, 0.620672, 1.090550, 1.090550, M_PI/7, 1);
172       generate_matrices(hept_matrices, opure, nall);
173       }
174     else if(use && noft == 2) {
175       mesher oeuc = msh(gNormal, 6, sqrt(3)/6, .5, .5, 0, 1);
176       generate_matrices(hept_matrices, oeuc, nall);
177       }
178     else if(use && noft == 3) {
179       generate_matrices(hept_matrices, ohex, nall);
180       }
181     else {
182       generate_matrices(hex_matrices, ohex, nall);
183       generate_matrices(hept_matrices, ohept, nall);
184       }
185     }
186   else {
187     generate_matrices(hex_matrices, ohex, msh(geometry, S6, cgi.hexvdist, cgi.hexhexdist, cgi.hcrossf, (S3-3)*M_PI/S3, scale));
188     generate_matrices(hept_matrices, ohept, msh(geometry, S7, cgi.rhexf, cgi.hcrossf, cgi.hcrossf, M_PI/S7, scale));
189     }
190   }
191 
bshape2(hpcshape & sh,PPR prio,int shapeid,matrixlist & m)192 void geometry_information::bshape2(hpcshape& sh, PPR prio, int shapeid, matrixlist& m) {
193   auto& matrices = m.v;
194   int osym = m.o.sym;
195   int nsym = m.n.sym;
196 
197   int whereis = 0;
198   while(polydata[whereis] != NEWSHAPE || polydata[whereis+1] != shapeid) whereis++;
199   int rots = polydata[whereis+2]; int sym = polydata[whereis+3];
200   whereis += 4;
201   int qty = 0;
202   while(polydata[whereis + 2*qty] != NEWSHAPE) qty++;
203 
204   vector<hyperpoint> lst;
205   for(int i=0; i<qty; i++) {
206     dynamicval<eGeometry> dg(geometry, gNormal);
207     lst.push_back(hpxy(polydata[whereis+2*i], polydata[whereis+2*i+1]));
208     }
209   if(sym == 2)
210   for(int i=qty-1; i>=0; i--) {
211     dynamicval<eGeometry> dg(geometry, gNormal);
212     lst.push_back(hpxy(polydata[whereis+2*i], -polydata[whereis+2*i+1]));
213     }
214 
215   hyperpoint lstmid = hpxyz(0,0,0);
216   for(auto pp: lst) lstmid += pp;
217   transmatrix T = spin(-m.o.bspi);
218   while((spin(2*M_PI / rots) * T* lstmid)[0] < (T*lstmid)[0])
219     T = spin(2*M_PI / rots) * T;
220   while((spin(-2*M_PI / rots) * T* lstmid)[0] < (T*lstmid)[0])
221     T = spin(-2*M_PI / rots) * T;
222   T = spin(m.o.bspi) * T;
223   for(auto &pp: lst) pp = T * pp;
224 
225   if(osym % rots && rots % osym) printf("warning: rotation oddity (shapeid %d, osym=%d rots=%d)\n", shapeid, osym, rots);
226 
227   if(rots > osym && rots % osym == 0) {
228     int rep = rots / osym;
229     int s = lst.size();
230     for(int i=0; i<s*(rep-1); i++)
231       lst.push_back(spin(2*M_PI/rots) * lst[i]);
232     rots /= rep;
233     }
234 
235   bshape(sh, prio);
236 
237   for(int r=0; r<nsym; r+=osym/rots) {
238     for(hyperpoint h: lst) {
239       hyperpoint nh = may_kleinize(h);
240       int mapped = 0;
241       for(auto& m: matrices) {
242         hyperpoint z = m.first * h;
243         if(z[0] > -1e-5 && z[1] > -1e-5 && z[2] > -1e-5) {
244           nh = m.second[r] * z, mapped++;
245           }
246         }
247       if(mapped == 0) printf("warning: not mapped (shapeid %d)\n", shapeid);
248       hpcpush(mid(nh, nh));
249       }
250     }
251 
252   hpcpush(hpc[last->s]);
253   }
254 
sizeto(T & t,int n)255 template<class T> void sizeto(T& t, int n) {
256   if(isize(t) <= n) t.resize(n+1);
257   }
258 
bshape_regular(floorshape & fsh,int id,int sides,ld shift,ld size,cell * c)259 void geometry_information::bshape_regular(floorshape &fsh, int id, int sides, ld shift, ld size, cell *c) {
260 
261   sizeto(fsh.b, id);
262   sizeto(fsh.shadow, id);
263 
264   #if CAP_BT
265   if(bt::in()) {
266 
267     const int STEP = vid.texture_step;
268 
269     for(int t=0; t<2; t++) {
270 
271       if(t == 0)
272         bshape(fsh.b[id], fsh.prio);
273       if(t == 1)
274         bshape(fsh.shadow[id], fsh.prio);
275 
276       for(int i=0; i<sides; i++) {
277         hyperpoint h0 = bt::get_corner_horo_coordinates(c, i) * size;
278         hyperpoint h1 = bt::get_corner_horo_coordinates(c, i+1) * size;
279         if(t) h0 *= SHADMUL, h1 *= SHADMUL;
280         hyperpoint hd = (h1 - h0) / STEP;
281         for(int j=0; j<STEP; j++) {
282           hpcpush(bt::get_horopoint(h0 + hd * j));
283           if(geometry == gBinary4 && among(i, 2, 4)) break;
284           if(geometry == gBinaryTiling && among(i, 0, 4)) break;
285           if(geometry == gTernary && among(i, 3, 5)) break;
286           }
287         }
288 
289       hpcpush(hpc[last->s]);
290       }
291 
292     for(int k=0; k<SIDEPARS; k++) {
293       if(isize(fsh.gpside[k]) < c->type)
294         fsh.gpside[k].resize(c->type);
295       for(int i=0; i<c->type; i++) {
296         sizeto(fsh.gpside[k][i], id);
297         bshape(fsh.gpside[k][i][id], PPR::LAKEWALL);
298         hyperpoint h0 = bt::get_corner_horo_coordinates(c, i) * size;
299         hyperpoint h1 = bt::get_corner_horo_coordinates(c, i+1) * size;
300         hyperpoint hd = (h1 - h0) / STEP;
301         for(int j=0; j<=STEP; j++)
302           hpcpush(iddspin_side(c, i) * bt::get_horopoint(h0 + hd * j));
303         chasmifyPoly(dlow_table[k], dhi_table[k], k);
304         }
305       }
306 
307     return;
308     }
309   #endif
310 
311   bshape(fsh.b[id], fsh.prio);
312   for(int t=0; t<=sides; t++)
313     hpcpush(xspinpush0(t*2 * M_PI / sides + shift * M_PI / S42, size));
314 
315   bshape(fsh.shadow[id], fsh.prio);
316   for(int t=0; t<=sides; t++)
317     hpcpush(xspinpush0(t*2 * M_PI / sides + shift * M_PI / S42, size * SHADMUL));
318 
319   for(int k=0; k<SIDEPARS; k++) {
320     fsh.side[k].resize(2);
321     bshape(fsh.side[k][id], PPR::LAKEWALL);
322     hpcpush(xspinpush0(+M_PI/sides, size));
323     hpcpush(xspinpush0(-M_PI/sides, size));
324     chasmifyPoly(dlow_table[k], dhi_table[k], k);
325     }
326   }
327 
328 #if CAP_IRR
329 namespace irr { void generate_floorshapes(); }
330 #endif
331 
332 // !siid equals pseudohept(c)
333 
generate_floorshapes_for(int id,cell * c,int siid,int sidir)334 void geometry_information::generate_floorshapes_for(int id, cell *c, int siid, int sidir) {
335   DEBBI(DF_POLY, ("generate_floorshapes_for ", id));
336 
337   for(auto pfsh: all_plain_floorshapes) {
338     auto& fsh = *pfsh;
339 
340     if(STDVAR && (standard_tiling() || bt::in())) {
341 
342       ld hexside = fsh.rad0, heptside = fsh.rad1;
343 
344       for(int k=0; k<SIDEPARS; k++) sizeto(fsh.side[k], id);
345 
346       ld td = (PURE && !(S7&1)) ? S42+S6 : 0;
347       if(&fsh == &shBigHepta) td += S6;
348 
349       if(S3 >= OINF && !(S7 & 1)) td = S42 * 1. / S7;
350 
351       int b = 0;
352       if(S3 == 4 && BITRUNCATED) b += S14;
353 
354       if(id)
355         bshape_regular(fsh, id, S7, td, heptside, c);
356 
357       else if(PURE) {
358         if(&fsh == &shTriheptaFloor)
359           bshape_regular(fsh, 0, S7/2, 0, hexside, c);
360         else if(&fsh == &shBigTriangle)
361           bshape_regular(fsh, 0, S7/2, S12, hexside, c);
362         else
363           bshape_regular(fsh, 0, S7, td, heptside, c);
364         }
365       else if(&fsh == &shBigTriangle)
366         bshape_regular(fsh, 0, S3, b+S14, hexside, c);
367       else if(&fsh == &shTriheptaFloor)
368         bshape_regular(fsh, 0, S3, b, hexside, c);
369       else
370         bshape_regular(fsh, 0, S6, S7, hexside, c);
371 
372 
373       continue;
374       }
375 
376     // special
377     ld sca = 3 * shFullFloor.rad0 / fsh.rad0;
378 
379     vector<hyperpoint> cornerlist;
380 
381     int cor = c->type;
382 
383     if(&fsh == &shTriheptaFloor) {
384       if(!siid) {
385         for(int i=0; i<cor; i++)
386           cornerlist.push_back(midcorner(c, i, .49));
387         }
388       else {
389         for(int i=0; i<cor; i++) {
390           int ri = i;
391           if((i&1) == ((sidir+siid)&1)) ri--;
392           ri = c->c.fix(ri);
393           cornerlist.push_back(mid(get_corner_position(c, ri, 3.1), get_corner_position(c, c->c.fix(ri+1), 3.1)));
394           }
395         }
396       }
397 
398     else if(&fsh == &shBigTriangle) {
399       if(!siid) {
400         for(int i=0; i<cor; i++) cornerlist.push_back(hpxy(0,0));
401         }
402       else if(geosupport_chessboard()) {
403         for(int i=0; i<cor; i++) {
404           hyperpoint nc = nearcorner(c, i);
405           cornerlist.push_back(mid_at(hpxy(0,0), nc, .94));
406           }
407         }
408       else {
409         for(int i=0; i<cor; i++) {
410           int ri = i;
411           if((i&1) != ((sidir+siid)&1)) ri--;
412           ri = c->c.fix(ri);
413           hyperpoint nc = nearcorner(c, ri);
414           cornerlist.push_back(mid_at(hpxy(0,0), nc, .94));
415           }
416         }
417       }
418 
419     else if(&fsh == &shBigHepta) {
420       if(!siid) {
421         for(int i=0; i<cor; i++) {
422           hyperpoint nc = nearcorner(c, i);
423           cornerlist.push_back(mid_at(hpxy(0,0), nc, .94));
424           }
425         }
426       else {
427         for(int i=0; i<cor; i++) cornerlist.push_back(hpxy(0,0));
428         }
429       }
430 
431     else if(arb::in()) {
432       vector<hyperpoint> actual;
433       for(int j=0; j<cor; j++)
434         actual.push_back(get_corner_position(c, j));
435 
436       ld min_dist = 1e3;
437       for(int j=0; j<cor; j++)
438       for(int k=0; k<j; k++) {
439         ld dist = hdist(actual[j], actual[k]);
440         if(dist > 1e-6 && dist < min_dist)
441           min_dist = dist;
442         }
443 
444       ld dist = min_dist * (1 - 3 / sca) * arb::current_or_slided().boundary_ratio;
445 
446       ld area = 0;
447       for(int j=0; j<cor; j++) {
448         hyperpoint current = kleinize(actual[j]);
449         hyperpoint last = kleinize(actual[j?j-1:cor-1]);
450         area += current[0] * last[1] - last[0] * current[1];
451         }
452       if(area < 0) dist = -dist;
453 
454       for(int j=0; j<cor; j++) {
455         hyperpoint last = actual[j?j-1:cor-1];
456         hyperpoint current = ypush(1e-6 * randd()) * xpush(1e-6) * actual[j];
457         hyperpoint next = actual[j<cor-1?j+1:0];
458         auto T = gpushxto0(current);
459         last = T * last;
460         next = T * next;
461         hyperpoint a = rspintox(last) * ypush0(dist);
462         hyperpoint b = rspintox(last) * xpush(hdist0(last)) * ypush0(dist);
463 
464         hyperpoint c = rspintox(next) * ypush0(-dist);
465         hyperpoint d = rspintox(next) * xpush(hdist0(next)) * ypush0(-dist);
466 
467         hyperpoint h = linecross(a, b, c, d);
468 
469         cornerlist.push_back(rgpushxto0(current) * h);
470         }
471       }
472 
473     else {
474       for(int j=0; j<cor; j++)
475         cornerlist.push_back(get_corner_position(c, j, sca));
476       }
477 
478     sizeto(fsh.b, id);
479 
480     bshape(fsh.b[id], fsh.prio);
481     if(cor == 2) {
482       /* give digons some width */
483       for(int i=0; i<cor; i++) hpcpush(spin(-.1) * cornerlist[i]), hpcpush(spin(+.1) * cornerlist[i]);
484       hpcpush(spin(-.1) * cornerlist[0]);
485       }
486     else if(&fsh == &shTriheptaFloor && cor == 4 && siid)
487       /* trihepta floors generate digons too */
488       for(int i=0; i<=cor; i++) hpcpush(spin((i&1) ? .1 : -.1) * cornerlist[i%cor]);
489     else
490       for(int i=0; i<=cor; i++) hpcpush(cornerlist[i%cor]);
491 
492     sizeto(fsh.shadow, id);
493     bshape(fsh.shadow[id], fsh.prio);
494     for(int i=0; i<=cor; i++)
495       hpcpush(mid_at(hpxy(0,0), cornerlist[i%cor], SHADMUL));
496 
497     for(int k=0; k<SIDEPARS; k++) {
498       if(isize(fsh.gpside[k]) < cor)
499         fsh.gpside[k].resize(cor);
500       for(int cid=0; cid<cor; cid++) {
501         sizeto(fsh.gpside[k][cid], id);
502         bshape(fsh.gpside[k][cid][id], fsh.prio);
503         hpcpush(iddspin_side(c, cid) * cornerlist[cid]);
504         hpcpush(iddspin_side(c, cid) * cornerlist[(cid+1)%cor]);
505         chasmifyPoly(dlow_table[k], dhi_table[k], k);
506         }
507       }
508     }
509 
510   for(auto pfsh: all_escher_floorshapes) {
511 
512     auto& fsh = *pfsh;
513 
514     sizeto(fsh.b, id);
515     sizeto(fsh.shadow, id);
516 
517     if(STDVAR && standard_tiling()) {
518       generate_matrices_scale(fsh.scale, fsh.noftype);
519       if(PURE && geosupport_football() < 2) {
520         bshape2(fsh.b[id], fsh.prio, fsh.shapeid2 ? fsh.shapeid2 : fsh.shapeid1, hept_matrices);
521         }
522       else {
523         if(id == 0) bshape2(fsh.b[0], fsh.prio, fsh.shapeid0, hex_matrices);
524         if(id == 1) bshape2(fsh.b[1], fsh.prio, fsh.shapeid1, hept_matrices);
525         }
526       generate_matrices_scale(fsh.scale * SHADMUL, fsh.noftype);
527       if(PURE && geosupport_football() < 2) {
528         bshape2(fsh.shadow[id], fsh.prio, fsh.shapeid2 ? fsh.shapeid2 : fsh.shapeid1, hept_matrices);
529         }
530       else {
531         if(id == 0) bshape2(fsh.shadow[0], fsh.prio, fsh.shapeid0, hex_matrices);
532         if(id == 1) bshape2(fsh.shadow[1], fsh.prio, fsh.shapeid1, hept_matrices);
533         }
534       }
535 
536     else {
537       generate_matrices_scale(fsh.scale, fsh.noftype);
538 
539       auto& m = (siid && geosupport_football() == 2) ? hex_matrices : hept_matrices;
540 
541       int cor = c->type;
542 
543       m.n.sym = cor;
544 
545       int v = sidir+siid;
546       for(auto& mvi: m.v) mvi.second.resize(cor);
547 
548       for(int ii=0; ii<2; ii++) {
549         int i = 0;
550         for(int d=0; d<m.o.sym; d++) {
551           hyperpoint center = hpxy(0,0);
552 
553           for(int cid=0; cid<cor; cid++) {
554             hyperpoint nlcorner = get_corner_position(c, (d+cid+v+1) % cor, 3 / fsh.scale * (ii ? 1/SHADMUL : 1));
555             hyperpoint nrcorner = get_corner_position(c, (d+cid+v+2) % cor, 3 / fsh.scale * (ii ? 1/SHADMUL : 1));
556 
557             hyperpoint nfar = nearcorner(c, (d+cid+v+1) % cor);
558 
559             hyperpoint nlfar = farcorner(c, (d+cid+v+1) % cor, 0);
560             hyperpoint nrfar = farcorner(c, (d+cid+v+1) % cor, 1);
561             m.v[i].second[cid] = build_matrix(center, nlcorner, nrcorner,C02);
562             m.v[i+1].second[cid] = build_matrix(nfar, nlcorner, nrcorner,C02);
563             m.v[i+2].second[cid] = build_matrix(nfar, nlcorner, nlfar,C02);
564             m.v[i+3].second[cid] = build_matrix(nfar, nrcorner, nrfar,C02);
565             }
566 
567           i += 4;
568           }
569 
570         if(i != isize(m.v)) printf("warning: i=%d sm=%d\n", i, isize(m.v));
571         bshape2((ii?fsh.shadow:fsh.b)[id], fsh.prio, (fsh.shapeid2 && geosupport_football() < 2) ? fsh.shapeid2 : siid?fsh.shapeid0:fsh.shapeid1, m);
572         }
573       }
574     }
575 
576   #if MAXMDIM >= 4
577   if(WDIM == 2 && GDIM == 3) {
578     finishshape();
579     for(auto pfsh: all_plain_floorshapes) {
580       auto& fsh = *pfsh;
581 
582       for(int i=fsh.shadow[id].s; i<fsh.shadow[id].e; i++)
583         hpc[i] = orthogonal_move(hpc[i], FLOOR - human_height / 100);
584 
585       for(int k=0; k<SIDEPARS; k++) {
586         sizeto(fsh.levels[k], id);
587         bshape(fsh.levels[k][id], fsh.prio);
588         last->flags |= POLY_TRIANGLES;
589         last->tinf = &floor_texture_vertices[fsh.id];
590         last->texture_offset = 0;
591 
592         #if CAP_BT
593         if(bt::in())
594           for(int t=0; t<c->type; t++)
595             texture_order([&] (ld x, ld y) {
596               hyperpoint left = bt::get_corner_horo_coordinates(c, t);
597               hyperpoint right = bt::get_corner_horo_coordinates(c, t+1);
598               hpcpush(orthogonal_move(bt::get_horopoint(left * x + right * y), dfloor_table[k]));
599               });
600         else
601         #endif
602         if(1) {
603           int s = fsh.b[id].s;
604           int e = fsh.b[id].e-1;
605           for(int t=0; t<e-s; t++) {
606             hyperpoint v1 = may_kleinize(hpc[s+t]) - C0;
607             hyperpoint v2 = may_kleinize(hpc[s+t+1]) - C0;
608             texture_order([&] (ld x, ld y) {
609               hpcpush(
610                 orthogonal_move(
611                   normalize(C0 + v1 * x + v2 * y)
612                   , dfloor_table[k])
613                 );
614               });
615             }
616           }
617 
618         finishshape();
619         ensure_vertex_number(fsh.levels[k][id]);
620         }
621 
622       for(int co=0; co<2; co++) {
623         sizeto(fsh.cone[co], id);
624         bshape(fsh.cone[co][id], fsh.prio);
625         last->flags |= POLY_TRIANGLES;
626         last->tinf = &floor_texture_vertices[fsh.id];
627         last->texture_offset = 0;
628         ld h = (FLOOR - WALL) / (co+1);
629         ld top = co ? (FLOOR + WALL) / 2 : WALL;
630         #if CAP_BT
631         if(bt::in())
632           for(int t=0; t<c->type; t++)
633             texture_order([&] (ld x, ld y) {
634               hyperpoint left = bt::get_corner_horo_coordinates(c, t);
635               hyperpoint right = bt::get_corner_horo_coordinates(c, t+1);
636               hpcpush(orthogonal_move(bt::get_horopoint(left * x + right * y), top + h * (x+y)));
637               });
638         else
639         #endif
640         if(1) {
641           int s = fsh.b[id].s;
642           int e = fsh.b[id].e-1;
643           for(int t=0; t<e-s; t++) {
644             hyperpoint v1 = may_kleinize(hpc[s+t]) - C0;
645             hyperpoint v2 = may_kleinize(hpc[s+t+1]) - C0;
646             texture_order([&] (ld x, ld y) { hpcpush(orthogonal_move(normalize(C0 + v1 * x + v2 * y), top + h * (x+y))); });
647             }
648           }
649 
650         finishshape();
651         ensure_vertex_number(fsh.cone[co][id]);
652         }
653 
654       for(int l=0; l<SIDEPARS; l++) {
655         for(auto& li: fsh.side[l])
656           bind_floor_texture(li, fsh.id);
657         if(isize(fsh.gpside[l]) < c->type)
658           fsh.gpside[l].resize(c->type);
659         for(auto& gs: fsh.gpside[l]) {
660           for(auto& li: gs)
661             bind_floor_texture(li, fsh.id);
662           }
663         }
664       }
665 
666     for(auto pfsh: all_escher_floorshapes) {
667       auto& fsh = *pfsh;
668 
669       for(int l=0; l<SIDEPARS; l++) {
670         fsh.levels[l] = shFullFloor.levels[l];
671         fsh.shadow = shFullFloor.shadow;
672         for(auto& li: fsh.levels[l]) bind_floor_texture(li, fsh.id);
673         fsh.side[l] = shFullFloor.side[l];
674         for(auto& li: fsh.side[l]) bind_floor_texture(li, fsh.id);
675         if(isize(fsh.gpside[l]) < c->type)
676           fsh.gpside[l].resize(c->type);
677         for(int e=0; e<c->type; e++) {
678           fsh.gpside[l][e] = shFullFloor.gpside[l][e];
679           for(auto& li: fsh.gpside[l][e])
680             bind_floor_texture(li, fsh.id);
681           }
682         fsh.cone[0] = shFullFloor.cone[0];
683         fsh.cone[1] = shFullFloor.cone[1];
684         for(int c=0; c<2; c++)
685           for(auto& li: fsh.cone[c])
686             bind_floor_texture(li, fsh.id);
687         }
688       }
689     finishshape();
690     }
691   #endif
692   }
693 
generate_floorshapes()694 void geometry_information::generate_floorshapes() {
695 
696   DEBBI(DF_POLY, ("generate_floorshapes"));
697 
698   heptagon modelh;
699   cell model;
700   model.master = &modelh;
701   modelh.c7 = &model;
702   model.type = modelh.type = S7;
703 
704   auto mmerge1 = [&] (int i, int j) { model.c.setspin(i, j, false); modelh.c.setspin(i, j, false); };
705   auto mmerge = [&] (int i, int j) { mmerge1(i, j); mmerge1(j, i); };
706 
707   for(int i=0; i<S7; i++) {
708     model.move(i) = &model;
709     modelh.move(i) = &modelh;
710     model.c.setspin(i, i, false);
711     modelh.c.setspin(i, i, false);
712     }
713 
714   if(WDIM == 3) ;
715 
716   #if CAP_IRR
717   else if(IRREGULAR) {
718     DEBBI(DF_POLY, ("generate_floorshapes: irregular"));
719 
720     int cc = isize(irr::cells);
721 
722     for(int id=0; id<cc; id++) {
723       irr::cellindex[&model] = id;
724       auto& vs = irr::cells[id];
725       model.type = isize(vs.vertices);
726       int siid = !vs.is_pseudohept;
727       int sidir = 0;
728       if(siid) sidir = irr::cells[vs.neid[0]].is_pseudohept;
729       generate_floorshapes_for(id, &model, !vs.is_pseudohept, sidir);
730       }
731 
732     printf("done\n");
733     }
734   #endif
735 
736   else if(GOLDBERG_INV) { /* will be generated on the fly */ }
737 
738   else if(inforder::mixed()) { /* will be generated on the fly */ }
739 
740   #if CAP_BT
741   else if(kite::in()) {
742     dynamicval<bool> ncor(approx_nearcorner, true);
743     for(int i=0; i<2; i++) {
744       modelh.s = hstate(i); /* kite/dart shape */
745       kite::no_adj = true;
746       generate_floorshapes_for(i, &model, 0, 0);
747       kite::no_adj = false;
748       }
749     }
750   #endif
751 
752   #if CAP_ARCM
753   else if(arcm::in()) {
754     arcm::parent_index_of(&modelh) = 0;
755     auto &ac = arcm::current;
756     for(int i=0; i<2*ac.N + 2; i++) {
757       if(ac.regular && i>=2 && i < 2*ac.N) continue;
758       arcm::id_of(&modelh) = i;
759       model.type = isize(ac.triangles[i]);
760       if(DUAL) model.type /= 2, arcm::parent_index_of(&modelh) = !(i&1);
761 
762       if(BITRUNCATED)
763         generate_floorshapes_for(i, &model, !arcm::pseudohept(&model), arcm::pseudohept(&model) ? 0 : 1^(i&1));
764       else if(geosupport_football() == 2)
765         generate_floorshapes_for(i, &model, !arcm::pseudohept(&model), i >= 4 ? 1 : 0);
766       else
767         generate_floorshapes_for(i, &model, 0, 0);
768       }
769     }
770   #endif
771 
772   else if(arb::in()) {
773     auto& c = arb::current;
774     int n = isize(c.shapes);
775     vector<cell> models(n);
776     vector<heptagon> modelh(n);
777     for(int i=0; i<n; i++) {
778       auto &ms = models[i];
779       auto &mh = modelh[i];
780       mh.fieldval = -1;
781       for(auto& t: ms.c.move_table) t = nullptr;
782       for(auto& t: mh.c.move_table) t = nullptr;
783       }
784     for(int i=0; i<n; i++) {
785       auto &ms = models[i];
786       auto &mh = modelh[i];
787       ms.master = &mh;
788       mh.c7 = &ms;
789       mh.zebraval = i;
790       auto& sh = c.shapes[i];
791       ms.type = mh.type = sh.size();
792       }
793     for(int i=0; i<n; i++) {
794       auto &ms = models[i];
795       auto &mh = modelh[i];
796       auto& sh = c.shapes[i];
797       for(int j=0; j<sh.size(); j++) {
798         auto& co = sh.connections[j];
799         mh.c.connect(j, &modelh[co.sid], co.eid, co.mirror);
800         ms.c.connect(j, &models[co.sid], co.eid, co.mirror);
801         }
802       }
803     for(int i=0; i<n; i++) generate_floorshapes_for(i, &models[i], 0, 0);
804     }
805 
806   else if(geometry == gBinary4) {
807     for(int i: {0,1}) {
808       modelh.zebraval = i;
809       mmerge(2, 4); mmerge(0, 3); mmerge(1, 3); mmerge(i, 3);
810       generate_floorshapes_for(i, &model, 1, 0);
811       }
812     }
813 
814   else if(geometry == gTernary) {
815     for(int i: {0,1,2}) {
816       modelh.zebraval = i;
817       mmerge(3, 5); for(int a=0; a<3; a++) mmerge1(a, 4); mmerge(4, i);
818       generate_floorshapes_for(i, &model, 1, 0);
819       }
820     }
821 
822   else if(PURE && geometry != gBinaryTiling && geosupport_football() < 2) {
823     generate_floorshapes_for(0, &model, 1, 0);
824     }
825 
826   else if(bt::in()) {
827     dynamicval<hrmap*> c(currentmap, bt::new_alt_map(nullptr));
828     model.type = S6; generate_floorshapes_for(0, &model, 0, 0);
829     model.type = S7; generate_floorshapes_for(1, &model, 1, 0);
830     delete currentmap;
831     }
832 
833   else {
834     static hrmap_standard stdmap;
835     dynamicval<hrmap*> c(currentmap, &stdmap);
836     // cell model;
837     model.type = S6; generate_floorshapes_for(0, &model, 0, 0);
838     model.type = S7; generate_floorshapes_for(1, &model, 0, 0);
839     }
840   }
841 
842 #if CAP_GP
843 EX namespace gp {
844 
clear_plainshapes()845   EX void clear_plainshapes() {
846     for(int m=0; m<3; m++)
847     for(int sd=0; sd<8; sd++)
848     for(int i=0; i<GOLDBERG_LIMIT; i++)
849     for(int j=0; j<GOLDBERG_LIMIT; j++)
850     for(int k=0; k<8; k++)
851       cgi.gpdata->pshid[m][sd][i][j][k] = -1;
852     cgi.gpdata->nextid = 0;
853     }
854 
build_plainshape(int & id,gp::local_info & li,cell * c0,int siid,int sidir)855   void build_plainshape(int& id, gp::local_info& li, cell *c0, int siid, int sidir) {
856     cgi.require_shapes();
857     id = cgi.gpdata->nextid++;
858 
859     bool master = !(li.relative.first||li.relative.second);
860     int cor = master ? S7 : SG6;
861     if(master) li.last_dir = -1;
862     DEBB(DF_GP, (format("last=%d at=%d,%d tot=%d siid=%d sidir=%d cor=%d id=%d\n", li.last_dir, li.relative.first, li.relative.second, li.total_dir, siid, sidir, cor, id)));
863 
864     cgi.generate_floorshapes_for(id, c0, siid, sidir);
865 
866     cgi.finishshape();
867     cgi.extra_vertices();
868     }
869 
get_plainshape_id(cell * c)870   EX int get_plainshape_id(cell *c) {
871     if(li_for != c) {
872       li_for = c;
873       current_li = get_local_info(c);
874       }
875     int siid, sidir;
876     cell *c1 = c;
877     auto f = [&] {
878       if(geosupport_threecolor() == 2) {
879         auto si = patterns::getpatterninfo(c1, patterns::PAT_COLORING, patterns::SPF_NO_SUBCODES);
880         siid = si.id>>2;
881         // if(siid == 2) si.dir++;
882         // if(siid != pattern_threecolor(c)) printf("threecolor mismatch\n");
883         // if(pattern_threecolor(createMov(c, c->fixd(si.dir))) != (siid+1)%3) printf("threecolor mismatch direction\n");
884         sidir = c1->c.fix(si.dir);
885         }
886       else if(geosupport_football() == 2) {
887         siid = !pseudohept(c1);
888         sidir = !ishex1(c1);
889         }
890       else if(geosupport_chessboard()) {
891         siid = !chessvalue(c1);
892         sidir = 0;
893         }
894       else {
895         siid = 0;
896         sidir = 0;
897         }
898       };
899     if(INVERSE && gp::variation_for(gp::param) == eVariation::goldberg) {
900       c1 = gp::get_mapped(c);
901       UIU(f());
902       }
903     else if(INVERSE) {
904       siid = 0;
905       sidir = 0;
906       }
907     else f();
908     auto& id = cgi.gpdata->pshid[siid][sidir][current_li.relative.first&GOLDBERG_MASK][current_li.relative.second&GOLDBERG_MASK][gmod(current_li.total_dir, S6)];
909     if(id == -1 && sphere && isize(cgi.shFloor.b) > 0) {
910       forCellEx(c1, c) if(!gmatrix0.count(c1)) return 0;
911       }
912     if(id == -1) build_plainshape(id, current_li, c, siid, sidir);
913     return id;
914     }
915   EX }
916 #endif
917 
918 qfloorinfo qfi;
919 
set_no_floor()920 EX void set_no_floor() {
921   qfi.fshape = NULL;
922   qfi.shape = NULL;
923   qfi.tinf = NULL;
924   qfi.usershape = -1;
925   }
926 
set_floor(floorshape & sh)927 EX void set_floor(floorshape& sh) {
928   qfi.fshape = &sh;
929   qfi.shape = NULL;
930   qfi.tinf = NULL;
931   qfi.usershape = -1;
932   }
933 
set_floor(hpcshape & sh)934 EX void set_floor(hpcshape& sh) {
935   qfi.shape = &sh;
936   qfi.fshape = NULL;
937   qfi.spin = Id;
938   qfi.tinf = NULL;
939   qfi.usershape = -1;
940   }
941 
set_floor(const transmatrix & spin,hpcshape & sh)942 EX void set_floor(const transmatrix& spin, hpcshape& sh) {
943   qfi.shape = &sh;
944   qfi.fshape = NULL;
945   qfi.spin = spin;
946   qfi.usershape = -1;
947   }
948 
shvid(cell * c)949 EX int shvid(cell *c) {
950   return currentmap->shvid(c);
951   }
952 
shvid(cell * c)953 int hrmap_standard::shvid(cell *c) {
954   if(GOLDBERG)
955     return gp::get_plainshape_id(c);
956   #if CAP_IRR
957   else if(IRREGULAR)
958     return irr::cellindex[c];
959   #endif
960   else if(geosupport_football() == 2)
961     return pseudohept(c);
962   else if(inforder::mixed()) {
963     int t = c->type;
964     static vector<bool> computed;
965     if(isize(computed) <= t) computed.resize(t+1);
966     if(!computed[t]) {
967       computed[t] = true;
968       cell model;
969       heptagon modelh;
970       model.type = t;
971       modelh.type = t;
972       S7 = t;
973       for(int i=0; i<S7; i++) {
974         model.move(i) = &model;
975         modelh.move(i) = &modelh;
976         model.c.setspin(i, i, false);
977         modelh.c.setspin(i, i, false);
978         }
979 
980       cgi.tessf = edge_of_triangle_with_angles(0, M_PI/t, M_PI/t);
981       cgi.crossf = cgi.tessf;
982 
983       cgi.require_shapes();
984       println(hlog, "generating floorshapes for ", t);
985       cgi.generate_floorshapes_for(t, &model, 0, 0);
986       cgi.finishshape();
987       cgi.extra_vertices();
988       }
989     return t;
990     }
991   else if(PURE)
992     return 0;
993   else
994     return ctof(c);
995   }
996 
draw_shapevec(cell * c,const shiftmatrix & V,const vector<hpcshape> & shv,color_t col,PPR prio IS (PPR::DEFAULT))997 EX struct dqi_poly *draw_shapevec(cell *c, const shiftmatrix& V, const vector<hpcshape> &shv, color_t col, PPR prio IS(PPR::DEFAULT)) {
998   if(no_wall_rendering) return NULL;
999   if(!c) return &queuepolyat(V, shv[0], col, prio);
1000   else if(WDIM == 3) return NULL;
1001   else if(currentmap->strict_tree_rules()) return &queuepolyat(V, shv[shvid(c)], col, prio);
1002 
1003   #if CAP_GP
1004   else if(GOLDBERG) {
1005     int id = gp::get_plainshape_id(c);
1006     if(isize(shv) > id) return &queuepolyat(V, shv[id], col, prio);
1007     return NULL;
1008     }
1009   #endif
1010   #if CAP_IRR
1011   else if(IRREGULAR) {
1012     int id = irr::cellindex[c];
1013     if(id < 0 || id >= isize(shv)) {
1014       return NULL;
1015       }
1016     return &queuepolyat(V, shv[id], col, prio);
1017     }
1018   #endif
1019   #if CAP_ARCM
1020   else if(arcm::in()) {
1021     return &queuepolyat(V, shv[shvid(c)], col, prio);
1022     }
1023   #endif
1024   else if(GOLDBERG && ishex1(c))
1025     return &queuepolyat(V * pispin, shv[0], col, prio);
1026   else if(!(S7&1) && PURE && !kite::in() && !a4) {
1027     auto si = patterns::getpatterninfo(c, patterns::PAT_COLORING, 0);
1028     if(si.id == 8) si.dir++;
1029     transmatrix D = applyPatterndir(c, si);
1030     return &queuepolyat(V*D, shv[shvid(c)], col, prio);
1031     }
1032   else
1033     return &queuepolyat(V, shv[shvid(c)], col, prio);
1034   }
1035 
draw_floorshape(cell * c,const shiftmatrix & V,const floorshape & fsh,color_t col,PPR prio IS (PPR::DEFAULT))1036 EX void draw_floorshape(cell *c, const shiftmatrix& V, const floorshape &fsh, color_t col, PPR prio IS(PPR::DEFAULT)) {
1037   if(no_wall_rendering) return;
1038   draw_shapevec(c, V, fsh.b, col, prio);
1039   }
1040 
draw_qfi(cell * c,const shiftmatrix & V,color_t col,PPR prio IS (PPR::DEFAULT),vector<hpcshape> floorshape::* tab IS (& floorshape::b))1041 EX void draw_qfi(cell *c, const shiftmatrix& V, color_t col, PPR prio IS(PPR::DEFAULT), vector<hpcshape> floorshape::* tab IS(&floorshape::b)) {
1042   if(no_wall_rendering) return;
1043   if(qfi.shape)
1044     queuepolyat(V * qfi.spin, *qfi.shape, col, prio);
1045   else if(qfi.usershape >= 0) {
1046     mapeditor::drawUserShape(V * qfi.spin, mapeditor::sgFloor, qfi.usershape, col, c);
1047     }
1048   else if(!qfi.fshape) ;
1049 #if CAP_TEXTURE
1050   else if(qfi.tinf) {
1051     auto& poly = queuetable(V * qfi.spin, qfi.tinf->vertices, isize(qfi.tinf->vertices), texture::config.mesh_color, texture::config.recolor(col), prio == PPR::DEFAULT ? PPR::FLOOR : prio);
1052     poly.tinf = qfi.tinf;
1053     poly.offset_texture = 0;
1054     poly.flags = POLY_INVERSE;
1055     }
1056 #endif
1057   else draw_shapevec(c, V, (qfi.fshape->*tab), col, prio);
1058   }
1059 
1060 EX bool floorshape_debug;
viewmat()1061 EX void viewmat() {
1062   if(floorshape_debug) {
1063     shiftmatrix V = ggmatrix(cwt.at);
1064 
1065     for(int i=0; i<cwt.at->type; i++) {
1066       shiftpoint ci = V * get_corner_position(cwt.at, i);
1067       shiftpoint ci1 = V * get_corner_position(cwt.at, (i+1) % cwt.at->type);
1068 
1069       shiftpoint cn = V * nearcorner(cwt.at, i);
1070       shiftpoint cf0 = V * farcorner(cwt.at, i, 0);
1071       shiftpoint cf1 = V * farcorner(cwt.at, i, 1);
1072       queuestr(ci, 20, its(i), 0x0000FF, 1);
1073       if(vid.grid)
1074         queuestr(cn, 20, its(i), 0x00FF00, 1);
1075       else
1076         queuestr(V * currentmap->adj(cwt.at, i) * C0, 20, its(i), 0x00FFFF, 1);
1077       queueline(V * C0, ci, 0xFFFFFFFF, 3);
1078       queueline(ci, ci1, 0xFFFF00FF, 3);
1079       queueline(ci, cn, 0xFF00FFFF, 3);
1080       queueline(ci1, cn, 0xFF0000FF, 3);
1081       queueline(ci, cf0, 0x00FFFFFF, 3);
1082       queueline(cn, cf0, 0x00FF00FF, 3);
1083       queueline(cn, cf1, 0x0000FFFF, 3);
1084       }
1085     }
1086   }
1087 
__anon60f1d2c30902null1088 auto floor_hook = arg::add1("-floordebug", [] { floorshape_debug = true; });
1089 #endif
1090 
1091 #if MAXMDIM < 4 || !CAP_GL
ensure_vertex_number(basic_textureinfo & bti,int qty)1092 EX void ensure_vertex_number(basic_textureinfo& bti, int qty) {}
ensure_vertex_number(hpcshape & sh)1093 EX void ensure_vertex_number(hpcshape& sh) {}
bind_floor_texture(hpcshape & li,int id)1094 EX void bind_floor_texture(hpcshape& li, int id) {}
1095 #endif
1096 
1097 #if MAXMDIM >= 4 && CAP_GL
1098 
1099 EX ld floor_texture_square_size;
1100 
draw_shape_for_texture(floorshape * sh)1101 void draw_shape_for_texture(floorshape* sh) {
1102 
1103   int id = sh->id;
1104 
1105   const ld s1 = 1;
1106   const ld s3 = 3 * s1;
1107   const ld sd = s1/2;
1108 
1109   ld gx = (id % 8) * s3 - 3.5 * s3;
1110   ld gy = (id / 8) * s3 - 3.5 * s3;
1111 
1112   if(1) {
1113     dynamicval<ld> v(vid.linewidth, 8);
1114     curvepoint(eupush(gx+s1, gy-s1) * C0);
1115     curvepoint(eupush(gx+s1, gy+s1) * C0);
1116     curvepoint(eupush(gx-s1, gy+s1) * C0);
1117     curvepoint(eupush(gx-s1, gy-s1) * C0);
1118     curvepoint(eupush(gx+s1, gy-s1) * C0);
1119     queuecurve(shiftless(Id), 0x000000FF, 0xFFFFFFFF - 0x1010100 * (sh->pstrength * 24/10), PPR::LAKELEV);
1120     }
1121 
1122   poly_outline = 0xFFFFFFFF - 0x1010100 * (sh->pstrength * 3/2);
1123 
1124   for(int a=-1; a<=1; a++)
1125   for(int b=-1; b<=1; b++)
1126     queuepoly(shiftless(eupush(gx+a, gy+b)), sh->b[0], 0xFFFFFFFF);
1127 
1128   if(sh == &cgi.shCrossFloor) {
1129     queuepoly(shiftless(eupush(gx, gy) * spin(M_PI/4)), cgi.shCross, 0x808080FF);
1130     }
1131 
1132   if(1) {
1133     dynamicval<ld> v(vid.linewidth, 8);
1134     curvepoint(eupush(gx+sd, gy-sd) * C0);
1135     curvepoint(eupush(gx+sd, gy+sd) * C0);
1136     curvepoint(eupush(gx-sd, gy+sd) * C0);
1137     curvepoint(eupush(gx-sd, gy-sd) * C0);
1138     curvepoint(eupush(gx+sd, gy-sd) * C0);
1139     queuecurve(shiftless(Id), 0x40404000 + sh->fstrength * 192/10, 0, PPR::LINE);
1140     }
1141 
1142   for(int i=0; i<(ISMOBILE ? 10 : 1000); i++) {
1143     hyperpoint h1 = hpxy(sd * (6*randd()-3), sd * (6*randd()-3));
1144     hyperpoint h2 = hpxy(sd * (6*randd()-3), sd * (6*randd()-3));
1145     ld d = hdist(h1, h2);
1146     hyperpoint h3 = h1 + (h2-h1) /d * min(d, .1);
1147     for(int a=0; a<4; a++) {
1148       curvepoint(eupush(gx,gy) * eupush(spin(90*degree*a) * h1) * C0);
1149       curvepoint(eupush(gx,gy) * eupush(spin(90*degree*a) * h3) * C0);
1150       queuecurve(shiftless(Id), 0x10101010, 0, PPR::LINE);
1151       }
1152     }
1153 
1154   auto& ftv = floor_texture_vertices[sh->id];
1155   ftv.tvertices.clear();
1156   ftv.texture_id = floor_textures->renderedTexture;
1157 
1158   hyperpoint center = eupush(gx, gy) * C0;
1159   hyperpoint v1 = hpxyz3(sd, sd, 0, 0);
1160   hyperpoint v2 = hpxyz3(sd, -sd, 0, 0);
1161 
1162   if(1) {
1163     hyperpoint inmodel;
1164     applymodel(shiftless(center), inmodel);
1165     glvertex tmap;
1166     tmap[0] = (1 + inmodel[0] * pconf.scale) / 2;
1167     tmap[1] = (1 - inmodel[1] * pconf.scale) / 2;
1168     applymodel(shiftless(center + v1), inmodel);
1169     tmap[2] = (1 + inmodel[0] * pconf.scale) / 2 - tmap[0];
1170     floor_texture_map[sh->id] = tmap;
1171     }
1172 
1173   auto tvec_at = [&] (ld x, ld y) {
1174     hyperpoint h = center + v1 * x + v2 * y;
1175     hyperpoint inmodel;
1176     applymodel(shiftless(h), inmodel);
1177     glvec2 v;
1178     v[0] = (1 + inmodel[0] * pconf.scale) / 2;
1179     v[1] = (1 - inmodel[1] * pconf.scale) / 2;
1180     return v;
1181     };
1182 
1183   // SL2 needs 6 times more
1184   texture_order([&] (ld x, ld y) {
1185     auto v = tvec_at(x, y);
1186     ftv.tvertices.push_back(glhr::makevertex(v[0], v[1], 0));
1187     });
1188 
1189   floor_texture_square_size = 2 * (tvec_at(1, 0)[0] - tvec_at(0, 0)[0]);
1190   }
1191 
1192 /** copy the texture vertices so that there are at least qty of them */
ensure_vertex_number(basic_textureinfo & bti,int qty)1193 EX void ensure_vertex_number(basic_textureinfo& bti, int qty) {
1194   int s = isize(bti.tvertices);
1195   if(!s) return;
1196   while(isize(bti.tvertices) <= qty) {
1197     for(int i=0; i<s; i++) bti.tvertices.push_back(bti.tvertices[i]);
1198     }
1199   }
1200 
1201 /** ensure_vertex_number for a hpcshape */
ensure_vertex_number(hpcshape & sh)1202 EX void ensure_vertex_number(hpcshape& sh) {
1203   ensure_vertex_number(*sh.tinf, sh.e - sh.s);
1204   }
1205 
bind_floor_texture(hpcshape & li,int id)1206 EX void bind_floor_texture(hpcshape& li, int id) {
1207   li.tinf = &floor_texture_vertices[id];
1208   ensure_vertex_number(li);
1209   }
1210 
1211 #if HDR
1212 const int FLOORTEXTURESIZE = 4096;
1213 #endif
1214 
make_floor_textures_here()1215 void geometry_information::make_floor_textures_here() {
1216   require_shapes();
1217 
1218   dynamicval<videopar> vi(vid, vid);
1219   vid.xres = FLOORTEXTURESIZE;
1220   vid.yres = FLOORTEXTURESIZE;
1221   pconf.scale = 0.125;
1222   pconf.camera_angle = 0;
1223   pconf.alpha = 1;
1224   dynamicval<ld> lw(vid.linewidth, 2);
1225 
1226   floor_textures = new renderbuffer(vid.xres, vid.yres, vid.usingGL);
1227   resetbuffer rb;
1228 
1229   int q = isize(all_escher_floorshapes) + isize(all_plain_floorshapes);
1230   floor_texture_vertices.resize(q);
1231   floor_texture_map.resize(q);
1232 
1233   auto cd = current_display;
1234   cd->xtop = cd->ytop = 0;
1235   cd->xsize = cd->ysize = FLOORTEXTURESIZE;
1236   cd->xcenter = cd->ycenter = cd->scrsize = FLOORTEXTURESIZE/2;
1237 
1238   cd->radius = cd->scrsize * pconf.scale;
1239 
1240   floor_textures->enable();
1241   #if CAP_VR
1242   dynamicval<int> i(vrhr::state, 0);
1243   #endif
1244   floor_textures->clear(0); // 0xE8E8E8 = 1
1245 
1246   // gradient vertices
1247   vector<glhr::colored_vertex> gv;
1248   gv.emplace_back(-1, -1, 0, 0, 0);
1249   gv.emplace_back(+1, -1, 0, 0, 0);
1250   gv.emplace_back(+1, +1, 1, 1, 1);
1251   gv.emplace_back(-1, -1, 0, 0, 0);
1252   gv.emplace_back(+1, +1, 1, 1, 1);
1253   gv.emplace_back(-1, +1, 1, 1, 1);
1254 
1255   #if CAP_RAY
1256   dynamicval<bool> riu(ray::in_use, false);
1257   #endif
1258 
1259   if(1) {
1260     current_display->next_shader_flags = GF_VARCOLOR;
1261     dynamicval<eModel> m(pmodel, mdPixel);
1262     current_display->set_all(0,0);
1263     glhr::new_projection();
1264     glhr::id_modelview();
1265     glhr::prepare(gv);
1266     glhr::set_depthtest(false);
1267     glDrawArrays(GL_TRIANGLES, 0, isize(gv));
1268     }
1269 
1270   shOverFloor.pstrength = 20;
1271   shFeatherFloor.pstrength = 40;
1272   shFeatherFloor.fstrength = 5;
1273   shTrollFloor.pstrength = 25;
1274   shCaveFloor.pstrength = 40;
1275   shCaveFloor.fstrength = 0;
1276   shDesertFloor.pstrength = 30;
1277   shDesertFloor.fstrength =10;
1278   shRoseFloor.pstrength = 30;
1279   shDragonFloor.pstrength = 30;
1280   shBarrowFloor.pstrength = 40;
1281 
1282   // all using Tortoise
1283   for(auto v: all_escher_floorshapes) if(v->shapeid2 == 178) v->pstrength = 20;
1284 
1285   ptds.clear();
1286 
1287   for(auto v: all_plain_floorshapes) draw_shape_for_texture(v);
1288   for(auto v: all_escher_floorshapes) draw_shape_for_texture(v);
1289 
1290   drawqueue();
1291 
1292   /*
1293   SDL_Surface *sdark = floor_textures->render();
1294   IMAGESAVE(sdark, "texture-test.png");
1295   */
1296   rb.reset();
1297   last_texture_step = vid.texture_step;
1298   }
1299 
make_floor_textures()1300 EX void make_floor_textures() {
1301   if(noGUI || !vid.usingGL) return;
1302   DEBBI(DF_POLY, ("make_floor_textures"));
1303   dynamicval<eGeometry> g(geometry, gEuclidSquare);
1304   dynamicval<eModel> gm(pmodel, mdDisk);
1305   dynamicval<eVariation> va(variation, eVariation::pure);
1306   dynamicval<geometryinfo1> gie(ginf[geometry].g, giEuclid2);
1307   dynamicval<geometryinfo1> gih(ginf[gNormal].g, giHyperb2);
1308   dynamicval<bool> a3(vid.always3, false);
1309   dynamicval<bool> hq(inHighQual, true);
1310   dynamicval<int> hd(darken, 0);
1311   dynamicval<ld> hll(levellines, 0);
1312   dynamicval<ld> gd(vid.depth, 1);
1313   dynamicval<ld> gc(vid.camera, 1);
1314   dynamicval<geometry_information*> dcgip(cgip, cgip);
1315   dynamicval<eStereo> gvs(vid.stereo_mode, sOFF);
1316   dynamicval<int> vgp(global_projection, 0);
1317   check_cgi();
1318   cgi.make_floor_textures_here();
1319   /* update texture ID in existing cgi's */
1320   for(auto& c: cgis) c.second.models_texture.texture_id = floor_textures->renderedTexture;
1321   }
1322 
1323 
1324 #endif
1325 }
1326