2021-03-31 16:04:02 +00:00
// compile with:
// ./mymake -O3 inner-maps
2021-03-31 16:04:34 +00:00
// used in: https://twitter.com/zenorogue/status/1212408644941295619
2021-03-31 16:04:02 +00:00
// run with:
2022-08-01 13:49:24 +00:00
// ./hyper -noscr -canvas r -canvas i -wsh 0 -smart 4 -shott 0 -alpha 1 -inner-map
2021-03-31 16:04:02 +00:00
# include "rogueviz.h"
namespace hr {
namespace inner {
bool out = true ;
EX struct renderbuffer * buf1 , * buf2 ;
map < cell * , basic_textureinfo > lti ;
ld mdist ;
bool for_klein = false ;
ld alpha = - .7 ;
cell * rendercenter ;
shiftmatrix rendercenterV ;
bool auto_move = false ;
2022-08-05 18:35:26 +00:00
bool full_disk = false ;
ld alpha_channel = 1 ;
2021-03-31 16:04:02 +00:00
ld texture_alpha = 1 ;
ld inner_alpha = 1 ;
2022-08-05 18:35:26 +00:00
/** 0 = not every heptagon, 1 = every heptagon, 2 = every cell */
int dense = 0 ;
2021-03-31 16:04:02 +00:00
// should do 30x -- temporarily disabled
ld iterations = 1 ;
ld iterations_bank ;
void gentexture ( ) {
2022-08-05 18:35:26 +00:00
if ( ! out ) return ;
iterations_bank + = iterations ;
println ( hlog , tie ( current_display - > xcenter , current_display - > ycenter , current_display - > xtop , current_display - > ytop , current_display - > xsize , current_display - > ysize ) ) ;
2021-03-31 16:04:02 +00:00
while ( iterations_bank > = 1 ) {
iterations_bank - = 1 ;
println ( hlog , " # = " , isize ( lti ) ) ;
dynamicval < bool > b ( out , false ) ;
dynamicval < ld > va ( pconf . alpha , texture_alpha ) ;
2022-08-05 18:35:26 +00:00
dynamicval < ld > vb ( pconf . scale , 1 ) ;
2021-03-31 16:04:02 +00:00
if ( ! buf1 ) {
buf1 = new renderbuffer ( rug : : texturesize , rug : : texturesize , true ) ;
buf2 = new renderbuffer ( rug : : texturesize , rug : : texturesize , true ) ;
}
resetbuffer rb ;
rug : : calcparam_rug ( ) ;
models : : configure ( ) ;
buf1 - > enable ( ) ;
buf1 - > clear ( 0 ) ;
buf2 - > use_as_texture ( ) ;
draw_boundary ( 0 ) ;
draw_boundary ( 1 ) ;
draw_model_elements ( ) ;
drawthemap ( ) ;
drawqueue ( ) ;
calcparam ( ) ;
rb . reset ( ) ;
swap ( buf1 , buf2 ) ;
rendercenter = centerover ;
rendercenterV = gmatrix [ centerover ] ;
}
2022-08-05 18:35:26 +00:00
calcparam ( ) ;
println ( hlog , tie ( current_display - > xcenter , current_display - > ycenter , current_display - > xtop , current_display - > ytop , current_display - > xsize , current_display - > ysize ) ) ;
current_display - > set_viewport ( 0 ) ;
reset_projection ( ) ;
2021-03-31 16:04:02 +00:00
}
void frame ( ) {
gentexture ( ) ;
if ( auto_move ) {
color_t col = minf [ moReptile ] . color ;
drawMonsterType ( moReptile , NULL , shiftless ( spin ( alpha ) ) , col , mdist , col ) ;
mapeditor : : drawplayer = false ;
}
}
bool done ;
2022-08-05 18:35:26 +00:00
// should be .5 for dense
ld crad = 1.82 ;
2021-03-31 16:04:02 +00:00
ld ceps = .02 ;
2022-08-05 18:35:26 +00:00
bool auto_crad = false ;
2021-03-31 16:04:02 +00:00
void need_redo ( ) {
done = false ;
}
2022-08-05 18:35:26 +00:00
struct shapes {
hpcshape edgeshape , circ ;
ld crad_p ;
} ;
struct inner_ext : gi_extension {
map < int , shapes > sh ;
} ;
shapes & get_shapes ( ld crad ) {
if ( ! cgi . ext [ " innermaps " ] ) cgi . ext [ " innermaps " ] = std : : make_unique < inner_ext > ( ) ;
auto & ie = ( inner_ext & ) * cgi . ext [ " innermaps " ] ;
int rad = int ( crad * 100000 + .5 ) ;
bool done = ie . sh . count ( rad ) ;
auto & sh = ie . sh [ rad ] ;
if ( done ) return sh ;
2021-03-31 16:04:02 +00:00
done = true ;
2022-08-05 18:35:26 +00:00
cgi . bshape ( sh . circ , PPR : : WALL ) ;
sh . circ . flags | = POLY_TRIANGLES ;
2021-03-31 16:04:02 +00:00
int k = for_klein ? 1 : 2 ;
int maxz = for_klein ? 120 : 30 ;
for ( int z = 0 ; z < maxz ; z + + ) {
ld ra = ( z + 0. ) / maxz * crad , rb = ( z + 1. ) / maxz * crad ;
for ( int i = 0 ; i < 360 ; i + = k ) {
ld a = i * degree ;
ld b = ( i + k ) * degree ;
cgi . hpcpush ( xspinpush0 ( a , ra ) ) ;
cgi . hpcpush ( xspinpush0 ( a , rb ) ) ;
cgi . hpcpush ( xspinpush0 ( b , rb ) ) ;
if ( z ) {
cgi . hpcpush ( xspinpush0 ( a , ra ) ) ;
cgi . hpcpush ( xspinpush0 ( b , ra ) ) ;
cgi . hpcpush ( xspinpush0 ( b , rb ) ) ;
}
}
}
cgi . finishshape ( ) ;
2022-08-05 18:35:26 +00:00
cgi . bshape ( sh . edgeshape , PPR : : WALL ) ;
if ( ! full_disk )
2021-03-31 16:04:02 +00:00
for ( int i = 0 ; i < = 360 ; i + = k ) {
ld a = i * degree ;
cgi . hpcpush ( xspinpush0 ( a , crad - ceps ) ) ;
}
for ( int i = 0 ; i < = 360 ; i + = k ) {
ld a = i * degree ;
cgi . hpcpush ( xspinpush0 ( a , crad + ceps ) ) ;
}
cgi . finishshape ( ) ;
cgi . extra_vertices ( ) ;
hyperpoint ph = xspinpush0 ( 0 , crad ) ;
ph / = ( inner_alpha + ph [ 2 ] ) ;
2022-08-05 18:35:26 +00:00
sh . crad_p = ph [ 0 ] ;
println ( hlog , " done " ) ;
return sh ;
2021-03-31 16:04:02 +00:00
}
set < cell * > gs ;
bool render ( cell * c , const shiftmatrix & V ) {
if ( ! buf1 | | ! buf2 | | ! rendercenter ) return false ;
2022-08-05 18:35:26 +00:00
if ( auto_crad ) {
crad = hdist0 ( mid ( get_corner_position ( c , 0 ) , get_corner_position ( c , 1 ) ) ) - ceps ;
}
auto & sh = get_shapes ( crad ) ;
2021-03-31 16:04:02 +00:00
if ( false & & ! gs . count ( c ) ) {
gs . insert ( c ) ;
c - > mondir = hrand ( c - > type ) ;
dont_face_pc = true ;
switch ( hrand ( 100 ) ) {
case 0 :
c - > monst = moOrangeDog ;
break ;
case 1 :
c - > item = itHell ;
break ;
case 2 :
c - > monst = moSalamander ;
break ;
case 3 :
c - > monst = moButterfly ;
break ;
case 4 :
c - > monst = moSparrowhawk ;
break ;
}
}
2022-08-05 18:35:26 +00:00
if ( dense = = 2 ? true : dense = = 1 ? pseudohept ( c ) : cdist50 ( c ) = = 0 ) {
2021-03-31 16:04:02 +00:00
dynamicval < color_t > po ( poly_outline , 0x000000FF ) ;
auto & p = lti [ c ] ;
p . texture_id = buf2 - > renderedTexture ;
p . tvertices . clear ( ) ;
/*inner_alpha = anyshiftclick ? 1 : 0;
hyperpoint ph = xspinpush0 ( 0 , crad ) ;
ph / = ( inner_alpha + ph [ 2 ] ) ;
crad_p = ph [ 0 ] ;
*/
2022-08-05 18:35:26 +00:00
if ( full_disk ) queuepoly ( V , sh . edgeshape , darkena ( c - > landparam , 0 , 0xFF ) ) ;
for ( int i = sh . circ . s ; i < sh . circ . e ; i + + ) {
2021-03-31 16:04:02 +00:00
hyperpoint h = cgi . hpc [ i ] ;
// hyperboloid to Poincare
h / = ( inner_alpha + h [ 2 ] ) ;
// scale up
2022-08-05 18:35:26 +00:00
h / = sh . crad_p ;
2021-03-31 16:04:02 +00:00
h * = .99999999 ;
// Poincare to hyperboloid
h = perspective_to_space ( h , inner_alpha , cgclass ) ;
/*
ld hr = sqhypot_d ( 2 , h ) ;
ld hz = ( 1 + hr ) / ( 1 - hr ) ;
h [ 0 ] * = ( hz + 1 ) ;
h [ 1 ] * = ( hz + 1 ) ;
h [ 2 ] = hz ;
*/
// move according to V
h = rendercenterV . T * inverse ( ggmatrix ( rendercenter ) . T ) * V . T * h ;
// texture coordinates
// hyperpoint scr;
// dynamicval<ld> b(pconf.alpha, anyshiftclick ? pconf.alpha : texture_alpha);
// applymodel(h, scr);
hyperpoint scr = h / ( texture_alpha + h [ 2 ] ) ;
p . tvertices . push_back ( glhr : : makevertex ( .5 + .5 * scr [ 0 ] , .5 - .5 * scr [ 1 ] , 0 ) ) ;
}
2022-08-05 18:35:26 +00:00
auto & pe = queuepoly ( V , sh . circ , 0xFFFFFFFF ) ;
pe . tinf = & p ;
part ( pe . color , 0 ) = 255 * alpha_channel ;
if ( ! full_disk ) queuepoly ( V , sh . edgeshape , darkena ( c - > landparam , 0 , 0xFF ) ) ;
2021-03-31 16:04:02 +00:00
}
return false ;
}
void shift ( ) {
if ( auto_move ) {
centerover = currentmap - > gamestart ( ) ;
mdist = ( ticks % 10000 ) * 6 / 10000. ;
View = spin ( alpha ) * xpush ( - mdist ) * spin ( - alpha ) ;
anims : : moved ( ) ;
centerover - > monst = moNone ;
forCellEx ( c1 , centerover ) c1 - > monst = moNone ;
}
}
void show ( ) {
cmode = sm : : SIDE | sm : : MAYDARK ;
2022-07-05 14:03:12 +00:00
gamescreen ( ) ;
2021-03-31 16:04:02 +00:00
dialog : : init ( XLAT ( " inner maps " ) , 0xFFFFFFFF , 150 , 0 ) ;
add_edit ( texture_alpha ) ;
add_edit ( inner_alpha ) ;
add_edit ( dense ) ;
add_edit ( crad ) ;
add_edit ( ceps ) ;
add_edit ( auto_move ) ;
2022-08-05 18:35:26 +00:00
add_edit ( auto_crad ) ;
2021-03-31 16:04:02 +00:00
add_edit ( iterations ) ;
dialog : : addBack ( ) ;
dialog : : display ( ) ;
}
2021-04-07 16:01:03 +00:00
void enable ( ) {
2021-03-31 16:04:02 +00:00
using rogueviz : : rv_hook ;
rv_hook ( hooks_frame , 100 , frame ) ;
rv_hook ( hooks_drawcell , 100 , render ) ;
rv_hook ( anims : : hooks_anim , 100 , shift ) ;
rv_hook ( hooks_o_key , 80 , [ ] ( o_funcs & v ) { v . push_back ( named_dialog ( " inner maps " , show ) ) ; } ) ;
2021-04-07 16:01:03 +00:00
}
auto hook = arg : : add3 ( " -inner-map " , enable )
2021-03-31 16:04:02 +00:00
+ addHook ( hooks_configfile , 100 , [ ] {
param_f ( texture_alpha , " inner_talpha " )
- > editable ( 0 , 5 , .1 , " texture projection distance " , " " , ' t ' ) ;
param_f ( inner_alpha , " inner_ialpha " )
- > editable ( 0 , 5 , .1 , " inner projection distance " , " " , ' i ' )
- > set_reaction ( need_redo ) ;
2022-08-05 18:35:26 +00:00
param_i ( dense , " inner_dense " )
- > editable ( 0 , 2 , 1 , " densely packed maps " , " 0=palace pattern, 1=heptagons, 2=all " , ' d ' ) ;
param_b ( auto_crad , " inner_auto_crad " )
- > editable ( " assign crad automatically to cell inradius " , ' a ' ) ;
2021-03-31 16:04:02 +00:00
param_f ( crad , " inner_crad " )
- > editable ( 0 , 10 , .1 , " radii of the inner maps " , " " , ' r ' )
- > set_reaction ( need_redo ) ;
param_f ( ceps , " inner_ceps " )
- > editable ( 0 , 0.1 , .001 , " map frame size " , " " , ' f ' )
- > set_reaction ( need_redo ) ;
param_b ( auto_move , " auto_move " )
- > editable ( " animate " , ' a ' ) ;
2022-08-05 18:35:26 +00:00
param_b ( full_disk , " inner_full_disk " )
- > editable ( " use full disk " , ' F ' ) ;
param_f ( alpha_channel , " inner_alpha_channel " )
- > editable ( 0 , .1 , 1 , " alpha channel to use in inner maps " , " " , ' C ' ) ;
2021-03-31 16:04:02 +00:00
param_f ( iterations , " inner_iterations " )
- > editable ( 0 , 30 , 0.2 , " iterations per frame " ,
" How many times per frame should we re-render the map " ,
' i ' )
- > set_reaction ( need_redo ) ;
2021-04-07 16:01:03 +00:00
} )
2021-06-25 11:53:23 +00:00
+ addHook_rvslides ( 52 , [ ] ( string s , vector < tour : : slide > & v ) {
2021-04-07 16:01:03 +00:00
if ( s ! = " projections " ) return ;
using namespace tour ;
v . push_back ( slide {
" projections/hyperbolic to hyperbolic " , 10 , LEGAL : : NONE | QUICKGEO ,
" We can also project a hyperbolic plane to a hyperbolic plane of different curvature. \n \n "
2021-04-16 17:41:45 +00:00
" Creatures living in the hyperbolic world may use the native Poincaré model to get conformal, circular, and totally useless maps of their whole world. \n \n "
2021-04-07 16:01:03 +00:00
" Press 'o' to change the settings. "
,
[ ] ( presmode mode ) {
slide_url ( mode , ' t ' , " Twitter link (with description) " , " https://twitter.com/zenorogue/status/1212408644941295619 " ) ;
setCanvas ( mode , ' r ' ) ;
if ( mode = = pmStart ) {
if ( ! shmup : : on ) restart_game ( rg : : shmup ) ;
slide_backup ( mapeditor : : drawplayer , true ) ;
enable ( ) ;
start_game ( ) ;
}
} } ) ;
} ) ;
2021-03-31 16:04:02 +00:00
}
}