2021-04-07 00:36:53 +00:00
# include "rogueviz.h"
2019-09-13 07:35:18 +00:00
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/*
3 D engines often represent rotations as unit quaternions . These form a three - dimensional elliptic space . What if we could fly through it ?
Lower left corner shows the rotation matching the current camera position . Beams in the rotation space correspond to bumps on the sphere .
Run like :
[ hyper ] - geo 2 - rotspace - rot_uscale 0.25 - qtm ( space of rotations of the sphere )
[ hyper ] - rotspace - rot_uscale 0.25 - qtm ( space of rotations of the hyperbolic plane , slow )
[ hyper ] - geo Nil - qtm ( Nil , which is not a space of rotations , but similar ; rendered in a similar way )
*/
namespace hr {
namespace hybrid { extern hrmap * pmap ; }
2019-09-13 16:46:08 +00:00
namespace qtm {
2021-04-07 00:36:53 +00:00
int qmode ;
2020-05-08 19:19:56 +00:00
2021-03-25 13:31:02 +00:00
color_t rainbow_color_at ( hyperpoint h ) {
2020-05-28 23:59:05 +00:00
ld sat = 1 - 1 / h [ 2 ] ;
2022-11-12 21:38:45 +00:00
ld hue = atan2 ( h [ 0 ] , h [ 1 ] ) / TAU ;
2020-05-28 23:59:05 +00:00
return rainbow_color ( sat , hue ) ;
}
2024-06-16 14:59:37 +00:00
int z_in_wall ( int z ) {
if ( qmode = = 0 ) return 1 ;
if ( qmode = = 1 ) {
if ( z = = 0 ) return 2 ;
return 1 ;
}
if ( qmode = = 2 ) {
if ( z ) return 0 ;
return 1 ;
}
if ( qmode = = 3 ) {
if ( among ( z , 1 , 3 , 4 ) ) return 0 ;
return 1 ;
}
return 1 ;
}
2019-09-13 07:35:18 +00:00
void set_cell ( cell * c ) {
2022-12-11 20:12:51 +00:00
if ( mhybrid ) {
2019-09-13 07:35:18 +00:00
cell * c1 = hybrid : : get_where ( c ) . first ;
2019-11-30 17:52:24 +00:00
if ( c1 - > land ! = laHive ) hybrid : : in_underlying_geometry ( [ & ] { set_cell ( c1 ) ; } ) ;
2019-09-13 07:35:18 +00:00
c - > land = c1 - > land ;
c - > wall = c1 - > wall ;
c - > landparam = c1 - > landparam ;
c - > item = itNone ;
c - > monst = moNone ;
2024-06-16 14:59:37 +00:00
int zw = z_in_wall ( hybrid : : get_where ( c ) . second ) ;
if ( zw = = 2 ) c - > landparam = 0xFFFFFF ;
if ( zw = = 0 ) c - > wall = waNone ;
2019-09-13 07:35:18 +00:00
}
else {
if ( c - > land = = laHive ) return ;
color_t col ;
2020-05-09 16:33:53 +00:00
if ( hyperbolic ) {
hyperpoint h = calc_relative_matrix ( c , currentmap - > gamestart ( ) , C0 ) * C0 ;
2021-03-25 13:31:02 +00:00
col = rainbow_color_at ( h ) ;
2020-05-09 16:33:53 +00:00
}
2019-09-13 07:35:18 +00:00
else if ( nil ) {
part ( col , 0 ) = 128 + c - > master - > zebraval * 50 ;
part ( col , 1 ) = 128 + c - > master - > emeraldval * 50 ;
part ( col , 2 ) = 255 ;
}
else {
hyperpoint h = calc_relative_matrix ( c , currentmap - > gamestart ( ) , C0 ) * C0 ;
part ( col , 0 ) = ( h [ 0 ] * 127.5 + 127.5 ) ;
part ( col , 1 ) = ( h [ 1 ] * 127.5 + 127.5 ) ;
part ( col , 2 ) = ( h [ 2 ] * 127.5 + 127.5 ) ;
}
c - > landparam = col ;
c - > land = laHive ;
2024-06-16 14:59:37 +00:00
bool wallmap =
( nil & & nilv : : nil_structure_index = = 0 ) ? ( c - > master - > zebraval & c - > master - > emeraldval & 1 ) :
( nil & & nilv : : nil_structure_index = = 2 ) ? ( gmod ( c - > master - > zebraval - c - > master - > emeraldval , 3 ) = = 0 ) :
pseudohept ( c ) ;
c - > wall = wallmap ? waWaxWall : waNone ;
2019-09-13 07:35:18 +00:00
c - > item = itNone ;
c - > monst = moNone ;
2024-06-16 14:59:37 +00:00
if ( wallmap & & nil ) {
int z = zgmod ( c - > master - > fieldval , nilv : : nilperiod [ 2 ] ) ;
int zw = z_in_wall ( z ) ;
println ( hlog , z , " -> " , zw ) ;
if ( zw = = 0 ) c - > wall = waNone ;
if ( zw = = 2 ) c - > landparam = 0xFFFFFF ;
}
2019-09-13 07:35:18 +00:00
}
}
2020-08-22 22:16:50 +00:00
bool may_set_cell ( cell * c , int d , cell * from ) {
2021-04-07 00:36:53 +00:00
set_cell ( c ) ;
2019-09-13 07:35:18 +00:00
return false ;
}
2021-04-07 00:36:53 +00:00
void enable ( ) {
2021-04-07 19:48:56 +00:00
rogueviz : : rv_hook ( hooks_cellgen , 100 , may_set_cell ) ;
2021-04-07 00:36:53 +00:00
}
2019-09-13 07:35:18 +00:00
int args ( ) {
using namespace arg ;
if ( 0 ) ;
2020-05-08 19:19:56 +00:00
else if ( argis ( " -qtm-stripe " ) ) {
2021-04-07 00:36:53 +00:00
qmode = 1 ;
2020-05-08 19:19:56 +00:00
}
else if ( argis ( " -qtm-no-stripe " ) ) {
2021-04-07 00:36:53 +00:00
qmode = 0 ;
2020-05-08 19:19:56 +00:00
}
else if ( argis ( " -qtm-stripe-only " ) ) {
2021-04-07 00:36:53 +00:00
qmode = 2 ;
2020-05-08 19:19:56 +00:00
}
2019-09-13 07:35:18 +00:00
else if ( argis ( " -qtm " ) ) {
PHASEFROM ( 2 ) ;
2021-04-07 00:36:53 +00:00
enable ( ) ;
2019-09-13 07:35:18 +00:00
}
2020-05-08 19:20:06 +00:00
else if ( argis ( " -spheredemo " ) ) {
start_game ( ) ;
auto c = currentmap - > allcells ( ) ;
for ( cell * cx : c ) cx - > wall = waNone , cx - > item = itNone , cx - > land = laCanvas , cx - > landparam = 0 ;
c [ 1 ] - > wall = waPalace ;
c [ 1 ] - > land = laPalace ;
int N = isize ( c ) ;
int i = 1 + N / 4 ;
int j = 1 + 2 * N / 4 + 4 ;
int k = 1 + 3 * N / 4 ;
2020-05-15 09:51:33 +00:00
j % = N ;
2020-05-08 19:20:06 +00:00
c [ i ] - > wall = waIcewall ;
c [ i ] - > land = laIce ;
c [ j ] - > wall = waBigTree ;
c [ j ] - > land = laDryForest ;
c [ k ] - > wall = waWaxWall ;
c [ k ] - > landparam = 0xFF0000 ;
}
2020-05-15 09:51:33 +00:00
else if ( argis ( " -two-way " ) ) {
start_game ( ) ;
cwt . at - > move ( 0 ) - > wall = waWaxWall ;
cwt . at - > move ( 0 ) - > landparam = 0xFF0000 ;
cwt . at - > move ( 6 ) - > wall = waWaxWall ;
cwt . at - > move ( 6 ) - > landparam = 0xFFFF40 ;
}
else if ( argis ( " -one-center " ) ) {
start_game ( ) ;
cwt . at - > wall = waWaxWall ;
cwt . at - > landparam = 0xFFD500 ;
}
2020-05-28 23:59:05 +00:00
else if ( argis ( " -one-line " ) ) {
start_game ( ) ;
cell * c = cwt . at ;
int i = 0 ;
do {
c = c - > cmove ( 0 ) ;
i + + ;
}
while ( c ! = cwt . at ) ;
for ( int j = 0 ; j < i ; j + + ) {
c - > wall = waWaxWall ;
c - > landparam = rainbow_color ( 1 , j * 1. / i ) ;
c = c - > cmove ( 0 ) ;
}
}
else if ( argis ( " -two-line " ) ) {
start_game ( ) ;
cell * c = cwt . at ;
int i = 0 ;
do {
c = c - > cmove ( 0 ) ;
i + + ;
}
while ( c ! = cwt . at ) ;
for ( int j = 0 ; j < i ; j + + ) {
c - > wall = waWaxWall ;
c - > landparam = rainbow_color ( 1 , j * 1. / i ) ;
c = c - > cmove ( 0 ) ;
}
vector < cell * > a ;
for ( cell * x : currentmap - > allcells ( ) ) {
bool good = true ;
forCellCM ( y , x ) if ( y - > wall = = waWaxWall ) good = false ;
if ( good ) a . push_back ( x ) ;
}
for ( cell * x : a ) {
x - > wall = waWaxWall ;
x - > landparam = 0xFFFFFF ;
}
vector < cell * > b ;
for ( cell * x : a ) {
bool good = false ;
forCellCM ( y , x ) if ( y - > wall ! = waWaxWall ) good = true ;
if ( good ) b . push_back ( x ) ;
}
for ( cell * x : b ) x - > wall = waNone ;
}
2019-09-13 07:35:18 +00:00
else return 1 ;
return 0 ;
}
2024-04-28 00:04:40 +00:00
# if CAP_RAY
# define IF_RAY(x) x
# else
# define IF_RAY(x)
# endif
2021-04-07 00:36:53 +00:00
auto hooks =
addHook ( hooks_args , 100 , args )
2021-06-25 11:53:23 +00:00
+ addHook_rvslides ( 180 , [ ] ( string s , vector < tour : : slide > & v ) {
2021-04-07 00:36:53 +00:00
if ( s ! = " mixed " ) return ;
using namespace tour ;
for ( int m : { 1 , 2 } ) {
string ex = m = = 1 ? " (A) " : " (B) " ;
string bonus = m = = 2 ? " \n \n To make stretching more interesting, only the 'stripes' are filled now. " : " " ;
v . push_back ( slide {
" rotations/isometries of 2-sphere " + ex , 10 , LEGAL : : NONE | QUICKGEO ,
" 3D engines often represent rotations as unit quaternions. These form a 3D elliptic space. What if we could fly through this space of rotations? \n \n "
" Rotation matching the current camera position shown in the corner. Beams in the rotation space correspond to bumps on the sphere. \n \n "
" You can also obtain a different geometry (Berger sphere) by stretching along the fibers. Press 5 to stretch. " + bonus
,
[ m ] ( presmode mode ) {
2024-06-16 14:16:56 +00:00
setWhiteCanvas ( mode ) ;
2021-04-07 00:36:53 +00:00
slide_url ( mode , ' t ' , " Twitter link " , " https://twitter.com/ZenoRogue/status/1166723332840001536 " ) ;
slide_url ( mode , ' s ' , " stretched Twitter link " , " https://twitter.com/ZenoRogue/status/1258035231996682244 " ) ;
if ( mode = = pmStart ) {
set_geometry ( gSphere ) ;
set_variation ( eVariation : : bitruncated ) ;
set_geometry ( gRotSpace ) ;
slide_backup ( rots : : underlying_scale , .25 ) ;
slide_backup ( qmode , m ) ;
2024-04-28 00:04:40 +00:00
IF_RAY (
2021-04-07 00:36:53 +00:00
slide_backup ( ray : : max_cells , 32768 ) ;
slide_backup ( ray : : fixed_map , true ) ;
2024-04-28 00:04:40 +00:00
)
2021-04-07 00:36:53 +00:00
slide_backup ( camera_speed , .1 ) ;
enable ( ) ;
start_game ( ) ;
}
2022-08-05 18:34:56 +00:00
rogueviz : : pres : : non_game_slide_scroll ( mode ) ;
2021-04-07 00:36:53 +00:00
if ( mode = = pmKey )
edit_stretch ( ) ;
} } ) ;
v . push_back ( slide {
" rotations/isometries of the hyperbolic plane " + ex , 10 , LEGAL : : NONE | QUICKGEO ,
" The hyperbolic analog of the previous slide. The space is PSL(2,R) now, which has a non-isotropic geometry. It can be represented using split quaternions. \n \n "
" Again, press 5 to stretch. " + bonus
,
[ m ] ( presmode mode ) {
2024-06-16 14:16:56 +00:00
setWhiteCanvas ( mode ) ;
2021-04-07 00:36:53 +00:00
slide_url ( mode , ' s ' , " stretched Twitter link " , " https://twitter.com/ZenoRogue/status/1259143275115687936 " ) ;
if ( mode = = pmStart ) {
set_geometry ( gKleinQuartic ) ;
set_variation ( eVariation : : bitruncated ) ;
set_geometry ( gRotSpace ) ;
slide_backup ( rots : : underlying_scale , .25 ) ;
slide_backup ( qmode , m ) ;
2024-04-28 00:04:40 +00:00
IF_RAY (
2021-04-07 00:36:53 +00:00
slide_backup ( ray : : max_cells , 32768 ) ;
slide_backup ( ray : : fixed_map , true ) ;
slide_backup ( ray : : want_use , 2 ) ;
2024-04-28 00:04:40 +00:00
)
2021-04-07 00:36:53 +00:00
slide_backup ( camera_speed , .1 ) ;
enable ( ) ;
start_game ( ) ;
}
2022-08-05 18:34:56 +00:00
rogueviz : : pres : : non_game_slide_scroll ( mode ) ;
2021-04-07 00:36:53 +00:00
if ( mode = = pmKey )
edit_stretch ( ) ;
} } ) ;
}
} ) ;
2019-09-13 07:35:18 +00:00
2024-04-28 00:04:40 +00:00
# undef IF_RAY
2019-09-13 07:35:18 +00:00
}
2019-09-13 16:46:08 +00:00
}