2021-03-30 21:02:40 +00:00
# include "rogueviz.h"
# define PSHIFT 0
# define RVPATH HYPERPATH "rogueviz / "
namespace rogueviz {
2021-04-07 16:31:27 +00:00
# ifndef RV_ALL
2021-03-30 21:02:40 +00:00
namespace cylon {
2021-03-31 09:13:37 +00:00
extern void enable ( ) ;
2021-03-30 21:02:40 +00:00
extern bool cylanim ;
}
2022-05-09 09:09:30 +00:00
namespace nilcompass {
bool draw_compass ( cell * c , const shiftmatrix & V ) ;
extern int zeroticks ;
}
2021-03-30 21:02:40 +00:00
namespace balls {
struct ball {
hyperpoint at ;
hyperpoint vel ;
} ;
extern vector < ball > balls ;
extern void initialize ( int ) ;
}
}
namespace hr {
namespace bricks {
2021-03-31 13:28:46 +00:00
extern int animation ;
2021-03-31 09:08:24 +00:00
void enable ( ) ;
2021-03-30 21:02:40 +00:00
extern void build ( bool in_pair ) ;
extern void build_stair ( ) ;
struct brick {
euc : : coord co ;
color_t col ;
int walls ;
hyperpoint location ;
hpcshape shRotWall [ 6 ] ;
} ;
extern vector < brick > bricks ;
}
namespace pentaroll {
2021-03-31 01:18:36 +00:00
extern void create_pentaroll ( bool ) ;
2021-03-30 21:02:40 +00:00
}
namespace ply {
2021-03-31 09:03:58 +00:00
extern bool animated ;
void enable ( ) ;
2021-03-30 21:02:40 +00:00
extern rogueviz : : objmodels : : model staircase ;
}
2021-04-07 16:31:27 +00:00
# endif
2021-03-30 21:02:40 +00:00
}
namespace hr {
namespace dmv {
transmatrix xyzscale ( ld x ) {
transmatrix T = Id ;
T [ 0 ] [ 0 ] = T [ 1 ] [ 1 ] = T [ 2 ] [ 2 ] = x ;
return T ;
}
using namespace rogueviz : : pres ;
using namespace hr : : tour ;
struct dmv_grapher : grapher {
dmv_grapher ( transmatrix U ) : grapher ( - 4 , - 4 , 11 , 11 ) {
T = T * U ;
for ( int x = - 3 ; x < = 10 ; x + + ) if ( x ) {
line ( p2 ( x , - 3 ) , p2 ( x , 10 ) , 0x8080FFFF ) ;
line ( p2 ( - 3 , x ) , p2 ( 10 , x ) , 0x8080FFFF ) ;
}
vid . linewidth * = 2 ;
arrow ( p2 ( 0 , - 3 ) , p2 ( 0 , 10 ) , .5 ) ;
arrow ( p2 ( - 3 , 0 ) , p2 ( 10 , 0 ) , .5 ) ;
vid . linewidth / = 2 ;
}
} ;
void nil_screen ( presmode mode , int id ) {
2022-04-21 10:39:49 +00:00
use_angledir ( mode , id = = 0 ) ;
setCanvas ( mode , ' 0 ' ) ;
if ( mode = = pmStart ) {
slide_backup ( pmodel ) ;
slide_backup ( pconf . clip_min ) ;
slide_backup ( pconf . clip_max ) ;
slide_backup ( vid . cells_drawn_limit ) ;
stop_game ( ) , pmodel = mdHorocyclic , geometry = gCubeTiling , pconf . clip_min = - 10000 , pconf . clip_max = + 100 , start_game ( ) ;
}
2021-03-30 21:02:40 +00:00
add_stat ( mode , [ id ] {
cmode | = sm : : SIDE ;
2022-04-21 10:39:49 +00:00
calcparam ( ) ;
vid . cells_drawn_limit = 0 ;
drawthemap ( ) ;
// flat_model_enabler fme;
2021-03-30 21:02:40 +00:00
initquickqueue ( ) ;
2022-04-21 10:39:49 +00:00
dmv_grapher g ( MirrorZ * cspin ( 1 , 2 , .8 * angle ) * spin ( angle / 2 ) ) ;
2021-03-30 21:02:40 +00:00
vid . linewidth * = 3 ;
ld t = 1e-3 ;
2022-04-21 10:39:49 +00:00
2021-03-30 21:02:40 +00:00
if ( id = = 2 ) {
2022-04-21 10:33:37 +00:00
t = inHighQual ? ticks * 4. / anims : : period : ticks / 1000. ;
2021-03-30 21:02:40 +00:00
if ( t - floor ( t ) > .5 ) t = ceil ( t ) ;
else t = floor ( t ) + 2 * ( t - floor ( t ) ) ;
t - = floor ( t / 4 ) * 4 ;
ld t2 = 90 * degree * t ;
curvepoint ( p2 ( 0 , 0 ) ) ;
curvepoint ( p2 ( 5 , 5 ) ) ;
curvepoint ( p2 ( 5 + 2 * cos ( t2 ) , 5 + 2 * sin ( t2 ) ) ) ;
curvepoint ( p2 ( 0 , 0 ) ) ;
color_t col = cos ( t2 ) > sin ( t2 ) ? 0xFF808000 : 0x8080FF00 ;
queuecurve ( g . T , col | 0xFF , col | 0x20 , PPR : : LINE ) ;
}
2022-04-21 10:39:49 +00:00
if ( id < 3 ) {
g . arrow ( p2 ( 5 , 5 ) , p2 ( 7 , 5 ) , .3 ) ;
g . arrow ( p2 ( 5 , 5 ) , p2 ( 5 , 7 ) , .3 ) ;
g . arrow ( p2 ( 5 , 5 ) , p2 ( 3 , 5 ) , .3 ) ;
g . arrow ( p2 ( 5 , 5 ) , p2 ( 5 , 3 ) , .3 ) ;
}
2021-03-30 21:02:40 +00:00
vid . linewidth / = 3 ;
2022-04-21 10:39:49 +00:00
if ( id < 3 ) {
if ( id = = 2 ) {
drawMonsterType ( moEagle , nullptr , g . pos ( 5 , 5 , 1.5 ) * spin ( - t * 90 * degree ) * xyzscale ( 1.5 ) , 0x40C040 , ticks / 1000. , 0 ) ;
}
2021-03-30 21:02:40 +00:00
2022-04-21 10:39:49 +00:00
color_t dark = 0xFF ;
write_in_space ( g . pos ( 7.5 , 5 , 1 ) * MirrorY , max_glfont_size , 1. , " E " , dark ) ;
write_in_space ( g . pos ( 5 , 7.5 , 1 ) * MirrorY , max_glfont_size , 1. , " N " , dark ) ;
write_in_space ( g . pos ( 2.5 , 5 , 1 ) * MirrorY , max_glfont_size , 1. , " W " , dark ) ;
write_in_space ( g . pos ( 5 , 2.5 , 1 ) * MirrorY , max_glfont_size , 1. , " S " , dark ) ;
}
2021-03-30 21:02:40 +00:00
2022-04-21 10:39:49 +00:00
if ( id = = 3 ) {
vid . linewidth * = 3 ;
t = ticks / anims : : period ;
ld ti = ticks / 1000. ;
t = frac ( t ) ;
vector < hyperpoint > loop = { p2 ( 9 , 4 ) , p2 ( 9 , 9 ) , p2 ( 1 , 9 ) , p2 ( 1 , 5 ) , p2 ( 6 , 6 ) , p2 ( 9 , 4 ) } ;
int q = isize ( loop ) - 1 ;
for ( hyperpoint h : loop ) curvepoint ( h ) ;
queuecurve ( g . T , 0x40C040FF , 0 , PPR : : LINE ) ;
ld total_length = 0 ;
for ( int i = 0 ; i < q ; i + + ) total_length + = hypot_d ( 2 , loop [ i + 1 ] - loop [ i ] ) ;
t * = total_length ;
t * = 1.2 ;
curvepoint ( p2 ( 0 , 0 ) ) ;
shiftmatrix T1 = g . pos ( loop [ 0 ] [ 0 ] , loop [ 0 ] [ 1 ] , 1.5 ) ;
shiftmatrix T2 = g . pos ( loop [ 0 ] [ 0 ] , loop [ 0 ] [ 1 ] , 1.5 ) ;
ld t1 = t ;
for ( int i = 0 ; i < = q ; i + + ) {
curvepoint ( loop [ i ] ) ;
if ( i = = q ) {
T1 = g . pos ( loop [ i ] [ 0 ] , loop [ i ] [ 1 ] , 1.5 ) * rspintox ( loop [ i ] - loop [ i - 1 ] ) ;
break ;
}
ld len = hypot_d ( 2 , loop [ i + 1 ] - loop [ i ] ) ;
if ( len < t1 ) { t1 - = len ; continue ; }
hyperpoint cur = lerp ( loop [ i ] , loop [ i + 1 ] , t1 / len ) ;
T1 = g . pos ( cur [ 0 ] , cur [ 1 ] , 1.5 ) * rspintox ( loop [ i + 1 ] - loop [ i ] ) ;
curvepoint ( cur ) ;
break ;
}
curvepoint ( p2 ( 0 , 0 ) ) ;
color_t col = 0x8080FF00 ;
queuecurve ( g . T , col | 0xFF , col | 0x40 , PPR : : LINE ) ;
ld z = 0 ;
ld zsca = .05 ;
vector < pair < hyperpoint , hyperpoint > > vlines ;
for ( int i = 0 ; i < = q ; i + + ) {
vlines . emplace_back ( loop [ i ] , loop [ i ] + ztangent ( z ) ) ;
curvepoint ( loop [ i ] + ztangent ( z ) ) ;
if ( i = = q ) {
T2 = g . pos ( loop [ i ] [ 0 ] , loop [ i ] [ 1 ] , 1.5 ) * cpush ( 2 , z ) * rspintox ( loop [ i ] - loop [ i - 1 ] ) ;
break ;
}
ld len = hypot_d ( 2 , loop [ i + 1 ] - loop [ i ] ) ;
if ( len < t ) {
t - = len ;
z + = ( loop [ i + 1 ] [ 1 ] * loop [ i ] [ 0 ] - loop [ i + 1 ] [ 0 ] * loop [ i ] [ 1 ] ) * zsca ;
continue ;
}
hyperpoint cur = lerp ( loop [ i ] , loop [ i + 1 ] , t / len ) ;
z + = ( cur [ 1 ] * loop [ i ] [ 0 ] - cur [ 0 ] * loop [ i ] [ 1 ] ) * zsca ;
T2 = g . pos ( cur [ 0 ] , cur [ 1 ] , 1.5 ) * cpush ( 2 , z ) * rspintox ( loop [ i + 1 ] - loop [ i ] ) ;
curvepoint ( cur + ztangent ( z ) ) ;
break ;
}
queuecurve ( g . T , 0x40C040FF , 0 , PPR : : LINE ) ;
for ( auto l : vlines ) queueline ( g . T * l . first , g . T * l . second , 0x40 , 0 , PPR : : MONSTER_BODY ) ;
vid . linewidth / = 3 ;
drawMonsterType ( moEagle , nullptr , T2 , 0x40C040 , ti , 0 ) ;
auto & bp = cgi . shEagle ;
if ( bp . she > bp . shs & & bp . she < bp . shs + 1000 ) {
auto & p = queuepolyat ( T1 , bp , 0x80 , PPR : : TRANSPARENT_SHADOW ) ;
p . outline = 0 ;
p . subprio = - 100 ;
p . offset = bp . shs ;
p . cnt = bp . she - bp . shs ;
p . flags & = ~ POLY_TRIANGLES ;
p . tinf = NULL ;
}
// queuepolyat(T2, cgi.shEagle, 0x40C040FF, PPR::SUPERLINE);
}
2021-03-30 21:02:40 +00:00
quickqueue ( ) ;
2022-04-21 10:39:49 +00:00
glflush ( ) ;
2021-03-30 21:02:40 +00:00
dialog : : init ( ) ;
// dialog::addTitle(id ? "Nil coordinates" : "Cartesian coordinates", forecolor, 150);
poly_outline = 0xFFFFFFFF ;
dialog : : addBreak ( 100 ) ;
dialog : : addBreak ( 50 ) ;
2022-04-21 10:39:49 +00:00
auto dirbox = [ ] ( string s ) {
return " \\ makebox[5em][r]{ \\ textsf{ " + s + " }} " ;
} ;
auto cbox = [ ] ( string s ) {
return " \\ makebox[9em][l]{$ " + s + " $} " ;
} ;
dialog_may_latex ( dirbox ( " start: " ) + cbox ( " (x,y,z) " ) , " start: (x,y,z) " ) ;
dialog : : addBreak ( 50 ) ;
2021-03-30 21:02:40 +00:00
if ( id = = 0 ) {
2022-04-21 10:39:49 +00:00
dialog_may_latex ( dirbox ( " N: " ) + cbox ( " (x,y+d,z) " ) , " N: (x,y+d,z) " ) ;
dialog_may_latex ( dirbox ( " W: " ) + cbox ( " (x-d,y,z) " ) , " W: (x-d,y,z) " ) ;
dialog_may_latex ( dirbox ( " S: " ) + cbox ( " (x,y-d,z) " ) , " S: (x,y-d,z) " ) ;
dialog_may_latex ( dirbox ( " E: " ) + cbox ( " (x+d,y,z) " ) , " E: (x+d,y,z) " ) ;
2021-03-30 21:02:40 +00:00
}
else {
2022-04-21 10:39:49 +00:00
dialog_may_latex ( dirbox ( " N: " ) + cbox ( " (x,y+d,z+ \\ frac{xd}{2}) " ) , " N: (x,y+d,z+xd/2) " , t = = 1 ? 0xFFD500 : dialog : : dialogcolor ) ;
dialog_may_latex ( dirbox ( " W: " ) + cbox ( " (x-d,y,z+ \\ frac{yd}{2}) " ) , " W: (x-d,y,z+yd/2) " , t = = 2 ? 0xFFD500 : dialog : : dialogcolor ) ;
dialog_may_latex ( dirbox ( " S: " ) + cbox ( " (x,y-d,z- \\ frac{xd}{2}) " ) , " S: (x,y-d,z-xd/2) " , t = = 3 ? 0xFFD500 : dialog : : dialogcolor ) ;
dialog_may_latex ( dirbox ( " E: " ) + cbox ( " (x+d,y,z- \\ frac{yd}{2}) " ) , " E: (x+d,y,z-yd/2) " , t = = 0 ? 0xFFD500 : dialog : : dialogcolor ) ;
2021-03-30 21:02:40 +00:00
}
dialog : : addBreak ( 50 ) ;
2022-04-21 10:39:49 +00:00
dialog_may_latex ( dirbox ( " U: " ) + cbox ( " (x,y,z-d) " ) , " U: (x,y,z-d) " ) ;
dialog_may_latex ( dirbox ( " D: " ) + cbox ( " (x,y,z+d) " ) , " D: (x,y,z+d) " ) ;
2021-03-30 21:02:40 +00:00
dialog : : display ( ) ;
dynamicval < eGeometry > gg ( geometry , gNil ) ;
return false ;
} ) ;
}
ld geo_zero ;
void geodesic_screen ( presmode mode , int id ) {
if ( mode = = pmStart ) geo_zero = ticks ;
use_angledir ( mode , id = = 0 ) ;
setCanvas ( mode , ' 0 ' ) ;
2022-03-01 07:37:30 +00:00
if ( mode = = pmStart ) {
slide_backup ( pmodel ) ;
slide_backup ( pconf . clip_min ) ;
slide_backup ( pconf . clip_max ) ;
slide_backup ( vid . cells_drawn_limit ) ;
stop_game ( ) , pmodel = mdHorocyclic , geometry = gCubeTiling , pconf . clip_min = - 10000 , pconf . clip_max = + 100 , start_game ( ) ;
}
2021-03-30 21:02:40 +00:00
add_stat ( mode , [ id ] {
cmode | = sm : : SIDE ;
calcparam ( ) ;
vid . cells_drawn_limit = 0 ;
drawthemap ( ) ;
// flat_model_enabler fme;
initquickqueue ( ) ;
dmv_grapher g ( MirrorZ * cspin ( 1 , 2 , .3 * angle / ( M_PI / 2 ) ) * spin ( angle / 2 ) ) ;
ld val = 25 ;
ld rv = sqrt ( val ) ;
// pi*rad*rad == 25
ld rad = sqrt ( val / M_PI ) ;
ld rr = rad * sqrt ( 1 / 2. ) ;
ld radh = sqrt ( val / M_PI - 2 ) ;
ld rrh = radh * sqrt ( 1 / 2. ) ;
ld zmove = val - M_PI * radh * radh ;
ld len = hypot ( 2 * M_PI * radh , zmove ) ;
2022-04-21 10:39:49 +00:00
ld t = inHighQual ? ticks / 1000. : ( ticks - geo_zero ) / 500 ;
2021-03-30 21:02:40 +00:00
auto frac_of = [ & ] ( ld z ) { return t - z * floor ( t / z ) ; } ;
t = frac_of ( val ) ;
auto draw_path = [ & ] ( auto f , color_t col ) {
vid . linewidth * = 5 ;
for ( ld t = 0 ; t < = 25 ; t + = 1 / 16. ) curvepoint ( f ( t ) ) ;
queuecurve ( g . T , col , 0 , PPR : : LINE ) ;
auto be_shadow = [ & ] ( hyperpoint & h ) {
// ld part = 1 - angle / (M_PI / 2);
// h[0] += h[2] * part / 10;
h [ 2 ] = 0 ;
} ;
for ( ld t = 0 ; t < = 25 ; t + = 1 / 16. ) {
hyperpoint h = f ( t ) ;
be_shadow ( h ) ;
curvepoint ( h ) ;
}
queuecurve ( g . T , col & 0xFFFFFF40 , 0 , PPR : : LINE ) ;
vid . linewidth / = 5 ;
hyperpoint eaglepos = f ( t ) ;
hyperpoint next_eaglepos = f ( t + 1e-2 ) ;
// queuepolyat(g.pos(x+z * .1,y,1.5) * spin(s), cgi.shEagle, 0x40, PPR::MONSTER_SHADOW).outline = 0;
drawMonsterType ( moEagle , nullptr , g . T * eupush ( eaglepos ) * rspintox ( next_eaglepos - eaglepos ) * xyzscale ( 2 ) , col > > 8 , t , 0 ) ;
be_shadow ( eaglepos ) ;
be_shadow ( next_eaglepos ) ;
auto & bp = cgi . shEagle ;
println ( hlog , tie ( bp . shs , bp . she ) ) ;
if ( bp . she > bp . shs & & bp . she < bp . shs + 1000 ) {
auto & p = queuepolyat ( g . T * eupush ( eaglepos ) * rspintox ( next_eaglepos - eaglepos ) * xyzscale ( 2 ) , bp , 0x18 , PPR : : TRANSPARENT_SHADOW ) ;
p . outline = 0 ;
p . subprio = - 100 ;
p . offset = bp . shs ;
p . cnt = bp . she - bp . shs ;
p . flags & = ~ POLY_TRIANGLES ;
p . tinf = NULL ;
return ;
}
} ;
color_t straight = 0x80FF80FF ;
color_t square = 0xcd7f32FF ;
color_t circle = 0xaaa9adFF ;
color_t helix = 0xFFD500FF ;
if ( id > = 0 )
draw_path ( [ & ] ( ld t ) { return point31 ( 0 , 0 , t ) ; } , straight ) ;
if ( id > = 1 )
draw_path ( [ & ] ( ld t ) {
if ( t < rv )
return point31 ( t , 0 , 0 ) ;
else if ( t < rv * 2 )
return point31 ( rv , t - rv , rv * ( t - rv ) / 2 ) ;
else if ( t < rv * 3 )
return point31 ( rv - ( t - rv * 2 ) , rv , rv * rv / 2 + rv * ( t - 2 * rv ) / 2 ) ;
else if ( t < rv * 4 )
return point31 ( 0 , rv - ( t - rv * 3 ) , val ) ;
else
return point31 ( 0 , 0 , val ) ;
} , square ) ;
if ( id > = 2 )
draw_path ( [ & ] ( ld t ) {
ld tx = min ( t , 2 * M_PI * rad ) ;
ld ta = tx / rad - 135 * degree ;
ld x = rr + rad * cos ( ta ) ;
ld y = rr + rad * sin ( ta ) ;
ld z = rad * tx / 2 - ( ( rr * x ) - ( rr * y ) ) / 2 ;
return point31 ( x , y , z ) ;
} , circle ) ;
if ( id > = 3 )
draw_path ( [ & ] ( ld t ) {
ld tx = min ( t , len ) ;
ld ta = tx / len * 2 * M_PI - 135 * degree ;
ld x = rrh + radh * cos ( ta ) ;
ld y = rrh + radh * sin ( ta ) ;
ld z = radh * radh * ( tx / len * 2 * M_PI ) / 2 - ( ( rrh * x ) - ( rrh * y ) ) / 2 + zmove * tx / len ;
return point31 ( x , y , z ) ;
} , helix ) ;
auto cat = [ ] ( PPR x ) {
if ( x = = PPR : : MONSTER_SHADOW ) return 1 ;
else if ( x = = PPR : : MONSTER_BODY ) return 2 ;
else return 0 ;
} ;
for ( int i = 1 ; i < isize ( ptds ) ; )
if ( i & & cat ( ptds [ i ] - > prio ) < cat ( ptds [ i - 1 ] - > prio ) ) {
swap ( ptds [ i ] , ptds [ i - 1 ] ) ;
i - - ;
}
else i + + ;
quickqueue ( ) ;
dialog : : init ( ) ;
2022-04-21 10:39:49 +00:00
dialog_may_latex ( " \\ textsf{from $(0,0,0)$ to $(0,0,25)$} " , " from (0,0,0) to (0,0,25) " , forecolor , 150 ) ;
2021-03-30 21:02:40 +00:00
dialog : : addBreak ( 100 ) ;
2022-04-21 10:39:49 +00:00
dialog_may_latex ( " \\ textsf{straight upwards} " , " straight upwards " , straight > > 8 ) ;
dialog_may_latex ( " $25$ " , " 25 " , straight > > 8 ) ;
2021-03-30 21:02:40 +00:00
if ( id > = 1 ) {
dialog : : addBreak ( 100 ) ;
2022-04-21 10:39:49 +00:00
dialog_may_latex ( " \\ textsf{square} " , " square " , square > > 8 ) ;
dialog_may_latex ( " $20$ " , " 20 " , square > > 8 ) ;
2021-03-30 21:02:40 +00:00
}
else dialog : : addBreak ( 300 ) ;
if ( id > = 2 ) {
dialog : : addBreak ( 100 ) ;
2022-04-21 10:39:49 +00:00
dialog_may_latex ( " \\ textsf{circle} " , " circle " , circle > > 8 ) ;
dialog_may_latex ( " $ " + fts ( 2 * M_PI * rad ) + " $ " , fts ( 2 * M_PI * rad ) , circle > > 8 ) ;
2021-03-30 21:02:40 +00:00
}
else dialog : : addBreak ( 300 ) ;
if ( id > = 3 ) {
dialog : : addBreak ( 100 ) ;
2022-04-21 10:39:49 +00:00
dialog_may_latex ( " \\ textsf{helix} " , " helix " , helix > > 8 ) ;
dialog_may_latex ( " $ " + fts ( len ) + " $ " , fts ( len ) , helix > > 8 ) ;
2021-03-30 21:02:40 +00:00
}
else dialog : : addBreak ( 300 ) ;
dialog : : display ( ) ;
return false ;
} ) ;
}
// i==0 - stairs
// i==1 - triangle
// i==2 - double triangle
void brick_slide ( int i , presmode mode , eGeometry geom , eModel md , int anim ) {
using namespace tour ;
setCanvas ( mode , ' 0 ' ) ;
if ( mode = = pmStart ) {
set_geometry ( geom ) ;
start_game ( ) ;
cgi . require_shapes ( ) ;
if ( i = = 0 )
bricks : : build_stair ( ) ;
if ( i = = 1 )
bricks : : build ( false ) ;
if ( i = = 2 )
bricks : : build ( true ) ;
2021-03-31 09:08:24 +00:00
bricks : : enable ( ) ;
2021-03-30 21:02:40 +00:00
tour : : slide_backup ( pconf . clip_min , - 100. ) ;
tour : : slide_backup ( pconf . clip_max , + 10. ) ;
tour : : slide_backup ( pconf . scale , i ? .2 : 2. ) ;
tour : : slide_backup ( mapeditor : : drawplayer , false ) ;
tour : : slide_backup ( pconf . rotational_nil , 0. ) ;
tour : : slide_backup ( vid . axes3 , false ) ;
bricks : : animation = anim ;
pmodel = md ;
View = Id ;
}
clearMessages ( ) ;
no_other_hud ( mode ) ;
}
void ply_slide ( tour : : presmode mode , eGeometry geom , eModel md , bool anim ) {
using namespace tour ;
if ( ! ply : : staircase . available ( ) ) {
2021-03-31 10:19:11 +00:00
slide_error ( mode , " (model not available) " ) ;
2021-03-30 21:02:40 +00:00
return ;
}
if ( mode = = pmStartAll ) {
rogueviz : : objmodels : : prec = 10 ;
dynamicval < eGeometry > g ( geometry , gNil ) ;
dynamicval < eVariation > v ( variation , eVariation : : pure ) ;
dynamicval < int > s ( vid . texture_step , 1 ) ;
check_cgi ( ) ;
cgi . require_shapes ( ) ;
}
setCanvas ( mode , ' 0 ' ) ;
if ( mode = = pmStart ) {
set_geometry ( geom ) ;
start_game ( ) ;
2021-03-31 09:03:58 +00:00
ply : : enable ( ) ;
2021-03-30 21:02:40 +00:00
tour : : slide_backup ( anims : : period , 40000. ) ;
tour : : slide_backup ( mapeditor : : drawplayer , false ) ;
tour : : slide_backup ( pconf . rotational_nil , 0. ) ;
tour : : slide_backup ( ply : : animated , anim ) ;
tour : : slide_backup ( vid . axes3 , false ) ;
tour : : slide_backup ( no_find_player , true ) ;
tour : : slide_backup ( vid . texture_step , 1 ) ;
tour : : slide_backup ( sightranges [ geom ] , 10. ) ;
tour : : slide_backup ( vid . cells_drawn_limit , 50 ) ;
pmodel = md ;
View = Id ;
}
clearMessages ( ) ;
no_other_hud ( mode ) ;
}
void impossible_ring_slide ( tour : : presmode mode ) {
using namespace tour ;
setCanvas ( mode , ' 0 ' ) ;
if ( mode = = pmStart ) {
set_geometry ( gCubeTiling ) ;
start_game ( ) ;
tour : : slide_backup ( pconf . clip_min , - 100. ) ;
tour : : slide_backup ( pconf . clip_max , + 10. ) ;
tour : : slide_backup ( mapeditor : : drawplayer , false ) ;
tour : : slide_backup ( vid . axes3 , false ) ;
pmodel = mdHorocyclic ;
View = Id ;
}
clearMessages ( ) ;
no_other_hud ( mode ) ;
use_angledir ( mode , true ) ;
add_temporary_hook ( mode , hooks_frame , 200 , [ ] {
for ( int id = 0 ; id < 2 ; id + + ) {
shiftmatrix T = ggmatrix ( currentmap - > gamestart ( ) ) ;
println ( hlog , " angle = " , angle ) ;
if ( id = = 1 ) T = T * spin ( 180 * degree ) * xpush ( 1.5 ) * cspin ( 0 , 2 , angle ) * xpush ( - 1.5 ) ;
for ( ld z : { + .5 , - .5 } ) {
for ( ld d = 0 ; d < = 180 ; d + + )
curvepoint ( C0 + spin ( d * degree ) * xtangent ( 1 ) + ztangent ( z ) ) ;
for ( ld d = 180 ; d > = 0 ; d - - )
curvepoint ( C0 + spin ( d * degree ) * xtangent ( 2 ) + ztangent ( z ) ) ;
curvepoint ( C0 + spin ( 0 ) * xtangent ( 1 ) + ztangent ( z ) ) ;
queuecurve ( T , 0xFF , 0xFF8080FF , PPR : : LINE ) ;
}
for ( ld d = 0 ; d < 180 ; d + = 5 ) for ( ld x : { 1 , 2 } ) {
for ( int i = 0 ; i < = 5 ; i + + )
curvepoint ( C0 + spin ( ( d + i ) * degree ) * xtangent ( x ) + ztangent ( .5 ) ) ;
for ( int i = 5 ; i > = 0 ; i - - )
curvepoint ( C0 + spin ( ( d + i ) * degree ) * xtangent ( x ) + ztangent ( - .5 ) ) ;
curvepoint ( C0 + spin ( ( d + 0 ) * degree ) * xtangent ( x ) + ztangent ( .5 ) ) ;
queuecurve ( T , 0xFF , 0xC06060FF , PPR : : LINE ) ;
}
for ( ld sgn : { - 1 , 1 } ) {
curvepoint ( C0 + xtangent ( sgn * 1 ) + ztangent ( + .5 ) ) ;
curvepoint ( C0 + xtangent ( sgn * 2 ) + ztangent ( + .5 ) ) ;
curvepoint ( C0 + xtangent ( sgn * 2 ) + ztangent ( - .5 ) ) ;
curvepoint ( C0 + xtangent ( sgn * 1 ) + ztangent ( - .5 ) ) ;
curvepoint ( C0 + xtangent ( sgn * 1 ) + ztangent ( + .5 ) ) ;
queuecurve ( T , 0xFF , 0x804040FF , PPR : : LINE ) ;
}
}
} ) ;
}
void enable_earth ( ) {
texture : : texture_aura = true ;
stop_game ( ) ;
set_geometry ( gSphere ) ;
2021-09-30 08:49:12 +00:00
enable_canvas ( ) ;
2021-03-30 21:02:40 +00:00
patterns : : whichCanvas = ' F ' ;
start_game ( ) ;
texture : : config . configname = " textures/earth.txc " ;
texture : : config . load ( ) ;
pmodel = mdDisk ;
pconf . alpha = 1000 ; pconf . scale = 999 ;
texture : : config . color_alpha = 255 ;
mapeditor : : drawplayer = false ;
fullcenter ( ) ;
View = spin ( 4 * M_PI / 5 + M_PI / 2 ) * View ;
}
slide dmv_slides [ ] = {
{ " Title Page " , 123 , LEGAL : : ANY | QUICKSKIP | NOTITLE , " " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
show_picture ( mode , " rogueviz/nil/penrose-triangle.png " ) ;
add_stat ( mode , [ ] {
2022-07-05 14:03:12 +00:00
cmode | = sm : : DARKEN ;
gamescreen ( ) ;
2021-03-30 21:02:40 +00:00
dialog : : init ( ) ;
dialog : : addBreak ( 400 ) ;
dialog : : addTitle ( " playing with impossibility " , dialog : : dialogcolor , 150 ) ;
dialog : : addBreak ( 1600 ) ;
dialog : : addTitle ( " a presentation about Nil geometry " , 0xFFC000 , 75 ) ;
dialog : : display ( ) ;
return true ;
} ) ;
no_other_hud ( mode ) ;
}
} ,
{ " Euclidean plane " , 999 , LEGAL : : NONE | QUICKGEO ,
" The sum of angles of a triangle is 180 degrees. \n \n " ,
[ ] ( presmode mode ) {
2021-09-30 08:49:12 +00:00
if ( mode = = pmStartAll ) enable_canvas ( ) ;
2021-03-30 21:02:40 +00:00
setCanvas ( mode , ' F ' ) ;
if ( mode = = pmStart ) {
stop_game ( ) ;
slide_backup ( firstland , laCanvas ) ;
slide_backup ( specialland , laCanvas ) ;
set_geometry ( gArchimedean ) ; arcm : : current . parse ( " 3^6 " ) ;
set_variation ( eVariation : : pure ) ;
slide_backup ( colortables [ ' F ' ] [ 0 ] , 0xC0FFC0 ) ;
slide_backup ( colortables [ ' F ' ] [ 1 ] , 0x80FF80 ) ;
slide_backup ( pconf . alpha , 1 ) ;
slide_backup ( pconf . scale , 1 ) ;
start_game ( ) ;
slide_backup ( patterns : : whichShape , ' 9 ' ) ;
slide_backup ( vid . use_smart_range , 2 ) ;
slide_backup ( mapeditor : : drawplayer , false ) ;
}
add_temporary_hook ( mode , hooks_frame , 200 , [ ] {
shiftmatrix T = ggmatrix ( currentmap - > gamestart ( ) ) ;
vid . linewidth * = 4 ;
shiftpoint h1 = T * xspinpush0 ( 0 , 2 ) ;
shiftpoint h2 = T * xspinpush0 ( 120 * degree , 2 ) ;
shiftpoint h3 = T * xspinpush0 ( 240 * degree , 2 ) ;
queueline ( h1 , h2 , 0xFF0000FF , 4 ) ;
queueline ( h2 , h3 , 0xFF0000FF , 4 ) ;
queueline ( h3 , h1 , 0xFF0000FF , 4 ) ;
vid . linewidth / = 4 ;
} ) ;
no_other_hud ( mode ) ;
}
} ,
{ " spherical triangles " , 999 , LEGAL : : NONE | QUICKGEO ,
" The simplest non-Euclidean geometry is the geometry on the sphere. \n \n "
" Here we see a spherical triangle with three right angles. \n \n "
" For creatures restricted to just this surface, they are indeed striaght lines! \n \n "
,
[ ] ( presmode mode ) {
setCanvas ( mode , ' 0 ' ) ;
if ( mode = = pmStart ) {
2022-03-01 07:37:30 +00:00
tour : : slide_backup ( mapeditor : : drawplayer , false ) ;
2021-03-30 21:02:40 +00:00
enable_earth ( ) ;
View = Id ;
View = spin ( 3 * M_PI / 5 ) * View ;
View = spin ( 90 * degree ) * View ;
View = cspin ( 2 , 0 , 45 * degree ) * View ;
View = cspin ( 1 , 2 , 30 * degree ) * View ;
playermoved = false ;
tour : : slide_backup ( vid . axes , 0 ) ;
tour : : slide_backup ( vid . drawmousecircle , false ) ;
tour : : slide_backup ( draw_centerover , false ) ;
}
add_temporary_hook ( mode , hooks_frame , 200 , [ ] {
shiftmatrix T = ggmatrix ( currentmap - > gamestart ( ) ) * spin ( - 3 * M_PI / 5 ) ;
vid . linewidth * = 4 ;
shiftpoint h1 = T * C0 ;
shiftpoint h2 = T * xpush0 ( M_PI / 2 ) ;
shiftpoint h3 = T * ypush0 ( M_PI / 2 ) ;
queueline ( h1 , h2 , 0xFF0000FF , 3 ) ;
queueline ( h2 , h3 , 0xFF0000FF , 3 ) ;
queueline ( h3 , h1 , 0xFF0000FF , 3 ) ;
vid . linewidth / = 4 ;
} ) ;
if ( mode = = pmStop ) {
texture : : config . tstate = texture : : tsOff ;
}
no_other_hud ( mode ) ;
}
} ,
{ " hyperbolic plane " , 999 , LEGAL : : NONE | QUICKGEO ,
" Hyperbolic geometry works the opposite way to spherical geometry. "
" In hyperbolic geometry, the sum of angles of a triangle is less than 180 degrees. \n \n " ,
[ ] ( presmode mode ) {
2021-09-30 08:49:12 +00:00
if ( mode = = pmStartAll ) enable_canvas ( ) ;
2021-03-30 21:02:40 +00:00
setCanvas ( mode , ' F ' ) ;
if ( mode = = pmStart ) {
stop_game ( ) ;
slide_backup ( firstland , laCanvas ) ;
slide_backup ( specialland , laCanvas ) ;
set_geometry ( gNormal ) ;
set_variation ( eVariation : : bitruncated ) ;
slide_backup ( colortables [ ' F ' ] [ 0 ] , 0xC0FFC0 ) ;
slide_backup ( colortables [ ' F ' ] [ 1 ] , 0x80FF80 ) ;
slide_backup ( pconf . alpha , 1 ) ;
slide_backup ( pconf . scale , 1 ) ;
slide_backup ( rug : : mouse_control_rug , true ) ;
start_game ( ) ;
slide_backup ( patterns : : whichShape , ' 9 ' ) ;
}
if ( mode = = pmStart ) {
rug : : modelscale = 1 ;
// rug::rug_perspective = false;
rug : : gwhere = gCubeTiling ;
rug : : texturesize = 1024 ;
slide_backup ( sightrange_bonus , - 1 ) ;
drawthemap ( ) ;
rug : : init ( ) ;
}
if ( mode = = pmStart ) {
stop_game ( ) ;
set_geometry ( gArchimedean ) ; arcm : : current . parse ( " 3^7 " ) ;
set_variation ( eVariation : : pure ) ;
start_game ( ) ;
}
add_temporary_hook ( mode , hooks_frame , 200 , [ ] {
shiftmatrix T = ggmatrix ( currentmap - > gamestart ( ) ) ;
vid . linewidth * = 16 ;
shiftpoint h1 = T * xspinpush0 ( 0 , 2 ) ;
shiftpoint h2 = T * xspinpush0 ( 120 * degree , 2 ) ;
shiftpoint h3 = T * xspinpush0 ( 240 * degree , 2 ) ;
queueline ( h1 , h2 , 0xFF0000FF , 4 ) ;
queueline ( h2 , h3 , 0xFF0000FF , 4 ) ;
queueline ( h3 , h1 , 0xFF0000FF , 4 ) ;
vid . linewidth / = 16 ;
} ) ;
if ( mode = = 3 ) {
rug : : close ( ) ;
}
no_other_hud ( mode ) ;
}
} ,
{ " A right-angled pentagon " , 999 , LEGAL : : NONE | QUICKGEO ,
" There is also three-dimensional hyperbolic geometry. \n "
" Here are some right-angled pentagons in three-dimensional hyperbolic space. \n "
,
[ ] ( presmode mode ) {
if ( mode = = pmStart ) {
slide_backup ( patterns : : rwalls , 10 ) ;
slide_backup ( vid . fov , 120 ) ;
}
setCanvas ( mode , ' 0 ' ) ;
if ( mode = = pmStart ) {
set_geometry ( gSpace534 ) ;
/*
static bool solved = false ;
if ( ! solved ) {
stop_game ( ) ;
set_geometry ( gSpace534 ) ;
start_game ( ) ;
stop_game ( ) ;
cgi . require_basics ( ) ;
fieldpattern : : field_from_current ( ) ;
set_geometry ( gFieldQuotient ) ;
currfp . Prime = 5 ; currfp . force_hash = 0x72414D0C ;
currfp . solve ( ) ;
solved = true ;
}
set_geometry ( gFieldQuotient ) ;
*/
start_game ( ) ;
2022-03-01 07:37:30 +00:00
tour : : slide_backup ( mapeditor : : drawplayer , false ) ;
2021-03-31 01:18:36 +00:00
pentaroll : : create_pentaroll ( true ) ;
2021-03-30 21:02:40 +00:00
tour : : slide_backup ( anims : : period , 30000. ) ;
tour : : slide_backup ( sightranges [ geometry ] , 4 ) ;
start_game ( ) ;
playermoved = false ;
}
no_other_hud ( mode ) ;
}
} ,
{ " Penrose triangle (1958), Oscar Reutersvärd's triangle (1934), Penrose Stairs (1959) " , 999 , LEGAL : : NONE ,
" The Penrose Triangle, "
" constructed by Lionel Penrose and Roger Penrose in 1958, "
" is an example of an impossible figure. "
" Many artists have used the Penrose Triangle to create "
" more complex constructions, such as the \" Waterfall \" "
" by M. C. Escher. \n \n "
" While it is known as Penrose Triangle, a very similar construction "
" has actually been discovered earlier by Oscar Reutersvärd (in 1934)! \n \n "
" In 1959 Lionel Penrose and Roger Penrose have constructed another "
" example of an impossible figure, called the Penrose staircase. " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
show_picture ( mode , " rogueviz/nil/penrose-all-small.png " ) ;
no_other_hud ( mode ) ;
}
} ,
{ " Ascending & Descending " , 999 , LEGAL : : NONE | QUICKGEO ,
" It is the most well known from \" Ascending and Descending \" by M. C. Escher. \n \n "
" This is a 3D model of Ascending and Descending by Lucian B. It is based on an optical illusion. "
,
[ ] ( presmode mode ) {
2021-04-02 22:57:37 +00:00
slide_url ( mode , ' m ' , " link to the original model " , " https://3dwarehouse.sketchup.com/model/3e6df6c24a95f583cefabc2ae69d584c/MC-Escher-Ascending-and-Descending " ) ;
2021-03-30 21:02:40 +00:00
ply_slide ( mode , gCubeTiling , mdPerspective , false ) ;
if ( ! ply : : staircase . available ( ) ) return ;
if ( mode = = pmStart ) {
tour : : slide_backup ( sightranges [ geometry ] , 200 ) ;
tour : : slide_backup ( vid . cells_drawn_limit , 200 ) ;
tour : : slide_backup ( camera_speed , 5 ) ;
centerover = euc : : get_at ( euc : : coord { 12 , - 23 , 8 } ) - > c7 ;
playermoved = false ;
int cid = 0 ;
for ( ld val : { 0.962503 , 0.254657 , - 0.0934754 , 0.000555891 , 0.0829357 , - 0.604328 , - 0.792408 , 0.0992114 , - 0.258282 , 0.754942 , - 0.602787 , 0.0957558 , 0. , 0. , 0. , 1. } )
View [ 0 ] [ cid + + ] = val ;
// tour::slide_backup(vid.fov, 120);
}
2022-08-05 18:34:56 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
if ( mode = = pmKey ) {
println ( hlog , ggmatrix ( currentmap - > gamestart ( ) ) ) ;
println ( hlog , View ) ;
println ( hlog , euc : : get_ispacemap ( ) [ centerover - > master ] ) ;
}
}
} ,
/*
{ " Penrose triangle (1958) " , 999 , LEGAL : : NONE ,
" The Penrose Triangle, "
" constructed by Lionel Penrose and Roger Penrose in 1958, "
" is an example of an impossible figure. "
" Many artists have used the Penrose Triangle to create "
" more complex constructions, such as the \" Waterfall \" "
" by M. C. Escher. " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
show_picture ( mode , " rogueviz/nil/penrose-triangle.png " ) ;
no_other_hud ( mode ) ;
}
} ,
{ " Oscar Reutersvärd's triangle (1934) " , 999 , LEGAL : : NONE ,
" While it is known as Penrose Triangle, a very similar construction "
" has actually been discovered earlier by Oscar Reutersvärd (in 1934)! " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
show_picture ( mode , " rogueviz/nil/reutersvard.png " ) ;
no_other_hud ( mode ) ;
}
} ,
{ " Penrose staircase (1959) " , 999 , LEGAL : : NONE ,
" In 1959 Lionel Penrose and Roger Penrose have constructed another "
" example of an impossible figure, called the Penrose staircase. \n \n "
" It is the most well known from \" Ascending and Descending \" by M. C. Escher. \n \n " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
show_picture ( mode , " rogueviz/nil/penrose-stairs.png " ) ;
no_other_hud ( mode ) ;
}
} , */
{ " non-Euclidean geometry so far " , 123 , LEGAL : : ANY ,
" People sometimes call such impossible constructions \" non-Euclidean \" . \n \n "
" These people generally use this name because they do not know the usual "
" mathematical meaning of \" non-Euclidean \" . \n \n "
" It seems that the geometries we know so far are something completely different... " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
add_stat ( mode , [ ] {
dialog : : init ( ) ;
color_t d = dialog : : dialogcolor ;
dialog : : addTitle ( " Euclidean geometry " , 0xC00000 , 200 ) ;
2022-04-21 10:39:49 +00:00
dialog : : addTitle ( " parallel lines stay in the same distance " , d , 150 ) ;
2021-03-30 21:02:40 +00:00
dialog : : addBreak ( 100 ) ;
dialog : : addTitle ( " spherical geometry " , 0xC00000 , 200 ) ;
2022-04-21 10:39:49 +00:00
dialog : : addTitle ( " no parallel lines -- they converge " , d , 150 ) ;
2021-03-30 21:02:40 +00:00
dialog : : addBreak ( 100 ) ;
dialog : : addTitle ( " hyperbolic geometry " , 0xC00000 , 200 ) ;
2022-04-21 10:39:49 +00:00
dialog : : addTitle ( " parallel lines diverge " , d , 150 ) ;
2021-03-30 21:02:40 +00:00
dialog : : display ( ) ;
return true ;
} ) ;
2022-08-12 07:09:38 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
}
} ,
2022-08-12 07:09:38 +00:00
{ " Compasses in Nil " , 123 , LEGAL : : ANY | QUICKGEO ,
2021-03-30 21:02:40 +00:00
" However, it turns out that there actually exists a non-Euclidean geometry, "
" known as the Nil geometry, where constructions such as Penrose staircases and "
" triangles naturally appear! \n \n "
" Nil is a three-dimensional geometry, which gives new possibilities -- "
2022-05-09 09:09:30 +00:00
" lines 'diverge in the third dimension' there. "
" Every point has "
" well-defined North, East, South, West, Up and Down direction. \n \n "
" (press Home/End and arrow keys to move) " ,
[ ] ( presmode mode ) {
setCanvas ( mode , ' 0 ' ) ;
slidecommand = " highlight dimensions " ;
if ( mode = = pmStart ) {
tour : : slide_backup ( pmodel , mdGeodesic ) ;
set_geometry ( gNil ) ;
start_game ( ) ;
rogueviz : : rv_hook ( hooks_drawcell , 100 , rogueviz : : nilcompass : : draw_compass ) ;
View = Id ;
shift_view ( ztangent ( .5 ) ) ;
}
2022-08-05 18:34:56 +00:00
non_game_slide_scroll ( mode ) ;
2022-05-09 09:09:30 +00:00
if ( mode = = pmStart | | mode = = pmKey )
rogueviz : : nilcompass : : zeroticks = ticks ;
}
} ,
{ " a Puzzle about a Bear " , 123 , LEGAL : : ANY ,
2021-03-30 21:02:40 +00:00
" To explain Nil geometry, we will start with a well-known puzzle. " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
add_stat ( mode , [ ] {
dialog : : init ( ) ;
color_t d = dialog : : dialogcolor ;
dialog : : addTitle ( " A bear walked five kilometers north, " , d , 150 ) ;
dialog : : addTitle ( " five kilometers east, five kilometers south, " , d , 150 ) ;
dialog : : addTitle ( " and returned exactly to the place it started. " , d , 150 ) ;
dialog : : addBreak ( 50 ) ;
dialog : : addTitle ( " What color is the bear? " , 0xC00000 , 200 ) ;
dialog : : display ( ) ;
return true ;
} ) ;
no_other_hud ( mode ) ;
}
} ,
2022-08-12 07:09:38 +00:00
{ " Cartesian coordinates " , 999 , LEGAL : : NONE | QUICKGEO ,
2021-03-30 21:02:40 +00:00
" The puzzle shows an important fact: every point on Earth has defined directions "
" (North, East, South, West), and in most life situations, we can assume that these "
" directions work the same as in the Cartesian system of coordinates. "
,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
nil_screen ( mode , 0 ) ;
no_other_hud ( mode ) ;
}
} ,
2022-08-12 07:09:38 +00:00
{ " Nil coordinates " , 999 , LEGAL : : NONE | QUICKGEO ,
2021-03-30 21:02:40 +00:00
" However, because Earth is curved (non-Euclidean), these directions actually "
" work different! If you are closer to the pole, moving East or West changes "
" your longitude much more quickly. \n \n "
" Nil is a three-dimensional geometry which is similar: while every point also has "
" well-defined NSEWUD directions, but they affect the coordinates in a different way "
" than in the Euclidean space with the usual coordinate system. \n \n "
" You may want to use the Pythagorean theorem to compute the length of these -- "
" this is not correct, all the moves are of length d. You would need to use the Pythagorean "
" theorem if you wanted to compute the length from (x,y,z) to (x,y-d,z). \n \n "
,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
nil_screen ( mode , 1 ) ;
no_other_hud ( mode ) ;
}
} ,
2022-08-12 07:09:38 +00:00
{ " Nil coordinates (area) " , 999 , LEGAL : : NONE | QUICKGEO ,
2021-03-30 21:02:40 +00:00
" The formulas look strange at a first glance, but the idea is actually simple: "
" the change in the 'z' coordinate is the area of a triangle, as shown in the picture. "
" The change is positive if we go counterclockwise, and negative if we go clockwise. \n \n "
2022-04-21 10:39:49 +00:00
,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
nil_screen ( mode , 2 ) ;
no_other_hud ( mode ) ;
}
} ,
2022-08-12 07:09:38 +00:00
{ " Nil coordinates (loop) " , 999 , LEGAL : : NONE | QUICKGEO ,
2022-04-21 10:39:49 +00:00
" If we make a tour in Nil moving only in the directions N, W, S, E, such that "
2021-03-30 21:02:40 +00:00
" the analogous tour in Euclidean space would return us to the starting point, "
" then the tour in Nil would return us directly above or below the starting point, "
" with the difference in the z-coordinate proportional to the area of the loop. "
,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
2022-04-21 10:39:49 +00:00
nil_screen ( mode , 3 ) ;
2021-03-30 21:02:40 +00:00
no_other_hud ( mode ) ;
}
} ,
{ " Simple Penrose stairs " , 999 , LEGAL : : NONE | QUICKGEO ,
" This lets us easily make a simple realization of the Penrose staircase in Nil. "
" Here is an attempt to create a Penrose staircase in Euclidean geometry... \n \n "
" (you can rotate this with mouse or arrow keys) "
,
[ ] ( presmode mode ) {
brick_slide ( 0 , mode , gCubeTiling , mdHorocyclic , 0 ) ;
2022-08-12 07:09:38 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
}
} ,
{ " Simple Penrose stairs in Nil " , 999 , LEGAL : : NONE | QUICKGEO ,
" We can use the magic of the Nil geometry to recompensate the lost height. \n \n "
" Press 5 to see how it looks when we walk around the stairs. When you rotate this slide, "
" you will notice that the stairs change shape when far from the central point -- "
" this is because we use the Nil rules of movement. "
,
[ ] ( presmode mode ) {
brick_slide ( 0 , mode , gNil , mdHorocyclic , 0 ) ;
if ( mode = = pmKey ) bricks : : animation = ! bricks : : animation ;
2022-08-12 07:09:38 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
}
} ,
{ " Simple Penrose stairs in Nil (FPP) " , 999 , LEGAL : : NONE | QUICKGEO ,
" This slide shows our stairs in the first person perspective, from the inside. "
,
[ ] ( presmode mode ) {
brick_slide ( 0 , mode , gNil , mdPerspective , 3 ) ;
if ( mode = = pmKey ) bricks : : animation ^ = 1 ;
}
} ,
{ " Geodesics in Nil " , 999 , LEGAL : : NONE | QUICKGEO ,
" But, was the first person perspective in the last slide 'correct'? \n \n "
" According to Fermat's Principle, the path taken by a light ray is "
" always one which is the shortest. Our previous visualization assumed "
" that light rays move in a fixed 'direction', which may be not the case. \n \n "
" Let's think a bit about moving from (0,0,0) to (0,0,25). We can of course "
" take the obvious path of length 25. Can we do it better? "
,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
geodesic_screen ( mode , 0 ) ;
no_other_hud ( mode ) ;
}
} ,
{ " Geodesics: square " , 999 , LEGAL : : NONE | QUICKGEO ,
" Yes, we can! Here is a square of edge length 5. Since such a square has an "
" area of 25 and perimeter of 20, it takes us to (0,0,25) in just 20 steps! "
,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
geodesic_screen ( mode , 1 ) ;
no_other_hud ( mode ) ;
}
} ,
{ " Geodesics: circle " , 999 , LEGAL : : NONE | QUICKGEO ,
" We can do even better. Queen Dido already knew that among shapes with the "
" given area, the circle has the shortest perimeter. A circle with area 25 "
" has even shorter length. "
,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
geodesic_screen ( mode , 2 ) ;
no_other_hud ( mode ) ;
}
} ,
{ " Geodesics: helix " , 999 , LEGAL : : NONE | QUICKGEO ,
" But that was just the silver medal. \n \n "
" For the gold medal, we need to combine the 'silver' and 'green' paths. "
" We make the circle slightly smaller, and we satisfy the difference by moving "
" slightly upwards. The length of such path can be computed using the Pythagorean "
" theorem, and minimized by differentiation. There is an optimal radius which "
" yields the best path. " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
geodesic_screen ( mode , 3 ) ;
no_other_hud ( mode ) ;
}
} ,
{ " Simple Penrose stairs in Nil (geodesics) " , 999 , LEGAL : : NONE | QUICKGEO ,
" The light ray paths ('geodesics') in Nil are like the ones constructed in "
" the last slide: they are helices, the steeper the helix, the smaller "
" its radius. \n \n "
" This slide presents the staircase in model perspective and the "
" geodesically correct view. The geodesically correct view appears to spin. "
,
[ ] ( presmode mode ) {
brick_slide ( 0 , mode , gNil , mdGeodesic , 3 ) ;
compare_projections ( mode , mdPerspective , mdGeodesic ) ;
}
} ,
{ " Penrose triangle (illusion) " , 999 , LEGAL : : NONE | QUICKGEO ,
" Can we also construct the Penrose triangle? "
" Yes, we can! In our space, we can construct an illusion "
" which looks like the Penrose triangle (rotate the scene and press '5'). "
" If we rotate this illusion in such a way that the 'paradox line' "
" is vertical, we can recompensate the difference by using the Nil geometry. "
" We need to scale our scene in such a way that the length of the white line "
" equals the area contained in the projection of the red line. "
,
[ ] ( presmode mode ) {
brick_slide ( 1 , mode , gCubeTiling , mdHorocyclic , 0 ) ;
static bool draw = false ;
if ( mode = = pmKey ) draw = ! draw ;
add_temporary_hook ( mode , hooks_prestats , 200 , [ ] {
if ( draw ) {
shiftmatrix Zero = ggmatrix ( currentmap - > gamestart ( ) ) ;
initquickqueue ( ) ;
// two first bricks are fake
int id = 0 ;
for ( auto & b : bricks : : bricks ) {
id + + ;
if ( id > = 2 ) curvepoint ( b . location ) ;
}
vid . linewidth * = 10 ;
queuecurve ( Zero , 0x0000FFFF , 0 , PPR : : SUPERLINE ) . flags | = POLY_FORCEWIDE ;
vid . linewidth / = 10 ;
curvepoint ( bricks : : bricks [ 2 ] . location ) ;
curvepoint ( bricks : : bricks . back ( ) . location ) ;
vid . linewidth * = 10 ;
queuecurve ( Zero , 0xFFFFFFFF , 0 , PPR : : SUPERLINE ) . flags | = POLY_FORCEWIDE ;
vid . linewidth / = 10 ;
quickqueue ( ) ;
}
return false ;
} ) ;
2022-08-12 07:09:38 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
// pmodel = (pmodel == mdGeodesic ? mdPerspective : mdGeodesic);
}
} ,
{ " Penrose triangle (Nil) " , 999 , LEGAL : : NONE | QUICKGEO ,
" Here we move around the Penrose triangle... "
,
[ ] ( presmode mode ) {
brick_slide ( 1 , mode , gNil , mdHorocyclic , 1 ) ;
// if(mode == pmKey) DRAW
// pmodel = (pmodel == mdGeodesic ? mdPerspective : mdGeodesic);
2022-08-12 07:09:38 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
}
} ,
{ " Penrose triangle (FPP) " , 999 , LEGAL : : NONE | QUICKGEO ,
" ... and see the Penrose triangle in first-person perspective. "
" Since the Penrose triangle is larger (we need stronger Nil effects "
" to make it work), the geodesic effects are also much stronger. "
,
[ ] ( presmode mode ) {
brick_slide ( 1 , mode , gNil , mdPerspective , 3 ) ;
compare_projections ( mode , mdPerspective , mdGeodesic ) ;
}
} ,
{ " Improbawall by Matt Taylor (emty01) " , 999 , LEGAL : : NONE | QUICKGEO ,
" This impossible construction by Matt Taylor was popular in early 2020. "
" How does it even work? \n \n "
" (the animation is not included with RogueViz) "
,
[ ] ( presmode mode ) {
2022-04-07 19:06:47 +00:00
static bool pic_exists , video_exists ;
if ( mode = = pmStartAll | | mode = = pmStart ) {
pic_exists = file_exists ( " rogueviz/nil/emty-ring.png " ) ;
video_exists = file_exists ( " rogueviz/nil/emty-ring.mp4 " ) ;
}
2021-04-02 22:57:37 +00:00
slide_url ( mode , ' i ' , " Instagram link " , " https://www.instagram.com/p/B756GCynErw/ " ) ;
2021-03-30 21:02:40 +00:00
empty_screen ( mode ) ;
2022-04-07 19:06:47 +00:00
if ( video_exists )
show_animation ( mode , " rogueviz/nil/emty-ring.mp4 " , 720 , 900 , 300 , 30 ) ;
else if ( pic_exists )
show_picture ( mode , " rogueviz/nil/emty-ring.png " ) ;
else
slide_error ( mode , " (image not available) " ) ;
2021-03-30 21:02:40 +00:00
no_other_hud ( mode ) ;
}
} ,
{ " how is this made " , 999 , LEGAL : : NONE | QUICKGEO ,
" Rotate this ring and press '5' to rotate a half of it by 90 degrees. "
" After rotating this ring so that the endpoints agree, we get another "
" case that can be solved in Nil geometry. "
,
[ ] ( presmode mode ) {
impossible_ring_slide ( mode ) ;
2022-08-12 07:09:38 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
}
} ,
{ " impossible ring in Nil " , 18 , LEGAL : : NONE | QUICKGEO ,
" Here is how it looks in Nil. Press '5' to animate. \n " ,
[ ] ( presmode mode ) {
setCanvas ( mode , ' 0 ' ) ;
slidecommand = " animation " ;
if ( mode = = pmKey ) {
tour : : slide_backup ( rogueviz : : cylon : : cylanim , ! rogueviz : : cylon : : cylanim ) ;
}
if ( mode = = pmStart ) {
stop_game ( ) ;
set_geometry ( gNil ) ;
2021-03-31 09:13:37 +00:00
rogueviz : : cylon : : enable ( ) ;
2021-03-30 21:02:40 +00:00
tour : : on_restore ( nilv : : set_flags ) ;
tour : : slide_backup ( nilv : : nilperiod , make_array ( 3 , 3 , 3 ) ) ;
nilv : : set_flags ( ) ;
start_game ( ) ;
}
2022-08-05 18:34:56 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
} } ,
{ " 3D model (geodesic) " , 999 , LEGAL : : NONE | QUICKGEO ,
" What if we try to move something more complex, rather than a simple geometric shape? \n \n "
" This slide is based on a 3D model of Ascending and Descending by Lucian B. "
" We have used the trick mentioned before to move into the Nil space. Here are the results. "
,
[ ] ( presmode mode ) {
2021-04-02 22:57:37 +00:00
slide_url ( mode , ' y ' , " YouTube link " , " https://www.youtube.com/watch?v=DurXAhFrmkE " ) ;
2021-03-30 21:02:40 +00:00
ply_slide ( mode , gNil , mdGeodesic , true ) ;
}
} ,
{ " 3D model (perspective) " , 999 , LEGAL : : NONE | QUICKGEO ,
" The same in the simple model. "
,
[ ] ( presmode mode ) {
ply_slide ( mode , gNil , mdPerspective , true ) ;
}
} ,
{ " two Penrose triangles (Euc) " , 999 , LEGAL : : NONE | QUICKGEO ,
" Here are two Penrose triangles. Can we move that to Nil? "
,
[ ] ( presmode mode ) {
brick_slide ( 2 , mode , gCubeTiling , mdHorocyclic , 0 ) ;
2022-08-12 07:09:38 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
}
} ,
{ " two Penrose triangles (Nil) " , 999 , LEGAL : : NONE | QUICKGEO ,
" No, we cannot -- one of the triangles has opposite orientation! \n \n "
" That is still impossible in Nil, so not all "
" impossible constructions can be realized in Nil. \n \n "
" For example, \" Waterfall \" by M. C. Escher is based on three "
" triangles with two different orientations. " ,
[ ] ( presmode mode ) {
brick_slide ( 2 , mode , gNil , mdHorocyclic , 0 ) ;
2022-08-12 07:09:38 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
}
} ,
{ " Balls in Nil " , 999 , LEGAL : : NONE | QUICKGEO | FINALSLIDE ,
" A perpetuum mobile in Nil as the final slide. That's all for today! "
,
[ ] ( presmode mode ) {
2021-04-02 22:57:37 +00:00
slide_url ( mode , ' y ' , " YouTube link " , " https://www.youtube.com/watch?v=mxvUAcgN3go " ) ;
2022-05-09 09:09:30 +00:00
slide_url ( mode , ' n ' , " Nil Rider " , " https://zenorogue.itch.io/nil-rider " ) ;
2021-03-30 21:02:40 +00:00
setCanvas ( mode , ' 0 ' ) ;
if ( mode = = pmStart ) {
stop_game ( ) ;
set_geometry ( gNil ) ;
check_cgi ( ) ;
cgi . require_shapes ( ) ;
start_game ( ) ;
rogueviz : : balls : : initialize ( 1 ) ;
rogueviz : : balls : : balls . resize ( 3 ) ;
pmodel = mdEquidistant ;
View = cspin ( 1 , 2 , M_PI / 2 ) ;
}
2022-08-05 18:34:56 +00:00
non_game_slide_scroll ( mode ) ;
2021-03-30 21:02:40 +00:00
}
} ,
{ " final slide " , 123 , LEGAL : : ANY | NOTITLE | QUICKSKIP | FINALSLIDE ,
" FINAL SLIDE " ,
[ ] ( presmode mode ) {
empty_screen ( mode ) ;
add_stat ( mode , [ ] {
dialog : : init ( ) ;
color_t d = dialog : : dialogcolor ;
dialog : : addTitle ( " Thanks for your attention! " , 0xC00000 , 200 ) ;
dialog : : addBreak ( 100 ) ;
dialog : : addTitle ( " twitter.com/zenorogue/ " , d , 150 ) ;
dialog : : display ( ) ;
return true ;
} ) ;
no_other_hud ( mode ) ;
}
}
} ;
int phooks =
0 +
2021-06-25 12:04:50 +00:00
addHook_slideshows ( 100 , [ ] ( tour : : ss : : slideshow_callback cb ) {
2022-03-01 07:37:47 +00:00
cb ( XLAT ( " Playing with Impossibility " ) , & dmv_slides [ 0 ] , ' i ' ) ;
2021-03-30 21:02:40 +00:00
} ) ;
}
}
// kolor zmienic dziada