2019-08-10 11:43:24 +00:00
// Hyperbolic Rogue - Hypersian Rug mode
2016-08-26 09:58:03 +00:00
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
2019-08-10 11:43:24 +00:00
/** \file rug.cpp
* \ brief Hypersian Rug mode
*
* See also surface . cpp for constant curvature surfaces .
*/
2016-08-26 09:58:03 +00:00
2019-09-05 07:15:40 +00:00
# include "hyper.h"
2018-06-10 23:58:31 +00:00
namespace hr {
2017-11-06 18:24:02 +00:00
2017-07-22 23:33:27 +00:00
# if CAP_RUG
2016-08-26 09:58:03 +00:00
# define TEXTURESIZE (texturesize)
# define HTEXTURESIZE (texturesize / 2)
2019-08-09 23:07:39 +00:00
EX bool rug_failure = false ;
2018-03-02 12:06:28 +00:00
2019-08-09 23:07:39 +00:00
EX namespace rug {
2016-08-26 09:58:03 +00:00
2020-04-14 15:46:40 +00:00
EX transmatrix rugView ;
2019-08-09 23:07:39 +00:00
EX ld lwidth = 2 ;
2019-03-30 16:46:50 +00:00
2019-08-09 23:07:39 +00:00
EX bool in_crystal ( ) { return surface : : sh = = surface : : dsCrystal ; }
2018-11-30 19:29:14 +00:00
2018-03-24 14:17:17 +00:00
bool computed = false ;
2019-08-09 23:07:39 +00:00
# if HDR
struct edge {
struct rugpoint * target ;
ld len ;
} ;
struct dexp_data {
hyperpoint params ;
hyperpoint cont ;
ld remaining_distance ;
} ;
struct rugpoint {
double x1 , y1 ;
bool valid ;
bool inqueue ;
double dist ;
2020-04-14 14:44:56 +00:00
hyperpoint h ; // point in the represented space
hyperpoint native ; // point in the native space
2019-08-09 23:07:39 +00:00
hyperpoint precompute ;
vector < edge > edges ;
vector < edge > anticusp_edges ;
// Find-Union algorithm
rugpoint * glue ;
rugpoint * getglue ( ) {
return glue ? ( glue = glue - > getglue ( ) ) : this ;
}
2020-04-14 14:44:56 +00:00
hyperpoint & gluenative ( ) {
return glue - > native ;
2019-08-09 23:07:39 +00:00
}
rugpoint ( ) { glue = NULL ; }
void glueto ( rugpoint * x ) {
x = x - > getglue ( ) ;
auto y = getglue ( ) ;
if ( x ! = y ) y - > glue = x ;
}
int dexp_id ;
dexp_data surface_point ;
} ;
struct triangle {
rugpoint * m [ 3 ] ;
2020-04-14 23:43:28 +00:00
triangle ( ) { m [ 0 ] = m [ 1 ] = m [ 2 ] = nullptr ; }
2019-08-09 23:07:39 +00:00
triangle ( rugpoint * m1 , rugpoint * m2 , rugpoint * m3 ) {
m [ 0 ] = m1 ; m [ 1 ] = m2 ; m [ 2 ] = m3 ;
}
} ;
# endif
EX vector < rugpoint * > points ;
EX vector < triangle > triangles ;
2018-03-24 14:17:17 +00:00
2018-02-03 13:35:06 +00:00
int when_enabled ;
2017-12-29 11:54:50 +00:00
struct rug_exception { } ;
2019-08-09 23:07:39 +00:00
EX bool fast_euclidean = true ;
EX bool good_shape ;
EX bool subdivide_first = false ;
EX bool spatial_rug = false ;
2018-02-27 18:27:20 +00:00
2019-08-09 23:07:39 +00:00
EX bool subdivide_further ( ) ;
EX void subdivide ( ) ;
2017-12-25 22:47:57 +00:00
2019-08-09 23:07:39 +00:00
EX ld modelscale = 1 ;
EX ld model_distance = 4 ;
2017-11-06 18:24:02 +00:00
2020-04-16 19:00:41 +00:00
# if HDR
constexpr eGeometry rgHyperbolic = gSpace534 ;
constexpr eGeometry rgEuclid = gCubeTiling ;
constexpr eGeometry rgSphere = gCell120 ;
constexpr eGeometry rgElliptic = gECell120 ;
# endif
2017-12-25 22:47:57 +00:00
2020-04-14 14:44:56 +00:00
EX eGeometry gwhere = rgEuclid ;
2020-04-16 22:53:58 +00:00
# if HDR
# define USING_NATIVE_GEOMETRY_IN_RUG dynamicval<eGeometry> gw(geometry, rug::rugged ? hr::rug::gwhere : geometry)
2020-04-14 14:44:56 +00:00
# define USING_NATIVE_GEOMETRY dynamicval<eGeometry> gw(geometry, hr::rug::gwhere)
2020-04-16 22:53:58 +00:00
# endif
2017-12-27 18:55:00 +00:00
2016-08-26 09:58:03 +00:00
// hypersian rug datatypes and globals
//-------------------------------------
2019-08-09 23:07:39 +00:00
EX bool rugged = false ;
2016-08-26 09:58:03 +00:00
bool genrug = false ;
2019-08-09 23:07:39 +00:00
EX int vertex_limit = 20000 ;
2017-12-27 09:52:54 +00:00
2019-08-09 23:07:39 +00:00
EX bool renderonce = false ;
EX int renderlate = 0 ;
EX bool rendernogl = false ;
EX int texturesize = 1024 ;
EX ld scale = 1 ;
EX ld ruggo = 0 ;
2016-08-26 09:58:03 +00:00
2019-08-09 23:07:39 +00:00
EX ld anticusp_factor = 1 ;
EX ld anticusp_dist ;
2018-02-27 18:37:57 +00:00
2019-08-09 23:07:39 +00:00
EX ld err_zero = 1e-3 , err_zero_current , current_total_error ;
2017-12-25 22:47:57 +00:00
2019-09-06 06:17:02 +00:00
EX int queueiter , qvalid , dt ;
2016-08-26 09:58:03 +00:00
2019-08-09 23:07:39 +00:00
EX rugpoint * finger_center ;
EX ld finger_range = .1 ;
EX ld finger_force = 1 ;
2018-01-29 15:28:06 +00:00
2020-04-16 22:53:58 +00:00
# define rconf (vid.rug_config)
2017-12-25 22:47:57 +00:00
2020-04-16 22:53:58 +00:00
EX bool perspective ( ) { return models : : is_perspective ( rconf . model ) ; }
2017-12-27 20:08:31 +00:00
2017-12-27 09:52:54 +00:00
void push_point ( hyperpoint & h , int coord , ld val ) {
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
if ( fast_euclidean & & euclid )
2017-12-27 09:52:54 +00:00
h [ coord ] + = val ;
else if ( ! val ) return ;
else {
2020-04-14 14:44:56 +00:00
h = cpush ( coord , val ) * h ;
2017-12-25 22:47:57 +00:00
}
}
2017-12-27 09:52:54 +00:00
2019-09-06 06:17:02 +00:00
EX void push_all_points ( int coord , ld val ) {
2017-12-27 09:52:54 +00:00
if ( ! val ) return ;
2018-06-22 12:47:24 +00:00
else for ( int i = 0 ; i < isize ( points ) ; i + + )
2020-04-14 14:44:56 +00:00
push_point ( points [ i ] - > native , coord , val ) ;
2017-12-27 09:52:54 +00:00
}
2017-12-25 22:47:57 +00:00
2016-08-26 09:58:03 +00:00
// construct the graph
//---------------------
int hyprand ;
2020-04-14 14:44:56 +00:00
bool rug_euclid ( ) { USING_NATIVE_GEOMETRY ; return euclid ; }
bool rug_hyperbolic ( ) { USING_NATIVE_GEOMETRY ; return hyperbolic ; }
bool rug_sphere ( ) { USING_NATIVE_GEOMETRY ; return sphere ; }
bool rug_elliptic ( ) { USING_NATIVE_GEOMETRY ; return elliptic ; }
2019-08-09 23:07:39 +00:00
EX rugpoint * addRugpoint ( hyperpoint h , double dist ) {
2016-08-26 09:58:03 +00:00
rugpoint * m = new rugpoint ;
m - > h = h ;
2017-12-25 22:47:57 +00:00
/*
2020-04-16 22:53:58 +00:00
ld tz = pconf . alpha + h [ 2 ] ;
2016-08-26 09:58:03 +00:00
m - > x1 = ( 1 + h [ 0 ] / tz ) / 2 ;
m - > y1 = ( 1 + h [ 1 ] / tz ) / 2 ;
2017-12-25 22:47:57 +00:00
*/
hyperpoint onscreen ;
applymodel ( m - > h , onscreen ) ;
2020-04-16 22:53:58 +00:00
m - > x1 = ( 1 + onscreen [ 0 ] * pconf . scale ) / 2 ;
m - > y1 = ( 1 - onscreen [ 1 ] * pconf . scale ) / 2 ;
2017-12-27 09:52:54 +00:00
m - > valid = false ;
2017-12-25 22:47:57 +00:00
2019-11-27 00:01:20 +00:00
if ( euclid & & quotient & & ! bounded ) {
2019-12-08 09:59:09 +00:00
hyperpoint h1 = inverse ( models : : euclidean_spin ) * eumove ( euc : : eu . user_axes [ 1 ] ) * C0 ;
2019-02-27 18:34:05 +00:00
h1 / = sqhypot_d ( 2 , h1 ) ;
2018-12-02 20:05:13 +00:00
if ( nonorientable ) h1 / = 2 ;
m - > valid = good_shape = true ;
ld d = h1 [ 0 ] * h [ 1 ] - h1 [ 1 ] * h [ 0 ] ;
ld a = h [ 0 ] * h1 [ 0 ] + h [ 1 ] * h1 [ 1 ] ;
2018-12-06 11:55:37 +00:00
// m->flat = modelscale * hpxyz(d * 2 * M_PI, sin(a * 2 * M_PI), cos(a * 2 * M_PI));
USING_NATIVE_GEOMETRY ;
hyperpoint hpoint = ypush ( modelscale ) * xpush0 ( modelscale * d * 2 * M_PI ) ;
ld hpdist = hdist0 ( hpoint ) ;
2019-02-27 18:34:05 +00:00
ld z = hypot_d ( 2 , hpoint ) ;
2018-12-06 11:55:37 +00:00
if ( z = = 0 ) z = 1 ;
hpoint = hpoint * hpdist / z ;
2020-04-14 14:44:56 +00:00
m - > native = point31 ( hpoint [ 0 ] , hpoint [ 1 ] * sin ( a * 2 * M_PI ) , hpoint [ 1 ] * cos ( a * 2 * M_PI ) ) ;
2018-12-02 20:05:13 +00:00
}
else if ( sphere ) {
2017-12-27 09:52:54 +00:00
m - > valid = good_shape = true ;
2017-12-27 10:59:37 +00:00
ld scale ;
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
if ( euclid ) {
2017-12-27 10:59:37 +00:00
scale = modelscale ;
}
2020-04-14 14:44:56 +00:00
else if ( hyperbolic ) {
2017-12-27 10:59:37 +00:00
// sinh(scale) = modelscale
scale = asinh ( modelscale ) ;
}
2020-04-14 14:44:56 +00:00
else if ( sphere ) {
2017-12-27 10:59:37 +00:00
if ( modelscale > = 1 )
// do as good as we can...
2018-01-30 23:11:49 +00:00
scale = M_PI / 2 - 1e-3 , good_shape = false , m - > valid = false ;
2017-12-27 10:59:37 +00:00
else scale = asin ( modelscale ) ;
}
2020-04-14 14:44:56 +00:00
else
scale = 1 ;
m - > native = h * scale ;
m - > native = hpxy3 ( m - > native [ 0 ] , m - > native [ 1 ] , m - > native [ 2 ] ) ;
2017-12-27 10:59:37 +00:00
}
2020-04-14 14:44:56 +00:00
else if ( euclid & & rug_euclid ( ) ) {
m - > native = h * modelscale ;
m - > native [ 2 ] = 0 ;
2020-04-17 13:38:09 +00:00
# if MAXMDIM >= 4
2020-04-14 14:44:56 +00:00
m - > native [ 3 ] = 1 ;
2020-04-17 13:38:09 +00:00
# endif
2018-01-28 11:25:56 +00:00
m - > valid = good_shape = true ;
2017-12-27 10:59:37 +00:00
}
2020-04-14 14:44:56 +00:00
else if ( rug_hyperbolic ( ) & & euclid ) {
2017-12-27 10:59:37 +00:00
m - > valid = good_shape = true ;
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
m - > native = tC0 ( parabolic13 ( h [ 0 ] * modelscale , h [ 1 ] * modelscale ) ) ;
}
2017-12-27 10:59:37 +00:00
2020-04-14 14:44:56 +00:00
else if ( rug_hyperbolic ( ) & & hyperbolic & & modelscale > = 1 ) {
m - > valid = good_shape = true ;
// radius of the equidistant
ld r = acosh ( modelscale ) ;
h [ 3 ] = h [ 2 ] ; h [ 2 ] = 0 ;
2017-12-27 10:59:37 +00:00
2017-12-27 18:55:00 +00:00
USING_NATIVE_GEOMETRY ;
2017-12-27 10:59:37 +00:00
2020-04-14 14:44:56 +00:00
m - > native = rgpushxto0 ( h ) * cpush0 ( 2 , r ) ;
2017-12-27 09:52:54 +00:00
}
2019-05-20 11:42:32 +00:00
else {
2020-04-14 14:44:56 +00:00
m - > native = h ;
2019-08-17 21:28:41 +00:00
ld hd = h [ LDIM ] ;
2020-04-17 15:17:22 +00:00
for ( int d = GDIM ; d < MAXMDIM - 1 ; d + + ) {
2020-04-14 14:44:56 +00:00
m - > native [ d ] = ( hd - .99 ) * ( rand ( ) % 1000 - rand ( ) % 1000 ) / 1000 ;
}
USING_NATIVE_GEOMETRY ;
2020-04-17 13:38:09 +00:00
# if MAXMDIM >= 4
2020-04-17 15:17:22 +00:00
m - > native [ 3 ] = 1 ;
m - > native = normalize ( m - > native ) ;
2020-04-17 13:38:09 +00:00
# endif
2019-05-20 11:42:32 +00:00
}
2017-12-27 18:55:00 +00:00
2016-08-26 09:58:03 +00:00
m - > inqueue = false ;
2017-03-23 10:53:57 +00:00
m - > dist = dist ;
2016-08-26 09:58:03 +00:00
points . push_back ( m ) ;
return m ;
}
2019-08-09 23:07:39 +00:00
EX rugpoint * findRugpoint ( hyperpoint h ) {
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( points ) ; i + + )
2020-04-14 14:44:56 +00:00
if ( geo_dist_q ( points [ i ] - > h , h ) < 1e-5 ) return points [ i ] ;
2017-12-27 05:31:47 +00:00
return NULL ;
}
2019-08-09 23:07:39 +00:00
EX rugpoint * findOrAddRugpoint ( hyperpoint h , double dist ) {
2017-12-27 05:31:47 +00:00
rugpoint * r = findRugpoint ( h ) ;
return r ? r : addRugpoint ( h , dist ) ;
2016-08-26 09:58:03 +00:00
}
2017-12-27 05:31:47 +00:00
void addNewEdge ( rugpoint * e1 , rugpoint * e2 , ld len = 1 ) {
2017-12-27 09:52:54 +00:00
edge e ; e . len = len ;
e . target = e2 ; e1 - > edges . push_back ( e ) ;
2016-08-26 09:58:03 +00:00
e . target = e1 ; e2 - > edges . push_back ( e ) ;
}
2019-08-09 23:07:39 +00:00
EX bool edge_exists ( rugpoint * e1 , rugpoint * e2 ) {
2018-02-27 18:37:57 +00:00
for ( auto & e : e1 - > edges )
if ( e . target = = e2 )
return true ;
return false ;
}
2017-12-27 05:31:47 +00:00
void addEdge ( rugpoint * e1 , rugpoint * e2 , ld len = 1 ) {
2018-02-27 18:37:57 +00:00
if ( ! edge_exists ( e1 , e2 ) )
addNewEdge ( e1 , e2 , len ) ;
}
void add_anticusp_edge ( rugpoint * e1 , rugpoint * e2 , ld len = 1 ) {
for ( auto & e : e1 - > anticusp_edges )
if ( e . target = = e2 ) return ;
edge e ; e . len = len ;
e . target = e2 ; e1 - > anticusp_edges . push_back ( e ) ;
e . target = e1 ; e2 - > anticusp_edges . push_back ( e ) ;
2016-08-26 09:58:03 +00:00
}
2019-08-09 23:07:39 +00:00
EX void addTriangle ( rugpoint * t1 , rugpoint * t2 , rugpoint * t3 , ld len IS ( 1 ) ) {
2017-12-27 05:31:47 +00:00
addEdge ( t1 - > getglue ( ) , t2 - > getglue ( ) , len ) ;
addEdge ( t2 - > getglue ( ) , t3 - > getglue ( ) , len ) ;
addEdge ( t3 - > getglue ( ) , t1 - > getglue ( ) , len ) ;
2016-08-26 09:58:03 +00:00
triangles . push_back ( triangle ( t1 , t2 , t3 ) ) ;
}
2017-12-27 09:52:54 +00:00
map < pair < rugpoint * , rugpoint * > , rugpoint * > halves ;
rugpoint * findhalf ( rugpoint * r1 , rugpoint * r2 ) {
if ( r1 > r2 ) swap ( r1 , r2 ) ;
2018-01-05 16:18:37 +00:00
return halves [ make_pair ( r1 , r2 ) ] ;
2017-12-27 09:52:54 +00:00
}
2016-08-26 09:58:03 +00:00
void addTriangle1 ( rugpoint * t1 , rugpoint * t2 , rugpoint * t3 ) {
2017-12-27 09:52:54 +00:00
rugpoint * t12 = findhalf ( t1 , t2 ) ;
rugpoint * t23 = findhalf ( t2 , t3 ) ;
rugpoint * t31 = findhalf ( t3 , t1 ) ;
2016-08-26 09:58:03 +00:00
addTriangle ( t1 , t12 , t31 ) ;
addTriangle ( t12 , t2 , t23 ) ;
addTriangle ( t23 , t3 , t31 ) ;
addTriangle ( t23 , t31 , t12 ) ;
}
bool psort ( rugpoint * a , rugpoint * b ) {
2017-12-25 22:47:57 +00:00
return hdist0 ( a - > h ) < hdist0 ( b - > h ) ;
2016-08-26 09:58:03 +00:00
}
2019-09-06 06:17:02 +00:00
EX void sort_rug_points ( ) {
2018-03-24 14:17:17 +00:00
sort ( points . begin ( ) , points . end ( ) , psort ) ;
}
2016-08-26 09:58:03 +00:00
void calcLengths ( ) {
2018-02-27 18:37:57 +00:00
for ( auto p : points )
for ( auto & edge : p - > edges )
2020-04-14 14:44:56 +00:00
edge . len = geo_dist_q ( p - > h , edge . target - > h ) * modelscale ;
2016-08-26 09:58:03 +00:00
}
2020-01-02 15:56:58 +00:00
EX void calcparam_rug ( ) {
2018-11-20 18:01:10 +00:00
auto cd = current_display ;
cd - > xtop = cd - > ytop = 0 ;
cd - > xsize = cd - > ysize = TEXTURESIZE ;
cd - > xcenter = cd - > ycenter = cd - > scrsize = HTEXTURESIZE ;
2020-04-16 22:53:58 +00:00
cd - > radius = cd - > scrsize * pconf . scale ;
2017-11-06 18:24:02 +00:00
}
2019-08-09 23:07:39 +00:00
EX void buildTorusRug ( ) {
2017-11-06 18:24:02 +00:00
2018-11-20 18:01:10 +00:00
calcparam_rug ( ) ;
2019-08-09 22:58:50 +00:00
models : : configure ( ) ;
2017-11-06 18:24:02 +00:00
2019-12-08 09:59:09 +00:00
auto p1 = to_loc ( euc : : eu . user_axes [ 0 ] ) ;
auto p2 = to_loc ( euc : : eu . user_axes [ 1 ] ) ;
2019-11-28 20:55:20 +00:00
2019-12-08 09:59:09 +00:00
hyperpoint xh = euc : : eumove ( p1 ) * C0 - C0 ;
hyperpoint yh = euc : : eumove ( p2 ) * C0 - C0 ;
2019-11-28 20:55:20 +00:00
if ( nonorientable ) yh * = 2 ;
2017-12-28 17:39:49 +00:00
2019-12-08 23:40:51 +00:00
bool flipped = false ; // sqhypot_d(2, xh) < sqhypot_d(2, yh);
2017-11-06 18:24:02 +00:00
2019-11-28 20:55:20 +00:00
if ( flipped ) swap ( xh , yh ) ;
2018-05-28 17:10:57 +00:00
2019-11-28 20:55:20 +00:00
cell * gs = currentmap - > gamestart ( ) ;
2017-11-06 18:24:02 +00:00
2019-11-28 20:55:20 +00:00
ld xfactor , yfactor ;
2017-11-06 18:24:02 +00:00
2019-11-28 20:55:20 +00:00
ld factor2 = sqhypot_d ( 2 , xh ) / sqhypot_d ( 2 , yh ) ;
ld factor = sqrt ( factor2 ) ;
yfactor = sqrt ( 1 / ( 1 + factor2 ) ) ;
xfactor = factor * yfactor ;
2018-06-12 17:26:34 +00:00
2019-11-28 20:55:20 +00:00
transmatrix T = build_matrix ( xh , yh , C0 , C03 ) ;
transmatrix iT = inverse ( T ) ;
if ( gwhere = = gSphere )
modelscale = hypot_d ( 2 , xh ) * xfactor * 2 * M_PI ;
2018-06-12 17:26:34 +00:00
2017-12-28 17:39:49 +00:00
map < pair < int , int > , rugpoint * > glues ;
2019-12-08 23:40:51 +00:00
ld mx = 0 ;
for ( int i = 0 ; i < 1000 ; i + + )
mx = max ( mx , hypot ( xfactor , yfactor * sin ( i ) ) / ( 1 - yfactor * cos ( i ) ) ) ;
println ( hlog , " mx = " , mx ) ;
2019-11-28 20:55:20 +00:00
auto addToruspoint = [ & ] ( hyperpoint h ) {
2017-11-06 18:24:02 +00:00
auto r = addRugpoint ( C0 , 0 ) ;
hyperpoint onscreen ;
2019-11-28 20:55:20 +00:00
hyperpoint h1 = gmatrix [ gs ] * T * h ;
applymodel ( h1 , onscreen ) ;
2017-11-06 18:24:02 +00:00
r - > x1 = onscreen [ 0 ] ;
r - > y1 = onscreen [ 1 ] ;
2019-11-28 20:55:20 +00:00
double alpha = - h [ 0 ] * 2 * M_PI ;
double beta = h [ 1 ] * 2 * M_PI ;
2017-12-28 17:39:49 +00:00
2019-12-08 23:40:51 +00:00
ld ax = alpha + 1.124651 , bx = beta + 1.214893 ;
ld x = xfactor * sin ( ax ) , y = xfactor * cos ( ax ) , z = yfactor * sin ( bx ) , t = yfactor * cos ( bx ) ;
2020-04-14 14:44:56 +00:00
if ( 1 ) {
hyperpoint hp = hyperpoint ( x , y , z , t ) ;
USING_NATIVE_GEOMETRY ;
/* spherical coordinates are already good, otherwise... */
if ( ! sphere ) {
/* stereographic projection to get Euclidean conformal torus */
2020-04-17 13:38:09 +00:00
hp / = ( t + 1 ) ;
2020-04-14 14:44:56 +00:00
hp / = mx ;
2020-04-17 13:38:09 +00:00
# if MAXMDIM >= 4
2020-04-14 14:44:56 +00:00
hp [ 3 ] = 1 ;
2020-04-17 13:38:09 +00:00
# endif
2020-04-14 14:44:56 +00:00
}
2019-12-08 23:40:51 +00:00
2020-04-14 14:44:56 +00:00
/* ... in H^3, use inverse Poincare to get hyperbolic conformal torus */
if ( hyperbolic )
hp = perspective_to_space ( hp , 1 , gcHyperbolic ) ;
}
2017-11-06 18:24:02 +00:00
r - > valid = true ;
2017-12-28 17:39:49 +00:00
static const int X = 100003 ; // a prime
auto gluefun = [ ] ( ld z ) { return int ( frac ( z + .5 / X ) * X ) ; } ;
2019-11-28 20:55:20 +00:00
auto p = make_pair ( gluefun ( h [ 0 ] ) , gluefun ( h [ 1 ] ) ) ;
2017-12-28 17:39:49 +00:00
auto & r2 = glues [ p ] ;
if ( r2 ) r - > glueto ( r2 ) ; else r2 = r ;
2017-11-06 18:24:02 +00:00
return r ;
} ;
2017-12-27 09:52:54 +00:00
2019-11-28 20:55:20 +00:00
int rugmax = ( int ) sqrt ( vertex_limit / isize ( currentmap - > allcells ( ) ) ) ;
2017-12-27 09:52:54 +00:00
if ( rugmax < 1 ) rugmax = 1 ;
if ( rugmax > 16 ) rugmax = 16 ;
2017-11-07 13:39:26 +00:00
ld rmd = rugmax ;
2019-11-28 20:55:20 +00:00
hyperpoint sx = iT * ( currentmap - > adj ( gs , 0 ) * C0 - C0 ) / rmd ;
hyperpoint sy = iT * ( currentmap - > adj ( gs , 1 ) * C0 - C0 ) / rmd ;
for ( int leaf = 0 ; leaf < ( nonorientable ? 2 : 1 ) ; leaf + + )
for ( cell * c : currentmap - > allcells ( ) ) {
hyperpoint h = iT * calc_relative_matrix ( c , gs , C0 ) * C0 ;
2017-12-28 17:39:49 +00:00
2019-11-28 20:55:20 +00:00
if ( leaf ) h [ flipped ? 0 : 1 ] + = .5 ;
2017-11-06 18:24:02 +00:00
2017-11-07 13:39:26 +00:00
rugpoint * rugarr [ 32 ] [ 32 ] ;
for ( int yy = 0 ; yy < = rugmax ; yy + + )
for ( int xx = 0 ; xx < = rugmax ; xx + + )
2019-11-28 20:55:20 +00:00
rugarr [ yy ] [ xx ] = addToruspoint ( h + xx * sx + yy * sy ) ;
2017-11-07 13:39:26 +00:00
for ( int yy = 0 ; yy < rugmax ; yy + + )
for ( int xx = 0 ; xx < rugmax ; xx + + )
2017-12-27 09:52:54 +00:00
addTriangle ( rugarr [ yy ] [ xx ] , rugarr [ yy + 1 ] [ xx ] , rugarr [ yy + 1 ] [ xx + 1 ] , modelscale / rugmax ) ,
2018-05-28 17:10:21 +00:00
addTriangle ( rugarr [ yy ] [ xx + 1 ] , rugarr [ yy ] [ xx ] , rugarr [ yy + 1 ] [ xx + 1 ] , modelscale / rugmax ) ;
2017-11-06 18:24:02 +00:00
}
double maxz = 0 ;
for ( auto p : points )
maxz = max ( maxz , max ( abs ( p - > x1 ) , abs ( p - > y1 ) ) ) ;
2020-04-16 22:53:58 +00:00
if ( 1 ) pconf . scale = 1 / maxz ;
2019-11-28 20:55:20 +00:00
if ( 1 ) for ( auto p : points )
2020-04-16 22:53:58 +00:00
p - > x1 = ( 1 + pconf . scale * p - > x1 ) / 2 ,
p - > y1 = ( 1 - pconf . scale * p - > y1 ) / 2 ;
2017-11-06 18:24:02 +00:00
2017-12-27 14:25:10 +00:00
qvalid = 0 ;
for ( auto p : points ) if ( ! p - > glue ) qvalid + + ;
2018-11-24 16:01:49 +00:00
println ( hlog , " qvalid = " , qvalid ) ;
2017-12-27 18:55:00 +00:00
2017-11-06 18:24:02 +00:00
return ;
}
2019-08-09 23:07:39 +00:00
EX void verify ( ) {
2017-12-27 10:59:37 +00:00
vector < ld > ratios ;
for ( auto m : points )
for ( auto & e : m - > edges ) {
auto m2 = e . target ;
ld l = e . len ;
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
ld l0 = geo_dist_q ( m - > native , m2 - > native ) ;
2019-05-20 11:42:32 +00:00
2017-12-27 10:59:37 +00:00
ratios . push_back ( l0 / l ) ;
}
2018-11-24 16:01:49 +00:00
println ( hlog , " Length verification: " ) ;
2017-12-27 10:59:37 +00:00
sort ( ratios . begin ( ) , ratios . end ( ) ) ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( ratios ) ; i + = isize ( ratios ) / 10 )
2018-11-24 16:01:49 +00:00
println ( hlog , ratios [ i ] ) ;
println ( hlog ) ;
2017-12-27 10:59:37 +00:00
}
2017-12-29 11:54:50 +00:00
void comp ( cell * & minimum , cell * next ) {
int nc = next - > cpdist , mc = minimum - > cpdist ;
if ( tie ( nc , next ) < tie ( mc , minimum ) )
minimum = next ;
}
2018-02-27 18:37:57 +00:00
2019-08-09 23:07:39 +00:00
EX void buildRug ( ) {
2016-08-26 09:58:03 +00:00
2018-03-24 14:17:17 +00:00
need_mouseh = true ;
good_shape = false ;
2019-11-27 00:01:20 +00:00
if ( euclid & & bounded ) {
2017-12-27 09:52:54 +00:00
good_shape = true ;
2017-11-06 18:24:02 +00:00
buildTorusRug ( ) ;
return ;
}
2019-11-13 23:26:50 +00:00
celllister cl ( centerover ? centerover : cwt . at , get_sightrange ( ) , vertex_limit , NULL ) ;
2017-12-29 11:54:50 +00:00
2016-08-26 09:58:03 +00:00
map < cell * , rugpoint * > vptr ;
2017-12-29 11:54:50 +00:00
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( cl . lst ) ; i + + )
2018-08-17 14:47:06 +00:00
vptr [ cl . lst [ i ] ] = addRugpoint ( ggmatrix ( cl . lst [ i ] ) * C0 , cl . dists [ i ] ) ;
2017-12-29 11:54:50 +00:00
for ( auto & p : vptr ) {
cell * c = p . first ;
rugpoint * v = p . second ;
2018-08-24 19:47:09 +00:00
2019-12-14 10:42:16 +00:00
if ( arcm : : in ( ) | | ( euclid & & quotient ) ) {
2020-01-18 15:03:32 +00:00
vector < rugpoint * > p ( c - > type + 1 ) ;
2018-08-24 19:47:09 +00:00
for ( int j = 0 ; j < c - > type ; j + + ) p [ j ] = findOrAddRugpoint ( ggmatrix ( c ) * get_corner_position ( c , j ) , v - > dist ) ;
for ( int j = 0 ; j < c - > type ; j + + ) addTriangle ( v , p [ j ] , p [ ( j + 1 ) % c - > type ] ) ;
2018-12-02 20:05:13 +00:00
2019-11-27 00:01:20 +00:00
if ( ( euclid & & quotient ) & & nonorientable ) {
2019-12-08 09:59:09 +00:00
transmatrix T = ggmatrix ( c ) * eumove ( euc : : eu . user_axes [ 1 ] ) ;
2018-12-02 20:05:13 +00:00
rugpoint * Tv = addRugpoint ( T * C0 , 0 ) ;
for ( int j = 0 ; j < c - > type ; j + + ) p [ j ] = findOrAddRugpoint ( T * get_corner_position ( c , j ) , v - > dist ) ;
for ( int j = 0 ; j < c - > type ; j + + ) addTriangle ( Tv , p [ j ] , p [ ( j + 1 ) % c - > type ] ) ;
}
2018-08-24 19:47:09 +00:00
}
else for ( int j = 0 ; j < c - > type ; j + + ) try {
2018-08-17 22:46:45 +00:00
cell * c2 = c - > move ( j ) ;
2017-12-29 11:54:50 +00:00
rugpoint * w = vptr . at ( c2 ) ;
2016-08-26 09:58:03 +00:00
// if(v<w) addEdge(v, w);
2018-08-17 22:46:45 +00:00
cell * c3 = c - > modmove ( j + 1 ) ;
2017-12-29 11:54:50 +00:00
rugpoint * w2 = vptr . at ( c3 ) ;
if ( a4 ) {
2018-08-17 22:46:45 +00:00
cell * c4 = ( cellwalker ( c , j ) + wstep - 1 ) . cpeek ( ) ;
2017-12-29 11:54:50 +00:00
cell * cm = c ; comp ( cm , c ) ; comp ( cm , c2 ) ; comp ( cm , c3 ) ; comp ( cm , c4 ) ;
if ( cm = = c | | cm = = c4 )
addTriangle ( v , w , w2 ) ;
}
else if ( v > w & & v > w2 )
addTriangle ( v , w , w2 ) ;
2016-08-26 09:58:03 +00:00
}
2018-06-07 11:58:00 +00:00
catch ( out_of_range & ) { }
2016-08-26 09:58:03 +00:00
}
2018-11-24 16:01:49 +00:00
println ( hlog , " vertices = " , isize ( points ) , " triangles= " , isize ( triangles ) ) ;
2016-08-26 09:58:03 +00:00
2018-02-27 18:27:20 +00:00
if ( subdivide_first )
for ( int i = 0 ; i < 20 & & subdivide_further ( ) ; i + + )
subdivide ( ) ;
2018-03-24 14:17:17 +00:00
sort_rug_points ( ) ;
2017-12-27 10:59:37 +00:00
2018-02-27 18:37:57 +00:00
calcLengths ( ) ;
2017-12-27 10:59:37 +00:00
verify ( ) ;
2018-01-30 23:11:49 +00:00
for ( auto p : points ) if ( p - > valid ) qvalid + + ;
2016-08-26 09:58:03 +00:00
}
// rug physics
queue < rugpoint * > pqueue ;
2019-09-06 06:17:02 +00:00
EX void enqueue ( rugpoint * m ) {
2016-08-26 09:58:03 +00:00
if ( m - > inqueue ) return ;
pqueue . push ( m ) ;
m - > inqueue = true ;
}
2018-02-27 18:37:57 +00:00
bool force_euclidean ( rugpoint & m1 , rugpoint & m2 , double rd , bool is_anticusp = false , double d1 = 1 , double d2 = 1 ) {
2017-12-27 09:52:54 +00:00
if ( ! m1 . valid | | ! m2 . valid ) return false ;
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
// double rd = geo_dist_q(m1.h, m2.h) * xd;
double t = sqhypot_d ( 3 , m1 . native - m2 . native ) ;
2018-02-27 18:37:57 +00:00
if ( is_anticusp & & t > rd * rd ) return false ;
2016-08-26 09:58:03 +00:00
t = sqrt ( t ) ;
2017-12-27 09:52:54 +00:00
current_total_error + = ( t - rd ) * ( t - rd ) ;
2017-12-27 05:31:47 +00:00
bool nonzero = abs ( t - rd ) > err_zero_current ;
2016-08-26 09:58:03 +00:00
double force = ( t - rd ) / t / 2 ; // 20.0;
2020-04-14 14:44:56 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
double di = ( m2 . native [ i ] - m1 . native [ i ] ) * force ;
m1 . native [ i ] + = di * d1 ;
m2 . native [ i ] - = di * d2 ;
2016-08-26 09:58:03 +00:00
if ( nonzero & & d2 > 0 ) enqueue ( & m2 ) ;
}
2017-12-27 09:52:54 +00:00
return nonzero ;
2016-08-26 09:58:03 +00:00
}
2018-02-27 18:37:57 +00:00
bool force ( rugpoint & m1 , rugpoint & m2 , double rd , bool is_anticusp = false , double d1 = 1 , double d2 = 1 ) {
2017-12-27 09:52:54 +00:00
if ( ! m1 . valid | | ! m2 . valid ) return false ;
2020-04-14 14:44:56 +00:00
if ( rug_euclid ( ) & & fast_euclidean ) {
2018-02-27 18:37:57 +00:00
return force_euclidean ( m1 , m2 , rd , is_anticusp , d1 , d2 ) ;
2017-12-25 22:47:57 +00:00
}
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
2017-12-25 22:47:57 +00:00
2020-04-14 14:44:56 +00:00
ld t = geo_dist_q ( m1 . native , m2 . native ) ;
2018-02-27 18:37:57 +00:00
if ( is_anticusp & & t > rd ) return false ;
2017-12-27 09:52:54 +00:00
current_total_error + = ( t - rd ) * ( t - rd ) ;
2017-12-27 05:31:47 +00:00
bool nonzero = abs ( t - rd ) > err_zero_current ;
2017-12-25 22:47:57 +00:00
double forcev = ( t - rd ) / 2 ; // 20.0;
2020-04-17 15:18:24 +00:00
transmatrix T = inverse ( rgpushxto0 ( m1 . native ) ) ;
hyperpoint ie = inverse_exp ( T * m2 . native ) ;
2017-12-25 22:47:57 +00:00
2020-04-17 15:18:24 +00:00
transmatrix iT = rgpushxto0 ( m1 . native ) ;
2017-12-25 22:47:57 +00:00
2020-04-14 14:44:56 +00:00
for ( int i = 0 ; i < MDIM ; i + + ) if ( std : : isnan ( m1 . native [ i ] ) ) {
2017-12-29 11:54:50 +00:00
addMessage ( " Failed! " ) ;
2020-04-17 15:18:24 +00:00
println ( hlog , " m1 = " , m1 . native ) ;
2017-12-29 11:54:50 +00:00
throw rug_exception ( ) ;
}
2020-04-17 15:18:24 +00:00
m1 . native = iT * direct_exp ( ie * ( d1 * forcev / t ) ) ;
m2 . native = iT * direct_exp ( ie * ( ( t - d2 * forcev ) / t ) ) ;
2020-04-14 14:44:56 +00:00
2017-12-25 22:47:57 +00:00
if ( nonzero & & d2 > 0 ) enqueue ( & m2 ) ;
2017-12-27 09:52:54 +00:00
return nonzero ;
2017-12-25 22:47:57 +00:00
}
2017-12-27 20:08:31 +00:00
vector < pair < ld , rugpoint * > > preset_points ;
2019-08-09 23:07:39 +00:00
EX void preset ( rugpoint * m ) {
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) return ;
2016-08-26 09:58:03 +00:00
int q = 0 ;
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
hyperpoint h = Hypc ;
2016-08-26 09:58:03 +00:00
2017-12-27 20:08:31 +00:00
preset_points . clear ( ) ;
2018-06-22 12:47:24 +00:00
for ( int j = 0 ; j < isize ( m - > edges ) ; j + + )
2016-08-26 09:58:03 +00:00
for ( int k = 0 ; k < j ; k + + ) {
rugpoint * a = m - > edges [ j ] . target ;
rugpoint * b = m - > edges [ k ] . target ;
if ( ! a - > valid ) continue ;
if ( ! b - > valid ) continue ;
double blen = - 1 ;
2018-06-22 12:47:24 +00:00
for ( int j2 = 0 ; j2 < isize ( a - > edges ) ; j2 + + )
2016-08-26 09:58:03 +00:00
if ( a - > edges [ j2 ] . target = = b ) blen = a - > edges [ j2 ] . len ;
if ( blen < = 0 ) continue ;
2018-06-22 12:47:24 +00:00
for ( int j2 = 0 ; j2 < isize ( a - > edges ) ; j2 + + )
for ( int k2 = 0 ; k2 < isize ( b - > edges ) ; k2 + + )
2016-08-26 09:58:03 +00:00
if ( a - > edges [ j2 ] . target = = b - > edges [ k2 ] . target & & a - > edges [ j2 ] . target ! = m ) {
rugpoint * c = a - > edges [ j2 ] . target ;
if ( ! c - > valid ) continue ;
double a1 = m - > edges [ j ] . len / blen ;
double a2 = m - > edges [ k ] . len / blen ;
double c1 = a - > edges [ j2 ] . len / blen ;
double c2 = b - > edges [ k2 ] . len / blen ;
double cz = ( c1 * c1 - c2 * c2 + 1 ) / 2 ;
2017-12-29 11:54:50 +00:00
double ch = sqrt ( c1 * c1 - cz * cz + 1e-10 ) ;
2016-08-26 09:58:03 +00:00
double az = ( a1 * a1 - a2 * a2 + 1 ) / 2 ;
2017-12-29 11:54:50 +00:00
double ah = sqrt ( a1 * a1 - az * az + 1e-10 ) ;
2016-08-26 09:58:03 +00:00
// c->h = a->h + (b->h-a->h) * cz + ch * ort
2020-04-14 14:44:56 +00:00
hyperpoint ort = ( c - > native - a - > native - cz * ( b - > native - a - > native ) ) / ch ;
2016-08-26 09:58:03 +00:00
// m->h = a->h + (b->h-a->h) * az - ah * ort
2020-04-14 14:44:56 +00:00
hyperpoint res = a - > native + ( b - > native - a - > native ) * az - ah * ort ;
2016-08-26 09:58:03 +00:00
2017-12-28 15:46:10 +00:00
h + = res ;
2017-03-23 10:53:57 +00:00
2017-12-27 20:08:31 +00:00
preset_points . emplace_back ( hypot ( blen * ( ah + ch ) , blen * ( az - cz ) ) , c ) ;
2017-03-23 10:53:57 +00:00
q + + ;
2016-08-26 09:58:03 +00:00
}
}
2020-04-17 13:38:09 +00:00
# if MAXMDIM >= 4
2020-04-14 14:44:56 +00:00
if ( q > 0 ) m - > native = normalize ( h ) ;
2020-04-17 13:38:09 +00:00
# else
if ( q > 0 ) m - > native = h / q ;
# endif
2020-04-14 14:44:56 +00:00
if ( std : : isnan ( m - > native [ 0 ] ) | | std : : isnan ( m - > native [ 1 ] ) | | std : : isnan ( m - > native [ 2 ] ) )
2017-12-29 11:54:50 +00:00
throw rug_exception ( ) ;
2016-08-26 09:58:03 +00:00
}
2019-05-20 11:42:32 +00:00
ld sse ( const hyperpoint & h ) {
2017-12-27 20:08:31 +00:00
ld sse = 0 ;
for ( auto & p : preset_points ) {
ld l = p . first ;
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
ld l0 = geo_dist_q ( h , p . second - > native ) ;
2017-12-27 20:08:31 +00:00
sse + = ( l0 - l ) * ( l0 - l ) ;
}
return sse ;
}
2019-08-09 23:07:39 +00:00
EX void optimize ( rugpoint * m , bool do_preset ) {
2017-12-27 20:08:31 +00:00
if ( do_preset ) {
preset ( m ) ;
2018-06-22 12:47:24 +00:00
// int ed0 = isize(preset_points);
2017-12-27 20:08:31 +00:00
for ( auto & e : m - > edges ) if ( e . target - > valid )
preset_points . emplace_back ( e . len , e . target ) ;
2020-04-14 14:44:56 +00:00
if ( ! rug_euclid ( ) ) {
ld cur = sse ( m - > native ) ;
2017-12-27 20:08:31 +00:00
for ( int it = 0 ; it < 500 ; it + + ) {
ld ex = exp ( - it / 60 ) ;
again :
2020-04-14 14:44:56 +00:00
hyperpoint last = m - > native ;
USING_NATIVE_GEOMETRY ;
m - > native = rgpushxto0 ( m - > native ) * cpush0 ( ( it / 2 ) % 3 , ( it & 1 ) ? ex : - ex ) ;
ld now = sse ( m - > native ) ;
2017-12-27 20:08:31 +00:00
if ( now < cur ) { cur = now ; ex * = 1.2 ; goto again ; }
2020-04-14 14:44:56 +00:00
else m - > native = last ;
2017-12-27 20:08:31 +00:00
}
}
}
for ( int it = 0 ; it < 50 ; it + + )
2018-06-22 12:47:24 +00:00
for ( int j = 0 ; j < isize ( m - > edges ) ; j + + )
2018-02-27 18:37:57 +00:00
force ( * m , * m - > edges [ j ] . target , m - > edges [ j ] . len , false , 1 , 0 ) ;
2017-12-27 20:08:31 +00:00
}
2016-08-26 09:58:03 +00:00
int divides = 0 ;
bool stop = false ;
2019-08-09 23:07:39 +00:00
EX bool subdivide_further ( ) {
2019-11-27 00:01:20 +00:00
if ( euclid & & bounded ) return false ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) return false ;
2018-06-22 12:47:24 +00:00
return isize ( points ) * 4 < vertex_limit ;
2017-12-27 09:52:54 +00:00
}
2019-08-09 23:07:39 +00:00
EX void subdivide ( ) {
2018-06-22 12:47:24 +00:00
int N = isize ( points ) ;
2017-12-25 22:47:57 +00:00
// if(euclid && gwhere == gEuclid) return;
2017-12-27 09:52:54 +00:00
if ( ! subdivide_further ( ) ) {
2017-12-27 10:59:37 +00:00
if ( euclid & & ! bounded & & gwhere = = gEuclid ) {
2018-11-24 16:01:49 +00:00
println ( hlog , " Euclidean -- full precision " ) ;
2017-12-27 10:59:37 +00:00
stop = true ;
}
else {
err_zero_current / = 2 ;
2018-11-24 16:01:49 +00:00
println ( hlog , " increasing precision to " , err_zero_current ) ;
2017-12-27 10:59:37 +00:00
for ( auto p : points ) enqueue ( p ) ;
}
2017-12-27 05:31:47 +00:00
return ;
}
2018-11-24 16:01:49 +00:00
println ( hlog , " subdivide " , make_pair ( N , isize ( triangles ) ) ) ;
2018-03-24 14:17:17 +00:00
need_mouseh = true ;
2016-08-26 09:58:03 +00:00
divides + + ;
vector < triangle > otriangles = triangles ;
triangles . clear ( ) ;
2017-12-27 09:52:54 +00:00
halves . clear ( ) ;
2017-12-27 20:08:31 +00:00
2016-08-26 09:58:03 +00:00
// subdivide edges
for ( int i = 0 ; i < N ; i + + ) {
rugpoint * m = points [ i ] ;
2018-06-22 12:47:24 +00:00
for ( int j = 0 ; j < isize ( m - > edges ) ; j + + ) {
2016-08-26 09:58:03 +00:00
rugpoint * m2 = m - > edges [ j ] . target ;
2017-12-27 09:52:54 +00:00
if ( m2 < m ) continue ;
2017-03-23 10:53:57 +00:00
rugpoint * mm = addRugpoint ( mid ( m - > h , m2 - > h ) , ( m - > dist + m2 - > dist ) / 2 ) ;
2018-01-05 18:05:41 +00:00
halves [ make_pair ( m , m2 ) ] = mm ;
2018-01-28 11:25:56 +00:00
if ( ! good_shape ) {
2020-04-17 13:38:09 +00:00
# if MAXMDIM >= 4
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
mm - > native = mid ( m - > native , m2 - > native ) ;
2020-04-17 13:38:09 +00:00
# else
mm - > native = ( m - > native + m2 - > native ) / 2 ;
# endif
2017-12-29 13:35:18 +00:00
}
2018-02-27 18:37:57 +00:00
mm - > valid = m - > valid & & m2 - > valid ;
if ( mm - > valid ) qvalid + + ;
2016-08-26 09:58:03 +00:00
mm - > inqueue = false ; enqueue ( mm ) ;
}
m - > edges . clear ( ) ;
}
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( otriangles ) ; i + + )
2016-08-26 09:58:03 +00:00
addTriangle1 ( otriangles [ i ] . m [ 0 ] , otriangles [ i ] . m [ 1 ] , otriangles [ i ] . m [ 2 ] ) ;
calcLengths ( ) ;
2018-11-24 16:01:49 +00:00
println ( hlog , " result " , make_tuple ( isize ( points ) , isize ( triangles ) ) ) ;
2016-08-26 09:58:03 +00:00
}
2019-08-09 23:07:39 +00:00
EX ld modeldist ( const hyperpoint & h1 , const hyperpoint & h2 ) {
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
return geo_dist_q ( h1 , h2 ) ;
2018-02-27 18:37:57 +00:00
}
typedef long long bincode ;
const bincode sY = ( 1 < < 16 ) ;
const bincode sZ = sY * sY ;
const bincode sT = sY * sY * sY ;
bincode acd_bin ( ld x ) {
return ( int ) floor ( x / anticusp_dist + .5 ) ;
}
bincode get_bincode ( hyperpoint h ) {
switch ( ginf [ gwhere ] . cclass ) {
2019-10-03 18:36:15 +00:00
case gcEuclid : case gcSolNIH : case gcNil : case gcProduct : case gcSL2 :
2018-02-27 18:37:57 +00:00
return acd_bin ( h [ 0 ] ) + acd_bin ( h [ 1 ] ) * sY + acd_bin ( h [ 2 ] ) * sZ ;
case gcHyperbolic :
2019-02-27 18:34:05 +00:00
return acd_bin ( hypot_d ( 3 , h ) ) ;
2018-02-27 18:37:57 +00:00
case gcSphere : {
2020-04-14 14:44:56 +00:00
return acd_bin ( h [ 0 ] ) + acd_bin ( h [ 1 ] ) * sY + acd_bin ( h [ 2 ] ) * sZ + acd_bin ( h [ 3 ] ) * sT ;
2018-02-27 18:37:57 +00:00
}
}
return 0 ;
}
void generate_deltas ( vector < bincode > & target , int dim , bincode offset ) {
if ( dim = = 0 ) {
if ( offset > 0 ) target . push_back ( offset ) ;
}
else {
generate_deltas ( target , dim - 1 , offset * sY ) ;
generate_deltas ( target , dim - 1 , offset * sY + 1 ) ;
generate_deltas ( target , dim - 1 , offset * sY - 1 ) ;
}
}
int detect_cusp_at ( rugpoint * p , rugpoint * q ) {
if ( hdist ( p - > h , q - > h ) * modelscale < = anticusp_dist )
return 0 ;
2020-04-14 14:44:56 +00:00
else if ( modeldist ( p - > native , q - > native ) > anticusp_dist - err_zero_current )
2018-02-27 18:37:57 +00:00
return 1 ;
else {
add_anticusp_edge ( p , q ) ;
enqueue ( p ) ;
enqueue ( q ) ;
return 2 ;
}
}
int detect_cusps ( ) {
ld max_edge_length = 0 ;
for ( auto p : points )
for ( auto e : p - > edges )
max_edge_length = max ( max_edge_length , e . len ) ;
anticusp_dist = anticusp_factor * max_edge_length ;
2018-12-12 01:49:23 +00:00
array < int , 3 > stats = { { 0 , 0 , 0 } } ;
2018-02-27 18:37:57 +00:00
map < bincode , vector < rugpoint * > > code_to_point ;
for ( auto p : points ) if ( p - > valid )
2020-04-14 14:44:56 +00:00
code_to_point [ get_bincode ( p - > native ) ] . push_back ( p ) ;
2018-02-27 18:37:57 +00:00
vector < bincode > deltas ;
generate_deltas ( deltas , gwhere = = gEuclid ? 3 : gwhere = = gNormal ? 1 : 4 , 0 ) ;
for ( auto b : code_to_point ) {
bincode at = b . first ;
for ( auto p : b . second )
for ( auto q : b . second )
if ( p < q ) stats [ detect_cusp_at ( p , q ) ] + + ;
for ( bincode bc : deltas )
if ( code_to_point . count ( at + bc ) )
for ( auto p : b . second )
for ( auto q : code_to_point [ at + bc ] )
stats [ detect_cusp_at ( p , q ) ] + + ;
}
/* printf("testing\n");
int stats2 [ 3 ] = { 0 , 0 , 0 } ;
for ( auto p : points ) if ( p - > valid )
for ( auto q : points ) if ( q - > valid ) if ( p < q ) {
stats2 [ detect_cusp_at ( p , q ) ] + + ;
}
printf ( " cusp stats: %d/%d/%d | %d/%d/%d \n " , stats [ 0 ] , stats [ 1 ] , stats [ 2 ] , stats2 [ 0 ] , stats2 [ 1 ] , stats2 [ 2 ] ) ; */
2018-11-24 16:01:49 +00:00
println ( hlog , " cusp stats: " , stats ) ;
2018-02-27 18:37:57 +00:00
return stats [ 2 ] ;
}
2019-08-09 23:07:39 +00:00
EX void addNewPoints ( ) {
2016-08-26 09:58:03 +00:00
2018-02-27 18:37:57 +00:00
if ( anticusp_factor & & detect_cusps ( ) )
return ;
2019-11-27 00:01:20 +00:00
if ( ( euclid & & quotient ) | | qvalid = = isize ( points ) ) {
2016-08-26 09:58:03 +00:00
subdivide ( ) ;
return ;
}
2019-05-04 16:28:03 +00:00
ld dist = hdist0 ( points [ qvalid ] - > h ) + .1e-6 ;
2016-08-26 09:58:03 +00:00
int oqvalid = qvalid ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( points ) ; i + + ) {
2016-08-26 09:58:03 +00:00
rugpoint & m = * points [ i ] ;
bool wasvalid = m . valid ;
2017-12-25 22:47:57 +00:00
m . valid = wasvalid | | sphere | | hdist0 ( m . h ) < = dist ;
2016-08-26 09:58:03 +00:00
if ( m . valid & & ! wasvalid ) {
qvalid + + ;
2018-03-24 14:17:17 +00:00
need_mouseh = true ;
2016-08-26 09:58:03 +00:00
2017-12-27 20:08:31 +00:00
if ( ! good_shape ) optimize ( & m , i > 7 ) ;
2016-08-26 09:58:03 +00:00
enqueue ( & m ) ;
}
}
2018-11-24 16:01:49 +00:00
if ( qvalid ! = oqvalid ) { println ( hlog , " adding new points " , make_tuple ( oqvalid , qvalid , isize ( points ) , dist , dt , queueiter ) ) ; }
2016-08-26 09:58:03 +00:00
}
2019-08-09 23:07:39 +00:00
EX void physics ( ) {
2016-08-26 09:58:03 +00:00
2019-02-27 18:34:18 +00:00
# if CAP_CRYSTAL
2018-11-30 19:29:14 +00:00
if ( in_crystal ( ) ) {
crystal : : build_rugdata ( ) ;
return ;
}
2019-02-27 18:34:18 +00:00
# endif
2018-11-30 19:29:14 +00:00
2018-01-28 11:25:56 +00:00
if ( good_shape ) return ;
2017-12-27 09:52:54 +00:00
auto t = SDL_GetTicks ( ) ;
2017-12-25 22:47:57 +00:00
2017-12-27 09:52:54 +00:00
current_total_error = 0 ;
2017-12-25 22:47:57 +00:00
while ( SDL_GetTicks ( ) < t + 5 & & ! stop )
2017-12-27 10:59:37 +00:00
for ( int it = 0 ; it < 50 & & ! stop ; it + + )
2016-08-26 09:58:03 +00:00
if ( pqueue . empty ( ) ) addNewPoints ( ) ;
else {
queueiter + + ;
rugpoint * m = pqueue . front ( ) ;
pqueue . pop ( ) ;
m - > inqueue = false ;
2017-12-27 09:52:54 +00:00
bool moved = false ;
2018-02-27 18:37:57 +00:00
for ( auto & e : m - > edges )
moved = force ( * m , * e . target , e . len ) | | moved ;
for ( auto & e : m - > anticusp_edges )
moved = force ( * m , * e . target , anticusp_dist , true ) | | moved ;
2017-12-27 09:52:54 +00:00
2018-03-24 14:17:17 +00:00
if ( moved ) enqueue ( m ) , need_mouseh = true ;
2017-12-27 14:25:10 +00:00
}
2017-12-27 20:08:31 +00:00
2016-08-26 09:58:03 +00:00
}
// drawing the Rug
//-----------------
2018-02-03 12:41:49 +00:00
bool use_precompute ;
2016-08-26 09:58:03 +00:00
extern int besti ;
2018-01-30 23:16:16 +00:00
# if CAP_ODS
2018-01-28 11:20:21 +00:00
/* these functions are for the ODS projection, used in VR videos */
2020-04-14 14:44:56 +00:00
bool project_ods ( hyperpoint h , hyperpoint & h1 , hyperpoint & h2 , bool eye ) {
2018-05-15 21:29:44 +00:00
USING_NATIVE_GEOMETRY ;
2018-01-28 11:20:21 +00:00
2020-04-14 14:44:56 +00:00
return ods : : project ( h , h1 , h2 , eye ) ;
2018-01-28 11:20:21 +00:00
// printf("%10.5lf %10.5lf %10.5lf ", azeq[0], azeq[1], azeq[2]);
// printf(" => %10.5lf %10.5lf %10.5lf %10.5lf", x, y, z, t);
// printf("\n");
return true ;
}
2018-01-30 23:16:16 +00:00
# endif
2018-01-28 11:20:21 +00:00
2018-02-11 18:08:17 +00:00
vector < glhr : : ct_vertex > ct_array ;
2018-02-03 18:19:27 +00:00
2019-03-30 16:46:50 +00:00
vector < glhr : : ct_vertex > cp_array ;
2020-04-15 16:09:27 +00:00
EX basic_textureinfo tinf ;
2020-04-14 15:46:40 +00:00
2016-08-26 09:58:03 +00:00
void drawTriangle ( triangle & t ) {
2020-04-14 15:46:40 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
if ( ! t . m [ i ] ) return ;
2017-12-27 05:31:47 +00:00
if ( ! t . m [ i ] - > valid ) return ;
2020-04-14 14:44:56 +00:00
}
2016-08-26 09:58:03 +00:00
2019-03-30 16:46:50 +00:00
ld col = 1 ;
2020-04-17 13:01:55 +00:00
if ( true ) {
hyperpoint hc = ( t . m [ 1 ] - > native - t . m [ 0 ] - > native ) ^ ( t . m [ 2 ] - > native - t . m [ 0 ] - > native ) ;
2019-03-30 16:46:50 +00:00
double hch = hypot_d ( 3 , hc ) ;
col = ( 2 + hc [ 0 ] / hch ) / 3 ;
2020-04-17 15:17:22 +00:00
if ( nonisotropic ) col = ( 9 + col ) / 10 ;
2019-03-30 16:46:50 +00:00
}
2020-04-14 15:46:40 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
curvepoint ( t . m [ i ] - > native ) ;
2020-04-17 13:01:55 +00:00
tinf . tvertices . push_back ( glhr : : pointtogl ( point3 ( t . m [ i ] - > x1 , t . m [ i ] - > y1 , col ) ) ) ;
2020-04-14 15:46:40 +00:00
}
2016-08-26 09:58:03 +00:00
}
2019-08-09 23:07:39 +00:00
EX struct renderbuffer * glbuf ;
2016-08-26 09:58:03 +00:00
2019-08-09 23:07:39 +00:00
EX void prepareTexture ( ) {
2019-11-03 14:52:19 +00:00
ensure_glbuf ( ) ;
if ( ! glbuf ) { rug : : close ( ) ; return ; }
2018-02-11 01:19:49 +00:00
resetbuffer rb ;
2018-11-17 18:24:02 +00:00
dynamicval < eStereo > d ( vid . stereo_mode , sOFF ) ;
2019-11-08 13:57:22 +00:00
dynamicval < ld > dl ( levellines , 0 ) ;
2018-11-20 18:01:10 +00:00
calcparam_rug ( ) ;
2019-08-09 22:58:50 +00:00
models : : configure ( ) ;
2016-08-26 09:58:03 +00:00
2018-02-01 12:42:47 +00:00
glbuf - > enable ( ) ;
glbuf - > clear ( 0 ) ;
2016-08-26 09:58:03 +00:00
2018-02-01 12:42:47 +00:00
ptds . clear ( ) ;
2019-03-30 16:47:16 +00:00
# if CAP_QUEUE
draw_boundary ( 0 ) ;
draw_boundary ( 1 ) ;
draw_model_elements ( ) ;
# endif
2018-02-01 12:42:47 +00:00
drawthemap ( ) ;
if ( mousing & & ! renderonce ) {
for ( int i = 0 ; i < numplayers ( ) ; i + + ) if ( multi : : playerActive ( i ) )
2018-08-17 14:47:06 +00:00
queueline ( tC0 ( ggmatrix ( playerpos ( i ) ) ) , mouseh , 0xFF00FF , 8 + vid . linequality ) ;
2016-08-26 09:58:03 +00:00
}
2018-02-01 12:42:47 +00:00
if ( finger_center ) {
transmatrix V = rgpushxto0 ( finger_center - > h ) ;
2019-12-26 22:38:28 +00:00
queuestr ( V , 0.5 , " X " , 0xFFFFFFFF , 2 ) ;
2018-02-01 12:42:47 +00:00
for ( int i = 0 ; i < 72 ; i + + )
2018-08-19 14:28:36 +00:00
queueline ( V * xspinpush0 ( i * M_PI / 32 , finger_range ) , V * xspinpush0 ( ( i + 1 ) * M_PI / 32 , finger_range ) , 0xFFFFFFFF , vid . linequality ) ;
2016-08-26 09:58:03 +00:00
}
2018-02-01 12:42:47 +00:00
drawqueue ( ) ;
2018-11-20 18:01:10 +00:00
calcparam ( ) ;
2018-02-11 01:19:49 +00:00
rb . reset ( ) ;
2016-08-26 09:58:03 +00:00
}
2019-08-09 23:07:39 +00:00
EX bool no_fog ;
2018-05-15 21:30:37 +00:00
2019-09-06 06:17:02 +00:00
EX ld lowrug = 1e-2 ;
EX ld hirug = 1e3 ;
2018-05-15 21:30:37 +00:00
2019-09-06 06:17:02 +00:00
EX GLuint alternate_texture ;
2018-05-18 15:34:12 +00:00
2019-09-06 06:17:02 +00:00
EX bool invert_depth ;
2018-09-03 14:32:11 +00:00
2020-04-14 15:46:40 +00:00
EX bool rug_control ( ) { return rug : : rugged ; }
2018-02-03 12:41:49 +00:00
2020-04-14 15:46:40 +00:00
# if HDR
2018-02-03 18:19:27 +00:00
2020-04-14 15:46:40 +00:00
struct using_rugview {
using_rugview ( ) { if ( rug_control ( ) ) swap ( View , rugView ) , swap ( geometry , gwhere ) ; }
~ using_rugview ( ) { if ( rug_control ( ) ) swap ( View , rugView ) , swap ( geometry , gwhere ) ; }
} ;
2019-03-30 16:46:50 +00:00
2020-04-14 15:46:40 +00:00
# endif
2018-02-03 12:41:49 +00:00
2016-08-26 09:58:03 +00:00
2020-04-14 15:46:40 +00:00
EX void drawRugScene ( ) {
USING_NATIVE_GEOMETRY ;
tinf . texture_id = alternate_texture ? alternate_texture : glbuf - > renderedTexture ;
tinf . tvertices . clear ( ) ;
ptds . clear ( ) ;
for ( auto t : triangles ) drawTriangle ( t ) ;
auto & rug = queuecurve ( 0 , 0xFFFFFFFF , PPR : : LINE ) ;
2020-04-17 15:17:22 +00:00
if ( nonisotropic ) {
transmatrix T2 = eupush ( tC0 ( inverse ( rugView ) ) ) ;
NLP = rugView * T2 ;
rug . V = inverse ( NLP ) * rugView ;
}
else {
rug . V = rugView ;
}
2020-04-14 15:46:40 +00:00
rug . offset_texture = 0 ;
rug . tinf = & tinf ;
2020-04-17 13:01:55 +00:00
rug . flags = POLY_TRIANGLES | POLY_FAT | POLY_PRINTABLE | POLY_ALWAYS_IN | POLY_ISSIDE | POLY_SHADE_TEXTURE ;
2016-08-26 09:58:03 +00:00
2020-04-16 22:53:58 +00:00
dynamicval < projection_configuration > p ( pconf , rconf ) ;
2020-04-17 00:21:44 +00:00
calcparam ( ) ;
2020-04-14 15:46:40 +00:00
drawqueue ( ) ;
2016-08-26 09:58:03 +00:00
}
// organization
//--------------
2019-08-09 23:07:39 +00:00
EX transmatrix currentrot ;
2019-11-03 14:52:19 +00:00
EX void close_glbuf ( ) {
delete glbuf ;
glbuf = nullptr ;
}
EX void ensure_glbuf ( ) {
if ( glbuf ) return ;
2018-02-01 12:42:47 +00:00
glbuf = new renderbuffer ( TEXTURESIZE , TEXTURESIZE , vid . usingGL & & ! rendernogl ) ;
2018-02-03 12:50:47 +00:00
if ( ! glbuf - > valid ) {
addMessage ( XLAT ( " Failed to enable " ) ) ;
2019-11-03 14:52:19 +00:00
close_glbuf ( ) ;
2018-02-03 12:50:47 +00:00
return ;
}
2019-11-03 14:52:19 +00:00
}
EX void reopen ( ) {
if ( rugged ) return ;
when_enabled = 0 ;
GLERR ( " before init " ) ;
ensure_glbuf ( ) ;
if ( ! glbuf ) { rugged = false ; return ; }
2018-02-03 12:50:47 +00:00
rugged = true ;
2016-08-26 09:58:03 +00:00
if ( renderonce ) prepareTexture ( ) ;
if ( ! rugged ) return ;
2018-03-24 14:17:17 +00:00
}
2019-08-09 23:07:39 +00:00
EX bool display_warning = true ;
2019-07-12 21:16:18 +00:00
2019-08-09 23:07:39 +00:00
EX void init_model ( ) {
2018-03-24 14:17:17 +00:00
clear_model ( ) ;
2016-08-26 09:58:03 +00:00
genrug = true ;
drawthemap ( ) ;
genrug = false ;
qvalid = 0 ; dt = 0 ; queueiter = 0 ;
2017-12-27 09:52:54 +00:00
err_zero_current = err_zero ;
2016-08-26 09:58:03 +00:00
2019-02-27 18:34:18 +00:00
# if CAP_CRYSTAL
2019-08-22 10:14:39 +00:00
if ( cryst & & surface : : sh = = surface : : dsNone ) {
2018-12-02 19:26:58 +00:00
surface : : sh = surface : : dsCrystal ;
crystal : : init_rotation ( ) ;
good_shape = true ;
return ;
}
2019-02-27 18:34:18 +00:00
# endif
2018-12-02 19:26:58 +00:00
2017-12-29 11:54:50 +00:00
try {
buildRug ( ) ;
while ( good_shape & & subdivide_further ( ) ) subdivide ( ) ;
currentrot = Id ;
2017-12-29 13:31:18 +00:00
bool valid = true ;
for ( rugpoint * r : points )
if ( r - > x1 < 0 | | r - > x1 > 1 | | r - > y1 < 0 | | r - > y1 > 1 )
valid = false ;
2020-04-16 22:53:58 +00:00
if ( sphere & & pmodel = = mdDisk & & pconf . alpha > 1 )
2017-12-29 13:31:18 +00:00
valid = false ;
2019-07-12 21:16:18 +00:00
if ( display_warning & & ! valid )
2017-12-29 13:31:18 +00:00
gotoHelp (
" Note: this mode is based on what you see on the screen -- but re-rendered in another way. "
2017-12-29 13:35:18 +00:00
" If not everything is shown on the screen (e.g., too zoomed in), the results will be incorrect "
" (though possibly interesting). "
2017-12-29 13:31:18 +00:00
" Use a different projection to fix this. "
) ;
2017-12-29 11:54:50 +00:00
}
catch ( rug_exception ) {
close ( ) ;
2018-03-24 14:17:17 +00:00
clear_model ( ) ;
2017-12-29 11:54:50 +00:00
}
2016-08-26 09:58:03 +00:00
}
2020-04-14 15:46:40 +00:00
EX void reset_view ( ) {
rugView = Id ;
if ( perspective ( ) ) {
using_rugview urv ;
shift_view ( ztangent ( model_distance ) ) ;
}
}
2019-08-09 23:07:39 +00:00
EX void init ( ) {
2019-05-28 23:09:38 +00:00
if ( dual : : state ) return ;
2018-03-24 14:17:17 +00:00
reopen ( ) ;
if ( rugged ) init_model ( ) ;
2020-04-14 15:46:40 +00:00
reset_view ( ) ;
2018-03-24 14:17:17 +00:00
}
2019-08-09 23:07:39 +00:00
EX void clear_model ( ) {
2016-08-26 09:58:03 +00:00
triangles . clear ( ) ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( points ) ; i + + ) delete points [ i ] ;
2016-08-26 09:58:03 +00:00
points . clear ( ) ;
pqueue = queue < rugpoint * > ( ) ;
2018-03-24 14:17:17 +00:00
}
2019-08-09 23:07:39 +00:00
EX void close ( ) {
2018-03-24 14:17:17 +00:00
if ( ! rugged ) return ;
rugged = false ;
2019-11-03 14:52:19 +00:00
close_glbuf ( ) ;
2018-01-29 15:30:21 +00:00
finger_center = NULL ;
2016-08-26 09:58:03 +00:00
}
int lastticks ;
2017-12-27 17:53:00 +00:00
ld protractor = 0 ;
2019-09-26 11:18:58 +00:00
# define CAP_HOLDKEYS (CAP_SDL && !ISWEB)
2018-02-11 18:08:17 +00:00
2019-08-09 23:07:39 +00:00
EX bool handlekeys ( int sym , int uni ) {
2020-04-14 14:44:56 +00:00
USING_NATIVE_GEOMETRY ;
2018-12-06 11:31:51 +00:00
if ( NUMBERKEY = = ' 1 ' ) {
2018-01-29 15:30:21 +00:00
ld bdist = 1e12 ;
if ( finger_center )
finger_center = NULL ;
else {
for ( auto p : points ) {
ld cdist = hdist ( p - > getglue ( ) - > h , mouseh ) ;
if ( cdist < bdist )
bdist = cdist , finger_center = p - > getglue ( ) ;
}
}
2018-02-27 18:39:22 +00:00
if ( renderonce ) renderlate + = 10 ;
2018-01-29 15:30:21 +00:00
return true ;
}
2018-12-06 11:31:51 +00:00
else if ( NUMBERKEY = = ' 2 ' ) {
2019-02-27 18:34:18 +00:00
# if CAP_CRYSTAL
2018-11-30 19:29:14 +00:00
if ( in_crystal ( ) )
crystal : : switch_z_coordinate ( ) ;
else
2019-02-27 18:34:18 +00:00
# endif
2020-04-14 15:46:40 +00:00
rotate_view ( cspin ( 0 , 2 , M_PI ) ) ;
2018-01-29 15:30:21 +00:00
return true ;
}
2018-12-06 11:31:51 +00:00
else if ( NUMBERKEY = = ' 3 ' ) {
2019-02-27 18:34:18 +00:00
# if CAP_CRYSTAL
2018-11-30 19:29:14 +00:00
if ( in_crystal ( ) )
2018-12-06 10:43:10 +00:00
crystal : : flip_z ( ) ;
2018-11-30 19:29:14 +00:00
else
2019-02-27 18:34:18 +00:00
# endif
2020-04-14 15:46:40 +00:00
rotate_view ( cspin ( 0 , 2 , M_PI / 2 ) ) ;
2018-01-29 15:30:21 +00:00
return true ;
}
2019-02-27 18:34:18 +00:00
# if CAP_CRYSTAL
2018-12-06 10:43:10 +00:00
else if ( sym = = SDLK_HOME & & in_crystal ( ) ) {
crystal : : next_home_orientation ( ) ;
return true ;
}
2019-02-27 18:34:18 +00:00
# endif
2018-01-29 15:30:21 +00:00
else return false ;
}
2019-08-09 23:07:39 +00:00
EX void finger_on ( int coord , ld val ) {
2018-01-29 15:30:21 +00:00
for ( auto p : points ) {
ld d = hdist ( finger_center - > h , p - > getglue ( ) - > h ) ;
2020-04-14 14:44:56 +00:00
push_point ( p - > native , coord , val * finger_force * exp ( - sqr ( d / finger_range ) ) ) ;
2018-01-29 15:30:21 +00:00
}
enqueue ( finger_center ) , good_shape = false ;
}
2018-02-03 13:35:06 +00:00
transmatrix last_orientation ;
2019-08-09 23:07:39 +00:00
EX ld ruggospeed = 1 ;
2018-05-18 15:34:12 +00:00
2019-08-09 23:07:39 +00:00
EX void actDraw ( ) {
2017-12-29 11:54:50 +00:00
try {
2018-02-11 01:19:49 +00:00
2016-08-26 09:58:03 +00:00
if ( ! renderonce ) prepareTexture ( ) ;
2018-02-12 15:21:55 +00:00
else if ( renderlate ) {
renderlate - - ;
prepareTexture ( ) ;
}
2018-09-02 13:11:35 +00:00
// do not display button
else playerfound = true ;
2018-11-17 18:24:02 +00:00
current_display - > set_viewport ( 0 ) ;
2016-08-26 09:58:03 +00:00
physics ( ) ;
drawRugScene ( ) ;
2018-02-03 13:31:17 +00:00
2016-08-26 09:58:03 +00:00
double alpha = ( ticks - lastticks ) / 1000.0 ;
lastticks = ticks ;
2020-04-14 15:46:40 +00:00
// if(ruggo) move_forward(ruggo * alpha);
2018-02-12 11:49:47 +00:00
# if CAP_HOLDKEYS
Uint8 * keystate = SDL_GetKeyState ( NULL ) ;
2018-03-24 14:17:17 +00:00
if ( keystate [ SDLK_LALT ] ) alpha / = 10 ;
2020-04-14 15:46:40 +00:00
# endif
2018-02-12 11:49:47 +00:00
2020-04-16 19:00:28 +00:00
# if CAP_HOLDKEYS
2018-01-29 15:30:21 +00:00
auto perform_finger = [ = ] ( ) {
if ( keystate [ SDLK_HOME ] ) finger_range / = exp ( alpha ) ;
if ( keystate [ SDLK_END ] ) finger_range * = exp ( alpha ) ;
if ( keystate [ SDLK_LEFT ] ) finger_on ( 0 , - alpha ) ;
if ( keystate [ SDLK_RIGHT ] ) finger_on ( 0 , alpha ) ;
if ( keystate [ SDLK_UP ] ) finger_on ( 1 , alpha ) ;
if ( keystate [ SDLK_DOWN ] ) finger_on ( 1 , - alpha ) ;
if ( keystate [ SDLK_PAGEDOWN ] ) finger_on ( 2 , - alpha ) ;
if ( keystate [ SDLK_PAGEUP ] ) finger_on ( 2 , + alpha ) ;
} ;
2017-12-25 22:47:57 +00:00
2020-04-14 15:46:40 +00:00
if ( finger_center )
2020-04-16 19:00:28 +00:00
perform_finger ( ) ;
# endif
2017-12-29 11:54:50 +00:00
}
catch ( rug_exception ) {
rug : : close ( ) ;
}
2016-08-26 09:58:03 +00:00
}
int besti ;
2017-12-27 14:25:10 +00:00
static const ld RADAR_INF = 1e12 ;
ld radar_distance = RADAR_INF ;
2019-08-09 23:07:39 +00:00
EX hyperpoint gethyper ( ld x , ld y ) {
2020-04-17 15:29:50 +00:00
projection_configuration bak = pconf ;
pconf = rconf ;
calcparam ( ) ;
double mx = ( x - current_display - > xcenter ) / current_display - > radius ;
double my = ( y - current_display - > ycenter ) / current_display - > radius / pconf . stretch ;
calcparam ( ) ;
2017-12-27 14:25:10 +00:00
radar_distance = RADAR_INF ;
2016-08-26 09:58:03 +00:00
2017-11-07 15:16:04 +00:00
double rx1 = 0 , ry1 = 0 ;
2017-11-06 18:24:02 +00:00
bool found = false ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( triangles ) ; i + + ) {
2017-11-06 18:24:02 +00:00
auto r0 = triangles [ i ] . m [ 0 ] ;
auto r1 = triangles [ i ] . m [ 1 ] ;
auto r2 = triangles [ i ] . m [ 2 ] ;
2019-03-30 16:46:50 +00:00
if ( ! r2 ) continue ;
2019-04-29 01:38:27 +00:00
if ( ! r0 - > valid | | ! r1 - > valid | | ! r2 - > valid ) continue ;
2017-12-27 12:09:58 +00:00
hyperpoint p0 , p1 , p2 ;
bool error = false ;
2017-12-27 13:12:27 +00:00
int spherepoints = 0 ;
2020-04-14 14:44:56 +00:00
if ( 1 ) {
USING_NATIVE_GEOMETRY ;
// USING_RUG_PMODEL;
// dynamicval<eModel> m(pmodel, mdEquidistant);
if ( elliptic & & pmodel = = mdDisk ) {
int sp =
( r0 - > native [ 3 ] < 0 ) + ( r1 - > native [ 3 ] < 0 ) + ( r2 - > native [ 3 ] < 0 ) ;
if ( sp = = 1 | | sp = = 2 ) continue ;
}
applymodel ( r0 - > native , p0 ) ;
applymodel ( r1 - > native , p1 ) ;
applymodel ( r2 - > native , p2 ) ;
}
2017-12-27 13:12:27 +00:00
if ( error | | spherepoints = = 1 | | spherepoints = = 2 ) continue ;
2017-12-27 12:09:58 +00:00
double dx1 = p1 [ 0 ] - p0 [ 0 ] ;
double dy1 = p1 [ 1 ] - p0 [ 1 ] ;
double dx2 = p2 [ 0 ] - p0 [ 0 ] ;
double dy2 = p2 [ 1 ] - p0 [ 1 ] ;
double dxm = mx - p0 [ 0 ] ;
double dym = my - p0 [ 1 ] ;
2017-11-06 18:24:02 +00:00
// A (dx1,dy1) = (1,0)
// B (dx2,dy2) = (0,1)
double det = dx1 * dy2 - dy1 * dx2 ;
double tx = dxm * dy2 - dym * dx2 ;
double ty = - ( dxm * dy1 - dym * dx1 ) ;
tx / = det ; ty / = det ;
if ( tx > = 0 & & ty > = 0 & & tx + ty < = 1 ) {
2017-12-27 12:09:58 +00:00
double rz1 = p0 [ 2 ] * ( 1 - tx - ty ) + p1 [ 2 ] * tx + p2 [ 2 ] * ty ;
2020-04-14 15:46:40 +00:00
rz1 = - rz1 ;
2017-12-27 14:25:10 +00:00
if ( rz1 < radar_distance ) {
radar_distance = rz1 ;
2017-11-06 18:24:02 +00:00
rx1 = r0 - > x1 + ( r1 - > x1 - r0 - > x1 ) * tx + ( r2 - > x1 - r0 - > x1 ) * ty ;
ry1 = r0 - > y1 + ( r1 - > y1 - r0 - > y1 ) * tx + ( r2 - > y1 - r0 - > y1 ) * ty ;
}
found = true ;
}
2016-08-26 09:58:03 +00:00
}
2020-04-17 15:29:50 +00:00
pconf = bak ;
2017-11-07 13:17:13 +00:00
if ( ! found ) return Hypc ;
2017-11-06 18:24:02 +00:00
double px = rx1 * TEXTURESIZE , py = ( 1 - ry1 ) * TEXTURESIZE ;
2016-08-26 09:58:03 +00:00
2018-11-20 18:01:10 +00:00
calcparam_rug ( ) ;
2019-08-09 22:58:50 +00:00
models : : configure ( ) ;
2018-06-10 23:58:31 +00:00
hyperpoint h = hr : : gethyper ( px , py ) ;
2018-11-20 18:01:10 +00:00
calcparam ( ) ;
2016-08-26 09:58:03 +00:00
return h ;
}
2019-08-09 23:07:39 +00:00
EX string makehelp ( ) {
2018-02-26 12:15:33 +00:00
return
XLAT (
" In this mode, HyperRogue is played on a 3D model of a part of the hyperbolic plane, "
" similar to one you get from the 'paper model creator' or by hyperbolic crocheting. \n \n " )
/*
" This requires some OpenGL extensions and may crash or not work correctly -- enabling "
" the 'render texture without OpenGL' options may be helpful in this case. Also the 'render once' option "
" will make the rendering faster, but the surface will be rendered only once, so "
" you won't be able to play a game on it. \n \n " */
# if !ISMOBILE
+ XLAT ( " Use arrow keys to rotate, Page Up/Down to zoom. " )
+ " \n \n " +
2018-03-02 12:06:28 +00:00
XLAT ( " In the perspective projection, you can use arrows to rotate the camera, Page Up/Down to go forward/backward, Shift+arrows to strafe, and Ctrl+arrows to rotate the model. " )
# endif
;
2018-02-26 12:15:33 +00:00
}
2019-08-09 23:07:39 +00:00
EX string geometry_name ( eGeometry g ) {
2019-02-06 15:34:22 +00:00
switch ( g ) {
case gNormal : return XLAT ( " hyperbolic " ) ;
case gEuclid : return XLAT ( " Euclidean " ) ;
case gSphere : return XLAT ( " spherical " ) ;
case gElliptic : return XLAT ( " elliptic " ) ;
default : return XLAT ( " unknown " ) ;
}
}
2019-05-03 09:45:51 +00:00
void change_texturesize ( ) {
if ( rugged ) {
close ( ) ;
reopen ( ) ;
}
}
2019-05-03 09:46:14 +00:00
ld old_distance ;
2020-04-14 14:44:56 +00:00
EX void rug_geometry_choice ( ) {
cmode = sm : : SIDE | sm : : MAYDARK ;
gamescreen ( 0 ) ;
dialog : : init ( XLAT ( " hypersian rug mode " ) , iinf [ itPalace ] . color , 150 , 100 ) ;
2020-04-17 15:17:22 +00:00
USING_NATIVE_GEOMETRY ;
dialog : : addBoolItem ( " Euclidean " , euclid , ' a ' ) ;
2020-04-14 14:44:56 +00:00
dialog : : add_action ( [ ] { gwhere = rgEuclid ; popScreen ( ) ; } ) ;
2020-04-17 15:17:22 +00:00
dialog : : addBoolItem ( " hyperbolic " , hyperbolic , ' b ' ) ;
2020-04-14 14:44:56 +00:00
dialog : : add_action ( [ ] { gwhere = rgHyperbolic ; popScreen ( ) ; } ) ;
2020-04-17 15:17:22 +00:00
dialog : : addBoolItem ( " spherical " , sphere & & ! elliptic , ' c ' ) ;
2020-04-14 14:44:56 +00:00
dialog : : add_action ( [ ] { gwhere = rgSphere ; popScreen ( ) ; } ) ;
2020-04-17 15:17:22 +00:00
dialog : : addBoolItem ( " elliptic " , elliptic , ' d ' ) ;
2020-04-14 14:44:56 +00:00
dialog : : add_action ( [ ] { gwhere = rgElliptic ; popScreen ( ) ; } ) ;
2020-04-17 15:17:22 +00:00
dialog : : addBoolItem ( " Nil " , nil , ' e ' ) ;
dialog : : add_action ( [ ] { gwhere = gNil ; popScreen ( ) ; } ) ;
dialog : : addBoolItem ( " Solv " , sol , ' e ' ) ;
dialog : : add_action ( [ ] { gwhere = gSol ; popScreen ( ) ; } ) ;
2020-04-14 14:44:56 +00:00
dialog : : addBack ( ) ;
dialog : : display ( ) ;
}
2019-08-09 23:07:39 +00:00
EX void show ( ) {
2018-12-13 16:02:10 +00:00
cmode = sm : : SIDE | sm : : MAYDARK ;
2017-12-27 14:25:10 +00:00
gamescreen ( 0 ) ;
2017-03-23 10:53:57 +00:00
dialog : : init ( XLAT ( " hypersian rug mode " ) , iinf [ itPalace ] . color , 150 , 100 ) ;
2017-10-30 09:01:49 +00:00
2017-12-27 14:25:10 +00:00
dialog : : addBoolItem ( XLAT ( " enable the Hypersian Rug mode " ) , rug : : rugged , ' u ' ) ;
2017-03-23 10:53:57 +00:00
dialog : : addBoolItem ( XLAT ( " render the texture only once " ) , ( renderonce ) , ' o ' ) ;
2018-02-03 12:54:51 +00:00
# if CAP_SDL
2017-12-27 14:25:10 +00:00
dialog : : addBoolItem ( XLAT ( " render texture without OpenGL " ) , ( rendernogl ) , ' g ' ) ;
2018-02-03 12:54:51 +00:00
# else
rendernogl = false ;
# endif
2017-03-23 10:53:57 +00:00
dialog : : addSelItem ( XLAT ( " texture size " ) , its ( texturesize ) + " x " + its ( texturesize ) , ' s ' ) ;
2017-12-27 14:25:10 +00:00
dialog : : addSelItem ( XLAT ( " vertex limit " ) , its ( vertex_limit ) , ' v ' ) ;
if ( rug : : rugged )
dialog : : lastItem ( ) . value + = " ( " + its ( qvalid ) + " ) " ;
2017-12-27 17:53:00 +00:00
dialog : : addSelItem ( XLAT ( " model distance " ) , fts ( model_distance ) , ' d ' ) ;
2020-04-16 22:53:58 +00:00
if ( rug : : rugged ) {
dialog : : addSelItem ( XLAT ( " projection " ) , models : : get_model_name ( rconf . model ) , ' p ' ) ;
}
else dialog : : addBreak ( 100 ) ;
2017-12-27 14:25:10 +00:00
if ( ! rug : : rugged )
2019-02-06 15:34:22 +00:00
dialog : : addSelItem ( XLAT ( " native geometry " ) , geometry_name ( gwhere ) , ' n ' ) ;
2017-12-27 14:25:10 +00:00
else
2019-05-21 22:01:30 +00:00
dialog : : addSelItem ( XLAT ( " radar " ) , radar_distance = = RADAR_INF ? " ∞ " : fts ( radar_distance , 4 ) , ' r ' ) ;
2018-01-28 11:21:10 +00:00
dialog : : addSelItem ( XLAT ( " model scale factor " ) , fts ( modelscale ) , ' m ' ) ;
if ( rug : : rugged )
2017-12-27 14:25:10 +00:00
dialog : : addSelItem ( XLAT ( " model iterations " ) , its ( queueiter ) , 0 ) ;
2018-02-03 12:41:49 +00:00
dialog : : addItem ( XLAT ( " stereo vision config " ) , ' f ' ) ;
2017-12-27 17:53:00 +00:00
// dialog::addSelItem(XLAT("protractor"), fts(protractor * 180 / M_PI) + "°", 'f');
2018-01-28 11:25:56 +00:00
if ( ! good_shape ) {
2019-05-21 22:01:30 +00:00
dialog : : addSelItem ( XLAT ( " maximum error " ) , fts ( err_zero ) , ' e ' ) ;
2017-12-27 14:25:10 +00:00
if ( rug : : rugged )
2019-05-21 22:01:30 +00:00
dialog : : lastItem ( ) . value + = " ( " + fts ( err_zero_current ) + " ) " ;
2017-11-07 13:39:26 +00:00
}
2018-02-27 18:39:46 +00:00
dialog : : addSelItem ( XLAT ( " automatic move speed " ) , fts ( ruggo ) , ' G ' ) ;
dialog : : addSelItem ( XLAT ( " anti-crossing " ) , fts ( anticusp_factor ) , ' A ' ) ;
2018-12-05 18:57:35 +00:00
dialog : : addBoolItem ( XLAT ( " 3D monsters/walls on the surface " ) , spatial_rug , ' S ' ) ;
dialog : : add_action ( [ ] ( ) { spatial_rug = ! spatial_rug ; } ) ;
2019-11-03 12:36:06 +00:00
edit_levellines ( ' L ' ) ;
2017-12-27 14:25:10 +00:00
2018-03-24 16:21:25 +00:00
# if CAP_SURFACE
2020-04-14 14:44:56 +00:00
if ( hyperbolic & & rug_euclid ( ) )
dialog : : addItem ( XLAT ( " smooth surfaces " ) , ' c ' ) ;
else
dialog : : addBreak ( 100 ) ;
2018-03-24 16:21:25 +00:00
# endif
2018-06-12 22:11:26 +00:00
dialog : : addBreak ( 50 ) ;
dialog : : addHelp ( ) ;
dialog : : addBack ( ) ;
2017-03-23 10:53:57 +00:00
dialog : : display ( ) ;
2017-07-10 18:47:38 +00:00
keyhandler = [ ] ( int sym , int uni ) {
dialog : : handleNavigation ( sym , uni ) ;
2016-08-26 09:58:03 +00:00
2018-06-12 22:11:26 +00:00
if ( uni = = ' h ' | | uni = = SDLK_F1 ) gotoHelp ( makehelp ( ) ) ;
2017-07-10 18:47:38 +00:00
else if ( uni = = ' u ' ) {
2017-12-27 14:25:10 +00:00
if ( rug : : rugged ) rug : : close ( ) ;
2018-03-24 16:21:25 +00:00
else {
# if CAP_SURFACE
surface : : sh = surface : : dsNone ;
# endif
rug : : init ( ) ;
}
2017-07-10 18:47:38 +00:00
}
2018-01-29 15:30:21 +00:00
else if ( uni = = ' R ' )
2018-02-13 12:37:20 +00:00
dialog : : editNumber ( finger_range , 0 , 1 , .01 , .1 , XLAT ( " finger range " ) ,
XLAT ( " Press 1 to enable the finger mode. " )
2018-01-29 15:30:21 +00:00
) ;
else if ( uni = = ' F ' )
2018-02-13 12:37:20 +00:00
dialog : : editNumber ( finger_force , 0 , 1 , .01 , .1 , XLAT ( " finger force " ) ,
XLAT ( " Press 1 to enable the finger force. " )
2018-01-29 15:30:21 +00:00
) ;
2018-03-24 16:21:25 +00:00
else if ( uni = = ' o ' )
2017-07-10 18:47:38 +00:00
renderonce = ! renderonce ;
2018-02-27 18:39:46 +00:00
else if ( uni = = ' G ' ) {
dialog : : editNumber ( ruggo , - 1 , 1 , .1 , 0 , XLAT ( " automatic move speed " ) ,
XLAT ( " Move automatically without pressing any keys. " )
) ;
}
else if ( uni = = ' A ' ) {
2018-02-27 18:47:35 +00:00
dialog : : editNumber ( anticusp_factor , 0 , 1.5 , .1 , 0 , XLAT ( " anti-crossing " ) ,
2018-02-27 18:39:46 +00:00
XLAT ( " The anti-crossing algorithm prevents the model from crossing itself, "
" by preventing points which should not be close from being close. "
" The bigger number, the more sensitive it is, but the embedding is slower. Set 0 to disable. " )
) ;
}
2017-12-27 14:25:10 +00:00
else if ( uni = = ' v ' ) {
2018-02-13 12:37:20 +00:00
dialog : : editNumber ( vertex_limit , 0 , 50000 , 500 , 3000 , ( " vertex limit " ) ,
XLAT ( " The more vertices, the more accurate the Hypersian Rug model is. "
" However, a number too high might make the model slow to compute and render. " )
2018-01-03 01:04:34 +00:00
) ;
2017-12-27 14:25:10 +00:00
dialog : : reaction = [ ] ( ) { err_zero_current = err_zero ; } ;
}
else if ( uni = = ' r ' )
2017-12-27 18:10:34 +00:00
addMessage ( XLAT ( " This just shows the 'z' coordinate of the selected point. " ) ) ;
2017-12-27 14:25:10 +00:00
else if ( uni = = ' m ' ) {
2019-05-03 09:46:14 +00:00
dialog : : editNumber ( modelscale , 0.1 , 10 , rugged ? .01 : .1 , 1 , XLAT ( " model scale factor " ) ,
2018-02-13 12:37:20 +00:00
XLAT ( " This is relevant when the native geometry is not Euclidean. "
2017-12-27 14:25:10 +00:00
" For example, if the native geometry is spherical, and scale < 1, a 2d sphere will be rendered as a subsphere; "
2018-02-13 12:37:20 +00:00
" if the native geometry is hyperbolic, and scale > 1, a hyperbolic plane will be rendered as an equidistant surface. " )
2017-12-27 14:25:10 +00:00
) ;
dialog : : scaleLog ( ) ;
2018-01-28 11:21:10 +00:00
if ( rug : : rugged ) {
2019-05-03 09:46:14 +00:00
static bool adjust_points = true ;
static bool camera_center = false ;
static bool adjust_edges = true ;
static bool adjust_distance = true ;
2018-01-28 11:21:10 +00:00
static ld last ;
last = modelscale ;
2019-05-03 09:46:14 +00:00
dialog : : extra_options = [ ] ( ) {
dialog : : addBoolItem_action ( XLAT ( " adjust points " ) , adjust_points , ' P ' ) ;
if ( adjust_points )
dialog : : addBoolItem_action ( XLAT ( " center on camera " ) , camera_center , ' C ' ) ;
else
dialog : : addBreak ( 100 ) ;
dialog : : addBoolItem_action ( XLAT ( " adjust edges " ) , adjust_edges , ' E ' ) ;
dialog : : addBoolItem_action ( XLAT ( " adjust distance " ) , adjust_distance , ' D ' ) ;
} ;
2018-01-28 11:21:10 +00:00
dialog : : reaction = [ ] ( ) {
2019-05-03 09:46:14 +00:00
if ( ! last | | ! modelscale ) return ;
if ( ! camera_center ) push_all_points ( 2 , model_distance ) ;
2018-01-28 11:21:10 +00:00
for ( auto p : points ) {
2019-05-03 09:46:14 +00:00
if ( adjust_edges ) for ( auto & e : p - > edges ) e . len * = modelscale / last ;
2020-04-14 14:44:56 +00:00
if ( adjust_points ) p - > native * = modelscale / last ;
2018-01-28 11:21:10 +00:00
enqueue ( p ) ;
}
2019-05-03 09:46:14 +00:00
if ( adjust_distance ) model_distance = model_distance * modelscale / last ;
2018-01-28 11:21:10 +00:00
last = modelscale ;
2018-01-28 11:25:56 +00:00
good_shape = false ;
2019-05-03 09:46:14 +00:00
if ( ! camera_center ) push_all_points ( 2 , - model_distance ) ;
2018-01-29 15:31:28 +00:00
} ;
2018-01-28 11:21:10 +00:00
}
2017-12-27 14:25:10 +00:00
}
2017-12-27 17:53:00 +00:00
else if ( uni = = ' p ' ) {
2020-04-16 22:53:58 +00:00
pushScreen ( models : : model_menu ) ;
2017-12-27 17:53:00 +00:00
}
2019-05-03 09:46:14 +00:00
else if ( uni = = ' d ' ) {
2018-02-13 12:37:20 +00:00
dialog : : editNumber ( model_distance , - 10 , 10 , .1 , 1 , XLAT ( " model distance " ) ,
XLAT ( " In the perspective projection, this sets the distance from the camera to the center of the model. "
" In the orthogonal projection this just controls the scale. " )
2018-01-03 01:04:34 +00:00
) ;
2019-05-03 09:46:14 +00:00
old_distance = model_distance ;
dialog : : reaction = [ ] ( ) {
2020-04-14 15:46:40 +00:00
if ( rug : : rugged & & perspective ( ) ) {
using_rugview rv ;
shift_view ( ztangent ( old_distance - model_distance ) ) ;
2019-05-03 09:46:14 +00:00
}
old_distance = model_distance ;
} ;
}
2017-12-27 14:25:10 +00:00
else if ( uni = = ' e ' ) {
2018-02-13 12:37:20 +00:00
dialog : : editNumber ( err_zero , 1e-9 , 1 , .1 , 1e-3 , XLAT ( " maximum error " ) ,
XLAT ( " New points are added when the current error in the model is smaller than this value. " )
2018-01-03 10:22:37 +00:00
) ;
2017-12-27 14:25:10 +00:00
dialog : : scaleLog ( ) ;
dialog : : reaction = [ ] ( ) { err_zero_current = err_zero ; } ;
}
2018-02-03 12:41:49 +00:00
else if ( uni = = ' f ' )
pushScreen ( showStereo ) ;
2020-04-17 13:38:09 +00:00
# if MAXMDIM >= 4
2020-04-14 14:44:56 +00:00
else if ( uni = = ' n ' & & ! rug : : rugged )
pushScreen ( rug_geometry_choice ) ;
2020-04-17 13:38:09 +00:00
# endif
2018-02-03 12:54:51 +00:00
else if ( uni = = ' g ' & & ! rug : : rugged & & CAP_SDL )
2017-07-10 18:47:38 +00:00
rendernogl = ! rendernogl ;
2019-05-03 09:45:51 +00:00
else if ( uni = = ' s ' ) {
2017-07-10 18:47:38 +00:00
texturesize * = 2 ;
2018-02-03 12:50:47 +00:00
if ( texturesize = = 8192 ) texturesize = 64 ;
2019-05-03 09:45:51 +00:00
change_texturesize ( ) ;
2017-07-10 18:47:38 +00:00
}
2018-03-24 16:21:25 +00:00
# if CAP_SURFACE
else if ( uni = = ' c ' )
pushScreen ( surface : : show_surfaces ) ;
# endif
2018-01-29 15:30:21 +00:00
else if ( handlekeys ( sym , uni ) ) ;
2017-07-10 18:47:38 +00:00
else if ( doexiton ( sym , uni ) ) popScreen ( ) ;
} ;
2016-08-26 09:58:03 +00:00
}
2019-08-09 23:07:39 +00:00
EX void select ( ) {
2019-05-28 23:09:38 +00:00
if ( dual : : state ) return ;
2017-12-27 14:25:10 +00:00
pushScreen ( rug : : show ) ;
2016-08-26 09:58:03 +00:00
}
2017-12-25 22:47:57 +00:00
2020-04-14 23:43:28 +00:00
EX void rug_save ( string fname ) {
fhstream f ( fname , " wb " ) ;
if ( ! f . f ) {
addMessage ( XLAT ( " Failed to save rug to %1 " , fname ) ) ;
return ;
}
f . write ( f . vernum ) ;
f . write ( gwhere ) ;
USING_NATIVE_GEOMETRY ;
int N = isize ( points ) ;
f . write ( N ) ;
map < rugpoint * , int > ids ;
for ( int i = 0 ; i < isize ( points ) ; i + + ) ids [ points [ i ] ] = i ;
f . write ( surface : : sh ) ;
for ( int i = 0 ; i < 4 ; i + + ) for ( int j = 0 ; j < 4 ; j + + )
f . write ( rugView [ i ] [ j ] ) ;
auto get_id = [ & ] ( rugpoint * r ) {
if ( ! r ) return int ( - 1 ) ;
return ids [ r ] ;
} ;
for ( auto p : points ) {
f . write ( p - > valid ) ;
f . write ( p - > x1 ) ;
f . write ( p - > y1 ) ;
f . write ( p - > native ) ;
f . write ( get_id ( p - > glue ) ) ;
}
int M = isize ( triangles ) ;
f . write ( M ) ;
for ( auto t : triangles ) {
f . write ( get_id ( t . m [ 0 ] ) ) ;
f . write ( get_id ( t . m [ 1 ] ) ) ;
f . write ( get_id ( t . m [ 2 ] ) ) ;
}
int cp = isize ( surface : : coverage ) ;
f . write ( cp ) ;
for ( auto p : surface : : coverage ) f . write ( p . first ) , f . write ( p . second ) ;
}
EX void rug_load ( string fname ) {
clear_model ( ) ;
fhstream f ( fname , " rb " ) ;
if ( ! f . f ) {
addMessage ( XLAT ( " Failed to load rug from %1 " , fname ) ) ;
return ;
}
f . read ( f . vernum ) ;
f . read ( gwhere ) ;
USING_NATIVE_GEOMETRY ;
int N = f . get < int > ( ) ;
println ( hlog , " N = " , N ) ;
points . resize ( N ) ;
for ( int i = 0 ; i < N ; i + + )
points [ i ] = new rugpoint ;
f . read ( surface : : sh ) ;
for ( int i = 0 ; i < 4 ; i + + ) for ( int j = 0 ; j < 4 ; j + + )
f . read ( rugView [ i ] [ j ] ) ;
auto by_id = [ & ] ( rugpoint * & p ) {
int i = f . get < int > ( ) ;
if ( i = = - 1 ) p = nullptr ;
else p = points [ i ] ;
} ;
for ( auto p : points ) {
f . read ( p - > valid ) ;
f . read ( p - > x1 ) ;
f . read ( p - > y1 ) ;
f . read ( p - > native ) ;
by_id ( p - > glue ) ;
}
triangles . resize ( f . get < int > ( ) ) ;
for ( auto & t : triangles ) {
by_id ( t . m [ 0 ] ) ;
by_id ( t . m [ 1 ] ) ;
by_id ( t . m [ 2 ] ) ;
}
surface : : coverage . resize ( f . get < int > ( ) ) ;
for ( auto p : surface : : coverage ) f . read ( p . first ) , f . read ( p . second ) ;
good_shape = true ;
}
2018-02-03 18:19:27 +00:00
# if CAP_COMMANDLINE
2017-12-25 22:47:57 +00:00
int rugArgs ( ) {
using namespace arg ;
if ( 0 ) ;
else if ( argis ( " -rugmodelscale " ) ) {
2018-11-09 13:26:31 +00:00
shift_arg_formula ( modelscale ) ;
2017-12-25 22:47:57 +00:00
}
else if ( argis ( " -ruggeo " ) ) {
2020-04-17 15:17:22 +00:00
shift ( ) ; gwhere = readGeo ( args ( ) ) ;
2020-04-14 14:44:56 +00:00
if ( gwhere = = gEuclid ) gwhere = rgEuclid ;
if ( gwhere = = gSphere ) gwhere = rgSphere ;
if ( gwhere = = gNormal ) gwhere = rgHyperbolic ;
if ( gwhere = = gElliptic ) gwhere = rgElliptic ;
2017-12-25 22:47:57 +00:00
}
else if ( argis ( " -rugpers " ) ) {
2020-04-17 15:17:22 +00:00
USING_NATIVE_GEOMETRY ;
rconf . model = nonisotropic ? mdGeodesic : mdPerspective ;
2017-12-25 22:47:57 +00:00
}
2018-02-12 15:21:55 +00:00
else if ( argis ( " -rugonce " ) ) {
renderonce = true ;
}
2020-04-14 23:43:28 +00:00
else if ( argis ( " -rugsave " ) ) {
shift ( ) ; rug_save ( args ( ) ) ;
}
else if ( argis ( " -rugload " ) ) {
PHASE ( 3 ) ;
start_game ( ) ;
calcparam ( ) ;
rug : : init ( ) ;
shift ( ) ; rug_load ( args ( ) ) ;
}
2018-04-09 13:56:23 +00:00
else if ( argis ( " -rugdist " ) ) {
2018-11-09 13:26:31 +00:00
shift_arg_formula ( model_distance ) ;
2018-04-09 13:56:23 +00:00
}
2018-02-12 15:21:55 +00:00
else if ( argis ( " -ruglate " ) ) {
2018-02-27 18:39:22 +00:00
renderonce = true ;
2018-02-12 15:21:55 +00:00
renderlate + = 10 ;
}
else if ( argis ( " -rugmany " ) ) {
renderonce = false ;
}
2019-03-30 16:46:50 +00:00
else if ( argis ( " -ruglwidth " ) ) {
shift_arg_formula ( lwidth ) ;
}
2018-02-12 11:49:47 +00:00
else if ( argis ( " -rugauto " ) ) {
2018-11-09 13:26:31 +00:00
shift_arg_formula ( ruggo ) ;
2018-02-12 11:49:47 +00:00
}
2017-12-25 22:47:57 +00:00
else if ( argis ( " -rugorth " ) ) {
2020-04-16 22:53:58 +00:00
rconf . model = mdEquidistant ;
2017-12-25 22:47:57 +00:00
}
else if ( argis ( " -rugerr " ) ) {
2018-11-09 13:26:31 +00:00
shift_arg_formula ( err_zero ) ;
2017-12-27 09:52:54 +00:00
}
2018-01-28 11:21:29 +00:00
else if ( argis ( " -rugtsize " ) ) {
shift ( ) ; rug : : texturesize = argi ( ) ;
2019-05-03 09:45:51 +00:00
change_texturesize ( ) ;
2018-01-28 11:21:29 +00:00
}
2017-12-27 09:52:54 +00:00
else if ( argis ( " -rugv " ) ) {
shift ( ) ; vertex_limit = argi ( ) ;
2020-04-09 05:40:47 +00:00
err_zero_current = err_zero ;
2017-12-25 22:47:57 +00:00
}
2018-02-03 12:41:49 +00:00
else if ( argis ( " -rugon " ) ) {
2018-02-12 11:49:47 +00:00
PHASE ( 3 ) ;
2020-04-14 23:43:45 +00:00
start_game ( ) ;
2018-02-12 11:49:47 +00:00
calcparam ( ) ;
rug : : init ( ) ;
2018-02-03 12:41:49 +00:00
}
2018-02-27 18:27:20 +00:00
else if ( argis ( " -sdfoff " ) ) {
subdivide_first = false ;
2018-01-29 15:31:14 +00:00
}
2018-02-27 18:27:20 +00:00
else if ( argis ( " -sdfon " ) ) {
subdivide_first = true ;
2018-01-28 11:20:21 +00:00
}
2018-02-27 18:39:54 +00:00
else if ( argis ( " -anticusp " ) ) {
2018-11-09 13:26:31 +00:00
shift_arg_formula ( anticusp_factor ) ;
2018-02-27 18:39:54 +00:00
}
2018-11-11 10:06:32 +00:00
else if ( argis ( " -d:rug " ) )
launch_dialog ( show ) ;
2017-12-25 22:47:57 +00:00
else return 1 ;
return 0 ;
}
auto rug_hook =
addHook ( hooks_args , 100 , rugArgs ) ;
2018-02-03 18:19:27 +00:00
# endif
2016-08-26 09:58:03 +00:00
}
# else
// fake for mobile
namespace rug {
bool rugged = false ;
bool renderonce = false ;
bool rendernogl = true ;
int texturesize = 512 ;
2017-07-24 22:21:36 +00:00
ld scale = 1.0f ;
2016-08-26 09:58:03 +00:00
}
# endif
2018-06-10 23:58:31 +00:00
}