1 // Hyperbolic Rogue -- basic geometry
2 // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
3
4 /** \file geometry.cpp
5 * \brief Calculation of basic, and less basic, constants in each geometry
6 */
7
8 #include "hyper.h"
9 namespace hr {
10
11 #if HDR
12 struct usershapelayer {
13 vector<hyperpoint> list;
14 bool sym;
15 int rots;
16 color_t color;
17 hyperpoint shift, spin;
18 ld zlevel;
19 int texture_offset;
20 PPR prio;
21 };
22
23 extern int usershape_changes;
24
25 static const int USERLAYERS = 32;
26
27 struct usershape { usershapelayer d[USERLAYERS]; };
28
29 struct hpcshape {
30 int s, e;
31 PPR prio;
32 int flags;
33 hyperpoint intester;
34 struct basic_textureinfo *tinf;
35 int texture_offset;
36 int shs, she;
clearhr::hpcshape37 void clear() { s = e = shs = she = texture_offset = 0; prio = PPR::ZERO; tinf = NULL; flags = 0; }
38 };
39
40 #define SIDE_SLEV 0
41 #define SIDE_WTS3 3
42 #define SIDE_WALL 4
43 #define SIDE_LAKE 5
44 #define SIDE_LTOB 6
45 #define SIDE_BTOI 7
46 #define SIDE_SKY 8
47 #define SIDE_HIGH 9
48 #define SIDE_HIGH2 10
49 #define SIDE_ASHA 11
50 #define SIDE_BSHA 12
51 #define SIDEPARS 13
52
53 /** GOLDBERG_BITS controls the size of tables for Goldberg: 2*(x+y) should be below (1<<GOLDBERG_BITS) */
54
55 #ifndef GOLDBERG_BITS
56 #define GOLDBERG_BITS 5
57 #endif
58
59 static const int GOLDBERG_LIMIT = (1<<GOLDBERG_BITS);
60 static const int GOLDBERG_MASK = (GOLDBERG_LIMIT-1);
61
62 #ifndef BADMODEL
63 #define BADMODEL 0
64 #endif
65
66 #ifndef WINGS
67 static const int WINGS = (BADMODEL ? 1 : 4);
68 #endif
69
70 typedef array<hpcshape, WINGS+1> hpcshape_animated;
71
72 extern vector<hpcshape> shPlainWall3D, shWireframe3D, shWall3D, shMiniWall3D;
73
74 struct floorshape {
75 bool is_plain;
76 int shapeid;
77 int id;
78 int pstrength; // pattern strength in 3D
79 int fstrength; // frame strength in 3D
80 PPR prio;
81 vector<hpcshape> b, shadow, side[SIDEPARS], levels[SIDEPARS], cone[2];
82 vector<vector<hpcshape>> gpside[SIDEPARS];
floorshapehr::floorshape83 floorshape() { prio = PPR::FLOOR; pstrength = fstrength = 10; }
84 };
85
86 struct plain_floorshape : floorshape {
87 ld rad0, rad1;
configurehr::plain_floorshape88 void configure(ld r0, ld r1) { rad0 = r0; rad1 = r1; }
89 };
90
91 extern vector<ld> equal_weights;
92
93 // noftype: 0 (shapeid2 is heptagonal or just use shapeid1), 1 (shapeid2 is pure heptagonal), 2 (shapeid2 is Euclidean), 3 (shapeid2 is hexagonal)
94 struct escher_floorshape : floorshape {
95 int shapeid0, shapeid1, noftype, shapeid2;
96 ld scale;
97 };
98
99 struct basic_textureinfo {
100 int texture_id;
101 vector<glvertex> tvertices;
102 vector<glvertex> colors;
103 };
104
105 /** additional modules can add extra shapes etc. */
106 struct gi_extension {
~gi_extensionhr::gi_extension107 virtual ~gi_extension() {}
108 };
109
110 /** both for 'heptagon' 3D cells and subdivided 3D cells */
111 struct subcellshape {
112 /** \brief raw coordinates of vertices of all faces */
113 vector<vector<hyperpoint>> faces;
114 /** \brief raw coordinates of all vertices in one vector */
115 vector<hyperpoint> vertices_only;
116 /** \brief cooked coordinates of vertices of all faces, computed from faces as: from_cellcenter * final_coords(v) */
117 vector<vector<hyperpoint>> faces_local;
118 /** \brief cooked coordinates of all vertices in one vector */
119 vector<hyperpoint> vertices_only_local;
120 /** \brief weights -- used to generate wall shapes in some geometries, empty otherwise */
121 vector<vector<double>> weights;
122 /** the center of every raw face */
123 vector<hyperpoint> face_centers;
124 vector<vector<char>> dirdist;
125 hyperpoint cellcenter;
126 transmatrix to_cellcenter;
127 transmatrix from_cellcenter;
128 /** \brief for adjacent directions a,b, next_dir[a][b] is the next direction adjacent to a, in (counter?)clockwise order from b */
129 vector<vector<char>> next_dir;
130 /** useful in product geometries */
131 vector<hyperpoint> walltester;
132
133 /** compute all the properties based on `faces`, for the main heptagon cellshape */
134 void compute_hept();
135
136 /** compute all the properties based on `faces`, for subcells */
137 void compute_sub();
138
139 /** common part of compute_hept and compute_sub */
140 void compute_common();
141 };
142
143 /** basic geometry parameters */
144 struct geometry_information {
145
146 /** distance from heptagon center to another heptagon center */
147 ld tessf;
148
149 /** distance from heptagon center to adjacent cell center (either hcrossf or tessf) */
150 ld crossf;
151
152 /** distance from heptagon center to small heptagon vertex */
153 ld hexf;
154
155 /** distance from heptagon center to big heptagon vertex */
156 ld hcrossf;
157
158 /** distance between adjacent hexagon vertices */
159 ld hexhexdist;
160
161 /** distance between hexagon vertex and hexagon center */
162 ld hexvdist;
163
164 /** distance between heptagon vertex and hexagon center (either hcrossf or something else) */
165 ld hepvdist;
166
167 /** distance from heptagon center to heptagon vertex (either hexf or hcrossf) */
168 ld rhexf;
169
170 /** basic parameters for 3D geometries */
171 map<int, int> close_distances;
172
173 int loop, face, schmid;
174
175 transmatrix spins[32], adjmoves[32];
176
177 unique_ptr<struct subcellshape> heptshape;
178 vector<struct subcellshape> subshapes;
179
180 ld adjcheck;
181 ld strafedist;
182
183 ld ultra_mirror_dist, ultra_material_part, ultra_mirror_part;
184
185 vector<transmatrix> ultra_mirrors;
186
187 vector<pair<string, string> > rels;
188 int xp_order, r_order, rx_order;
189
190 transmatrix full_X, full_R, full_P;
191
192 /** for 2D geometries */
193 vector<transmatrix> heptmove, hexmove, invhexmove;
194
195 int base_distlimit;
196
197 /** size of the Sword (from Orb of the Sword), used in the shmup mode */
198 ld sword_size;
199 /** scale factor for the graphics of most things*/
200 ld scalefactor;
201 ld orbsize, floorrad0, floorrad1, zhexf;
202 ld corner_bonus;
203 ld hexshift;
204 ld asteroid_size[8];
205 ld wormscale;
206 ld tentacle_length;
207 /** level in product geometries */
208 ld plevel;
209 /** level for a z-step */
210 int single_step;
211 /** the number of levels in PSL */
212 int psl_steps;
213
214 /** for binary tilings */
215 transmatrix direct_tmatrix[14];
216 transmatrix inverse_tmatrix[14];
217
218 /** a bitmask for hr::bt::use_direct_for */
219 int use_direct;
220
221 /** various parameters related to the 3D view */
222 ld INFDEEP, BOTTOM, HELLSPIKE, LAKE, WALL, FLOOR, STUFF,
223 SLEV[4], FLATEYE,
224 LEG0, LEG1, LEG, LEG3, GROIN, GROIN1, GHOST,
225 BODY, BODY1, BODY2, BODY3,
226 NECK1, NECK, NECK3, HEAD, HEAD1, HEAD2, HEAD3,
227 ALEG0, ALEG, ABODY, AHEAD, BIRD, LOWSKY, SKY, HIGH, HIGH2,
228 SHALLOW;
229 ld human_height, slev;
230
231 ld eyelevel_familiar, eyelevel_human, eyelevel_dog;
232
233 #if CAP_SHAPES
234 hpcshape
235 shSemiFloorSide[SIDEPARS],
236 shBFloor[2],
237 shWave[8][2],
238 shCircleFloor,
239 shBarrel,
240 shWall[2], shMineMark[2], shBigMineMark[2], shFan,
241 shZebra[5],
242 shSwitchDisk,
243 shTower[11],
244 shEmeraldFloor[6],
245 shSemiFeatherFloor[2],
246 shSemiFloor[2], shSemiBFloor[2], shSemiFloorShadow,
247 shMercuryBridge[2],
248 shTriheptaSpecial[14],
249 shCross, shGiantStar[2], shLake, shMirror,
250 shHalfFloor[6], shHalfMirror[3],
251 shGem[2], shStar, shDisk, shDiskT, shDiskS, shDiskM, shDiskSq, shRing,
252 shTinyBird, shTinyShark,
253 shEgg,
254 shSpikedRing, shTargetRing, shSawRing, shGearRing, shPeaceRing, shHeptaRing,
255 shSpearRing, shLoveRing,
256 shFrogRing,
257 shPowerGearRing, shProtectiveRing, shTerraRing, shMoveRing, shReserved4, shMoonDisk,
258 shDaisy, shTriangle, shNecro, shStatue, shKey, shWindArrow,
259 shGun,
260 shFigurine, shTreat,
261 shElementalShard,
262 // shBranch,
263 shIBranch, shTentacle, shTentacleX, shILeaf[3],
264 shMovestar,
265 shWolf, shYeti, shDemon, shGDemon, shEagle, shGargoyleWings, shGargoyleBody,
266 shFoxTail1, shFoxTail2,
267 shDogBody, shDogHead, shDogFrontLeg, shDogRearLeg, shDogFrontPaw, shDogRearPaw,
268 shDogTorso,
269 shHawk,
270 shCatBody, shCatLegs, shCatHead, shFamiliarHead, shFamiliarEye,
271 shWolf1, shWolf2, shWolf3,
272 shRatEye1, shRatEye2, shRatEye3,
273 shDogStripes,
274 shPBody, shPSword, shPKnife,
275 shFerocityM, shFerocityF,
276 shHumanFoot, shHumanLeg, shHumanGroin, shHumanNeck, shSkeletalFoot, shYetiFoot,
277 shMagicSword, shMagicShovel, shSeaTentacle, shKrakenHead, shKrakenEye, shKrakenEye2,
278 shArrow,
279 shPHead, shPFace, shGolemhead, shHood, shArmor,
280 shAztecHead, shAztecCap,
281 shSabre, shTurban1, shTurban2, shVikingHelmet, shRaiderHelmet, shRaiderArmor, shRaiderBody, shRaiderShirt,
282 shWestHat1, shWestHat2, shGunInHand,
283 shKnightArmor, shKnightCloak, shWightCloak,
284 shGhost, shEyes, shSlime, shJelly, shJoint, shWormHead, shTentHead, shShark, shWormSegment, shSmallWormSegment, shWormTail, shSmallWormTail,
285 shSlimeEyes, shDragonEyes, shWormEyes, shGhostEyes,
286 shMiniGhost, shMiniEyes,
287 shHedgehogBlade, shHedgehogBladePlayer,
288 shWolfBody, shWolfHead, shWolfLegs, shWolfEyes,
289 shWolfFrontLeg, shWolfRearLeg, shWolfFrontPaw, shWolfRearPaw,
290 shFemaleBody, shFemaleHair, shFemaleDress, shWitchDress,
291 shWitchHair, shBeautyHair, shFlowerHair, shFlowerHand, shSuspenders, shTrophy,
292 shBugBody, shBugArmor, shBugLeg, shBugAntenna,
293 shPickAxe, shPike, shFlailBall, shFlailTrunk, shFlailChain, shHammerHead,
294 shBook, shBookCover, shGrail,
295 shBoatOuter, shBoatInner, shCompass1, shCompass2, shCompass3,
296 shKnife, shTongue, shFlailMissile, shTrapArrow,
297 shPirateHook, shPirateHood, shEyepatch, shPirateX,
298 // shScratch,
299 shHeptaMarker, shSnowball, shHugeDisk, shSun, shNightStar, shEuclideanSky,
300 shSkeletonBody, shSkull, shSkullEyes, shFatBody, shWaterElemental,
301 shPalaceGate, shFishTail,
302 shMouse, shMouseLegs, shMouseEyes,
303 shPrincessDress, shPrinceDress,
304 shWizardCape1, shWizardCape2,
305 shBigCarpet1, shBigCarpet2, shBigCarpet3,
306 shGoatHead, shRose, shRoseItem, shThorns,
307 shRatHead, shRatTail, shRatEyes, shRatCape1, shRatCape2,
308 shWizardHat1, shWizardHat2,
309 shTortoise[13][6],
310 shDragonLegs, shDragonTail, shDragonHead, shDragonSegment, shDragonNostril,
311 shDragonWings,
312 shSolidBranch, shWeakBranch, shBead0, shBead1,
313 shBatWings, shBatBody, shBatMouth, shBatFang, shBatEye,
314 shParticle[16], shAsteroid[8],
315 shReptile[5][4],
316 shReptileBody, shReptileHead, shReptileFrontFoot, shReptileRearFoot,
317 shReptileFrontLeg, shReptileRearLeg, shReptileTail, shReptileEye,
318
319 shTrylobite, shTrylobiteHead, shTrylobiteBody,
320 shTrylobiteFrontLeg, shTrylobiteRearLeg, shTrylobiteFrontClaw, shTrylobiteRearClaw,
321
322 shBullBody, shBullHead, shBullHorn, shBullRearHoof, shBullFrontHoof,
323
324 shButterflyBody, shButterflyWing, shGadflyBody, shGadflyWing, shGadflyEye,
325
326 shTerraArmor1, shTerraArmor2, shTerraArmor3, shTerraHead, shTerraFace,
327 shJiangShi, shJiangShiDress, shJiangShiCap1, shJiangShiCap2,
328
329 shPikeBody, shPikeEye,
330
331 shAsymmetric,
332
333 shPBodyOnly, shPBodyArm, shPBodyHand, shPHeadOnly,
334
335 shDodeca;
336
337 hpcshape shFrogRearFoot, shFrogFrontFoot, shFrogRearLeg, shFrogFrontLeg, shFrogRearLeg2, shFrogBody, shFrogEye, shFrogStripe, shFrogJumpFoot, shFrogJumpLeg;
338
339 hpcshape_animated
340 shAnimatedEagle, shAnimatedTinyEagle, shAnimatedGadfly, shAnimatedHawk, shAnimatedButterfly,
341 shAnimatedGargoyle, shAnimatedGargoyle2, shAnimatedBat, shAnimatedBat2;
342
343 hpcshape shTinyArrow;
344
345 hpcshape shReserved[16];
346
347 int orb_inner_ring; //< for shDisk* shapes, the number of vertices in the inner ring
348 int res1, res2;
349
350 map<int, hpcshape> shPipe;
351
352 vector<hpcshape> shPlainWall3D, shWireframe3D, shWall3D, shMiniWall3D;
353 vector<hyperpoint> walltester;
354
355 vector<int> wallstart;
356 vector<transmatrix> raywall;
357
358 vector<struct plain_floorshape*> all_plain_floorshapes;
359 vector<struct escher_floorshape*> all_escher_floorshapes;
360
361 plain_floorshape
362 shFloor,
363 shMFloor, shMFloor2, shMFloor3, shMFloor4, shFullFloor,
364 shBigTriangle, shTriheptaFloor, shBigHepta;
365
366 escher_floorshape
367 shStarFloor, shCloudFloor, shCrossFloor, shChargedFloor,
368 shSStarFloor, shOverFloor, shTriFloor, shFeatherFloor,
369 shBarrowFloor, shNewFloor, shTrollFloor, shButterflyFloor,
370 shLavaFloor, shLavaSeabed, shSeabed, shCloudSeabed,
371 shCaveSeabed, shPalaceFloor, shDemonFloor, shCaveFloor,
372 shDesertFloor, shPowerFloor, shRoseFloor, shSwitchFloor,
373 shTurtleFloor, shRedRockFloor[3], shDragonFloor;
374
375 ld dlow_table[SIDEPARS], dhi_table[SIDEPARS], dfloor_table[SIDEPARS];
376
377 int prehpc;
378 vector<hyperpoint> hpc;
379 bool first;
380
381 bool validsidepar[SIDEPARS];
382
383 vector<glvertex> ourshape;
384 #endif
385
386 hpcshape shFullCross[2];
387 hpcshape *last;
388
389 int SD3, SD6, SD7, S12, S14, S21, S28, S42, S36, S84;
390
391 vector<pair<int, cell*>> walloffsets;
392
393 vector<array<int, 3>> symmetriesAt;
394
395 struct cellrotation_t {
396 transmatrix M;
397 vector<int> mapping;
398 int inverse_id;
399 };
400
401 vector<cellrotation_t> cellrotations;
402
403 #ifndef SCALETUNER
404 static constexpr
405 #endif
406 double bscale7 = 1, brot7 = 0, bscale6 = 1, brot6 = 0;
407
408 vector<hpcshape*> allshapes;
409
410 transmatrix shadowmulmatrix;
411
412 map<usershapelayer*, hpcshape> ushr;
413
414 void prepare_basics();
415 void prepare_compute3();
416 void prepare_shapes();
417 void prepare_usershapes();
418
419 void hpcpush(hyperpoint h);
420 void hpcsquare(hyperpoint h1, hyperpoint h2, hyperpoint h3, hyperpoint h4);
421 void chasmifyPoly(double fac, double fac2, int k);
422 void shift(hpcshape& sh, double dx, double dy, double dz);
423 void initPolyForGL();
424 void extra_vertices();
425 transmatrix ddi(int a, ld x);
426 void drawTentacle(hpcshape &h, ld rad, ld var, ld divby);
427 hyperpoint hpxyzsc(double x, double y, double z);
428 hyperpoint turtlevertex(int u, double x, double y, double z);
429
430 void bshape(hpcshape& sh, PPR prio);
431 void finishshape();
432 void bshape(hpcshape& sh, PPR prio, double shzoom, int shapeid, double bonus = 0, flagtype flags = 0);
433
434 void copyshape(hpcshape& sh, hpcshape& orig, PPR prio);
435 void zoomShape(hpcshape& old, hpcshape& newsh, double factor, PPR prio);
436 void pushShape(usershapelayer& ds);
437 void make_sidewalls();
438 void procedural_shapes();
439 void make_wall(int id, const vector<hyperpoint> vertices, vector<ld> weights = equal_weights);
440
441 void reserve_wall3d(int i);
442 void compute_cornerbonus();
443 void create_wall3d();
444 void configure_floorshapes();
445
446 void init_floorshapes();
447 void bshape2(hpcshape& sh, PPR prio, int shapeid, struct matrixlist& m);
448 void bshape_regular(floorshape &fsh, int id, int sides, ld shift, ld size, cell *model);
449 void generate_floorshapes_for(int id, cell *c, int siid, int sidir);
450 void generate_floorshapes();
451 void make_floor_textures_here();
452
453 vector<hyperpoint> get_shape(hpcshape sh);
454 void add_cone(ld z0, const vector<hyperpoint>& vh, ld z1);
455 void add_prism_sync(ld z0, vector<hyperpoint> vh0, ld z1, vector<hyperpoint> vh1);
456 void add_prism(ld z0, vector<hyperpoint> vh0, ld z1, vector<hyperpoint> vh1);
457 void shift_last(ld z);
458 void shift_shape(hpcshape& sh, ld z);
459 void shift_shape_orthogonally(hpcshape& sh, ld z);
460 void add_texture(hpcshape& sh);
461 void make_ha_3d(hpcshape& sh, bool isarmor, ld scale);
462 void make_humanoid_3d(hpcshape& sh);
463 void addtri(array<hyperpoint, 3> hs, int kind);
464 void make_armor_3d(hpcshape& sh, int kind = 1);
465 void make_foot_3d(hpcshape& sh);
466 void make_head_only();
467 void make_head_3d(hpcshape& sh);
468 void make_paw_3d(hpcshape& sh, hpcshape& legsh);
469 void make_abody_3d(hpcshape& sh, ld tail);
470 void make_ahead_3d(hpcshape& sh);
471 void make_skeletal(hpcshape& sh, ld push = 0);
472 void make_revolution(hpcshape& sh, int mx = 180, ld push = 0);
473 void make_revolution_cut(hpcshape &sh, int each = 180, ld push = 0, ld width = 99);
474 void clone_shape(hpcshape& sh, hpcshape& target);
475 void animate_bird(hpcshape& orig, hpcshape_animated& animated, ld body);
476 void slimetriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev);
477 void balltriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev);
478 void make_ball(hpcshape& sh, ld rad, int lev);
479 void make_star(hpcshape& sh, ld rad);
480 void make_euclidean_sky();
481 void adjust_eye(hpcshape& eye, hpcshape head, ld shift_eye, ld shift_head, int q, ld zoom=1);
482 void shift_last_straight(ld z);
483 void queueball(const transmatrix& V, ld rad, color_t col, eItem what);
484 void make_shadow(hpcshape& sh);
485 void make_3d_models();
486
487 /* Goldberg parameters */
488 #if CAP_GP
489 struct gpdata_t {
490 vector<array<array<array<transmatrix, 6>, GOLDBERG_LIMIT>, GOLDBERG_LIMIT>> Tf;
491 transmatrix corners;
492 ld alpha;
493 int area;
494 int pshid[3][8][GOLDBERG_LIMIT][GOLDBERG_LIMIT][8];
495 int nextid;
496 };
497 shared_ptr<gpdata_t> gpdata = nullptr;
498 #endif
499
500 int state = 0;
501 int usershape_state = 0;
502
503 /** contains the texture point coordinates for 3D models */
504 basic_textureinfo models_texture;
505
geometry_informationhr::geometry_information506 geometry_information() { last = NULL; }
507
require_basicshr::geometry_information508 void require_basics() { if(state & 1) return; state |= 1; prepare_basics(); }
require_shapeshr::geometry_information509 void require_shapes() { if(state & 2) return; state |= 2; prepare_shapes(); }
require_usershapeshr::geometry_information510 void require_usershapes() { if(usershape_state == usershape_changes) return; usershape_state = usershape_changes; prepare_usershapes(); }
511 int timestamp;
512
513 hpcshape& generate_pipe(ld length, ld width);
514
515 map<string, unique_ptr<gi_extension>> ext;
516 };
517 #endif
518
get_hsh()519 EX subcellshape& get_hsh() {
520 if(!cgi.heptshape) cgi.heptshape = (unique_ptr<subcellshape>) (new subcellshape);
521 return *cgi.heptshape;
522 }
523
add_wall(int i,const vector<hyperpoint> & h)524 EX void add_wall(int i, const vector<hyperpoint>& h) {
525 auto& f = get_hsh().faces;
526 if(isize(f) <= i) f.resize(i+1);
527 f[i] = h;
528 }
529
530 /** values of hcrossf and hexf for the standard geometry. Since polygons are
531 * usually drawn in this geometry, the scale in other geometries is usually
532 * based on comparing these values to the values in the other geometry.
533 */
534
535 #if HDR
536 static const ld hcrossf7 = 0.620672, hexf7 = 0.378077, tessf7 = 1.090550, hexhexdist7 = 0.566256;
537 #endif
538
scale_used()539 EX bool scale_used() { return (shmup::on && geometry == gNormal && BITRUNCATED) ? (cheater || autocheat) : true; }
540
is_subcube_based(eVariation var)541 EX bool is_subcube_based(eVariation var) {
542 return among(var, eVariation::subcubes, eVariation::dual_subcubes, eVariation::bch, eVariation::bch_oct);
543 }
544
is_reg3_variation(eVariation var)545 EX bool is_reg3_variation(eVariation var) {
546 return var == eVariation::coxeter;
547 }
548
prepare_basics()549 void geometry_information::prepare_basics() {
550
551 DEBBI(DF_INIT | DF_POLY | DF_GEOM, ("prepare_basics"));
552
553 hexshift = 0;
554
555 ld ALPHA = 2 * M_PI / S7;
556
557 ld fmin, fmax;
558
559 ld s3, beta;
560
561 heptshape = nullptr;
562
563 if(arcm::in() && !prod)
564 ginf[gArchimedean].cclass = gcHyperbolic;
565
566 dynamicval<eVariation> gv(variation, variation);
567 bool inv = INVERSE;
568 if(INVERSE) {
569 variation = gp::variation_for(gp::param);
570 println(hlog, "bitruncated = ", BITRUNCATED);
571 }
572
573 if(hybri) {
574 auto t = this;
575 ld d = prod ? 1 : 2;
576 hybrid::in_underlying_geometry([&] {
577 t->rhexf = cgi.rhexf / d;
578 t->hexf = cgi.hexf / d;
579 t->crossf = cgi.crossf / d;
580 t->hcrossf = cgi.crossf / d;
581 t->tessf = cgi.tessf / d;
582 t->hexvdist = cgi.hexvdist / d;
583 t->hexhexdist = hdist(xpush0(cgi.hcrossf), xspinpush0(M_PI*2/S7, cgi.hcrossf)) / d;
584 t->base_distlimit = cgi.base_distlimit-1;
585 });
586 goto hybrid_finish;
587 }
588
589 if((sphere || hyperbolic) && WDIM == 3 && !bt::in()) {
590 rhexf = hexf = 0.378077;
591 crossf = hcrossf = 0.620672;
592 tessf = 1.090550;
593 hexhexdist = 0.566256;
594 goto finish;
595 }
596
597 s3 = S3;
598 if(fake::in() && !arcm::in()) s3 = fake::around;
599
600 beta = (S3 >= OINF && !fake::in()) ? 0 : 2*M_PI/s3;
601
602 tessf = euclid ? 1 : edge_of_triangle_with_angles(beta, M_PI/S7, M_PI/S7);
603
604 if(elliptic && S7 == 4 && !fake::in()) tessf = M_PI/2;
605
606 hcrossf = euclid ? tessf / 2 / sin(M_PI/s3) : edge_of_triangle_with_angles(M_PI/2, M_PI/S7, beta/2);
607
608 if(S3 >= OINF) hcrossf = 10;
609
610 crossf = BITRUNCATED ? hcrossf : tessf;
611
612 fmin = 0, fmax = tessf;
613 for(int p=0; p<100; p++) {
614 ld f = (fmin+fmax) / 2;
615 hyperpoint H = xpush0(f);
616 hyperpoint H1 = spin(2*M_PI/S7) * H;
617 hyperpoint H2 = xpush0(tessf-f);
618 ld v1 = intval(H, H1), v2 = intval(H, H2);
619
620 if(fake::in() && WDIM == 2) {
621 hexvdist = hdist(xpush0(f), xspinpush0(ALPHA/2, hcrossf));
622 v2 = hdist(
623 spin(M_PI/2/S3) * xpush0(hexvdist),
624 spin(-M_PI/2/S3) * xpush0(hexvdist)
625 );
626
627 v1 = hdist(
628 spin(M_PI/S7) * xpush0(f),
629 spin(-M_PI/S7) * xpush0(f)
630 );
631 }
632
633 if(v1 < v2) fmin = f; else fmax = f;
634 }
635 hexf = fmin;
636
637 rhexf = BITRUNCATED ? hexf : hcrossf;
638
639 if(BITRUNCATED && !(S7&1))
640 hexshift = ALPHA/2 + ALPHA * ((S7-1)/2) + M_PI;
641
642 finish:
643
644 heptmove.resize(S7);
645 hexmove.resize(S7);
646 invhexmove.resize(S7);
647
648 for(int d=0; d<S7; d++)
649 heptmove[d] = spin(-d * ALPHA) * xpush(tessf) * spin(M_PI);
650
651 for(int d=0; d<S7; d++)
652 hexmove[d] = spin(hexshift-d * ALPHA) * xpush(-crossf)* spin(M_PI);
653
654 for(int d=0; d<S7; d++) invhexmove[d] = iso_inverse(hexmove[d]);
655
656 hexvdist = hdist(xpush0(hexf), xspinpush0(ALPHA/2, hcrossf));
657
658 hexhexdist = fake::in() ?
659 2 * hdist0(mid(xspinpush0(M_PI/S6, hexvdist), xspinpush0(-M_PI/S6, hexvdist)))
660 : hdist(xpush0(crossf), xspinpush0(M_PI*2/S7, crossf));
661
662 DEBB(DF_GEOM | DF_POLY,
663 (format("S7=%d S6=%d hexf = " LDF" hcross = " LDF" tessf = " LDF" hexshift = " LDF " hexhex = " LDF " hexv = " LDF "\n", S7, S6, hexf, hcrossf, tessf, hexshift,
664 hexhexdist, hexvdist)));
665
666 base_distlimit = ginf[geometry].distlimit[!BITRUNCATED];
667
668 #if CAP_GP
669 gp::compute_geometry(inv);
670 #endif
671 #if CAP_IRR
672 irr::compute_geometry();
673 #endif
674 #if CAP_ARCM
675 if(arcm::in()) {
676 auto& ac = arcm::current_or_fake();
677 if(fake::in()) ac = arcm::current;
678 ac.compute_geometry();
679 crossf = hcrossf7 * ac.scale();
680 hexvdist = ac.scale() * .5;
681 rhexf = ac.scale() * .5;
682 }
683 #endif
684 #if CAP_BT
685 if(bt::in()) hexvdist = rhexf = 1, tessf = 1, scalefactor = 1, crossf = hcrossf7;
686 if(geometry == gHoroRec || kite::in() || sol || nil || nih) hexvdist = rhexf = .5, tessf = .5, scalefactor = .5, crossf = hcrossf7/2;
687 if(bt::in()) scalefactor *= min<ld>(vid.binary_width, 1), crossf *= min<ld>(vid.binary_width, 1);
688 #endif
689 #if CAP_BT && MAXMDIM >= 4
690 if(bt::in()) bt::build_tmatrix();
691 #endif
692 #if MAXMDIM >= 4
693 if(reg3::in()) reg3::generate();
694 if(euc::in(3)) euc::generate();
695 #if CAP_SOLV
696 else if(sn::in()) sn::create_faces();
697 #endif
698 #if CAP_BT
699 else if(bt::in()) bt::create_faces();
700 #endif
701 else if(nil) nilv::create_faces();
702 #endif
703
704 hybrid_finish:
705
706 scalefactor = crossf / hcrossf7;
707 orbsize = crossf;
708
709 if(fake::in() && WDIM == 2) {
710 auto& u = *fake::underlying_cgip;
711 geometry = fake::underlying;
712 ld orig = xpush0(u.hcrossf)[0] / xpush0(u.hcrossf)[GDIM];
713 geometry = gFake;
714 ld our = xpush0(hcrossf)[0] / xpush0(hcrossf)[GDIM];
715 fake::scale = our / orig;
716 // if(debugflags & DF_GEOM)
717 }
718
719 if(fake::in() && WDIM == 3) {
720 auto& u = fake::underlying_cgip;
721 crossf = u->crossf * fake::scale;
722 scalefactor = u->scalefactor * fake::scale;
723 orbsize = u->orbsize * fake::scale;
724 hexf = u->hexf * fake::scale;
725 rhexf = u->rhexf * fake::scale;
726 hexvdist = u->hexvdist * fake::scale;
727 hcrossf = u->hcrossf * fake::scale;
728 }
729
730 if(arb::in()) {
731 auto csc = arb::current_or_slided().cscale;
732 scalefactor = csc;
733 hcrossf = crossf = orbsize = hcrossf7 * csc;
734 hexf = rhexf = hexvdist = csc * arb::current_or_slided().floor_scale;
735 base_distlimit = arb::current.range;
736 }
737
738 if(is_subcube_based(variation)) {
739 scalefactor /= reg3::subcube_count;
740 orbsize /= reg3::subcube_count;
741 }
742
743 if(scale_used()) {
744 scalefactor *= vid.creature_scale;
745 orbsize *= vid.creature_scale;
746 }
747
748 zhexf = BITRUNCATED ? hexf : crossf* .55;
749 if(scale_used()) zhexf *= vid.creature_scale;
750 if(WDIM == 2 && GDIM == 3) zhexf *= 1.5, orbsize *= 1.2;
751
752 floorrad0 = hexvdist* (GDIM == 3 ? 1 : 0.92);
753 floorrad1 = rhexf * (GDIM == 3 ? 1 : 0.94);
754
755 if(euc::in(2,4)) {
756 if(!BITRUNCATED)
757 floorrad0 = floorrad1 = rhexf * (GDIM == 3 ? 1 : .94);
758 else
759 floorrad0 = hexvdist * (GDIM == 3 ? 1 : .9),
760 floorrad1 = rhexf * (GDIM == 3 ? 1 : .8);
761 }
762
763 plevel = vid.plevel_factor * scalefactor;
764 single_step = 1;
765 if(hybri && !prod) {
766 #if CAP_ARCM
767 if(hybrid::underlying == gArchimedean)
768 arcm::current.get_step_values(psl_steps, single_step);
769 #else
770 if(0) ;
771 #endif
772 else {
773 single_step = S3 * S7 - 2 * S7 - 2 * S3;
774 psl_steps = 2 * S7;
775 if(BITRUNCATED) psl_steps *= S3;
776 if(inv) psl_steps = 2 * S3;
777 if(single_step < 0) single_step = -single_step;
778 }
779 DEBB(DF_GEOM | DF_POLY, ("steps = ", psl_steps, " / ", single_step));
780 plevel = M_PI * single_step / psl_steps;
781 }
782
783 if(hybri) {
784 /* we do not want too short creatures, better make the scale factor smaller */
785 scalefactor = min(scalefactor, cgi.plevel * 1.8 / vid.height_width);
786 }
787
788 set_sibling_limit();
789
790 prepare_compute3();
791 if(hyperbolic && &currfp != &fieldpattern::fp_invalid)
792 currfp.analyze();
793
794 #if CAP_SOLV
795 if(asonov::in()) {
796 asonov::prepare();
797 asonov::prepare_walls();
798 }
799 #endif
800 }
801
xspinpush(ld dir,ld dist)802 EX transmatrix xspinpush(ld dir, ld dist) {
803 if(euclid)
804 return eupush(cos(dir) * dist, -sin(dir) * dist);
805 else
806 return spin(dir) * xpush(dist) * spin(-dir);
807 }
808
809 EX purehookset hooks_swapdim;
810
811 EX namespace geom3 {
812
813 // Here we convert between the following parameters:
814
815 // abslev: level below the plane
816 // lev: level above the world (abslev = depth-lev)
817 // projection: projection parameter
818 // factor: zoom factor
819
abslev_to_projection(ld abslev)820 EX ld abslev_to_projection(ld abslev) {
821 if(sphere || euclid) return vid.camera+abslev;
822 return tanh(abslev) / tanh(vid.camera);
823 }
824
projection_to_abslev(ld proj)825 ld projection_to_abslev(ld proj) {
826 if(sphere || euclid) return proj-vid.camera;
827 // tanh(abslev) / tanh(camera) = proj
828 return atanh(proj * tanh(vid.camera));
829 }
830
lev_to_projection(ld lev)831 ld lev_to_projection(ld lev) {
832 return abslev_to_projection(vid.depth - lev);
833 }
834
projection_to_factor(ld proj)835 ld projection_to_factor(ld proj) {
836 return lev_to_projection(0) / proj;
837 }
838
factor_to_projection(ld fac)839 EX ld factor_to_projection(ld fac) {
840 return lev_to_projection(0) / fac;
841 }
842
lev_to_factor(ld lev)843 EX ld lev_to_factor(ld lev) {
844 if(prod) return -lev;
845 if(WDIM == 3) return lev;
846 if(GDIM == 3) return vid.depth - lev;
847 return projection_to_factor(lev_to_projection(lev));
848 }
factor_to_lev(ld fac)849 EX ld factor_to_lev(ld fac) {
850 if(prod) return -fac;
851 if(GDIM == 3) return fac;
852 return vid.depth - projection_to_abslev(factor_to_projection(fac));
853 }
854
do_auto_eye()855 EX void do_auto_eye() {
856 if(!vid.auto_eye) return;
857 auto& cs = getcs();
858 if(cs.charid < 4)
859 vid.eye = cgi.eyelevel_human;
860 else if(cs.charid < 8)
861 vid.eye = cgi.eyelevel_dog;
862 else if(cs.charid == 8)
863 vid.eye = cgi.eyelevel_familiar;
864 }
865
866 // how should we scale at level lev
scale_at_lev(ld lev)867 EX ld scale_at_lev(ld lev) {
868 if(sphere || euclid) return 1;
869 return cosh(vid.depth - lev);
870 }
871
872 EX string invalid;
873
actual_wall_height()874 EX ld actual_wall_height() {
875 if(hybri) return cgi.plevel;
876 #if CAP_GP
877 if(GOLDBERG && vid.gp_autoscale_heights)
878 return vid.wall_height * min<ld>(4 / hypot_d(2, gp::next), 1);
879 #endif
880 return vid.wall_height;
881 }
882 EX }
883
prepare_compute3()884 void geometry_information::prepare_compute3() {
885 using namespace geom3;
886 DEBBI(DF_INIT | DF_POLY | DF_GEOM, ("geom3::compute"));
887 // tanh(depth) / tanh(camera) == pconf.alpha
888 invalid = "";
889
890 if(GDIM == 3) ;
891 else if(vid.tc_alpha < vid.tc_depth && vid.tc_alpha < vid.tc_camera)
892 pconf.alpha = tan_auto(vid.depth) / tan_auto(vid.camera);
893 else if(vid.tc_depth < vid.tc_alpha && vid.tc_depth < vid.tc_camera) {
894 ld v = pconf.alpha * tan_auto(vid.camera);
895 if(hyperbolic && (v<1e-6-12 || v>1-1e-12)) invalid = XLAT("cannot adjust depth"), vid.depth = vid.camera;
896 else vid.depth = atan_auto(v);
897 }
898 else {
899 ld v = tan_auto(vid.depth) / pconf.alpha;
900 if(hyperbolic && (v<1e-12-1 || v>1-1e-12)) invalid = XLAT("cannot adjust camera"), vid.camera = vid.depth;
901 else vid.camera = atan_auto(v);
902 }
903
904 if(fabs(pconf.alpha) < 1e-6) invalid = XLAT("does not work with perfect Klein");
905
906 if(invalid != "") {
907 INFDEEP = .7;
908 BOTTOM = .8;
909 HELLSPIKE = .85;
910 LAKE = .9;
911 FLOOR = 1;
912 WALL = 1.25;
913 SLEV[0] = 1;
914 SLEV[1] = 1.08;
915 SLEV[2] = 1.16;
916 SLEV[3] = 1.24;
917 FLATEYE = 1.03;
918 LEG1 = 1.025;
919 LEG = 1.05;
920 LEG3 = 1.075;
921 GROIN = 1.09;
922 GROIN1 = 1.105;
923 GHOST = 1.1;
924 BODY = 1.15;
925 BODY1 = 1.151;
926 BODY2 = 1.152;
927 BODY3 = 1.153;
928 NECK1 = 1.16;
929 NECK = 1.17;
930 NECK3 = 1.18;
931 HEAD = 1.188;
932 HEAD1= 1.189;
933 HEAD2= 1.190;
934 HEAD3= 1.191;
935 ABODY = 1.08;
936 AHEAD = 1.12;
937 BIRD = 1.20;
938 }
939 else {
940 INFDEEP = GDIM == 3 ? (sphere ? M_PI/2 : +5) : (euclid || sphere) ? 0.01 : lev_to_projection(0) * tanh(vid.camera);
941 ld wh = actual_wall_height();
942 WALL = lev_to_factor(wh);
943 FLOOR = lev_to_factor(0);
944
945 human_height = vid.human_wall_ratio * wh;
946 if(WDIM == 3) human_height = scalefactor * vid.height_width / 2;
947 if(hybri) human_height = min(human_height, cgi.plevel * .9);
948
949 ld reduce = (WDIM == 3 ? human_height / 2 : 0);
950
951 LEG0 = lev_to_factor(human_height * .0 - reduce);
952 LEG1 = lev_to_factor(human_height * .1 - reduce);
953 LEG = lev_to_factor(human_height * .2 - reduce);
954 LEG3 = lev_to_factor(human_height * .3 - reduce);
955 GROIN = lev_to_factor(human_height * .4 - reduce);
956 GROIN1= lev_to_factor(human_height * .5 - reduce);
957 BODY = lev_to_factor(human_height * .6 - reduce);
958 BODY1 = lev_to_factor(human_height * .61 - reduce);
959 BODY2 = lev_to_factor(human_height * .62 - reduce);
960 BODY3 = lev_to_factor(human_height * .63 - reduce);
961 NECK1 = lev_to_factor(human_height * .7 - reduce);
962 NECK = lev_to_factor(human_height * .8 - reduce);
963 NECK3 = lev_to_factor(human_height * .9 - reduce);
964 HEAD = lev_to_factor(human_height * .97 - reduce);
965 HEAD1 = lev_to_factor(human_height * .98 - reduce);
966 HEAD2 = lev_to_factor(human_height * .99 - reduce);
967 HEAD3 = lev_to_factor(human_height - reduce);
968
969 reduce = (GDIM == 3 ? human_height * .3 : 0);
970
971 STUFF = lev_to_factor(0) - max(orbsize * 0.3, zhexf * .6);
972
973 ABODY = lev_to_factor(human_height * .4 - reduce);
974 ALEG0 = lev_to_factor(human_height * .0 - reduce);
975 ALEG = lev_to_factor(human_height * .2 - reduce);
976 AHEAD = lev_to_factor(human_height * .6 - reduce);
977 BIRD = lev_to_factor(WDIM == 3 ? 0 : (vid.human_wall_ratio+1)/2 * wh * .8);
978 GHOST = lev_to_factor(WDIM == 3 ? 0 : human_height * .5);
979 FLATEYE = lev_to_factor(human_height * .15);
980
981 slev = vid.rock_wall_ratio * wh / 3;
982 for(int s=0; s<=3; s++)
983 SLEV[s] = lev_to_factor(vid.rock_wall_ratio * wh * s/3);
984 LAKE = lev_to_factor(-vid.lake_top);
985 SHALLOW = lev_to_factor(-.4);
986 HELLSPIKE = lev_to_factor(-(vid.lake_top+vid.lake_bottom)/2);
987 BOTTOM = lev_to_factor(-vid.lake_bottom);
988 LOWSKY = lev_to_factor(2 * wh);
989 HIGH = LOWSKY;
990 HIGH2 = lev_to_factor(3 * wh);
991 SKY = LOWSKY - 5;
992 }
993 }
994
995 EX namespace geom3 {
996
apply_always3()997 EX void apply_always3() {
998 for(geometryinfo& gi: ginf) {
999 auto &g = gi.g;
1000 if(vid.always3 && g.gameplay_dimension == 2 && g.graphical_dimension == 2) {
1001 g.graphical_dimension++;
1002 g.homogeneous_dimension++;
1003 g.sig[3] = g.sig[2];
1004 g.sig[2] = g.sig[1];
1005 }
1006 if(!vid.always3 && g.gameplay_dimension == 2 && g.graphical_dimension == 3) {
1007 g.graphical_dimension--;
1008 g.homogeneous_dimension--;
1009 g.sig[1] = g.sig[2];
1010 g.sig[2] = g.sig[3];
1011 }
1012 }
1013 }
1014
1015 #if MAXMDIM >= 4
switch_always3()1016 EX void switch_always3() {
1017 if(dual::split(switch_always3)) return;
1018 #if CAP_GL && CAP_RUG
1019 if(rug::rugged) rug::close();
1020 #endif
1021 vid.always3 = !vid.always3;
1022 apply_always3();
1023 swapmatrix(View);
1024 callhooks(hooks_swapdim);
1025 }
1026 #endif
1027
switch_tpp()1028 EX void switch_tpp() {
1029 if(dual::split(switch_fpp)) return;
1030 if(pmodel == mdDisk && pconf.camera_angle) {
1031 vid.yshift = 0;
1032 pconf.camera_angle = 0;
1033 pconf.xposition = 0;
1034 pconf.yposition = 0;
1035 pconf.scale = 1;
1036 vid.fixed_facing = false;
1037 }
1038 else {
1039 vid.yshift = -0.3;
1040 pconf.camera_angle = -45;
1041 pconf.scale = 18/16. * vid.xres / vid.yres / multi::players;
1042 pconf.xposition = 0;
1043 pconf.yposition = -0.9;
1044 vid.fixed_facing = true;
1045 vid.fixed_facing_dir = 90;
1046 }
1047 }
1048
switch_fpp()1049 EX void switch_fpp() {
1050 #if MAXMDIM >= 4
1051 #if CAP_GL && CAP_RUG
1052 if(rug::rugged) rug::close();
1053 #endif
1054 if(dual::split(switch_fpp)) return;
1055 check_cgi(); cgi.require_basics();
1056 View = iso_inverse(models::rotmatrix()) * View;
1057 if(!vid.always3) {
1058 vid.always3 = true;
1059 apply_always3();
1060 ld ms = min<ld>(cgi.scalefactor, 1);
1061 vid.wall_height = 1.5 * ms;
1062 if(sphere) {
1063 vid.depth = M_PI / 6;
1064 vid.wall_height = M_PI / 3;
1065 }
1066 vid.human_wall_ratio = 0.8;
1067 if(euclid && allowIncreasedSight() && vid.use_smart_range == 0) {
1068 genrange_bonus = gamerange_bonus = sightrange_bonus = cgi.base_distlimit * 3/2;
1069 }
1070 vid.camera = 0;
1071 vid.depth = ms;
1072 if(pmodel == mdDisk) pmodel = mdPerspective;
1073 swapmatrix(View);
1074 swapmatrix(current_display->which_copy);
1075 callhooks(hooks_swapdim);
1076 for(auto m: allmaps) m->on_dim_change();
1077 if(cgflags & qIDEAL && vid.texture_step < 32)
1078 vid.texture_step = 32;
1079 #if CAP_RACING
1080 racing::player_relative = true;
1081 #endif
1082 }
1083 else {
1084 vid.always3 = false;
1085 apply_always3();
1086 vid.wall_height = .3;
1087 vid.human_wall_ratio = .7;
1088 vid.camera = 1;
1089 vid.depth = 1;
1090 if(pmodel == mdPerspective) pmodel = mdDisk;
1091 swapmatrix(View);
1092 swapmatrix(current_display->which_copy);
1093 callhooks(hooks_swapdim);
1094 for(auto m: allmaps) m->on_dim_change();
1095 }
1096 View = models::rotmatrix() * View;
1097 #endif
1098 }
1099
1100 EX }
1101
1102 EX geometry_information *cgip;
1103 EX map<string, geometry_information> cgis;
1104
1105 #if HDR
1106 #define cgi (*cgip)
1107 #endif
1108
1109 EX int last_texture_step;
1110
1111 int ntimestamp;
1112
1113 EX hookset<void(string&)> hooks_cgi_string;
1114
cgi_string()1115 EX string cgi_string() {
1116 string s;
1117 auto V = [&] (string a, string b) { s += a; s += ": "; s += b; s += "; "; };
1118 V("GEO", its(int(geometry)));
1119 V("VAR", its(int(variation)));
1120
1121 if(arb::in() && arb::using_slided) {
1122 for(auto& sl: arb::current.sliders)
1123 V("AS", fts(sl.current));
1124 }
1125
1126 if(fake::in()) {
1127 if(hyperbolic) V("H", fts(fake::around));
1128 if(euclid) V("E", fts(fake::around));
1129 if(sphere) V("S", fts(fake::around));
1130 V("G", FPIU(cgi_string()));
1131 return s;
1132 }
1133
1134 if(GOLDBERG_INV) V("GP", its(gp::param.first) + "," + its(gp::param.second));
1135 if(IRREGULAR) V("IRR", its(irr::irrid));
1136 if(is_subcube_based(variation)) V("SC", its(reg3::subcube_count));
1137 if(variation == eVariation::coxeter) V("COX", its(reg3::coxeter_param));
1138
1139 #if CAP_ARCM
1140 if(arcm::in()) V("ARCM", arcm::current.symbol);
1141 #endif
1142
1143 if(arb::in()) V("ARB", its(arb::current.order));
1144
1145 if(cryst) V("CRYSTAL", its(ginf[gCrystal].sides) + its(ginf[gCrystal].vertex));
1146
1147 if(bt::in() || GDIM == 3) V("WQ", its(vid.texture_step));
1148
1149 if(hybri) {
1150 V("U", PIU(cgi_string()));
1151 // its(int(hybrid::underlying)));
1152 }
1153
1154 if(prod) V("PL", fts(vid.plevel_factor));
1155
1156 if(geometry == gFieldQuotient) { V("S3=", its(S3)); V("S7=", its(S7)); }
1157 if(nil) V("NIL", its(S7));
1158
1159 if(bt::in()) V("BT", fts(vid.binary_width));
1160
1161 if(nil) V("NILW", fts(nilv::nilwidth));
1162
1163 if(GDIM == 2) {
1164 V("CAMERA", fts(vid.camera));
1165 }
1166
1167 if(WDIM == 2) {
1168 V("WH", fts(vid.wall_height));
1169 V("HW", fts(vid.human_wall_ratio));
1170 V("RW", fts(vid.rock_wall_ratio));
1171 V("DEPTH", fts(vid.depth));
1172 V("ASH", ONOFF(vid.gp_autoscale_heights));
1173 V("LT", fts(vid.lake_top));
1174 V("LB", fts(vid.lake_bottom));
1175 }
1176
1177 V("3D", ONOFF(vid.always3));
1178
1179 if(scale_used()) V("CS", fts(vid.creature_scale));
1180
1181 if(WDIM == 3) V("HTW", fts(vid.height_width));
1182
1183 V("LQ", its(vid.linequality));
1184
1185 callhooks(hooks_cgi_string, s);
1186
1187 return s;
1188 }
1189
check_cgi()1190 EX void check_cgi() {
1191 string s = cgi_string();
1192
1193 cgip = &cgis[s];
1194 cgi.timestamp = ++ntimestamp;
1195 if(hybri) hybrid::underlying_cgip->timestamp = ntimestamp;
1196 if(fake::in()) fake::underlying_cgip->timestamp = ntimestamp;
1197 if(arcm::alt_cgip) arcm::alt_cgip->timestamp = ntimestamp;
1198
1199 if(isize(cgis) > 4) {
1200 vector<pair<int, string>> timestamps;
1201 for(auto& t: cgis) timestamps.emplace_back(-t.second.timestamp, t.first);
1202 sort(timestamps.begin(), timestamps.end());
1203 while(isize(timestamps) > 4) {
1204 DEBB(DF_GEOM, ("erasing geometry ", timestamps.back().second));
1205 cgis.erase(timestamps.back().second);
1206 timestamps.pop_back();
1207 }
1208 }
1209
1210 if(floor_textures && last_texture_step != vid.texture_step) {
1211 println(hlog, "changed ", last_texture_step, " to ", vid.texture_step);
1212 delete floor_textures;
1213 floor_textures = NULL;
1214 }
1215
1216 #if MAXMDIM >= 4 && CAP_GL
1217 if(!floor_textures && GDIM == 3 && (cgi.state & 2))
1218 make_floor_textures();
1219 #endif
1220
1221 }
1222
clear_cgis()1223 void clear_cgis() {
1224 printf("clear_cgis\n");
1225 for(auto& p: cgis) if(&p.second != &cgi) { cgis.erase(p.first); return; }
1226 }
1227
1228 auto ah_clear_geo = addHook(hooks_clear_cache, 0, clear_cgis);
1229
1230 }
1231