2016-08-26 09:58:03 +00:00
// Hyperbolic Rogue
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
// implementation of the Hypersian Rug mode
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)
2017-07-22 23:33:27 +00:00
# if !CAP_GLEW
# if ISLINUX
2016-08-26 09:58:03 +00:00
extern " C " {
GLAPI void APIENTRY glGenFramebuffers ( GLsizei n , GLuint * framebuffers ) ;
GLAPI void APIENTRY glBindFramebuffer ( GLenum target , GLuint framebuffer ) ;
GLAPI void APIENTRY glFramebufferTexture ( GLenum target , GLenum attachment , GLuint texture , GLint level ) ;
GLAPI GLenum APIENTRY glCheckFramebufferStatus ( GLenum target ) ;
GLAPI void APIENTRY glDrawBuffers ( GLsizei n , const GLenum * bufs ) ;
GLAPI void APIENTRY glGenRenderbuffers ( GLsizei n , GLuint * renderbuffers ) ;
GLAPI void APIENTRY glBindRenderbuffer ( GLenum target , GLuint renderbuffer ) ;
GLAPI void APIENTRY glRenderbufferStorage ( GLenum target , GLenum internalformat , GLsizei width , GLsizei height ) ;
GLAPI void APIENTRY glFramebufferRenderbuffer ( GLenum target , GLenum attachment , GLenum renderbuffertarget , GLuint renderbuffer ) ;
GLAPI void APIENTRY glDeleteRenderbuffers ( GLsizei n , const GLuint * renderbuffers ) ;
GLAPI void APIENTRY glDeleteFramebuffers ( GLsizei n , const GLuint * framebuffers ) ;
}
# endif
2017-07-22 23:33:27 +00:00
# if ISMAC
2016-08-26 09:58:03 +00:00
# define glFramebufferTexture glFramebufferTextureEXT
# endif
2017-07-04 13:38:33 +00:00
# endif
2016-08-26 09:58:03 +00:00
namespace rug {
2017-12-29 11:54:50 +00:00
struct rug_exception { } ;
2017-12-27 05:31:47 +00:00
bool fast_euclidean = true ;
2017-12-27 09:52:54 +00:00
bool keep_shape = true ;
bool good_shape ;
2017-12-25 22:47:57 +00:00
2017-12-27 09:52:54 +00:00
ld modelscale = 1 ;
2017-12-27 17:53:00 +00:00
ld model_distance = 2 ;
2017-11-06 18:24:02 +00:00
2017-12-27 17:53:00 +00:00
ld fov = 90 ;
2017-12-27 14:25:10 +00:00
2017-12-25 22:47:57 +00:00
eGeometry gwhere = gEuclid ;
2017-12-27 18:55:00 +00:00
# define USING_NATIVE_GEOMETRY dynamicval<eGeometry> gw(geometry, gwhere == gElliptic ? gSphere : gwhere)
2016-08-26 09:58:03 +00:00
// hypersian rug datatypes and globals
//-------------------------------------
bool rugged = false ;
bool genrug = false ;
bool glew = false ;
2017-12-27 09:52:54 +00:00
int vertex_limit = 20000 ;
2016-08-26 09:58:03 +00:00
bool renderonce = false ;
bool rendernogl = false ;
int texturesize = 1024 ;
2017-07-16 21:00:55 +00:00
ld scale = 1 ;
2016-08-26 09:58:03 +00:00
2017-12-27 09:52:54 +00:00
ld err_zero = 1e-3 , err_zero_current , current_total_error ;
2017-12-25 22:47:57 +00:00
2016-08-26 09:58:03 +00:00
int queueiter , qvalid , dt ;
struct edge {
struct rugpoint * target ;
double len ;
} ;
struct rugpoint {
double x1 , y1 ;
bool valid ;
bool inqueue ;
2017-03-23 10:53:57 +00:00
double dist ;
2016-08-26 09:58:03 +00:00
hyperpoint h ;
hyperpoint flat ;
vector < edge > edges ;
2017-12-27 05:31:47 +00:00
// Find-Union algorithm
rugpoint * glue = NULL ;
rugpoint * getglue ( ) {
return glue ? ( glue = glue - > getglue ( ) ) : this ;
}
hyperpoint & glueflat ( ) {
return glue - > flat ;
}
void glueto ( rugpoint * x ) {
x = x - > getglue ( ) ;
auto y = getglue ( ) ;
if ( x ! = y ) y - > glue = x ;
}
2016-08-26 09:58:03 +00:00
} ;
struct triangle {
rugpoint * m [ 3 ] ;
triangle ( rugpoint * m1 , rugpoint * m2 , rugpoint * m3 ) {
m [ 0 ] = m1 ; m [ 1 ] = m2 ; m [ 2 ] = m3 ;
}
} ;
vector < rugpoint * > points ;
vector < triangle > triangles ;
2017-12-25 22:47:57 +00:00
bool rug_perspective = false ;
// extra geometry functions
//--------------------------
// returns a matrix M
// such that inverse(M) * h1 = ( |h1|, 0, 0) and inverse(M) * h2 = ( .., .., 0)
transmatrix orthonormalize ( hyperpoint h1 , hyperpoint h2 ) {
using namespace hyperpoint_vec ;
2017-12-27 09:52:54 +00:00
hyperpoint vec [ 3 ] = { h1 , h2 , h1 ^ h2 } ;
2017-12-25 22:47:57 +00:00
2017-12-27 09:52:54 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
for ( int j = 0 ; j < i ; j + + ) vec [ i ] - = vec [ j ] * ( vec [ i ] | vec [ j ] ) ;
if ( zero3 ( vec [ i ] ) ) {
// 'random' direction
vec [ i ] = hpxyz ( 1.12 , 1.512 + i , 1.12904 + i ) ;
for ( int j = 0 ; j < i ; j + + ) vec [ i ] - = vec [ j ] * ( vec [ i ] | vec [ j ] ) ;
}
vec [ i ] / = hypot3 ( vec [ i ] ) ;
}
2017-12-25 22:47:57 +00:00
transmatrix M ;
for ( int i = 0 ; i < 3 ; i + + ) for ( int j = 0 ; j < 3 ; j + + )
M [ i ] [ j ] = vec [ j ] [ i ] ;
return M ;
}
hyperpoint azeq_to_hyperboloid ( hyperpoint h ) {
if ( abs ( h [ 2 ] ) > 1e-4 ) printf ( " Error: h[2] = %lf \n " , h [ 2 ] ) ;
if ( euclid ) {
h [ 2 ] = 1 ;
return h ;
}
ld d = hypot ( h [ 0 ] , h [ 1 ] ) ;
if ( d = = 0 ) {
h [ 2 ] = 1 ;
return h ;
}
if ( sphere ) {
2017-12-27 09:52:54 +00:00
ld d0 = d ? d : 1 ;
h [ 0 ] = sin ( d ) * h [ 0 ] / d0 ;
h [ 1 ] = sin ( d ) * h [ 1 ] / d0 ;
2017-12-25 22:47:57 +00:00
h [ 2 ] = cos ( d ) ;
}
else {
2017-12-27 09:52:54 +00:00
ld d0 = d ? d : 1 ;
h [ 0 ] = sinh ( d ) * h [ 0 ] / d0 ;
h [ 1 ] = sinh ( d ) * h [ 1 ] / d0 ;
2017-12-25 22:47:57 +00:00
h [ 2 ] = cosh ( d ) ;
}
return h ;
}
hyperpoint hyperboloid_to_azeq ( hyperpoint h ) {
if ( euclid ) {
h [ 2 ] = 0 ;
return h ;
}
else {
ld d = hdist0 ( h ) ;
if ( d = = 0 ) { h [ 2 ] = 0 ; return h ; }
2017-12-27 09:52:54 +00:00
ld d2 = hypot2 ( h ) ;
2017-12-25 22:47:57 +00:00
if ( d2 = = 0 ) { h [ 2 ] = 0 ; return h ; }
h [ 0 ] = d * h [ 0 ] / d2 ;
h [ 1 ] = d * h [ 1 ] / d2 ;
h [ 2 ] = 0 ;
return h ;
}
}
2017-12-27 20:08:31 +00:00
struct normalizer {
transmatrix M , Mi ;
dynamicval < eGeometry > gw ;
normalizer ( hyperpoint h1 , hyperpoint h2 ) : gw ( geometry , gwhere = = gElliptic ? gSphere : gwhere ) {
M = orthonormalize ( h1 , h2 ) ;
Mi = inverse ( M ) ;
}
hyperpoint operator ( ) ( hyperpoint h ) { return azeq_to_hyperboloid ( Mi * h ) ; }
hyperpoint operator [ ] ( hyperpoint h ) { return M * hyperboloid_to_azeq ( h ) ; }
} ;
2017-12-27 09:52:54 +00:00
void push_point ( hyperpoint & h , int coord , ld val ) {
if ( fast_euclidean & & gwhere = = gEuclid )
h [ coord ] + = val ;
else if ( ! val ) return ;
else {
// if(zero3(h)) { h[0] = 1e-9; h[1] = 1e-10; h[2] = 1e-11; }
2017-12-27 20:08:31 +00:00
normalizer n ( hpxyz ( coord = = 0 , coord = = 1 , coord = = 2 ) , h ) ;
hyperpoint f = n ( h ) ;
h = n [ xpush ( val ) * f ] ;
2017-12-25 22:47:57 +00:00
}
}
2017-12-27 09:52:54 +00:00
void push_all_points ( int coord , ld val ) {
if ( ! val ) return ;
else for ( int i = 0 ; i < size ( points ) ; i + + )
push_point ( points [ i ] - > flat , coord , val ) ;
}
2017-12-25 22:47:57 +00:00
2016-08-26 09:58:03 +00:00
// construct the graph
//---------------------
int hyprand ;
2017-03-23 10:53:57 +00:00
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
/*
2016-08-26 09:58:03 +00:00
ld tz = vid . alphax + h [ 2 ] ;
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 ) ;
m - > x1 = ( 1 + onscreen [ 0 ] * vid . scale ) / 2 ;
m - > y1 = ( 1 + onscreen [ 1 ] * vid . scale ) / 2 ;
2017-12-27 09:52:54 +00:00
m - > valid = false ;
2017-12-25 22:47:57 +00:00
2017-12-27 10:59:37 +00:00
using namespace hyperpoint_vec ;
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 ;
if ( gwhere = = gEuclid ) {
scale = modelscale ;
}
else if ( gwhere = = gNormal ) {
// sinh(scale) = modelscale
scale = asinh ( modelscale ) ;
}
2017-12-27 18:55:00 +00:00
else /* sphere/elliptic*/ {
2017-12-27 10:59:37 +00:00
if ( modelscale > = 1 )
// do as good as we can...
scale = M_PI / 2 - 1e-3 , good_shape = false ;
else scale = asin ( modelscale ) ;
}
m - > flat = h * scale ;
}
else if ( euclid & & gwhere = = gEuclid ) {
m - > flat = h * modelscale ;
}
else if ( gwhere = = gNormal & & ( euclid | | ( hyperbolic & & modelscale > = 1 ) ) ) {
m - > valid = good_shape = true ;
ld d = hdist0 ( h ) ;
ld d0 = hypot2 ( h ) ; if ( ! d0 ) d0 = 1 ;
hyperpoint hpoint ;
bool orig_euclid = euclid ;
2017-12-27 18:55:00 +00:00
USING_NATIVE_GEOMETRY ;
2017-12-27 10:59:37 +00:00
if ( orig_euclid ) {
d * = modelscale ;
// point on a horocycle going through C0, in distance d along the horocycle
hpoint = hpxy ( d * d / 2 , d ) ;
}
else {
// radius of the equidistant
ld r = acosh ( modelscale ) ;
// point on an equdistant going through C0 in distance d along the guiding line
// hpoint = hpxy(cosh(r) * sinh(r) * (cosh(d) - 1), sinh(d) * cosh(r));
hpoint = xpush ( r ) * ypush ( d ) * xpush ( - r ) * C0 ;
2017-12-27 17:53:00 +00:00
hpoint [ 0 ] = - hpoint [ 0 ] ;
2017-12-27 10:59:37 +00:00
}
ld hpdist = hdist0 ( hpoint ) ;
ld z = hypot2 ( hpoint ) ;
2017-12-27 09:52:54 +00:00
if ( z = = 0 ) z = 1 ;
2017-12-27 10:59:37 +00:00
m - > flat = hpxyz ( hpdist * h [ 0 ] / d0 * hpoint [ 1 ] / z , hpdist * h [ 1 ] / d0 * hpoint [ 1 ] / z , - hpdist * hpoint [ 0 ] / z ) ;
2017-12-27 09:52:54 +00:00
}
else m - > flat = // hpxyz(h[0], h[1], sin(atan2(h[0], h[1]) * 3 + hyprand) * (h[2]-1) / 1000);
2017-12-27 18:55:00 +00:00
hpxyz ( h [ 0 ] , h [ 1 ] , ( h [ 2 ] - .99 ) * ( rand ( ) % 1000 - rand ( ) % 1000 ) / 1000 ) ;
if ( rug_perspective )
push_point ( m - > flat , 2 , - model_distance ) ;
2017-12-25 22:47:57 +00:00
2017-12-27 09:52:54 +00:00
// if(rug_perspective && gwhere == gEuclid) m->flat[2] -= 3;
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 ;
}
2017-12-27 05:31:47 +00:00
rugpoint * findRugpoint ( hyperpoint h ) {
2016-08-26 09:58:03 +00:00
for ( int i = 0 ; i < size ( points ) ; i + + )
2017-12-28 17:39:49 +00:00
if ( intvalxyz ( points [ i ] - > h , h ) < 1e-5 ) return points [ i ] ;
2017-12-27 05:31:47 +00:00
return NULL ;
}
rugpoint * findOrAddRugpoint ( hyperpoint h , double dist ) {
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 ) ;
}
2017-12-27 05:31:47 +00:00
void addEdge ( rugpoint * e1 , rugpoint * e2 , ld len = 1 ) {
2016-08-26 09:58:03 +00:00
for ( int i = 0 ; i < size ( e1 - > edges ) ; i + + )
if ( e1 - > edges [ i ] . target = = e2 ) return ;
2017-12-27 05:31:47 +00:00
addNewEdge ( e1 , e2 , len ) ;
2016-08-26 09:58:03 +00:00
}
2017-12-27 05:31:47 +00:00
void addTriangle ( rugpoint * t1 , rugpoint * t2 , rugpoint * t3 , ld len = 1 ) {
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 ) ;
return halves [ { r1 , r2 } ] ;
}
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
}
void calcLengths ( ) {
2017-12-25 22:47:57 +00:00
for ( int i = 0 ; i < size ( points ) ; i + + ) for ( int j = 0 ; j < size ( points [ i ] - > edges ) ; j + + ) {
ld d = hdist ( points [ i ] - > h , points [ i ] - > edges [ j ] . target - > h ) ;
if ( elliptic & & d > M_PI / 2 ) d = M_PI - d ;
points [ i ] - > edges [ j ] . len = d * modelscale ;
}
2016-08-26 09:58:03 +00:00
}
2017-11-06 18:24:02 +00:00
void setVidParam ( ) {
2017-12-25 22:47:57 +00:00
vid . xres = vid . yres = TEXTURESIZE ;
vid . scrsize = HTEXTURESIZE ;
vid . radius = vid . scrsize * vid . scale ; vid . xcenter = HTEXTURESIZE ; vid . ycenter = HTEXTURESIZE ;
2017-11-06 18:24:02 +00:00
vid . beta = 2 ; vid . alphax = 1 ; vid . eye = 0 ; vid . goteyes = false ;
}
void buildTorusRug ( ) {
using namespace torusconfig ;
setVidParam ( ) ;
struct toruspoint {
int x , y ;
2017-12-28 17:39:49 +00:00
toruspoint ( ) { x = y = getqty ( ) ; }
2017-11-06 18:24:02 +00:00
toruspoint ( int _x , int _y ) : x ( _x ) , y ( _y ) { }
int d2 ( ) {
2017-12-25 22:47:57 +00:00
return x * x + ( euclid6 ? x * y : 0 ) + y * y ;
2017-11-06 18:24:02 +00:00
}
} ;
vector < toruspoint > zeropoints ;
vector < toruspoint > tps ( qty ) ;
2017-12-28 17:39:49 +00:00
auto & mode = tmodes [ torus_mode ] ;
bool single = mode . flags & TF_SINGLE ;
bool klein = mode . flags & TF_KLEIN ;
2017-11-06 18:24:02 +00:00
pair < toruspoint , toruspoint > solution ;
2017-12-28 17:39:49 +00:00
if ( single ) {
for ( int ax = - qty ; ax < qty ; ax + + )
for ( int ay = - qty ; ay < qty ; ay + + ) {
int v = ( ax * dx + ay * dy ) % qty ;
if ( v < 0 ) v + = qty ;
toruspoint tp ( ax , ay ) ;
if ( tps [ v ] . d2 ( ) > tp . d2 ( ) ) tps [ v ] = tp ;
if ( v = = 0 )
zeropoints . emplace_back ( ax , ay ) ;
}
ld bestsol = 1e12 ;
for ( auto p1 : zeropoints )
for ( auto p2 : zeropoints ) {
int det = p1 . x * p2 . y - p2 . x * p1 . y ;
if ( det < 0 ) continue ;
if ( det ! = qty & & det ! = - qty ) continue ;
ld quality = ld ( p1 . d2 ( ) ) * p2 . d2 ( ) ;
if ( quality < bestsol * 3 )
if ( quality < bestsol )
bestsol = quality , solution . first = p1 , solution . second = p2 ;
}
2017-11-06 18:24:02 +00:00
2017-12-28 17:39:49 +00:00
if ( solution . first . d2 ( ) > solution . second . d2 ( ) )
swap ( solution . first , solution . second ) ;
}
else {
if ( klein )
solution . first = toruspoint ( 2 * sdx , 0 ) ;
else
solution . first = toruspoint ( sdx , 0 ) ;
if ( mode . flags & TF_WEIRD )
solution . second = toruspoint ( sdy / 2 , sdy ) ;
else
solution . second = toruspoint ( 0 , sdy ) ;
if ( solution . first . d2 ( ) > solution . second . d2 ( ) )
swap ( solution . first , solution . second ) ;
2017-11-06 18:24:02 +00:00
}
ld factor = sqrt ( ld ( solution . second . d2 ( ) ) / solution . first . d2 ( ) ) ;
printf ( " factor = %lf \n " , factor ) ;
2017-12-28 17:39:49 +00:00
if ( factor < = 2.05 ) factor = 2.2 ;
2017-11-06 18:24:02 +00:00
factor - = 1 ;
// 22,1
// 7,-17
// transmatrix z1 = {{{22,7,0}, {1,-17,0}, {0,0,1}}};
transmatrix z1 = { { { ( ld ) solution . first . x , ( ld ) solution . second . x , 0 } , { ( ld ) solution . first . y , ( ld ) solution . second . y , 0 } , { 0 , 0 , 1 } } } ;
transmatrix z2 = inverse ( z1 ) ;
2017-12-28 17:39:49 +00:00
map < pair < int , int > , rugpoint * > glues ;
2017-11-07 13:39:26 +00:00
auto addToruspoint = [ & ] ( ld x , ld y ) {
2017-11-06 18:24:02 +00:00
auto r = addRugpoint ( C0 , 0 ) ;
hyperpoint onscreen ;
applymodel ( tC0 ( eumove ( x , y ) ) , onscreen ) ;
// take point (1,0)
// apply eumove(1,0)
// divide by EUCSCALE
// multiply by vid.radius (= HTEXTURESIZE * rugzoom)
// add 1, divide by texturesize
r - > x1 = onscreen [ 0 ] ;
r - > y1 = onscreen [ 1 ] ;
// r->y1 = (1 + onscreen[1] * rugzoom / EUCSCALE)/2;
hyperpoint h1 = hpxyz ( x , y , 0 ) ;
hyperpoint h2 = z2 * h1 ;
double alpha = - h2 [ 0 ] * 2 * M_PI ;
double beta = - h2 [ 1 ] * 2 * M_PI ;
// r->flat = {alpha, beta, 0};
double sc = ( factor + 1 ) / 4 ;
2017-12-28 17:39:49 +00:00
2017-12-27 09:52:54 +00:00
r - > flat = r - > h = hpxyz ( ( factor + cos ( alpha ) ) * cos ( beta ) * sc , ( factor + cos ( alpha ) ) * sin ( beta ) * sc , - sin ( alpha ) * sc ) ;
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 ) ; } ;
auto p = make_pair ( gluefun ( h2 [ 0 ] ) , gluefun ( h2 [ 1 ] ) ) ;
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
int rugmax = ( int ) sqrt ( vertex_limit / qty ) ;
if ( rugmax < 1 ) rugmax = 1 ;
if ( rugmax > 16 ) rugmax = 16 ;
2017-11-07 13:39:26 +00:00
ld rmd = rugmax ;
2017-12-28 17:39:49 +00:00
for ( int leaf = 0 ; leaf < ( klein ? 2 : 1 ) ; leaf + + )
for ( int i = 0 ; i < getqty ( ) ; i + + ) {
int x , y ;
if ( single ) {
x = tps [ i ] . x ;
y = tps [ i ] . y ;
}
else {
x = i % sdx ;
y = i / sdx ;
if ( x > sdx / 2 ) x - = sdx ;
if ( y > sdy / 2 ) y - = sdy ;
if ( leaf ) {
x + = sdx ;
if ( x > sdx ) x - = 2 * sdx ;
}
}
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 + + )
2017-12-28 17:39:49 +00:00
rugarr [ yy ] [ xx ] = addToruspoint ( x + xx / rmd , y + ( yy - xx ) / rmd ) ;
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 ) ,
addTriangle ( rugarr [ yy ] [ xx ] , rugarr [ yy ] [ xx + 1 ] , 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 ) ) ) ;
// maxz * rugzoom * vid.radius == vid.radius
2017-12-25 22:47:57 +00:00
vid . scale = 1 / maxz ;
2017-11-06 18:24:02 +00:00
for ( auto p : points )
2017-12-25 22:47:57 +00:00
p - > x1 = ( vid . xcenter + vid . radius * vid . scale * p - > x1 ) / vid . xres ,
p - > y1 = ( vid . ycenter - vid . radius * vid . scale * p - > y1 ) / vid . yres ;
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 + + ;
2017-12-27 05:31:47 +00:00
printf ( " qvalid = %d \n " , qvalid ) ;
2017-12-27 18:55:00 +00:00
if ( rug_perspective )
push_all_points ( 2 , - model_distance ) ;
2017-12-27 05:31:47 +00:00
2017-11-06 18:24:02 +00:00
return ;
}
2017-12-27 10:59:37 +00:00
void verify ( ) {
vector < ld > ratios ;
for ( auto m : points )
for ( auto & e : m - > edges ) {
auto m2 = e . target ;
ld l = e . len ;
2017-12-27 20:08:31 +00:00
normalizer n ( m - > flat , m2 - > flat ) ;
hyperpoint h1 = n ( m - > flat ) ;
hyperpoint h2 = n ( m2 - > flat ) ;
2017-12-27 10:59:37 +00:00
ld l0 = hdist ( h1 , h2 ) ;
ratios . push_back ( l0 / l ) ;
}
printf ( " Length verification: \n " ) ;
sort ( ratios . begin ( ) , ratios . end ( ) ) ;
for ( int i = 0 ; i < size ( ratios ) ; i + = size ( ratios ) / 10 )
printf ( " %lf \n " , ratios [ i ] ) ;
printf ( " \n " ) ;
}
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 ;
}
2016-08-26 09:58:03 +00:00
void buildRug ( ) {
2017-11-06 18:24:02 +00:00
if ( torus ) {
2017-12-27 09:52:54 +00:00
good_shape = true ;
2017-11-06 18:24:02 +00:00
buildTorusRug ( ) ;
return ;
}
2017-12-29 11:54:50 +00:00
celllister cl ( centerover . c ? centerover . c : cwt . c , sightrange , vertex_limit , NULL ) ;
2016-08-26 09:58:03 +00:00
map < cell * , rugpoint * > vptr ;
2017-12-29 11:54:50 +00:00
for ( cell * c : cl . lst )
vptr [ c ] = addRugpoint ( shmup : : ggmatrix ( c ) * C0 , c - > cpdist ) ;
for ( auto & p : vptr ) {
cell * c = p . first ;
rugpoint * v = p . second ;
for ( int j = 0 ; j < c - > type ; j + + ) try {
2016-08-26 09:58:03 +00:00
cell * c2 = c - > mov [ 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);
cell * c3 = c - > mov [ ( j + 1 ) % c - > type ] ;
2017-12-29 11:54:50 +00:00
rugpoint * w2 = vptr . at ( c3 ) ;
if ( a4 ) {
cellwalker cw ( c , j ) ;
cwstep ( cw ) ; cwspin ( cw , - 1 ) ; cwstep ( cw ) ;
cell * c4 = cw . c ;
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
}
2017-12-29 11:54:50 +00:00
catch ( out_of_range ) { }
2016-08-26 09:58:03 +00:00
}
printf ( " vertices = %d triangles= %d \n " , size ( points ) , size ( triangles ) ) ;
calcLengths ( ) ;
sort ( points . begin ( ) , points . end ( ) , psort ) ;
2017-12-27 10:59:37 +00:00
verify ( ) ;
2016-08-26 09:58:03 +00:00
}
// rug physics
queue < rugpoint * > pqueue ;
void enqueue ( rugpoint * m ) {
if ( m - > inqueue ) return ;
pqueue . push ( m ) ;
m - > inqueue = true ;
}
2017-12-27 09:52:54 +00:00
bool force_euclidean ( rugpoint & m1 , rugpoint & m2 , double rd , double d1 = 1 , double d2 = 1 ) {
if ( ! m1 . valid | | ! m2 . valid ) return false ;
2016-08-26 09:58:03 +00:00
// double rd = hdist(m1.h, m2.h) * xd;
// if(rd > rdz +1e-6 || rd< rdz-1e-6) printf("%lf %lf\n", rd, rdz);
double t = 0 ;
for ( int i = 0 ; i < 3 ; i + + ) t + = ( m1 . flat [ i ] - m2 . flat [ i ] ) * ( m1 . flat [ i ] - m2 . flat [ i ] ) ;
t = sqrt ( t ) ;
2017-12-27 09:52:54 +00:00
/* printf("%s ", display(m1.flat));
printf ( " %s " , display ( m2 . flat ) ) ;
printf ( " %lf/%lf \n " , t , rd ) ; */
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;
for ( int i = 0 ; i < 3 ; i + + ) {
double di = ( m2 . flat [ i ] - m1 . flat [ i ] ) * force ;
m1 . flat [ i ] + = di * d1 ;
m2 . flat [ i ] - = di * d2 ;
if ( nonzero & & d2 > 0 ) enqueue ( & m2 ) ;
}
2017-12-27 09:52:54 +00:00
return nonzero ;
2016-08-26 09:58:03 +00:00
}
2017-12-27 09:52:54 +00:00
bool force ( rugpoint & m1 , rugpoint & m2 , double rd , double d1 = 1 , double d2 = 1 ) {
if ( ! m1 . valid | | ! m2 . valid ) return false ;
2017-12-25 22:47:57 +00:00
if ( gwhere = = gEuclid & & fast_euclidean ) {
2017-12-27 09:52:54 +00:00
return force_euclidean ( m1 , m2 , rd , d1 , d2 ) ;
2017-12-25 22:47:57 +00:00
}
// double rd = hdist(m1.h, m2.h) * xd;
// if(rd > rdz +1e-6 || rd< rdz-1e-6) printf("%lf %lf\n", rd, rdz);
using namespace hyperpoint_vec ;
2017-12-27 20:08:31 +00:00
normalizer n ( m1 . flat , m2 . flat ) ;
hyperpoint f1 = n ( m1 . flat ) ;
hyperpoint f2 = n ( m2 . flat ) ;
2017-12-25 22:47:57 +00:00
ld t = hdist ( f1 , f2 ) ;
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;
transmatrix T = gpushxto0 ( f1 ) ;
transmatrix T1 = spintox ( T * f2 ) * T ;
transmatrix iT1 = inverse ( T1 ) ;
2017-12-29 11:54:50 +00:00
for ( int i = 0 ; i < 3 ; i + + ) if ( isnan ( m1 . flat [ i ] ) ) {
addMessage ( " Failed! " ) ;
throw rug_exception ( ) ;
}
2017-12-25 22:47:57 +00:00
/*
printf ( " %p %p \n " , & m1 , & m2 ) ;
printf ( " m1 = %s \n " , display ( m1 . flat ) ) ;
printf ( " m2 = %s \n " , display ( m2 . flat ) ) ;
printf ( " Mi * m1 = %s \n " , display ( Mi * m1 . flat ) ) ;
printf ( " Mi * m2 = %s \n " , display ( Mi * m2 . flat ) ) ;
printf ( " f1 = %s \n " , display ( f1 ) ) ;
printf ( " T * f1 = %s \n " , display ( T * f1 ) ) ;
printf ( " T1 * f1 = %s \n " , display ( T1 * f1 ) ) ;
printf ( " f2 = %s \n " , display ( f2 ) ) ;
printf ( " T * f2 = %s \n " , display ( T * f2 ) ) ;
printf ( " T1 * f2 = %s \n " , display ( T1 * f2 ) ) ;
printf ( " iT1 = %s \n " , display ( iT1 * C0 ) ) ;
printf ( " iT1 + t = %s \n " , display ( iT1 * xpush ( t ) * C0 ) ) ;
*/
f1 = iT1 * xpush ( forcev ) * C0 ;
f2 = iT1 * xpush ( t - forcev ) * C0 ;
2017-12-27 20:08:31 +00:00
m1 . flat = n [ f1 ] ;
m2 . flat = n [ f2 ] ;
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 ;
2016-08-26 09:58:03 +00:00
void preset ( rugpoint * m ) {
int q = 0 ;
hyperpoint h ;
for ( int i = 0 ; i < 3 ; i + + ) h [ i ] = 0 ;
using namespace hyperpoint_vec ;
2017-12-27 20:08:31 +00:00
preset_points . clear ( ) ;
2016-08-26 09:58:03 +00:00
for ( int j = 0 ; j < size ( m - > edges ) ; j + + )
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 ;
for ( int j2 = 0 ; j2 < size ( a - > edges ) ; j2 + + )
if ( a - > edges [ j2 ] . target = = b ) blen = a - > edges [ j2 ] . len ;
if ( blen < = 0 ) continue ;
for ( int j2 = 0 ; j2 < size ( a - > edges ) ; j2 + + )
for ( int k2 = 0 ; k2 < size ( b - > edges ) ; k2 + + )
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
hyperpoint ort = ( c - > flat - a - > flat - cz * ( b - > flat - a - > flat ) ) / ch ;
// m->h = a->h + (b->h-a->h) * az - ah * ort
hyperpoint res = a - > flat + ( b - > flat - a - > flat ) * az - ah * ort ;
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 + + ;
2017-12-28 15:46:10 +00:00
2017-12-29 13:35:18 +00:00
// printf("A %lf %lf %lf %lf C %lf %lf %lf %lf\n", a1, a2, az, ah, c1, c2, cz, ch);
2016-08-26 09:58:03 +00:00
}
}
2017-12-28 15:46:10 +00:00
if ( q > 0 ) m - > flat = h / q ;
2017-12-29 13:35:18 +00:00
// printf("preset (%d) -> %s\n", q, display(m->flat));
2017-12-29 11:54:50 +00:00
if ( isnan ( m - > flat [ 0 ] ) | | isnan ( m - > flat [ 1 ] ) | | isnan ( m - > flat [ 2 ] ) )
throw rug_exception ( ) ;
2016-08-26 09:58:03 +00:00
}
2017-12-27 20:08:31 +00:00
ld sse ( hyperpoint h ) {
ld sse = 0 ;
for ( auto & p : preset_points ) {
ld l = p . first ;
normalizer n ( h , p . second - > flat ) ;
hyperpoint h1 = n ( h ) ;
hyperpoint h2 = n ( p . second - > flat ) ;
ld l0 = hdist ( h1 , h2 ) ;
sse + = ( l0 - l ) * ( l0 - l ) ;
}
return sse ;
}
void optimize ( rugpoint * m , bool do_preset ) {
if ( do_preset ) {
preset ( m ) ;
2017-12-30 14:12:15 +00:00
// int ed0 = size(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 ) ;
if ( gwhere > = gSphere ) {
ld cur = sse ( m - > flat ) ;
for ( int it = 0 ; it < 500 ; it + + ) {
ld ex = exp ( - it / 60 ) ;
again :
hyperpoint last = m - > flat ;
switch ( it % 6 ) {
case 0 : m - > flat [ 0 ] + = ex ; break ;
case 1 : m - > flat [ 0 ] - = ex ; break ;
case 2 : m - > flat [ 1 ] + = ex ; break ;
case 3 : m - > flat [ 1 ] - = ex ; break ;
case 4 : m - > flat [ 2 ] + = ex ; break ;
case 5 : m - > flat [ 2 ] - = ex ; break ;
}
ld now = sse ( m - > flat ) ;
if ( now < cur ) { cur = now ; ex * = 1.2 ; goto again ; }
else m - > flat = last ;
}
2017-12-29 13:35:18 +00:00
// printf("edges = [%d] %d sse = %lf\n",ed0, size(preset_points), cur);
2017-12-27 20:08:31 +00:00
}
}
for ( int it = 0 ; it < 50 ; it + + )
for ( int j = 0 ; j < size ( m - > edges ) ; j + + )
force ( * m , * m - > edges [ j ] . target , m - > edges [ j ] . len , 1 , 0 ) ;
}
2016-08-26 09:58:03 +00:00
int divides = 0 ;
bool stop = false ;
2017-12-27 09:52:54 +00:00
bool subdivide_further ( ) {
if ( torus ) return false ;
return size ( points ) * 4 < vertex_limit ;
}
2016-08-26 09:58:03 +00:00
void subdivide ( ) {
int N = size ( 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 ) {
printf ( " Euclidean -- full precision \n " ) ;
stop = true ;
}
else {
err_zero_current / = 2 ;
printf ( " increasing precision to %lg \n " , err_zero_current ) ;
for ( auto p : points ) enqueue ( p ) ;
}
2017-12-27 05:31:47 +00:00
return ;
}
2016-08-26 09:58:03 +00:00
printf ( " subdivide (%d,%d) \n " , N , size ( triangles ) ) ;
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 ] ;
for ( int j = 0 ; j < size ( m - > edges ) ; j + + ) {
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 ) ;
2017-12-27 09:52:54 +00:00
halves [ { m , m2 } ] = mm ;
2017-12-29 13:35:18 +00:00
if ( ! good_shape | | ( torus & & ! keep_shape ) ) {
using namespace hyperpoint_vec ;
normalizer n ( m - > flat , m2 - > flat ) ;
hyperpoint h1 = n ( m - > flat ) ;
hyperpoint h2 = n ( m2 - > flat ) ;
mm - > flat = n [ mid ( h1 , h2 ) ] ;
}
2016-08-26 09:58:03 +00:00
mm - > valid = true ; qvalid + + ;
mm - > inqueue = false ; enqueue ( mm ) ;
}
m - > edges . clear ( ) ;
}
for ( int i = 0 ; i < size ( otriangles ) ; i + + )
addTriangle1 ( otriangles [ i ] . m [ 0 ] , otriangles [ i ] . m [ 1 ] , otriangles [ i ] . m [ 2 ] ) ;
calcLengths ( ) ;
printf ( " result (%d,%d) \n " , size ( points ) , size ( triangles ) ) ;
2017-12-27 20:08:31 +00:00
2016-08-26 09:58:03 +00:00
}
void addNewPoints ( ) {
2017-12-27 14:25:10 +00:00
if ( torus | | qvalid = = size ( points ) ) {
2016-08-26 09:58:03 +00:00
subdivide ( ) ;
return ;
}
2017-12-25 22:47:57 +00:00
double dist = hdist0 ( points [ qvalid ] - > h ) + .1e-6 ;
2016-08-26 09:58:03 +00:00
int oqvalid = qvalid ;
for ( int i = 0 ; i < size ( points ) ; i + + ) {
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 + + ;
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 ) ;
}
}
2017-12-27 09:52:54 +00:00
if ( qvalid ! = oqvalid ) { printf ( " adding new points %4d %4d %4d %.9lf %9d %9d \n " , oqvalid , qvalid , size ( points ) , dist , dt , queueiter ) ; }
2016-08-26 09:58:03 +00:00
}
void physics ( ) {
2017-12-27 09:52:54 +00:00
if ( keep_shape & & good_shape ) return ;
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 ;
2016-08-26 09:58:03 +00:00
for ( int j = 0 ; j < size ( m - > edges ) ; j + + )
2017-12-27 09:52:54 +00:00
moved = force ( * m , * m - > edges [ j ] . target , m - > edges [ j ] . len ) | | moved ;
if ( moved ) enqueue ( m ) ;
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
//-----------------
int eyemod ;
2017-12-27 05:31:47 +00:00
void getco ( rugpoint * m , hyperpoint & h , int & spherepoints ) {
using namespace hyperpoint_vec ;
h = m - > getglue ( ) - > flat ;
2017-12-27 18:55:00 +00:00
if ( rug_perspective & & gwhere > = gSphere ) {
2017-12-27 13:12:27 +00:00
if ( h [ 2 ] > 0 ) {
ld rad = hypot3 ( h ) ;
// turn M_PI to -M_PI
2017-12-27 18:55:00 +00:00
// the only difference between sphere and elliptic is here:
// in elliptic, we subtract PI from the distance
ld rad_to = ( gwhere = = gSphere ? M_PI + M_PI : M_PI ) - rad ;
2017-12-27 13:12:27 +00:00
ld r = - rad_to / rad ;
h * = r ;
spherepoints + + ;
}
2017-12-25 22:47:57 +00:00
}
2017-12-27 05:31:47 +00:00
if ( eyemod ) h [ 0 ] + = eyemod * h [ 2 ] * vid . eye ;
2016-08-26 09:58:03 +00:00
}
extern int besti ;
void drawTriangle ( triangle & t ) {
2017-12-27 05:31:47 +00:00
using namespace hyperpoint_vec ;
for ( int i : { 0 , 1 , 2 } ) {
if ( ! t . m [ i ] - > valid ) return ;
if ( t . m [ i ] - > dist > = sightrange + .51 ) return ;
}
2016-08-26 09:58:03 +00:00
dt + + ;
2017-12-25 22:47:57 +00:00
int spherepoints = 0 ;
2017-12-27 05:31:47 +00:00
array < hyperpoint , 3 > h ;
for ( int i : { 0 , 1 , 2 } ) getco ( t . m [ i ] , h [ i ] , spherepoints ) ;
2017-12-25 22:47:57 +00:00
if ( spherepoints = = 1 | | spherepoints = = 2 ) return ;
2016-08-26 09:58:03 +00:00
2017-12-27 05:31:47 +00:00
hyperpoint hc = ( h [ 1 ] - h [ 0 ] ) ^ ( h [ 2 ] - h [ 0 ] ) ;
double hch = hypot3 ( hc ) ;
2016-08-26 09:58:03 +00:00
2017-12-27 05:31:47 +00:00
glNormal3f ( hc [ 0 ] / hch , hc [ 1 ] / hch , hc [ 2 ] / hch ) ;
2016-08-26 09:58:03 +00:00
2017-12-27 05:31:47 +00:00
for ( int i : { 0 , 1 , 2 } ) {
glTexCoord2f ( t . m [ i ] - > x1 , t . m [ i ] - > y1 ) ;
glVertex3f ( h [ i ] [ 0 ] , h [ i ] [ 1 ] , h [ i ] [ 2 ] ) ;
}
2016-08-26 09:58:03 +00:00
}
GLuint FramebufferName = 0 ;
GLuint renderedTexture = 0 ;
GLuint depth_stencil_rb = 0 ;
SDL_Surface * texture ;
Uint32 * expanded_data ;
void initTexture ( ) {
if ( ! rendernogl ) {
2017-07-22 23:33:27 +00:00
# if !ISPANDORA
2016-08-26 09:58:03 +00:00
FramebufferName = 0 ;
glGenFramebuffers ( 1 , & FramebufferName ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , FramebufferName ) ;
glGenTextures ( 1 , & renderedTexture ) ;
glBindTexture ( GL_TEXTURE_2D , renderedTexture ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , TEXTURESIZE , TEXTURESIZE , 0 , GL_RGB , GL_UNSIGNED_BYTE , 0 ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
2017-07-04 13:38:33 +00:00
# ifdef TEX
2016-08-26 09:58:03 +00:00
glFramebufferTexture ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , renderedTexture , 0 ) ;
2017-07-04 13:38:33 +00:00
# else
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , renderedTexture , 0 ) ;
# endif
2016-08-26 09:58:03 +00:00
GLenum DrawBuffers [ 1 ] = { GL_COLOR_ATTACHMENT0 } ;
glDrawBuffers ( 1 , DrawBuffers ) ;
glGenRenderbuffers ( 1 , & depth_stencil_rb ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , depth_stencil_rb ) ;
glRenderbufferStorage ( GL_RENDERBUFFER , GL_DEPTH24_STENCIL8 , TEXTURESIZE , TEXTURESIZE ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER , depth_stencil_rb ) ;
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_STENCIL_ATTACHMENT , GL_RENDERBUFFER , depth_stencil_rb ) ;
if ( glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ! = GL_FRAMEBUFFER_COMPLETE ) {
addMessage ( " Failed to initialize the framebuffer " ) ;
rugged = false ;
}
2017-03-23 10:53:57 +00:00
# endif
2016-08-26 09:58:03 +00:00
}
else {
texture = SDL_CreateRGBSurface ( SDL_SWSURFACE , TEXTURESIZE , TEXTURESIZE , 32 , 0 , 0 , 0 , 0 ) ;
glGenTextures ( 1 , & renderedTexture ) ;
glBindTexture ( GL_TEXTURE_2D , renderedTexture ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
expanded_data = new Uint32 [ TEXTURESIZE * TEXTURESIZE ] ;
}
}
void prepareTexture ( ) {
videopar svid = vid ;
setVidParam ( ) ;
if ( rendernogl ) {
vid . usingGL = false ;
SDL_Surface * sav = s ;
s = texture ;
SDL_FillRect ( s , NULL , 0 ) ;
drawfullmap ( ) ;
s = sav ;
for ( int y = 0 ; y < TEXTURESIZE ; y + + ) for ( int x = 0 ; x < TEXTURESIZE ; x + + )
expanded_data [ y * TEXTURESIZE + x ] = qpixel ( texture , x , TEXTURESIZE - 1 - y ) | 0xFF000000 ;
glBindTexture ( GL_TEXTURE_2D , renderedTexture ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , TEXTURESIZE , TEXTURESIZE , 0 , GL_BGRA , GL_UNSIGNED_BYTE , expanded_data ) ;
}
else {
2017-07-22 23:33:27 +00:00
# if !ISPANDORA
2016-08-26 09:58:03 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , FramebufferName ) ;
glViewport ( 0 , 0 , TEXTURESIZE , TEXTURESIZE ) ;
setGLProjection ( ) ;
ptds . clear ( ) ;
drawthemap ( ) ;
2017-12-27 13:12:27 +00:00
if ( mousing & & ! renderonce ) {
2017-11-06 18:24:02 +00:00
for ( int i = 0 ; i < numplayers ( ) ; i + + ) if ( multi : : playerActive ( i ) )
queueline ( tC0 ( shmup : : ggmatrix ( playerpos ( i ) ) ) , mouseh , 0xFF00FF , 8 ) ;
}
2016-08-26 09:58:03 +00:00
drawqueue ( ) ;
2017-03-23 10:53:57 +00:00
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
# endif
2016-08-26 09:58:03 +00:00
}
vid = svid ;
if ( ! rendernogl ) glViewport ( 0 , 0 , vid . xres , vid . yres ) ;
}
void closeTexture ( ) {
if ( rendernogl ) {
SDL_FreeSurface ( texture ) ;
glDeleteTextures ( 1 , & renderedTexture ) ;
delete [ ] expanded_data ;
}
else {
2017-07-22 23:33:27 +00:00
# if !ISPANDORA
2016-08-26 09:58:03 +00:00
glDeleteTextures ( 1 , & renderedTexture ) ;
glDeleteRenderbuffers ( 1 , & depth_stencil_rb ) ;
glDeleteFramebuffers ( 1 , & FramebufferName ) ;
2017-03-23 10:53:57 +00:00
# endif
2016-08-26 09:58:03 +00:00
}
}
double xview , yview ;
2017-07-04 13:38:33 +00:00
void glcolorClear ( int color ) {
unsigned char * c = ( unsigned char * ) ( & color ) ;
glClearColor ( c [ 3 ] / 255.0 , c [ 2 ] / 255.0 , c [ 1 ] / 255.0 , c [ 0 ] / 255.0 ) ;
}
2016-08-26 09:58:03 +00:00
void drawRugScene ( ) {
GLfloat light_ambient [ ] = { 3.5 , 3.5 , 3.5 , 1.0 } ;
GLfloat light_diffuse [ ] = { 1.0 , 1.0 , 1.0 , 1.0 } ;
GLfloat light_position [ ] = { 0.0 , 0.0 , 0.0 , 1.0 } ;
glLightfv ( GL_LIGHT0 , GL_AMBIENT , light_ambient ) ;
glLightfv ( GL_LIGHT0 , GL_DIFFUSE , light_diffuse ) ;
glLightfv ( GL_LIGHT0 , GL_POSITION , light_position ) ;
glLightModeli ( GL_LIGHT_MODEL_TWO_SIDE , GL_TRUE ) ;
GLERR ( " lighting " ) ;
glEnable ( GL_LIGHTING ) ;
glEnable ( GL_LIGHT0 ) ;
glBindTexture ( GL_TEXTURE_2D , renderedTexture ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
2017-07-04 13:38:33 +00:00
if ( backcolor = = 0 )
glClearColor ( 0.05 , 0.05 , 0.05 , 1 ) ;
else
glcolorClear ( backcolor < < 8 | 0xFF ) ;
2016-08-26 09:58:03 +00:00
glClearDepth ( 1.0f ) ;
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glDisable ( GL_BLEND ) ;
glEnable ( GL_TEXTURE_2D ) ;
glEnable ( GL_DEPTH_TEST ) ;
2017-03-23 10:53:57 +00:00
glDepthFunc ( GL_LESS ) ;
2016-08-26 09:58:03 +00:00
2017-12-27 17:53:00 +00:00
ld tanfov = tan ( fov * M_PI / 360 ) ;
2017-12-25 22:47:57 +00:00
if ( rug_perspective ) {
2017-12-27 12:09:58 +00:00
ld vnear = .001 ;
ld vfar = 1000 ;
2017-12-27 17:53:00 +00:00
ld sca = vnear * tanfov / vid . xres ;
xview = - tanfov ;
yview = - tanfov * vid . yres / vid . xres ;
2017-12-25 22:47:57 +00:00
glFrustum ( - sca * vid . xres , sca * vid . xres , - sca * vid . yres , sca * vid . yres , vnear , vfar ) ;
}
else {
2017-12-27 17:53:00 +00:00
xview = tanfov * model_distance ;
yview = tanfov * model_distance * vid . yres / vid . xres ;
2016-08-26 09:58:03 +00:00
2017-12-25 22:47:57 +00:00
glOrtho ( - xview , xview , - yview , yview , - 1000 , 1000 ) ;
}
2016-08-26 09:58:03 +00:00
2017-12-27 14:25:10 +00:00
glColor4f ( 1.f , 1.f , 1.f , 1.f ) ;
2017-12-27 18:55:00 +00:00
if ( rug_perspective & & gwhere > = gSphere ) {
2017-12-27 13:12:27 +00:00
glEnable ( GL_FOG ) ;
glFogi ( GL_FOG_MODE , GL_LINEAR ) ;
glFogf ( GL_FOG_START , 0 ) ;
2017-12-27 18:55:00 +00:00
glFogf ( GL_FOG_END , gwhere = = gSphere ? 10 : 4 ) ;
2017-12-27 13:12:27 +00:00
}
2016-08-26 09:58:03 +00:00
if ( vid . eye > .001 | | vid . eye < - .001 ) {
selectEyeMask ( 1 ) ;
glClear ( GL_DEPTH_BUFFER_BIT ) ;
glBegin ( GL_TRIANGLES ) ;
eyemod = 1 ;
for ( int t = 0 ; t < size ( triangles ) ; t + + )
drawTriangle ( triangles [ t ] ) ;
glEnd ( ) ;
selectEyeMask ( - 1 ) ;
eyemod = - 1 ;
glClear ( GL_DEPTH_BUFFER_BIT ) ;
glBegin ( GL_TRIANGLES ) ;
for ( int t = 0 ; t < size ( triangles ) ; t + + )
drawTriangle ( triangles [ t ] ) ;
glEnd ( ) ;
selectEyeMask ( 0 ) ;
}
else {
glBegin ( GL_TRIANGLES ) ;
for ( int t = 0 ; t < size ( triangles ) ; t + + )
drawTriangle ( triangles [ t ] ) ;
glEnd ( ) ;
}
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_LIGHTING ) ;
glEnable ( GL_BLEND ) ;
2017-12-27 13:12:27 +00:00
glDisable ( GL_FOG ) ;
2016-08-26 09:58:03 +00:00
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
selectEyeGL ( 0 ) ;
2017-12-27 13:12:27 +00:00
need_mouseh = true ;
2016-08-26 09:58:03 +00:00
}
// organization
//--------------
transmatrix currentrot ;
void init ( ) {
2017-07-22 23:33:27 +00:00
# if CAP_GLEW
2016-08-26 09:58:03 +00:00
if ( ! glew ) {
glew = true ;
GLenum err = glewInit ( ) ;
if ( GLEW_OK ! = err ) {
addMessage ( " Failed to initialize GLEW " ) ;
return ;
}
}
# endif
if ( rugged ) return ;
rugged = true ;
if ( scale < .01 | | scale > 100 ) scale = 1 ;
initTexture ( ) ;
if ( renderonce ) prepareTexture ( ) ;
if ( ! rugged ) return ;
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
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 ;
if ( sphere & & pmodel = = mdDisk & & vid . alpha > 1 )
valid = false ;
if ( ! valid )
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 ( ) ;
}
2016-08-26 09:58:03 +00:00
}
void close ( ) {
if ( ! rugged ) return ;
rugged = false ;
closeTexture ( ) ;
triangles . clear ( ) ;
for ( int i = 0 ; i < size ( points ) ; i + + ) delete points [ i ] ;
points . clear ( ) ;
pqueue = queue < rugpoint * > ( ) ;
}
int lastticks ;
2017-12-27 17:53:00 +00:00
ld protractor = 0 ;
2016-08-26 09:58:03 +00:00
void actDraw ( ) {
2017-12-29 11:54:50 +00:00
try {
2016-08-26 09:58:03 +00:00
if ( ! renderonce ) prepareTexture ( ) ;
physics ( ) ;
drawRugScene ( ) ;
Uint8 * keystate = SDL_GetKeyState ( NULL ) ;
int qm = 0 ;
double alpha = ( ticks - lastticks ) / 1000.0 ;
lastticks = ticks ;
2017-12-25 22:47:57 +00:00
transmatrix t = Id ;
if ( rug_perspective ) {
2017-12-27 17:53:00 +00:00
if ( keystate [ SDLK_HOME ] ) qm + + , t = t * rotmatrix ( alpha , 0 , 1 ) , protractor + = alpha ;
if ( keystate [ SDLK_END ] ) qm + + , t = t * rotmatrix ( alpha , 1 , 0 ) , protractor - = alpha ;
2017-12-25 22:47:57 +00:00
if ( ! keystate [ SDLK_LSHIFT ] ) {
2017-12-27 17:53:00 +00:00
if ( keystate [ SDLK_DOWN ] ) qm + + , t = t * rotmatrix ( alpha , 2 , 1 ) , protractor + = alpha ;
if ( keystate [ SDLK_UP ] ) qm + + , t = t * rotmatrix ( alpha , 1 , 2 ) , protractor - = alpha ;
if ( keystate [ SDLK_LEFT ] ) qm + + , t = t * rotmatrix ( alpha , 2 , 0 ) , protractor + = alpha ;
if ( keystate [ SDLK_RIGHT ] ) qm + + , t = t * rotmatrix ( alpha , 0 , 2 ) , protractor - = alpha ;
2017-12-25 22:47:57 +00:00
}
ld push = 0 ;
if ( keystate [ SDLK_PAGEDOWN ] ) push - = alpha ;
if ( keystate [ SDLK_PAGEUP ] ) push + = alpha ;
ld strafex = 0 , strafey = 0 ;
if ( keystate [ SDLK_LSHIFT ] ) {
2017-12-25 23:40:09 +00:00
if ( keystate [ SDLK_LEFT ] ) strafex + = alpha ;
if ( keystate [ SDLK_RIGHT ] ) strafex - = alpha ;
2017-12-25 22:47:57 +00:00
if ( keystate [ SDLK_UP ] ) strafey - = alpha ;
if ( keystate [ SDLK_DOWN ] ) strafey + = alpha ;
}
2016-08-26 09:58:03 +00:00
2017-12-27 18:10:34 +00:00
if ( qm ) {
if ( keystate [ SDLK_LCTRL ] )
push_all_points ( 2 , + model_distance ) ;
for ( int i = 0 ; i < size ( points ) ; i + + ) {
points [ i ] - > flat = t * points [ i ] - > flat ;
}
if ( keystate [ SDLK_LCTRL ] )
push_all_points ( 2 , - model_distance ) ;
2017-12-25 22:47:57 +00:00
}
2017-12-27 17:53:00 +00:00
model_distance - = push ;
2017-12-25 22:47:57 +00:00
push_all_points ( 2 , push ) ;
push_all_points ( 0 , strafex ) ;
push_all_points ( 1 , strafey ) ;
}
else {
if ( keystate [ SDLK_HOME ] ) qm + + , t = inverse ( currentrot ) ;
if ( keystate [ SDLK_END ] ) qm + + , t = currentrot * rotmatrix ( alpha , 0 , 1 ) * inverse ( currentrot ) ;
if ( keystate [ SDLK_DOWN ] ) qm + + , t = t * rotmatrix ( alpha , 1 , 2 ) ;
if ( keystate [ SDLK_UP ] ) qm + + , t = t * rotmatrix ( alpha , 2 , 1 ) ;
if ( keystate [ SDLK_LEFT ] ) qm + + , t = t * rotmatrix ( alpha , 0 , 2 ) ;
if ( keystate [ SDLK_RIGHT ] ) qm + + , t = t * rotmatrix ( alpha , 2 , 0 ) ;
2017-12-27 17:53:00 +00:00
if ( keystate [ SDLK_PAGEUP ] ) model_distance / = exp ( alpha ) ;
if ( keystate [ SDLK_PAGEDOWN ] ) model_distance * = exp ( alpha ) ;
2017-12-25 22:47:57 +00:00
if ( qm ) {
currentrot = t * currentrot ;
for ( int i = 0 ; i < size ( points ) ; i + + ) points [ i ] - > flat = t * points [ i ] - > flat ;
}
2016-08-26 09:58:03 +00:00
}
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 13:12:27 +00:00
void getco_pers ( rugpoint * r , hyperpoint & p , int & spherepoints , bool & error ) {
getco ( r , p , spherepoints ) ;
2017-12-27 12:09:58 +00:00
if ( rug_perspective ) {
if ( p [ 2 ] > = 0 )
error = true ;
else {
p [ 0 ] / = p [ 2 ] ;
p [ 1 ] / = p [ 2 ] ;
}
}
}
2017-12-27 14:25:10 +00:00
static const ld RADAR_INF = 1e12 ;
ld radar_distance = RADAR_INF ;
2016-08-26 09:58:03 +00:00
hyperpoint gethyper ( ld x , ld y ) {
double mx = ( ( x * 2 / vid . xres ) - 1 ) * xview ;
double my = ( 1 - ( y * 2 / vid . yres ) ) * yview ;
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 ;
for ( int i = 0 ; i < size ( triangles ) ; i + + ) {
auto r0 = triangles [ i ] . m [ 0 ] ;
auto r1 = triangles [ i ] . m [ 1 ] ;
auto r2 = triangles [ i ] . m [ 2 ] ;
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 ;
getco_pers ( r0 , p0 , spherepoints , error ) ;
getco_pers ( r1 , p1 , spherepoints , error ) ;
getco_pers ( r2 , p2 , spherepoints , error ) ;
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 ;
2017-12-27 18:10:34 +00:00
rz1 = - rz1 ; if ( ! rug_perspective ) rz1 + = model_distance ;
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
}
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
videopar svid = vid ;
setVidParam ( ) ;
hyperpoint h = : : gethyper ( px , py ) ;
vid = svid ;
return h ;
}
void show ( ) {
2017-12-27 14:25:10 +00:00
cmode = sm : : SIDE | sm : : MAYDARK ;
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-03-23 10:53:57 +00:00
dialog : : addItem ( XLAT ( " what's this? " ) , ' h ' ) ;
dialog : : addItem ( XLAT ( " take me back " ) , ' q ' ) ;
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 ' ) ;
2017-12-27 14:25:10 +00:00
dialog : : addBoolItem ( XLAT ( " render texture without OpenGL " ) , ( rendernogl ) , ' g ' ) ;
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 ' ) ;
2017-12-27 14:25:10 +00:00
dialog : : addBoolItem ( XLAT ( " projection " ) , rug_perspective , ' p ' ) ;
2017-12-27 17:53:00 +00:00
dialog : : lastItem ( ) . value = XLAT ( rug_perspective ? " perspective " :
gwhere = = gEuclid ? " orthogonal " : " azimuthal equidistant " ) ;
2017-12-27 14:25:10 +00:00
if ( ! rug : : rugged )
2017-12-27 17:53:00 +00:00
dialog : : addSelItem ( XLAT ( " native geometry " ) , XLAT ( gwhere ? ginf [ gwhere ] . name : " hyperbolic " ) , ' n ' ) ;
2017-12-27 14:25:10 +00:00
else
dialog : : addSelItem ( XLAT ( " radar " ) , radar_distance = = RADAR_INF ? " ∞ " : fts4 ( radar_distance ) , ' r ' ) ;
if ( ! rug : : rugged )
2018-01-04 19:05:34 +00:00
dialog : : addSelItem ( XLAT ( " model scale factor " ) , fts ( modelscale ) , ' m ' ) ;
2017-12-27 14:25:10 +00:00
else
dialog : : addSelItem ( XLAT ( " model iterations " ) , its ( queueiter ) , 0 ) ;
dialog : : addSelItem ( XLAT ( " field of view " ) , fts ( fov ) + " ° " , ' f ' ) ;
2017-12-27 17:53:00 +00:00
// dialog::addSelItem(XLAT("protractor"), fts(protractor * 180 / M_PI) + "°", 'f');
2017-12-27 14:25:10 +00:00
if ( rug : : rugged & & torus )
dialog : : addBoolItem ( XLAT ( " keep shape " ) , keep_shape , ' k ' ) ;
if ( ! ( keep_shape & & good_shape ) ) {
2018-01-03 10:22:37 +00:00
dialog : : addSelItem ( XLAT ( " maximum error " ) , ftsg ( err_zero ) , ' e ' ) ;
2017-12-27 14:25:10 +00:00
if ( rug : : rugged )
dialog : : lastItem ( ) . value + = " ( " + ftsg ( err_zero_current ) + " ) " ;
2017-11-07 13:39:26 +00:00
}
2017-12-27 14:25:10 +00:00
2017-03-23 10:53:57 +00:00
dialog : : display ( ) ;
2017-07-10 18:47:38 +00:00
keyhandler = [ ] ( int sym , int uni ) {
2017-07-22 23:33:27 +00:00
# if ISPANDORA
2017-07-10 18:47:38 +00:00
rendernogl = true ;
# endif
dialog : : handleNavigation ( sym , uni ) ;
2016-08-26 09:58:03 +00:00
2017-07-10 18:47:38 +00:00
if ( uni = = ' h ' ) gotoHelp (
2018-01-03 01:04:34 +00:00
XLAT (
2016-08-26 09:58:03 +00:00
" 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 "
2018-01-03 01:04:34 +00:00
" Use arrow keys to rotate, Page Up/Down to zoom. " )
+ " \n \n " +
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. " )
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 ( ) ;
else rug : : init ( ) ;
2017-07-10 18:47:38 +00:00
}
2017-12-27 14:25:10 +00:00
else if ( uni = = ' o ' & & ! rug : : rugged )
2017-07-10 18:47:38 +00:00
renderonce = ! renderonce ;
2017-12-27 14:25:10 +00:00
else if ( uni = = ' v ' ) {
2018-01-03 01:04:34 +00:00
dialog : : editNumber ( vertex_limit , 0 , 50000 , 500 , 3000 , " vertex limit " ,
" The more vertices, the more accurate the Hypersian Rug model is. "
2018-01-04 19:05:34 +00:00
" 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 ' ) {
dialog : : editNumber ( modelscale , 0.1 , 10 , .1 , 1 , " model scale factor " ,
2018-01-04 19:05:34 +00:00
" 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; "
" if the native geometry is hyperbolic, and scale > 1, a hyperbolic plane will be rendered as an equidistant surface. "
) ;
dialog : : scaleLog ( ) ;
}
2017-12-27 17:53:00 +00:00
else if ( uni = = ' p ' ) {
2017-12-27 14:25:10 +00:00
rug_perspective = ! rug_perspective ;
2017-12-27 17:53:00 +00:00
if ( rugged ) {
if ( rug_perspective )
push_all_points ( 2 , - model_distance ) ;
else
push_all_points ( 2 , + model_distance ) ;
}
}
else if ( uni = = ' d ' )
2018-01-03 01:04:34 +00:00
dialog : : editNumber ( model_distance , - 10 , 10 , .1 , 1 , " model distance " ,
" 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. "
) ;
2017-12-27 14:25:10 +00:00
else if ( uni = = ' e ' ) {
2018-01-03 10:22:37 +00:00
dialog : : editNumber ( err_zero , 1e-9 , 1 , .1 , 1e-3 , " maximum error " ,
" New points are added when the current error in the model is smaller than this value. "
) ;
2017-12-27 14:25:10 +00:00
dialog : : scaleLog ( ) ;
dialog : : reaction = [ ] ( ) { err_zero_current = err_zero ; } ;
}
else if ( uni = = ' k ' )
keep_shape = ! keep_shape ;
else if ( uni = = ' f ' ) {
dialog : : editNumber ( fov , 1 , 170 , 1 , 45 , " field of view " ,
2018-01-03 01:04:34 +00:00
" Horizontal field of view, in the perspective projection. "
" In the orthogonal projection this just controls the scale. "
2017-12-27 14:25:10 +00:00
) ;
}
2017-12-27 17:53:00 +00:00
else if ( uni = = ' n ' & & ! rug : : rugged )
gwhere = eGeometry ( ( gwhere + 1 ) % 4 ) ;
2017-07-22 23:33:27 +00:00
# if !ISPANDORA
2017-12-27 14:25:10 +00:00
else if ( uni = = ' g ' & & ! rug : : rugged )
2017-07-10 18:47:38 +00:00
rendernogl = ! rendernogl ;
# endif
2017-12-27 14:25:10 +00:00
else if ( uni = = ' s ' & & ! rug : : rugged ) {
2017-07-10 18:47:38 +00:00
texturesize * = 2 ;
if ( texturesize = = 8192 ) texturesize = 128 ;
}
else if ( doexiton ( sym , uni ) ) popScreen ( ) ;
} ;
2016-08-26 09:58:03 +00:00
}
void select ( ) {
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
int rugArgs ( ) {
using namespace arg ;
if ( 0 ) ;
else if ( argis ( " -rugmodelscale " ) ) {
shift ( ) ; modelscale = argf ( ) ;
}
else if ( argis ( " -ruggeo " ) ) {
shift ( ) ; gwhere = ( eGeometry ) argi ( ) ;
}
else if ( argis ( " -rugpers " ) ) {
rug_perspective = true ;
}
else if ( argis ( " -rugorth " ) ) {
rug_perspective = false ;
}
else if ( argis ( " -rugerr " ) ) {
2017-12-27 09:52:54 +00:00
shift ( ) ; err_zero = argf ( ) ;
}
2017-12-27 14:25:10 +00:00
else if ( argis ( " -rugkeep " ) ) {
shift ( ) ; keep_shape = true ;
}
else if ( argis ( " -rugnokeep " ) ) {
shift ( ) ; keep_shape = false ;
}
2017-12-27 09:52:54 +00:00
else if ( argis ( " -rugv " ) ) {
shift ( ) ; vertex_limit = argi ( ) ;
2017-12-25 22:47:57 +00:00
}
else return 1 ;
return 0 ;
}
auto rug_hook =
addHook ( hooks_args , 100 , rugArgs ) ;
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