1 // HyperRogue
2 // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
3 
4 /** \file 3d-models.cpp
5  *  \brief This file contains the routines to convert HyperRogue's old vector graphics into 3D models
6  */
7 
8 #include "hyper.h"
9 #include "earcut.hpp"
10 
11 namespace hr {
12 
13 ld eyepos;
14 
15 #if MAXMDIM >= 4
16 
17 #define S (cgi.scalefactor / 0.805578)
18 #define SH (cgi.scalefactor / 0.805578 * vid.height_width / 1.5)
19 
20 #define revZ ((WDIM == 2 || prod) ? -1 : 1)
21 
22 hyperpoint shcenter;
23 
24 EX hyperpoint front_leg, rear_leg;
25 EX transmatrix front_leg_move, rear_leg_move, front_leg_move_inverse, rear_leg_move_inverse;
26 EX ld leg_length;
27 
get_shape(hpcshape sh)28 vector<hyperpoint> geometry_information::get_shape(hpcshape sh) {
29   vector<hyperpoint> res;
30   for(int i=sh.s; i<sh.e-1; i++) res.push_back(hpc[i]);
31   return res;
32   }
33 
get_center(const vector<hyperpoint> & vh)34 hyperpoint get_center(const vector<hyperpoint>& vh) {
35   hyperpoint h = Hypc;
36   for(auto h1: vh) h = h + h1;
37   return normalize_flat(h);
38   }
39 
zc(ld z)40 EX ld zc(ld z) {
41   if(WDIM == 2 && GDIM == 3)
42     return geom3::lev_to_factor(cgi.human_height * z);
43   return cgi.human_height * (z - 0.5) * revZ;
44   }
45 
add_cone(ld z0,const vector<hyperpoint> & vh,ld z1)46 void geometry_information::add_cone(ld z0, const vector<hyperpoint>& vh, ld z1) {
47   last->flags |= POLY_TRIANGLES;
48   for(int i=0; i<isize(vh); i++) {
49     hpcpush(zpush(z0) * vh[i]);
50     hpcpush(zpush(z0) * vh[(i+1) % isize(vh)]);
51     hpcpush(zpush(z1) * shcenter);
52     }
53   }
54 
add_prism_sync(ld z0,vector<hyperpoint> vh0,ld z1,vector<hyperpoint> vh1)55 void geometry_information::add_prism_sync(ld z0, vector<hyperpoint> vh0, ld z1, vector<hyperpoint> vh1) {
56   last->flags |= POLY_TRIANGLES;
57   for(int i=0; i<isize(vh0); i++) {
58     int i1 = (i+1) % isize(vh0);
59     hpcpush(zpush(z0) * vh0[i]);
60     hpcpush(zpush(z1) * vh1[i]);
61     hpcpush(zpush(z0) * vh0[i1]);
62     hpcpush(zpush(z1) * vh1[i]);
63     hpcpush(zpush(z0) * vh0[i1]);
64     hpcpush(zpush(z1) * vh1[i1]);
65     }
66   }
67 
add_prism(ld z0,vector<hyperpoint> vh0,ld z1,vector<hyperpoint> vh1)68 void geometry_information::add_prism(ld z0, vector<hyperpoint> vh0, ld z1, vector<hyperpoint> vh1) {
69   last->flags |= POLY_TRIANGLES;
70 
71   struct mixed {
72     ld angle;
73     int owner;
74     hyperpoint h;
75     mixed(ld a, int o, hyperpoint _h) : angle(a), owner(o), h(_h) {}
76     };
77 
78   transmatrix T0 = gpushxto0(get_center(vh0));
79   transmatrix T1 = gpushxto0(get_center(vh1));
80 
81   vector<mixed> pairs;
82   for(auto h: vh0) pairs.emplace_back(atan2(T0*h), 0, h);
83   for(auto h: vh1) pairs.emplace_back(atan2(T1*h), 1, h);
84   sort(pairs.begin(), pairs.end(), [&] (const mixed p, const mixed q) { return p.angle < q.angle; });
85 
86   hyperpoint lasts[2];
87   for(auto pp: pairs) lasts[pp.owner] = pp.h;
88 
89   for(auto pp: pairs) {
90     int id = pp.owner;
91     hpcpush(zpush(z0) * lasts[0]);
92     hpcpush(zpush(z1) * lasts[1]);
93     hpcpush(zpush(id == 0 ? z0 : z1) * pp.h);
94     lasts[id] = pp.h;
95     }
96   }
97 
shift_last(ld z)98 void geometry_information::shift_last(ld z) {
99   for(int i=last->s; i<isize(hpc); i++) hpc[i] = zshift(hpc[i], z);
100   }
101 
shift_shape(hpcshape & sh,ld z)102 void geometry_information::shift_shape(hpcshape& sh, ld z) {
103   for(int i=sh.s; i<sh.e; i++) hpc[i] = zshift(hpc[i], z);
104   }
105 
shift_shape_orthogonally(hpcshape & sh,ld z)106 void geometry_information::shift_shape_orthogonally(hpcshape& sh, ld z) {
107   for(int i=sh.s; i<sh.e; i++) hpc[i] = orthogonal_move(hpc[i], z);
108   }
109 
110 extern renderbuffer *floor_textures;
111 
add_texture(hpcshape & sh)112 void geometry_information::add_texture(hpcshape& sh) {
113 #if CAP_GL
114   if(!floor_textures) return;
115   auto& utt = models_texture;
116   sh.tinf = &utt;
117   sh.texture_offset = isize(utt.tvertices);
118   for(int i=sh.s; i<isize(hpc); i++) {
119     hyperpoint h = hpc[i];
120     if(prod) h = product::inverse_exp(h);
121     ld rad = hypot_d(3, h);
122     ld factor = 0.50 + (0.17 * h[2] + 0.13 * h[1] + 0.15 * h[0]) / rad;
123     utt.tvertices.push_back(glhr::makevertex(0, factor, 0));
124     }
125 #endif
126   }
127 
scaleshape(const vector<hyperpoint> & vh,ld s)128 vector<hyperpoint> scaleshape(const vector<hyperpoint>& vh, ld s) {
129   vector<hyperpoint> res;
130   for(hyperpoint h: vh) res.push_back(normalize_flat(h * s + shcenter * (1-s)));
131   return res;
132   }
133 
get_zlevel(hyperpoint h)134 ld get_zlevel(hyperpoint h) {
135   if(prod) return zlevel(h);
136   if(sl2) return atan2(h[2], h[3]);
137   return asin_auto(h[2]);
138   }
139 
make_ha_3d(hpcshape & sh,bool isarmor,ld scale)140 void geometry_information::make_ha_3d(hpcshape& sh, bool isarmor, ld scale) {
141   shcenter = C0;
142 
143   auto groin = get_shape(shHumanGroin);
144   auto body = get_shape(shPBodyOnly);
145   auto neck = get_shape(shHumanNeck);
146   auto hand = get_shape(shPBodyHand);
147   auto arm = get_shape(shPBodyArm);
148   groin = scaleshape(groin, scale);
149   neck = scaleshape(neck, scale);
150 
151   auto fullbody = get_shape(sh);
152 
153   auto body7 = body[7];
154   auto body26 = body[26];
155   body.clear();
156 
157   bool foundplus = false, foundminus = false;
158   for(hyperpoint h: fullbody) {
159     if(h[1] > 0.14 * S) {
160       if(foundplus) ;
161       else foundplus = true, body.push_back(body7);
162       }
163     else if(h[1] < -0.14 * S) {
164       if(foundminus) ;
165       else foundminus = true, body.push_back(body26);
166       }
167     else body.push_back(h);
168     }
169 
170   auto arm8 = arm[8];
171   bool armused = false;
172   arm.clear();
173   for(hyperpoint h: fullbody) {
174     if(h[1] < 0.08 * S) ;
175     else if(h[0] > -0.03 * S) {
176       if(armused) ;
177       else armused = true, arm.push_back(arm8);
178       }
179     else arm.push_back(h);
180     }
181 
182   auto hand0 = hand[0];
183   hand.clear();
184   hand.push_back(hand0);
185   for(hyperpoint h: fullbody) {
186     if(h[1] + h[0] > 0.13 * S) hand.push_back(h);
187     }
188 
189   bshape(sh, PPR::MONSTER_BODY);
190   add_cone(zc(0.4), groin, zc(0.36));
191   add_prism_sync(zc(0.4), groin, zc(0.6), groin);
192   add_prism(zc(0.6), groin, zc(0.7), body);
193   add_prism(zc(0.7), body, zc(0.8), neck);
194 
195   add_cone(zc(0.8), neck, zc(0.83));
196 
197   int at0 = isize(hpc);
198   ld h = human_height;
199 
200   if(isize(arm) > 3) {
201     shcenter = get_center(arm);
202     int arm0 = isize(hpc);
203     add_prism_sync(BODY - h*.03, arm, BODY + h*.03, arm);
204     add_cone(BODY + h*.03, arm, BODY + h*.05);
205     add_cone(BODY - h*.03, arm, BODY - h*.05);
206     int arm1 = isize(hpc);
207     for(int i=arm0; i<arm1; i++) {
208       hyperpoint h = hpc[i];
209       ld zl = get_zlevel(h);
210       h = zpush(-zl) * h;
211       ld rad = hdist0(h);
212       rad = (rad - 0.1124*S) / (0.2804*S - 0.1124*S);
213       rad = 1 - rad;
214       rad *= zc(0.7) - BODY;
215       hpc[i] = zpush(rad) * hpc[i];
216       }
217     }
218    // 0.2804 - keep
219    // 0.1124 - move
220 
221   if(isize(hand) > 3) {
222     shcenter = get_center(hand);
223     add_cone(BODY, hand, BODY + 0.05 * human_height);
224     add_cone(BODY, hand, BODY - 0.05 * human_height);
225     }
226 
227   int at1 = isize(hpc);
228   for(int i=at0; i<at1; i++) hpc.push_back(Mirror * hpc[i]);
229 
230   add_texture(sh);
231   shift_last(-BODY);
232   }
233 
make_humanoid_3d(hpcshape & sh)234 void geometry_information::make_humanoid_3d(hpcshape& sh) { make_ha_3d(sh, false, 1); }
235 
addtri(array<hyperpoint,3> hs,int kind)236 void geometry_information::addtri(array<hyperpoint, 3> hs, int kind) {
237   ld ds[3];
238   ds[0] = hdist(hs[0], hs[1]);
239   ds[1] = hdist(hs[1], hs[2]);
240   ds[2] = hdist(hs[2], hs[0]);
241   ld maxds = 0;
242   for(int i=0; i<3; i++) maxds = max(ds[i], maxds) - 1e-3;
243 
244   if(maxds > 0.02*S) for(int i=0; i<3; i++) {
245     int j = (i+1) % 3;
246     int k = (j+1) % 3;
247     if(hdist(hs[i], hs[j]) > maxds) {
248       auto hm = mid(hs[i], hs[j]);
249       addtri(make_array(hm, hs[i], hs[k]), kind);
250       addtri(make_array(hm, hs[j], hs[k]), kind);
251       return;
252       }
253     }
254 
255   if(kind) {
256     array<hyperpoint, 3> ht;
257     ld hsh[3];
258     ld shi[3];
259     bool ok = true;
260     ld zzes[3];
261     for(int s=0; s<3; s++) {
262       hs[s] = normalize_flat(hs[s]);
263       hyperpoint h = hs[s];
264       ld zz = zc(0.78);
265       hsh[s] = abs(h[1]);
266       zz -= h[1] * h[1] / 0.14 / 0.14 * 0.01 / S / S * SH;
267       zz -= h[0] * h[0] / 0.10 / 0.10 * 0.01 / S / S * SH;
268       if(abs(h[1]) > 0.14*S) ok = false, zz -= revZ * (abs(h[1])/S - 0.14) * SH;
269       if(abs(h[0]) > 0.08*S) ok = false, zz -= revZ * (abs(h[0])/S - 0.08) * (abs(h[0])/S - 0.08) * 25 * SH;
270       h = normalize_flat(h);
271       if(!prod || kind != 1) ht[s] = zpush(zz) * h;
272       else ht[s] = h;
273       if(hsh[s] < 0.1*S) shi[s] = 0.5;
274       else if(hsh[s] < 0.12*S) shi[s] = 0.1 + 0.4 * (hsh[s]/S - 0.1) / (0.12 - 0.1);
275       else shi[s] = 0.1;
276       zzes[s] = zz;
277       }
278     if(ok && kind == 1) {
279       array<array<hyperpoint, 3>, 6> htx;
280       for(int i=0; i<6; i++) htx[i] = ht;
281 
282       for(int i=0; i<3; i++) {
283         htx[0][i][0] *= 0.7; htx[0][i][1] *= 0.7;
284         htx[1][i][0] *= 1.2; htx[1][i][1] *= 1.7;
285         htx[2][i][1] *= 1.7;
286         htx[4][i][0] = htx[4][i][0] * 0.4 + scalefactor * 0.1;
287         htx[5][i][0] = htx[5][i][0] * 0.3 + scalefactor * 0.1;
288         if(!prod)
289           for(int a=0; a<6; a++) htx[a][i] = hpxy3(htx[a][i][0], htx[a][i][1], htx[a][i][2]);
290         else
291           for(int a=0; a<6; a++) htx[a][i] = zpush(zzes[i]) * hpxy(htx[a][i][0], htx[a][i][1]);
292         }
293       ld levels[6] = {0, 0.125, 0.125, 0.250, 0.375, 0.5};
294       for(int a=0; a<6; a++) for(int i=0; i<3; i++)
295         htx[a][i] = zpush(-min(shi[i], levels[a]) * human_height * revZ) * htx[a][i];
296 
297       hpcpush(htx[0][0]);
298       hpcpush(htx[0][1]);
299       hpcpush(htx[0][2]);
300 
301       for(int a=0; a<5; a++) for(int i=0; i<3; i++) {
302         int j = (i+1) % 3;
303         int b = a+1;
304         hpcpush(htx[a][i]);
305         hpcpush(htx[a][j]);
306         hpcpush(htx[b][i]);
307         hpcpush(htx[a][j]);
308         hpcpush(htx[b][i]);
309         hpcpush(htx[b][j]);
310         }
311       }
312     else
313       hpcpush(ht[0]), hpcpush(ht[1]), hpcpush(ht[2]);
314     }
315   else {
316     for(int s=0; s<3; s++) {
317       hyperpoint h = hs[s];
318       ld zz = zc(eyepos);
319       if(h[0] < -0.05*S) zz += revZ * (h[0]/S + 0.05) * SH;
320       if(hdist0(h) <= 0.0501*S) {
321         zz += revZ * sqrt(0.0026 - pow(hdist0(h)/S, 2)) * SH;
322         }
323       hpcpush(zpush(zz) * h);
324       }
325     }
326   }
327 
disable(hpcshape & sh)328 void disable(hpcshape& sh) {
329   sh.s = sh.e = 0;
330   }
331 
make_armor_3d(hpcshape & sh,int kind)332 void geometry_information::make_armor_3d(hpcshape& sh, int kind) {
333 
334   if(BADMODEL) {
335     disable(sh);
336     return;
337     }
338   auto body = get_shape(sh);
339   vector<vector<array<ld, 2> >> pts(2);
340 
341   for(hyperpoint h: body) {
342     array<ld, 2> p;
343     p[0] = h[0] / h[LDIM];
344     p[1] = h[1] / h[LDIM];
345     pts[0].emplace_back(p);
346     }
347 
348   bshape(sh, sh.prio);
349 
350   vector<int> indices = mapbox::earcut<int> (pts);
351 
352   last->flags |= POLY_TRIANGLES;
353 
354   last->flags |= POLY_TRIANGLES;
355   for(int k=0; k<isize(indices); k+=3) {
356     addtri(make_array(body[indices[k]], body[indices[k+1]], body[indices[k+2]]), kind);
357     }
358 
359   add_texture(sh);
360   if(&sh == &shHood || &sh == &shWightCloak || &sh == &shArmor)
361     shift_last(-HEAD);
362   else
363     shift_last(-BODY);
364   }
365 
make_foot_3d(hpcshape & sh)366 void geometry_information::make_foot_3d(hpcshape& sh) {
367   auto foot = get_shape(sh);
368   auto leg = get_shape(shHumanLeg);
369   auto leg5 = scaleshape(leg, 0.8);
370 
371   bshape(sh, PPR::MONSTER_BODY);
372   shcenter = get_center(leg);
373   add_cone(zc(0), foot, zc(0));
374   add_prism(zc(0), foot, zc(0.1), leg);
375   add_prism_sync(zc(0.1), leg, zc(0.4), leg5);
376   add_cone(zc(0.4), leg5, zc(0.45));
377   add_texture(sh);
378   // shift_last(-LEG0);
379   for(int i=last->s; i<isize(hpc); i++) hpc[i] = cpush(0, -0.0125*S) * hpc[i];
380   }
381 
make_head_only()382 void geometry_information::make_head_only() {
383 
384   auto addpt = [this] (int d, int u) {
385     hpcpush(zpush(zc(eyepos) + 0.06 * SH * sin(u * degree)) * xspinpush0(d * degree, 0.05 * S * cos(u * degree)));
386     };
387 
388   bshape(shPHeadOnly, shPHeadOnly.prio);
389   last->flags |= POLY_TRIANGLES;
390   for(int d=0; d<360; d+=(BADMODEL ? 60 : 30))
391   for(int u=-90; u<=90; u+=(BADMODEL ? 90 : 30)) {
392     addpt(d, u);
393     addpt(d+30, u);
394     addpt(d, u+30);
395     addpt(d+30, u+30);
396     addpt(d+30, u);
397     addpt(d, u+30);
398     }
399 
400   add_texture(shPHeadOnly);
401   shift_last(-HEAD - revZ * 0.01 * SH);
402   }
403 
404 
make_head_3d(hpcshape & sh)405 void geometry_information::make_head_3d(hpcshape& sh) {
406   auto head = get_shape(sh);
407   vector<vector<array<ld, 2> >> pts(2);
408 
409   for(hyperpoint h: head) {
410     array<ld, 2> p;
411     p[0] = h[0] / h[LDIM];
412     p[1] = h[1] / h[LDIM];
413     pts[0].emplace_back(p);
414     }
415 
416   array<ld, 2> zero = make_array<ld>(0,0);
417   pts[1].emplace_back(zero);
418   head.push_back(C0);
419 
420   bshape(sh, sh.prio);
421 
422   vector<int> indices = mapbox::earcut<int> (pts);
423 
424   last->flags |= POLY_TRIANGLES;
425   for(int k=0; k<isize(indices); k+=3) {
426     addtri(make_array(head[indices[k]], head[indices[k+1]], head[indices[k+2]]), 0);
427     }
428 
429   add_texture(sh);
430   shift_last(-HEAD);
431   }
432 
make_paw_3d(hpcshape & sh,hpcshape & legsh)433 void geometry_information::make_paw_3d(hpcshape& sh, hpcshape& legsh) {
434   auto foot = get_shape(sh);
435   auto leg = get_shape(legsh);
436 
437   bshape(sh, PPR::MONSTER_BODY);
438   shcenter = get_center(leg);
439   add_cone(zc(0), foot, zc(0));
440   add_prism(zc(0), foot, zc(0.1), leg);
441   add_prism_sync(zc(0.1), leg, zc(0.4), leg);
442   add_cone(zc(0.4), leg, zc(0.45));
443   add_texture(sh);
444   }
445 
make_abody_3d(hpcshape & sh,ld tail)446 void geometry_information::make_abody_3d(hpcshape& sh, ld tail) {
447   auto body = get_shape(sh);
448   shcenter = get_center(body);
449 
450   vector<hyperpoint> notail;
451   ld minx = 9;
452   for(hyperpoint h: body) minx = min(minx, h[0]);
453   for(hyperpoint h: body) if(h[0] >= minx + tail) notail.push_back(h);
454 
455   auto body8 = scaleshape(notail, 0.8);
456 
457   bshape(sh, PPR::MONSTER_BODY);
458   add_prism(zc(0.4), body8, zc(0.45), body);
459   add_prism(zc(0.45), body, zc(0.5), notail);
460   add_prism_sync(zc(0.6), body8, zc(0.5), notail);
461   add_cone(zc(0.4), body8, zc(0.36));
462   add_cone(zc(0.6), body8, zc(0.64));
463   add_texture(sh);
464   if(GDIM == 3 && WDIM == 2) shift_last(-ABODY);
465   }
466 
make_ahead_3d(hpcshape & sh)467 void geometry_information::make_ahead_3d(hpcshape& sh) {
468   auto body = get_shape(sh);
469   shcenter = get_center(body);
470   auto body8 = scaleshape(body, 0.5);
471 
472   bshape(sh, PPR::MONSTER_BODY);
473   add_prism_sync(zc(0.4), body8, zc(0.5), body);
474   add_prism_sync(zc(0.6), body8, zc(0.5), body);
475   add_cone(zc(0.4), body8, zc(0.36));
476   add_cone(zc(0.6), body8, zc(0.64));
477   add_texture(sh);
478   }
479 
make_skeletal(hpcshape & sh,ld push)480 void geometry_information::make_skeletal(hpcshape& sh, ld push) {
481   auto body = get_shape(sh);
482   shcenter = get_center(body);
483 
484   bshape(sh, PPR::MONSTER_BODY);
485   add_prism_sync(zc(0.48), body, zc(0.5), body);
486   add_prism_sync(zc(0.52), body, zc(0.5), body);
487   add_cone(zc(0.48), body, zc(0.47));
488   add_cone(zc(0.52), body, zc(0.53));
489   add_texture(sh);
490   shift_last(-push);
491   }
492 
yzspin(ld alpha,hyperpoint h)493 hyperpoint yzspin(ld alpha, hyperpoint h) {
494   if(prod) return product::direct_exp(cspin(1, 2, alpha) * product::inverse_exp(h));
495   else return cspin(1, 2, alpha) * h;
496   }
497 
make_revolution(hpcshape & sh,int mx,ld push)498 void geometry_information::make_revolution(hpcshape& sh, int mx, ld push) {
499   auto body = get_shape(sh);
500   bshape(sh, PPR::MONSTER_BODY);
501   int step = (BADMODEL ? 60 : (mx == 360 ? 24 : 10));
502   for(int i=0; i<isize(body); i++) {
503     hyperpoint h0 = body[i];
504     hyperpoint h1 = body[(i+1) % isize(body)];
505     for(int s=0; s<mx; s+=step) {
506       hpcpush(yzspin(s * degree, h0));
507       hpcpush(yzspin(s * degree, h1));
508       hpcpush(yzspin((s+step) * degree, h0));
509       hpcpush(yzspin(s * degree, h1));
510       hpcpush(yzspin((s+step) * degree, h0));
511       hpcpush(yzspin((s+step) * degree, h1));
512       }
513     }
514   last->flags |= POLY_TRIANGLES;
515   add_texture(sh);
516   shift_last(-push);
517   }
518 
make_revolution_cut(hpcshape & sh,int each,ld push,ld width)519 void geometry_information::make_revolution_cut(hpcshape &sh, int each, ld push, ld width) {
520   auto body = get_shape(sh);
521   body.resize(isize(body) / 2);
522   ld fx = body[0][0];
523   ld lx = body.back()[0];
524   body.insert(body.begin(), hpxy(fx + (fx-lx) * 1e-3, 0));
525   body.push_back(hpxy(lx + (lx-fx) * 1e-3, 0));
526   int n = isize(body);
527 
528   auto gbody = body;
529 
530   int it = 0;
531 
532   vector<int> nextid(n);
533   vector<int> lastid(n);
534   vector<bool> stillin(n, true);
535   for(int i=0; i<n; i++) nextid[i] = i+1;
536   for(int i=0; i<n; i++) lastid[i] = i-1;
537   nextid[n-1] = n-1; lastid[0] = 0;
538 
539   while(true) {
540     it++;
541     int cand = -1;
542     ld cv = 0;
543     for(int i=1; i<n-1; i++) if(stillin[i]) {
544       if((gbody[i][0] < gbody[lastid[i]][0] && gbody[i][0] < gbody[nextid[i]][0]) || (gbody[i][0] > gbody[lastid[i]][0] && gbody[i][0] > gbody[nextid[i]][0]) || abs(gbody[i][1]) > width)
545       if(abs(gbody[i][1]) > cv)
546         cand = i, cv = abs(gbody[i][1]);
547       }
548     if(cand == -1) break;
549     int i = cand;
550     lastid[nextid[i]] = lastid[i];
551     nextid[lastid[i]] = nextid[i];
552     stillin[i] = false;
553     }
554 
555   for(int i=n-1; i>=0; i--) if(!stillin[i] && !stillin[nextid[i]]) nextid[i] = nextid[nextid[i]];
556   for(int i=0; i<n; i++) if(!stillin[i] && !stillin[lastid[i]]) lastid[i] = lastid[lastid[i]];
557 
558   for(int i=0; i<n; i++) {
559     if(!stillin[i]) gbody[i] = normalize_flat(gbody[lastid[i]] * (i - lastid[i]) + gbody[nextid[i]] * (nextid[i] - i));
560     }
561 
562   bshape(sh, PPR::MONSTER_BODY);
563   int step = (BADMODEL ? 60 : 10);
564   for(int i=0; i<n; i++) {
565     for(int s=0; s<360; s+=step) {
566       auto& tbody = BADMODEL ? gbody : (s % each ? gbody : body);
567       auto& nbody = BADMODEL ? gbody : ((s+step) % each ? gbody : body);
568       int i1 = (i+1) % isize(body);
569       hyperpoint h0 = tbody[i];
570       hyperpoint h1 = tbody[i1];
571       hyperpoint hs0 = nbody[i];
572       hyperpoint hs1 = nbody[i1];
573       hpcpush(yzspin(s * degree, h0));
574       hpcpush(yzspin(s * degree, h1));
575       hpcpush(yzspin((s+step) * degree, hs0));
576       hpcpush(yzspin(s * degree, h1));
577       hpcpush(yzspin((s+step) * degree, hs0));
578       hpcpush(yzspin((s+step) * degree, hs1));
579       }
580     }
581   last->flags |= POLY_TRIANGLES;
582   add_texture(sh);
583   shift_last(-push);
584 
585   if(&sh == &shDogTorso) {
586     finishshape();
587     shDogStripes = shDogTorso;
588     add_texture(shDogStripes);
589     auto& utt = models_texture;
590     if(utt.tvertices.empty()) return;
591     int a = (6 * 360 / step);
592     for(int i=0; i<shDogStripes.e - shDogStripes.s; i++)
593       if(i % (2 * a) < a)
594         utt.tvertices[i + shDogStripes.texture_offset][1] /= 4;
595     }
596   }
597 
clone_shape(hpcshape & sh,hpcshape & target)598 void geometry_information::clone_shape(hpcshape& sh, hpcshape& target) {
599   target = sh;
600   target.s = isize(hpc);
601   for(int i=sh.s; i<sh.e; i++) hpc.push_back(hpc[i]);
602   target.e = isize(hpc);
603   }
604 
animate_bird(hpcshape & orig,hpcshape_animated & animated,ld body)605 void geometry_information::animate_bird(hpcshape& orig, hpcshape_animated& animated, ld body) {
606   for(int i=0; i<=WINGS; i++) {
607     auto& tgt = animated[i];
608     clone_shape(orig, tgt);
609     ld alpha = cos(180. * degree * i / WINGS) * 30 * degree;
610     for(int i=tgt.s; i<tgt.e; i++) {
611       if(abs(hpc[i][1]) > body) {
612         ld off = hpc[i][1] > 0 ? body : -body;
613         hpc[i][2] += abs(hpc[i][1] - off) * sin(alpha);
614         hpc[i][1] = off + (hpc[i][1] - off) * cos(alpha);
615         hpc[i] = normalize(hpc[i]);
616         }
617       }
618     }
619   // for(int i=0; i<30; i++) shift_shape(animated[i], BIRD);
620   // shift_shape(orig, BIRD);
621   }
622 
slimetriangle(hyperpoint a,hyperpoint b,hyperpoint c,ld rad,int lev)623 void geometry_information::slimetriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev) {
624   dynamicval<int> d(vid.texture_step, 8);
625   texture_order([&] (ld x, ld y) {
626     ld z = 1-x-y;
627     ld r = scalefactor * hcrossf7 * (0 + pow(max(x,max(y,z)), .3) * 0.8) * (hybri ? .5 : 1);
628     hyperpoint h = direct_exp(tangent_length(a*x+b*y+c*z, r));
629     hpcpush(h);
630     });
631   }
632 
balltriangle(hyperpoint a,hyperpoint b,hyperpoint c,ld rad,int lev)633 void geometry_information::balltriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev) {
634   if(lev == 0) {
635     hpcpush(direct_exp(a));
636     hpcpush(direct_exp(b));
637     hpcpush(direct_exp(c));
638     }
639   else {
640     auto midpoint = [&] (hyperpoint h1, hyperpoint h2) {
641       return tangent_length(h1+h2, rad);
642       };
643     hyperpoint cx = midpoint(a, b);
644     hyperpoint ax = midpoint(b, c);
645     hyperpoint bx = midpoint(c, a);
646     balltriangle(ax, bx, cx, rad, lev-1);
647     balltriangle(ax, bx, c , rad, lev-1);
648     balltriangle(ax, b , cx, rad, lev-1);
649     balltriangle(a , bx, cx, rad, lev-1);
650     }
651   }
652 
make_ball(hpcshape & sh,ld rad,int lev)653 void geometry_information::make_ball(hpcshape& sh, ld rad, int lev) {
654   bshape(sh, sh.prio);
655   sh.flags |= POLY_TRIANGLES;
656   hyperpoint tip = xtangent(rad);
657   hyperpoint atip = xtangent(-rad);
658   ld z = 63.43 * degree;
659   for(int i=0; i<5; i++) {
660     hyperpoint a = cspin(1, 2, (72 * i   ) * degree) * spin(z) * tip;
661     hyperpoint b = cspin(1, 2, (72 * i-72) * degree) * spin(z) * tip;
662     hyperpoint c = cspin(1, 2, (72 * i+36) * degree) * spin(M_PI-z) * tip;
663     hyperpoint d = cspin(1, 2, (72 * i-36) * degree) * spin(M_PI-z) * tip;
664     balltriangle(tip, a, b, rad, lev);
665     balltriangle(a, b, c, rad, lev);
666     balltriangle(b, c, d, rad, lev);
667     balltriangle(c, d, atip, rad, lev);
668     }
669   add_texture(sh);
670   }
671 
hpcsquare(hyperpoint h1,hyperpoint h2,hyperpoint h3,hyperpoint h4)672 void geometry_information::hpcsquare(hyperpoint h1, hyperpoint h2, hyperpoint h3, hyperpoint h4) {
673   last->flags |= POLY_TRIANGLES;
674   hpcpush(h1);
675   hpcpush(h2);
676   hpcpush(h3);
677   hpcpush(h2);
678   hpcpush(h3);
679   hpcpush(h4);
680   }
681 
make_star(hpcshape & sh,ld rad)682 void geometry_information::make_star(hpcshape& sh, ld rad) {
683   bshape(sh, sh.prio);
684   rad = sinh(rad);
685   sh.flags |= POLY_TRIANGLES | POLY_INTENSE;
686   int steps = (BADMODEL ? 8 : 64);
687   for(int a=0; a<steps; a++) {
688     ld z0 = (a-steps/2)*2.0/steps;
689     ld z1 = (a-steps/2+1)*2.0/steps;
690     ld r0 = sqrt(1 - z0*z0) * rad;
691     ld r1 = sqrt(1 - z1*z1) * rad;
692     z0 *= rad;
693     z1 *= rad;
694     for(int b=0; b<360; b+=(BADMODEL?60:15)) {
695       ld b0 = b * degree;
696       ld b1 = (b+15) * degree;
697       hpcsquare(
698         hpxy3(r0 * cos(b0), r0 * sin(b0), z0), hpxy3(r0 * cos(b1), r0 * sin(b1), z0),
699         hpxy3(r1 * cos(b0), r1 * sin(b0), z1), hpxy3(r1 * cos(b1), r1 * sin(b1), z1)
700         );
701       }
702     }
703   }
704 
make_euclidean_sky()705 void geometry_information::make_euclidean_sky() {
706   bshape(cgi.shEuclideanSky, PPR::EUCLIDEAN_SKY);
707   for(int x=-20; x<20; x++)
708   for(int y=-20; y<20; y++)
709     hpcsquare(
710       zpush(cgi.WALL) * hpxy(x, y),
711       zpush(cgi.WALL) * hpxy(x, y+1),
712       zpush(cgi.WALL) * hpxy(x+1, y),
713       zpush(cgi.WALL) * hpxy(x+1, y+1)
714       );
715   }
716 
717 /** res[0] and res[1] place H on the plane, while res[2] is the altitude */
psmin(hyperpoint H)718 hyperpoint psmin(hyperpoint H) {
719   if(prod) {
720     auto d = product_decompose(H);
721     d.second[2] = d.first;
722     return d.second;
723     }
724   hyperpoint res;
725   res[2] = asin_auto(H[2]);
726   ld cs = pow(cos_auto(res[2]), 2);
727   ld r = sqrt(cs+H[0]*H[0]+H[1]*H[1]);
728   res[0] = H[0] / r;
729   res[1] = H[1] / r;
730   return res;
731   }
732 
adjust_eye(hpcshape & eye,hpcshape head,ld shift_eye,ld shift_head,int q,ld zoom)733 void geometry_information::adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye, ld shift_head, int q, ld zoom) {
734   hyperpoint center = Hypc;
735   for(int i=eye.s; i<eye.e; i++) if(q == 1 || hpc[i][1] > 0) center += hpc[i];
736   center = normalize_flat(center);
737   // center /= (eye.e - eye.s);
738   ld rad = 0;
739   for(int i=eye.s; i<eye.e; i++) if(q == 1 || hpc[i][1] > 0) rad += hdist(center, hpc[i]);
740   rad /= (eye.e - eye.s);
741 
742   hyperpoint pscenter = psmin(center);
743 
744   ld pos = 0;
745   int qty = 0, qtyall = 0;
746 
747   vector<hyperpoint> pss;
748 
749   for(int i=head.s; i<head.e; i++) pss.push_back(psmin(zpush(shift_head) * hpc[i]));
750 
751   ld zmid = 0;
752   for(hyperpoint& h: pss) zmid += h[2];
753   zmid /= isize(pss);
754 
755   ld mindist = 1e9;
756   for(int i=0; i<isize(pss); i+=3) if(pss[i][2] < zmid || (WDIM == 3 && !prod)) {
757     ld d = sqhypot_d(2, pss[i]-pscenter) + sqhypot_d(2, pss[i+1]-pscenter) + sqhypot_d(2, pss[i+2]-pscenter);
758     if(d < mindist) mindist = d, pos = min(min(pss[i][2], pss[i+1][2]), pss[i+2][2]), qty++;
759     qtyall++;
760     }
761 
762   if(&eye == &shSkullEyes) cgi.eyelevel_human = pos = zc(eyepos) - 0.06 * SH * 0.05;
763   if(&eye == &shWolf1) cgi.eyelevel_dog = pos;
764   if(&eye == &shFamiliarEye) cgi.eyelevel_familiar = pos;
765 
766   make_ball(eye, rad, 0);
767   transmatrix T = zpush(-shift_eye) * rgpushxto0(center) * zpush(pos);
768   for(int i=eye.s; i<isize(hpc); i++) hpc[i] = T * hpc[i];
769   int s = isize(hpc);
770   if(&eye == &shSkullEyes)
771     for(int i=eye.s; i<s; i++) hpc[i] = xpush(0.07 * scalefactor) * hpc[i];
772   if(q == 2)
773     for(int i=eye.s; i<s; i++) {
774       hpcpush(MirrorY * hpc[i]);
775       auto& utt = models_texture;
776       if(!utt.tvertices.empty())
777         utt.tvertices.push_back(utt.tvertices[i - eye.s + eye.texture_offset]);
778       }
779 
780   finishshape();
781   // eye.prio = PPR::SUPERLINE;
782   }
783 
shift_last_straight(ld z)784 void geometry_information::shift_last_straight(ld z) {
785   for(int i=last->s; i<isize(hpc); i++) hpc[i] = zpush(z) * hpc[i];
786   }
787 
queueball(const shiftmatrix & V,ld rad,color_t col,eItem what)788 EX void queueball(const shiftmatrix& V, ld rad, color_t col, eItem what) {
789   if(what == itOrbSpeed) {
790     shiftmatrix V1 = V * cspin(1, 2, M_PI/2);
791     ld tt = ptick(100);
792     for(int t=0; t<5; t++) {
793       for(int a=-50; a<50; a++)
794         curvepoint(cspin(0, 2, a * M_PI/100.) * cspin(0, 1, t * 72 * degree + tt + a*2*M_PI/50.) * xpush0(rad));
795       queuecurve(V1, col, 0, PPR::LINE);
796       }
797     return;
798     }
799   ld z = 63.43 * degree;
800   shiftmatrix V1 = V * cspin(0, 2, M_PI/2);
801   if(what == itOrbShield) V1 = V * cspin(0, 1, ptick(500));
802   if(what == itOrbFlash) V1 = V * cspin(0, 1, ptick(1500));
803   if(what == itOrbShield) V1 = V * cspin(1, 2, ptick(1000));
804   if(what == itOrbFlash) V1 = V * cspin(1, 2, ptick(750));
805   if(what == itDiamond) V1 = V * cspin(1, 2, ptick(200));
806   if(what == itRuby) V1 = V * cspin(1, 2, ptick(300));
807   auto line = [&] (transmatrix A, transmatrix B) {
808     hyperpoint h0 = A * xpush0(1);
809     hyperpoint h1 = B * xpush0(1);
810     for(int i=0; i<=8; i++)
811       curvepoint(rspintox(normalize(h0*(8-i) + h1*i)) * xpush0(rad));
812     queuecurve(V1, col, 0, PPR::LINE);
813     };
814   for(int i=0; i<5; i++) {
815     auto a = cspin(1, 2, (72 * i   ) * degree) * spin(z);
816     auto b = cspin(1, 2, (72 * i-72) * degree) * spin(z);
817     auto c = cspin(1, 2, (72 * i+36) * degree) * spin(M_PI-z);
818     auto d = cspin(1, 2, (72 * i-36) * degree) * spin(M_PI-z);
819     line(Id, a);
820     line(a, b);
821     line(a, c);
822     line(a, d);
823     line(d, c);
824     line(c, spin(M_PI));
825     }
826   }
827 
make_shadow(hpcshape & sh)828 void geometry_information::make_shadow(hpcshape& sh) {
829   sh.shs = isize(hpc);
830   for(int i=sh.s; i < sh.e; i++) hpcpush(orthogonal_move(hpc[i], FLOOR - human_height / 100));
831   sh.she = isize(hpc);
832   }
833 
make_3d_models()834 void geometry_information::make_3d_models() {
835   if(GDIM == 2 || noGUI) return;
836   eyepos = WDIM == 2 ? 0.875 : 0.925;
837   DEBBI(DF_POLY, ("make_3d_models"));
838   shcenter = C0;
839 
840 #if CAP_GL
841   if(floor_textures) {
842     auto& utt = models_texture;
843     utt.tvertices.clear();
844     utt.texture_id = floor_textures->renderedTexture;
845     }
846 #endif
847 
848   if(WDIM == 2 || euclid) {
849     DEBB(DF_POLY, ("shadows"));
850     for(hpcshape* sh: {&shBatWings, &shBugBody, &shBullBody, &shButterflyWing, &shCatBody, &shDogBody, &shDogTorso,
851       &shEagle, &shFemaleBody, &shFlailMissile, &shGadflyWing, &shGargoyleWings, &shHawk, &shJiangShi, &shKnife,
852       &shPBody, &shPHead, &shRaiderBody, &shReptileBody, &shSkeletonBody, &shTongue, &shTrapArrow, &shTrylobite,
853       &shWaterElemental, &shWolfBody, &shYeti, &shWormHead, &shWormHead, &shDragonHead, &shDragonSegment, &shDragonTail,
854       &shTentacleX, &shTentHead, &shILeaf[0], &shILeaf[1], &shWormSegment, &shSmallWormSegment, &shFrogBody })
855       make_shadow(*sh);
856 
857     for(int i=0; i<8; i++) make_shadow(shAsteroid[i]);
858     }
859 
860   DEBB(DF_POLY, ("humanoids"));
861   make_humanoid_3d(shPBody);
862   make_humanoid_3d(shYeti);
863   make_humanoid_3d(shFemaleBody);
864   make_humanoid_3d(shRaiderBody);
865   make_humanoid_3d(shSkeletonBody);
866   make_humanoid_3d(shFatBody);
867   make_humanoid_3d(shWaterElemental);
868   make_humanoid_3d(shJiangShi);
869 
870   // shFatBody = shPBody;
871   // shFemaleBody = shPBody;
872   // shRaiderBody = shPBody;
873   // shJiangShi = shPBody;
874 
875   DEBB(DF_POLY, ("heads"));
876   make_head_3d(shFemaleHair);
877   make_head_3d(shPHead);
878   make_head_3d(shTurban1);
879   make_head_3d(shTurban2);
880   make_head_3d(shAztecHead);
881   make_head_3d(shAztecCap);
882   make_head_3d(shVikingHelmet);
883   make_head_3d(shRaiderHelmet);
884   make_head_3d(shWestHat1);
885   make_head_3d(shWestHat2);
886   make_head_3d(shWitchHair);
887   make_head_3d(shBeautyHair);
888   make_head_3d(shFlowerHair);
889   make_head_3d(shGolemhead);
890   make_head_3d(shPirateHood);
891   make_head_3d(shEyepatch);
892   make_head_3d(shSkull);
893   make_head_3d(shDemon);
894   make_head_3d(shGoatHead);
895   make_head_3d(shJiangShiCap1);
896   make_head_3d(shJiangShiCap2);
897   make_head_3d(shTerraHead);
898 
899   DEBB(DF_POLY, ("armors"));
900   make_armor_3d(shKnightArmor);
901   make_armor_3d(shKnightCloak, 2);
902   make_armor_3d(shPrinceDress);
903   make_armor_3d(shPrincessDress, 2);
904   make_armor_3d(shTerraArmor1);
905   make_armor_3d(shTerraArmor2);
906   make_armor_3d(shTerraArmor3);
907   make_armor_3d(shSuspenders);
908   make_armor_3d(shJiangShiDress);
909   make_armor_3d(shFemaleDress);
910   make_armor_3d(shWightCloak, 2);
911   make_armor_3d(shRaiderArmor);
912   make_armor_3d(shRaiderShirt);
913   make_armor_3d(shArmor);
914   make_armor_3d(shRatCape2, 2);
915 
916   make_armor_3d(shHood, 2);
917 
918   DEBB(DF_POLY, ("feet and paws"));
919   make_foot_3d(shHumanFoot);
920   make_foot_3d(shYetiFoot);
921   make_skeletal(shSkeletalFoot, WDIM == 2 ? zc(0.5) + human_height/40 - FLOOR : 0);
922 
923   hyperpoint front_leg = Hypc;
924   hyperpoint rear_leg = Hypc;
925   for(int i=shDogFrontPaw.s; i<shDogFrontPaw.e; i++) front_leg += hpc[i];
926   for(int i=shDogRearPaw.s; i<shDogRearPaw.e; i++) rear_leg += hpc[i];
927   front_leg = normalize(front_leg);
928   rear_leg = normalize(rear_leg);
929   front_leg_move = zpush(zc(0.4)) * rgpushxto0(front_leg);
930   front_leg_move_inverse = inverse(front_leg_move);
931   rear_leg_move = zpush(zc(0.4)) * rgpushxto0(rear_leg);
932   rear_leg_move_inverse = inverse(rear_leg_move);
933   leg_length = zc(0.4) - zc(0);
934 
935   make_paw_3d(shWolfFrontPaw, shWolfFrontLeg);
936   make_paw_3d(shWolfRearPaw, shWolfRearLeg);
937   make_paw_3d(shDogFrontPaw, shDogFrontLeg);
938   make_paw_3d(shDogRearPaw, shDogRearLeg);
939 
940   DEBB(DF_POLY, ("revolution"));
941   // make_abody_3d(shWolfBody, 0.01);
942   // make_ahead_3d(shWolfHead);
943   // make_ahead_3d(shFamiliarHead);
944   ld g = WDIM == 2 ? ABODY - zc(0.4) : 0;
945 
946   make_revolution_cut(shWolfBody, 30, g, 0.01*S);
947   make_revolution_cut(shWolfHead, 180, AHEAD - ABODY +g);
948   make_revolution_cut(shRatHead, 180, AHEAD - ABODY +g, 0.04*scalefactor);
949   make_revolution_cut(shRatCape1, 180, AHEAD - ABODY +g);
950   make_revolution_cut(shFamiliarHead, 30, AHEAD - ABODY +g);
951 
952   // make_abody_3d(shDogTorso, 0.01);
953   make_revolution_cut(shDogTorso, 30, +g);
954   make_revolution_cut(shDogHead, 180, AHEAD - ABODY +g);
955   // make_ahead_3d(shDogHead);
956 
957   // make_abody_3d(shCatBody, 0.05);
958   // make_ahead_3d(shCatHead);
959   make_revolution_cut(shCatBody, 30, +g);
960   make_revolution_cut(shCatHead, 180, AHEAD - ABODY +g, 0.055 * scalefactor);
961 
962   make_paw_3d(shReptileFrontFoot, shReptileFrontLeg);
963   make_paw_3d(shReptileRearFoot, shReptileRearLeg);
964   make_abody_3d(shReptileBody, -1);
965   // make_ahead_3d(shReptileHead);
966   make_revolution_cut(shReptileHead, 180, AHEAD - ABODY+g);
967 
968   make_paw_3d(shBullFrontHoof, shBullFrontHoof);
969   make_paw_3d(shBullRearHoof, shBullRearHoof);
970   // make_abody_3d(shBullBody, 0.05);
971   // make_ahead_3d(shBullHead);
972   // make_ahead_3d(shBullHorn);
973   make_revolution_cut(shBullBody, 180, +g);
974   make_revolution_cut(shBullHead, 60, AHEAD - ABODY +g);
975   shift_shape(shBullHorn, -g-(AHEAD - ABODY));
976   // make_revolution_cut(shBullHorn, 180, AHEAD - ABODY);
977 
978   make_paw_3d(shFrogFrontFoot, shFrogFrontLeg);
979   make_paw_3d(shFrogRearFoot, shFrogRearLeg);
980   make_paw_3d(shFrogJumpFoot, shFrogJumpLeg);
981 
982   make_paw_3d(shTrylobiteFrontClaw, shTrylobiteFrontLeg);
983   make_paw_3d(shTrylobiteRearClaw, shTrylobiteRearLeg);
984   make_abody_3d(shTrylobiteBody, 0);
985   // make_ahead_3d(shTrylobiteHead);
986   make_revolution_cut(shTrylobiteHead, 180, AHEAD - ABODY +g);
987 
988   make_revolution_cut(shShark, 180, WDIM == 2 ? -FLOOR : 0);
989   make_revolution_cut(shPikeBody, 180, WDIM == 2 ? -FLOOR : 0);
990 
991   make_revolution_cut(shGhost, 60, GHOST + g);
992 
993   make_revolution_cut(shEagle, 180, 0, 0.05*S);
994   make_revolution_cut(shHawk, 180, 0, 0.05*S);
995 
996   make_revolution_cut(shTinyBird, 180, 0, 0.025 * S);
997   make_revolution_cut(shTinyShark, 90);
998   make_revolution_cut(shMiniGhost, 60);
999 
1000   make_revolution_cut(shGargoyleWings, 180, 0, 0.05*S);
1001   make_revolution_cut(shGargoyleBody, 180, 0, 0.05*S);
1002   make_revolution_cut(shGadflyWing, 180, 0, 0.05*S);
1003   make_revolution_cut(shBatWings, 180, 0, 0.05*S);
1004   make_revolution_cut(shBatBody, 180, 0, 0.05*S);
1005 
1006   make_revolution_cut(shMouse, 180, -FLOOR);
1007   shift_shape(shMouseLegs, FLOOR - human_height / 200);
1008 
1009   make_revolution_cut(shJelly, 60);
1010   make_revolution(shFoxTail1);
1011   make_revolution(shFoxTail2);
1012   make_revolution(shGadflyBody, 180, 0);
1013   for(int i=0; i<8; i++)
1014     make_revolution(shAsteroid[i], 360);
1015 
1016   make_revolution_cut(shBugLeg, 60);
1017 
1018   make_revolution(shBugArmor, 180, ABODY);
1019   make_revolution_cut(shBugAntenna, 90, ABODY);
1020 
1021   make_revolution(shFrogBody, 180, WDIM == 2 ? g : ABODY);
1022 
1023   make_revolution_cut(shButterflyBody, 180, 0);
1024   make_revolution_cut(shButterflyWing, 180, 0, 0.05*S);
1025   finishshape();
1026 
1027   DEBB(DF_POLY, ("animatebirds"));
1028   animate_bird(shEagle, shAnimatedEagle, 0.05*S);
1029   animate_bird(shTinyBird, shAnimatedTinyEagle, 0.05*S/2);
1030 
1031   animate_bird(shButterflyWing, shAnimatedButterfly, 0);
1032   animate_bird(shGadflyWing, shAnimatedGadfly, 0);
1033   animate_bird(shHawk, shAnimatedHawk, 0.05*S);
1034   animate_bird(shGargoyleWings, shAnimatedGargoyle, 0.05*S);
1035   animate_bird(shGargoyleBody, shAnimatedGargoyle2, 0.05*S);
1036   animate_bird(shBatWings, shAnimatedBat, 0.05*S);
1037   animate_bird(shBatBody, shAnimatedBat2, 0.05*S);
1038 
1039   DEBB(DF_POLY, ("disablers"));
1040 
1041   disable(shWolfRearLeg);
1042   disable(shWolfFrontLeg);
1043   disable(shDogRearLeg);
1044   disable(shDogFrontLeg);
1045   disable(shReptileFrontLeg);
1046   disable(shReptileRearLeg);
1047   disable(shTrylobiteFrontLeg);
1048   disable(shTrylobiteRearLeg);
1049   disable(shPFace);
1050   disable(shJiangShi);
1051 
1052   disable(shFrogFrontLeg);
1053   disable(shFrogRearLeg);
1054   disable(shFrogRearLeg2);
1055   disable(shFrogJumpLeg);
1056 
1057   make_revolution_cut(shDragonSegment, 60, g);
1058   make_revolution_cut(shDragonHead, 60, g);
1059   make_revolution_cut(shDragonTail, 60, g);
1060   make_revolution_cut(shWormSegment, 60, g);
1061   make_revolution_cut(shSmallWormSegment, 60, g);
1062   make_revolution_cut(shWormHead, 60, g);
1063   make_revolution_cut(shWormTail, 60, g);
1064   make_revolution_cut(shSmallWormTail, 60, g);
1065   make_revolution_cut(shTentHead, 60, g);
1066   make_revolution_cut(shKrakenHead, 60, -FLOOR);
1067   make_revolution_cut(shSeaTentacle, 60, -FLOOR);
1068   make_revolution_cut(shDragonLegs, 60, g);
1069   make_revolution_cut(shDragonWings, 60, g);
1070   disable(shDragonNostril);
1071 
1072   make_head_only();
1073 
1074   DEBB(DF_POLY, ("balls"));
1075   make_ball(shDisk, orbsize*.2, 2);
1076   make_ball(shHeptaMarker, zhexf*.2, 1);
1077   make_ball(shSnowball, zhexf*.1, 1);
1078   if(euclid) {
1079     make_ball(shSun, 0.5, 2);
1080     make_euclidean_sky();
1081     }
1082   else
1083     make_star(shSun, 3);
1084   make_star(shNightStar, 0.75);
1085 
1086   if(WDIM == 2) {
1087     for(int i=0; i<3; i++) {
1088       clone_shape(shHalfFloor[i], shHalfFloor[i+3]);
1089       shift_shape_orthogonally(shHalfFloor[i], FLOOR - human_height * .007);
1090       shift_shape_orthogonally(shHalfFloor[i+3], WALL + human_height * .007);
1091       }
1092     }
1093 
1094   shift_shape(shBoatOuter, FLOOR);
1095   shift_shape(shBoatInner, (FLOOR+LAKE)/2);
1096 
1097   for(int i=0; i<14; i++)
1098     shift_shape(shTriheptaSpecial[i], FLOOR);
1099 
1100   shift_shape_orthogonally(shBigCarpet1, FLOOR - human_height * 1/40);
1101   shift_shape_orthogonally(shBigCarpet2, FLOOR - human_height * 2/40);
1102   shift_shape_orthogonally(shBigCarpet3, FLOOR - human_height * 3/40);
1103   for(int a=0; a<5; a++) for(int b=0; b<4; b++)
1104     shift_shape(shReptile[a][b], FLOOR - human_height * min(b, 2) / 40);
1105 
1106   shift_shape(shMineMark[0], FLOOR - human_height * 1/40);
1107   shift_shape(shMineMark[1], FLOOR - human_height * 1/40);
1108 
1109   for(int a=0; a<5; a++) shift_shape(shZebra[a], FLOOR);
1110 
1111   auto tortz = [] (int t) {
1112     if(t == 0) return 2;
1113     else if(t < 8) return 3;
1114     else if(t == 13) return 2;
1115     else return 1;
1116     };
1117 
1118   for(int t=0; t<13; t++) for(int u=0; u<4; u++)
1119     shift_shape(shTortoise[t][u], FLOOR - human_height * tortz(t) / 120);
1120 
1121   make_revolution_cut(shStatue, 60);
1122 
1123   shift_shape(shThorns, FLOOR - human_height * 1/40);
1124   clone_shape(shRose, shRoseItem);
1125   shift_shape(shRose, FLOOR - human_height * 1/20);
1126 
1127   DEBB(DF_POLY, ("slime"));
1128   bshape(shSlime, PPR::MONSTER_BODY);
1129   hyperpoint tip = xtangent(1);
1130   hyperpoint atip = xtangent(-1);
1131   ld z = 63.43 * degree;
1132   for(int i=0; i<5; i++) {
1133     auto a = cspin(1, 2, (72 * i   ) * degree) * spin(z) * xtangent(1);
1134     auto b = cspin(1, 2, (72 * i-72) * degree) * spin(z) * xtangent(1);
1135     auto c = cspin(1, 2, (72 * i+36) * degree) * spin(M_PI-z) * xtangent(1);
1136     auto d = cspin(1, 2, (72 * i-36) * degree) * spin(M_PI-z) * xtangent(1);
1137     slimetriangle(tip, a, b, 1, 0);
1138     slimetriangle(a, b, c, 1, 0);
1139     slimetriangle(b, c, d, 1, 0);
1140     slimetriangle(c, d, atip, 1, 0);
1141     }
1142   last->flags |= POLY_TRIANGLES;
1143   add_texture(*last);
1144   if(WDIM == 2) shift_last_straight(FLOOR);
1145   finishshape();
1146   shJelly = shSlime;
1147 
1148   shift_shape(shMagicSword, ABODY);
1149   shift_shape(shMagicShovel, ABODY);
1150 
1151   DEBB(DF_POLY, ("eyes"));
1152   adjust_eye(shSlimeEyes, shSlime, FLATEYE, 0, 2, 2);
1153   adjust_eye(shGhostEyes, shGhost, GHOST, GHOST, 2, WDIM == 2 ? 2 : 4);
1154   adjust_eye(shMiniEyes, shMiniGhost, GHOST, GHOST, 2, 2);
1155   adjust_eye(shWormEyes, shWormHead, 0, 0, 2, 4);
1156   adjust_eye(shDragonEyes, shDragonHead, 0, 0, 2, 4);
1157 
1158   adjust_eye(shKrakenEye, shKrakenHead, 0, 0, 1);
1159   adjust_eye(shKrakenEye2, shKrakenEye, 0, 0, 1, 2);
1160 
1161   shRatEye1 = shWolf1;
1162   shRatEye2 = shWolf2;
1163   shRatEye3 = shWolf3;
1164 
1165   adjust_eye(shWolf1, shDogHead, AHEAD, AHEAD, 1);
1166   adjust_eye(shWolf2, shDogHead, AHEAD, AHEAD, 1);
1167   for(int i=0; i<shWolf1.e-shWolf1.s; i++)
1168     hpc[shWolf2.s+i] = MirrorY * hpc[shWolf1.s+i];
1169   adjust_eye(shWolf3, shDogHead, AHEAD, AHEAD, 1);
1170   adjust_eye(shFamiliarEye, shWolfHead, AHEAD, AHEAD, 1);
1171 
1172   adjust_eye(shRatEye1, shRatHead, AHEAD, AHEAD, 1);
1173   adjust_eye(shRatEye2, shRatHead, AHEAD, AHEAD, 1);
1174   for(int i=shRatEye3.s; i<shRatEye3.e; i++) hpc[i] = xpush(-scalefactor * 0.02) * hpc[i];
1175   adjust_eye(shRatEye3, shRatHead, AHEAD, AHEAD, 1);
1176 
1177   adjust_eye(shWolfEyes, shWolfHead, AHEAD, AHEAD, 1);
1178 
1179   adjust_eye(shPikeEye, shPikeBody, 0, 0, 1);
1180   adjust_eye(shFrogEye, shFrogBody, 0, 0, 1);
1181 
1182   adjust_eye(shReptileEye, shReptileHead, AHEAD, AHEAD, 1);
1183   adjust_eye(shGadflyEye, shGadflyBody, 0, 0, 1);
1184 
1185   adjust_eye(shSkullEyes, shPHeadOnly, HEAD1, HEAD, 2, 2);
1186   shSkullEyes.tinf = NULL;
1187 
1188   adjust_eye(shMouseEyes, shMouse, FLOOR, FLOOR, 2, 1);
1189 
1190   shift_shape(shRatTail, zc(0.5) - LEG);
1191   for(int i=shRatTail.s; i<shRatTail.e; i++) hpc[i] = xpush(-scalefactor * 0.1) * hpc[i];
1192 
1193   shift_shape(shSemiFloorShadow, FLOOR - human_height / 100);
1194   shift_shape(shSemiFloor[0], WALL);
1195 
1196   bshape(shPalaceGate, PPR::WALL);
1197   for(int i=0; i<4; i++) {
1198     ld x = -0.219482 + (0.135153 + 0.219482) * (i+.5) / 4;
1199     for(int j=0; j<12; j++) {
1200       hyperpoint left = xpush(x) * xspinpush0(j * 30 * degree, 0.02);
1201       hyperpoint right = xpush(x) * xspinpush0((j+1) * 30 * degree, 0.02);
1202       hpcpush(orthogonal_move(left, FLOOR));
1203       hpcpush(orthogonal_move(right, FLOOR));
1204       hpcpush(orthogonal_move(left, WALL));
1205       hpcpush(orthogonal_move(right, FLOOR));
1206       hpcpush(orthogonal_move(left, WALL));
1207       hpcpush(orthogonal_move(right, WALL));
1208       }
1209     }
1210   shPalaceGate.flags |= POLY_TRIANGLES;
1211 
1212   for(int i=0; i<3; i++) {
1213 
1214     array<hpcshape*,3> sh = make_array(&shBigCarpet1, &shBigCarpet2, &shBigCarpet3);
1215 
1216     bshape(*sh[i], PPR::GFLOORa);
1217     for(int t=0; t<S7; t++) {
1218       dynamicval<int> dv(vid.texture_step, 16);
1219       texture_order([&] (ld x, ld y) {
1220         ld z = 1-x-y;
1221         ld rad = 2.1 - i * 0.2;
1222         hyperpoint hx = ddi(t*12, -zhexf*rad) * C0;
1223         hyperpoint hy = ddi(t*12+12, -zhexf*rad) * C0;
1224         hyperpoint hz = C0;
1225         hyperpoint h = hx * x + hy * y + hz * z;
1226         h = mid(h, h);
1227         h = orthogonal_move(h, FLOOR - human_height * (i+2.5) / 100 * (x+y+1)/2);
1228         hpcpush(h);
1229         });
1230       }
1231 
1232     sh[i]->flags |= POLY_TRIANGLES;
1233     }
1234 
1235   finishshape();
1236   }
1237 
generate_pipe(ld length,ld width)1238 hpcshape& geometry_information::generate_pipe(ld length, ld width) {
1239   int id = int(length * 17 + .5) + int(157003 * log(width+.001));
1240   if(shPipe.count(id)) return shPipe[id];
1241   hpcshape& pipe = shPipe[id];
1242   println(hlog, "generating pipe of length ", length, " and width ", width);
1243   bshape(pipe, PPR::WALL);
1244 
1245   const int MAX_X = 8;
1246   const int MAX_R = 20;
1247   auto at = [length, width] (int i, int a) {
1248     return xpush(i * length / MAX_X) * cspin(1, 2, 360 * degree * a / MAX_R) * ypush0(width);
1249     };
1250   for(int i=0; i<MAX_X; i++) {
1251     for(int a=0; a<MAX_R; a++) {
1252       hpcpush(at(i, a));
1253       hpcpush(at(i, a+1));
1254       hpcpush(at(i+1, a));
1255       hpcpush(at(i+1, a+1));
1256       hpcpush(at(i+1, a));
1257       hpcpush(at(i, a+1));
1258       }
1259     }
1260 
1261   for(int a=0; a<MAX_R; a++) {
1262     hpcpush(at(MAX_X, a));
1263     hpcpush(at(MAX_X, a+1));
1264     hpcpush(xpush0(length));
1265     hpcpush(at(MAX_X, a+1));
1266     hpcpush(at(MAX_X, a));
1267     hpcpush(C0);
1268     }
1269 
1270   last->flags |= POLY_TRIANGLES | POLY_PRINTABLE;
1271   add_texture(*last);
1272   finishshape();
1273   extra_vertices();
1274   return pipe;
1275   }
1276 
1277 #undef S
1278 #undef SH
1279 #undef revZ
1280 #endif
1281 
1282 }
1283