2019-10-21 22:37:57 +00:00
// Hyperbolic Rogue -- raycaster
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/** \file raycaster.cpp
* \ brief A raycaster to draw walls .
*/
# include "hyper.h"
namespace hr {
2020-03-27 20:49:20 +00:00
/** \brief raycaster */
2019-10-25 12:50:48 +00:00
EX namespace ray {
2020-03-21 09:49:07 +00:00
# if CAP_RAY
2019-11-03 13:19:11 +00:00
2019-10-25 12:50:48 +00:00
/** texture IDs */
2021-05-17 12:21:14 +00:00
GLuint txConnections = 0 , txWallcolor = 0 , txTextureMap = 0 , txVolumetric = 0 , txM = 0 , txWall = 0 ;
2019-10-21 22:37:57 +00:00
2019-10-25 12:50:48 +00:00
EX bool in_use ;
EX bool comparison_mode ;
/** 0 - never use, 2 - always use, 1 = smart selection */
EX int want_use = 1 ;
2021-02-18 14:47:45 +00:00
/** generate the map for raycasting just once */
EX bool fixed_map = false ;
2020-09-21 10:04:10 +00:00
EX ld exp_start = 1 ;
EX ld exp_decay_exp = 4 ;
EX ld exp_decay_poly = 10 ;
2019-10-25 13:05:17 +00:00
2020-10-18 12:38:21 +00:00
# ifdef GLES_ONLY
2020-10-15 14:37:43 +00:00
const int gms_limit = 16 ; /* enough for Bringris -- need to do better */
# else
2020-05-27 23:50:53 +00:00
const int gms_limit = 110 ;
2020-10-15 14:37:43 +00:00
# endif
2020-05-16 08:55:38 +00:00
2020-11-14 12:53:19 +00:00
EX int gms_array_size = 16 ;
2020-04-11 22:40:15 +00:00
EX ld maxstep_sol = .05 ;
2019-10-25 22:43:15 +00:00
EX ld maxstep_nil = .1 ;
2021-02-07 19:39:39 +00:00
EX ld maxstep_pro = .5 ;
2019-10-25 22:43:15 +00:00
EX ld minstep = .001 ;
2019-10-27 00:23:20 +00:00
EX ld reflect_val = 0 ;
2019-11-08 13:59:19 +00:00
static const int NO_LIMIT = 999999 ;
EX ld hard_limit = NO_LIMIT ;
2020-10-18 12:48:35 +00:00
EX int max_iter_sol = 600 ;
EX int max_iter_iso = 60 ;
2021-02-07 19:39:39 +00:00
EX int max_iter_eyes = 200 ;
2019-10-25 13:18:31 +00:00
2019-10-26 16:25:14 +00:00
EX int max_cells = 2048 ;
2019-10-25 22:12:30 +00:00
EX bool rays_generate = true ;
2019-11-08 13:58:46 +00:00
EX ld & exp_decay_current ( ) {
2020-05-15 09:46:26 +00:00
if ( fake : : in ( ) ) return * FPIU ( & exp_decay_current ( ) ) ;
2020-05-09 08:41:15 +00:00
return ( sn : : in ( ) | | hyperbolic | | sl2 ) ? exp_decay_exp : exp_decay_poly ;
2019-10-25 21:24:31 +00:00
}
2019-11-08 13:58:46 +00:00
EX int & max_iter_current ( ) {
2020-05-09 08:41:15 +00:00
if ( nonisotropic | | stretch : : in ( ) ) return max_iter_sol ;
2021-02-07 19:39:39 +00:00
else if ( is_eyes ( ) ) return max_iter_eyes ;
2019-10-25 21:24:31 +00:00
else return max_iter_iso ;
}
2021-02-07 19:39:39 +00:00
EX bool is_eyes ( ) {
# if CAP_VR
return vrhr : : active ( ) & & vrhr : : eyes = = vrhr : : eEyes : : equidistant ;
# else
return false ;
# endif
}
EX bool is_stepbased ( ) {
return nonisotropic | | stretch : : in ( ) | | is_eyes ( ) ;
}
2019-10-25 22:43:15 +00:00
ld & maxstep_current ( ) {
2020-05-09 08:41:15 +00:00
if ( sn : : in ( ) | | stretch : : in ( ) ) return maxstep_sol ;
2021-02-07 21:52:37 +00:00
# if CAP_VR
2021-02-07 19:39:39 +00:00
if ( vrhr : : active ( ) & & vrhr : : eyes = = vrhr : : eEyes : : equidistant )
return maxstep_pro ;
2021-02-07 21:52:37 +00:00
# endif
2021-02-07 19:39:39 +00:00
return maxstep_nil ;
2019-10-25 22:43:15 +00:00
}
2019-10-21 22:37:57 +00:00
# define IN_ODS 0
2019-10-26 15:03:10 +00:00
eGeometry last_geometry ;
2020-11-14 12:53:19 +00:00
bool need_many_cell_types ( ) {
2020-11-14 13:18:57 +00:00
return isize ( hybrid : : gen_sample_list ( ) ) > 2 ;
2020-11-14 12:53:19 +00:00
}
2019-10-25 12:50:48 +00:00
/** is the raycaster available? */
EX bool available ( ) {
2020-11-19 17:20:06 +00:00
# if CAP_VR
2020-12-26 20:13:32 +00:00
/* would need a completely different implementation */
2021-01-31 14:27:58 +00:00
if ( vrhr : : active ( ) & & vrhr : : eyes = = vrhr : : eEyes : : equidistant ) {
if ( reflect_val ) return false ;
2021-02-06 12:03:09 +00:00
if ( sol | | stretch : : in ( ) | | sl2 ) return false ;
2021-01-31 14:27:58 +00:00
}
2020-11-19 17:20:06 +00:00
# endif
2019-11-09 10:18:52 +00:00
if ( noGUI ) return false ;
if ( ! vid . usingGL ) return false ;
2020-06-03 13:11:20 +00:00
if ( GDIM = = 2 ) return false ;
if ( WDIM = = 2 & & ( kite : : in ( ) | | bt : : in ( ) ) ) return false ;
2021-01-31 14:27:58 +00:00
# ifdef GLES_ONLY
2020-11-14 12:53:19 +00:00
if ( need_many_cell_types ( ) ) return false ;
2021-06-01 16:03:38 +00:00
if ( ! euclid & & ! prod & & ! nil ) return false ;
2020-11-14 12:53:19 +00:00
# endif
2019-12-14 11:12:24 +00:00
if ( hyperbolic & & pmodel = = mdPerspective & & ! kite : : in ( ) )
2019-10-25 12:50:48 +00:00
return true ;
2020-05-08 19:18:47 +00:00
if ( sphere & & pmodel = = mdPerspective & & ! rotspace )
return true ;
2019-11-23 19:39:38 +00:00
if ( nil & & S7 = = 8 )
return false ;
2020-05-09 08:41:15 +00:00
if ( ( sn : : in ( ) | | nil | | sl2 ) & & pmodel = = mdGeodesic )
2019-10-25 12:50:48 +00:00
return true ;
2019-12-14 11:05:01 +00:00
if ( euclid & & pmodel = = mdPerspective & & ! bt : : in ( ) )
2019-10-25 12:50:48 +00:00
return true ;
2020-05-15 16:31:32 +00:00
if ( prod )
2020-05-08 19:18:47 +00:00
return true ;
2020-05-09 08:41:15 +00:00
if ( pmodel = = mdPerspective & & stretch : : in ( ) )
2019-10-28 16:33:17 +00:00
return true ;
2019-10-25 12:50:48 +00:00
return false ;
}
/** do we want to use the raycaster? */
EX bool requested ( ) {
2020-03-29 15:35:42 +00:00
if ( cgflags & qRAYONLY ) return true ;
2019-10-25 12:50:48 +00:00
if ( ! want_use ) return false ;
2020-07-28 14:45:04 +00:00
if ( stretch : : in ( ) & & sphere ) return true ;
2019-11-03 13:20:24 +00:00
# if CAP_TEXTURE
2019-11-03 10:00:47 +00:00
if ( texture : : config . tstate = = texture : : tsActive ) return false ;
2019-11-03 13:20:24 +00:00
# endif
2019-10-25 12:50:48 +00:00
if ( ! available ( ) ) return false ;
if ( want_use = = 2 ) return true ;
2020-07-27 16:49:27 +00:00
if ( rotspace ) return false ; // not very good
2020-05-15 09:46:26 +00:00
return racing : : on | | quotient | | fake : : in ( ) ;
2019-10-25 12:50:48 +00:00
}
2020-03-29 15:35:42 +00:00
# if HDR
2019-10-21 22:37:57 +00:00
struct raycaster : glhr : : GLprogram {
2020-12-26 20:12:34 +00:00
GLint uStart , uStartid , uM , uLength , uIPD ;
2019-10-22 10:07:38 +00:00
GLint uWallstart , uWallX , uWallY ;
2020-07-07 20:16:38 +00:00
GLint tConnections , tWallcolor , tTextureMap , tVolumetric ;
2019-11-09 11:12:16 +00:00
GLint uBinaryWidth , uPLevel , uLP , uStraighten , uReflectX , uReflectY ;
2019-10-25 13:05:17 +00:00
GLint uLinearSightRange , uExpStart , uExpDecay ;
2019-11-02 09:40:22 +00:00
GLint uBLevel ;
2020-05-08 19:14:31 +00:00
GLint uWallOffset , uSides ;
2020-08-08 14:08:51 +00:00
GLint uITOA , uATOI ;
2020-08-22 22:10:59 +00:00
GLint uToOrig , uFromOrig ;
2020-12-26 20:12:34 +00:00
GLint uProjection ;
2021-01-31 14:27:58 +00:00
GLint uEyeShift , uAbsUnit ;
2021-07-09 18:12:35 +00:00
GLint uMirrorShift ;
2019-10-21 22:37:57 +00:00
2021-05-17 12:21:14 +00:00
GLint tM , uInvLengthM ;
GLint tWall , uInvLengthWall ;
2020-03-29 15:35:42 +00:00
raycaster ( string vsh , string fsh ) ;
} ;
# endif
2021-06-01 16:03:18 +00:00
# ifdef GLES_ONLY
bool m_via_texture = false ;
bool wall_via_texture = false ;
static const bool can_via_texture = false ; /* textures are not precise enough ): */
# else
2021-05-17 12:21:14 +00:00
bool m_via_texture = true ;
bool wall_via_texture = true ;
2021-06-01 16:03:18 +00:00
static const bool can_via_texture = true ;
# endif
2021-05-17 12:21:14 +00:00
2020-03-29 15:35:42 +00:00
raycaster : : raycaster ( string vsh , string fsh ) : GLprogram ( vsh , fsh ) {
2021-06-09 02:44:04 +00:00
/* need to set shader_flags to 0 so that attributes are not enabled */
shader_flags = 0 ;
2019-10-21 22:37:57 +00:00
uStart = glGetUniformLocation ( _program , " uStart " ) ;
uStartid = glGetUniformLocation ( _program , " uStartid " ) ;
uM = glGetUniformLocation ( _program , " uM " ) ;
uLength = glGetUniformLocation ( _program , " uLength " ) ;
2020-12-26 20:12:34 +00:00
uProjection = glGetUniformLocation ( _program , " uProjection " ) ;
2019-10-21 22:37:57 +00:00
uIPD = glGetUniformLocation ( _program , " uIPD " ) ;
2019-10-22 10:07:38 +00:00
uWallstart = glGetUniformLocation ( _program , " uWallstart " ) ;
uWallX = glGetUniformLocation ( _program , " uWallX " ) ;
uWallY = glGetUniformLocation ( _program , " uWallY " ) ;
2019-10-22 20:42:48 +00:00
uBinaryWidth = glGetUniformLocation ( _program , " uBinaryWidth " ) ;
2019-11-08 14:01:03 +00:00
uStraighten = glGetUniformLocation ( _program , " uStraighten " ) ;
2019-10-28 16:33:17 +00:00
uPLevel = glGetUniformLocation ( _program , " uPLevel " ) ;
uLP = glGetUniformLocation ( _program , " uLP " ) ;
2019-11-09 11:12:16 +00:00
uReflectX = glGetUniformLocation ( _program , " uReflectX " ) ;
uReflectY = glGetUniformLocation ( _program , " uReflectY " ) ;
2021-07-09 18:12:35 +00:00
uMirrorShift = glGetUniformLocation ( _program , " uMirrorShift " ) ;
2019-10-25 13:05:17 +00:00
uLinearSightRange = glGetUniformLocation ( _program , " uLinearSightRange " ) ;
uExpDecay = glGetUniformLocation ( _program , " uExpDecay " ) ;
uExpStart = glGetUniformLocation ( _program , " uExpStart " ) ;
2019-11-02 09:40:22 +00:00
uBLevel = glGetUniformLocation ( _program , " uBLevel " ) ;
2019-10-21 22:37:57 +00:00
tConnections = glGetUniformLocation ( _program , " tConnections " ) ;
tWallcolor = glGetUniformLocation ( _program , " tWallcolor " ) ;
2019-10-26 08:32:44 +00:00
tTextureMap = glGetUniformLocation ( _program , " tTextureMap " ) ;
2020-07-07 20:16:38 +00:00
tVolumetric = glGetUniformLocation ( _program , " tVolumetric " ) ;
2021-05-17 12:21:14 +00:00
tM = glGetUniformLocation ( _program , " tM " ) ;
uInvLengthM = glGetUniformLocation ( _program , " uInvLengthM " ) ;
tWall = glGetUniformLocation ( _program , " tWall " ) ;
uInvLengthWall = glGetUniformLocation ( _program , " uInvLengthWall " ) ;
2020-02-07 18:13:18 +00:00
2020-05-08 19:14:31 +00:00
uWallOffset = glGetUniformLocation ( _program , " uWallOffset " ) ;
uSides = glGetUniformLocation ( _program , " uSides " ) ;
2020-08-08 14:08:51 +00:00
uITOA = glGetUniformLocation ( _program , " uITOA " ) ;
uATOI = glGetUniformLocation ( _program , " uATOI " ) ;
2020-08-22 22:10:59 +00:00
uToOrig = glGetUniformLocation ( _program , " uToOrig " ) ;
uFromOrig = glGetUniformLocation ( _program , " uFromOrig " ) ;
2021-01-31 14:27:58 +00:00
uEyeShift = glGetUniformLocation ( _program , " uEyeShift " ) ;
uAbsUnit = glGetUniformLocation ( _program , " uAbsUnit " ) ;
2019-10-21 22:37:57 +00:00
}
shared_ptr < raycaster > our_raycaster ;
2020-06-03 13:11:20 +00:00
int deg , irays ;
2019-10-28 16:33:17 +00:00
2020-01-15 17:39:35 +00:00
# ifdef GLES_ONLY
void add ( string & tgt , string type , string name , int min_index , int max_index ) {
2020-10-15 14:37:43 +00:00
if ( min_index > = max_index ) ;
else
2020-01-15 17:39:35 +00:00
if ( min_index + 1 = = max_index )
tgt + = " { return " + name + " [ " + its ( min_index ) + " ]; } " ;
else {
int mid = ( min_index + max_index ) / 2 ;
tgt + = " { if(i< " + its ( mid ) + " ) " ;
add ( tgt , type , name , min_index , mid ) ;
tgt + = " else " ;
add ( tgt , type , name , mid , max_index ) ;
tgt + = " } " ;
}
}
string build_getter ( string type , string name , int index ) {
string s = type + " get_ " + name + " (int i) \n " ;
add ( s , type , name , 0 , index ) ;
return s + " \n " ;
}
# define GET(array, index) "get_" array "(" index ")"
# else
# define GET(array, index) array "[" index "]"
# endif
2020-04-11 18:47:14 +00:00
EX hookset < void ( string & , string & ) > hooks_rayshader ;
EX hookset < bool ( shared_ptr < raycaster > ) > hooks_rayset ;
2020-03-29 15:35:42 +00:00
2021-02-07 17:30:20 +00:00
tuple <
# if CAP_VR
int , vrhr : : eEyes ,
# endif
2021-04-07 00:33:08 +00:00
string
2021-02-07 17:30:20 +00:00
> raycaster_state ( ) {
return make_tuple (
# if CAP_VR
vrhr : : state ,
vrhr : : eyes ,
# endif
2021-04-07 00:33:08 +00:00
cgi_string ( )
2021-02-07 17:30:20 +00:00
) ;
}
decltype ( raycaster_state ( ) ) saved_state ;
2021-07-07 21:33:34 +00:00
ld ray_scale = 8 ;
int max_wall_offset = 512 ;
int max_celltype = 64 ;
2019-10-21 22:37:57 +00:00
void enable_raycaster ( ) {
2020-05-09 16:30:36 +00:00
using glhr : : to_glsl ;
2021-02-07 17:30:20 +00:00
auto state = raycaster_state ( ) ;
if ( state ! = saved_state ) {
2020-05-08 19:14:31 +00:00
reset_raycaster ( ) ;
2021-02-07 17:30:20 +00:00
saved_state = state ;
2020-05-08 19:14:31 +00:00
}
2021-05-17 12:21:14 +00:00
auto getM = [ ] ( string s ) {
if ( m_via_texture )
return " getM( " + s + " ) " ;
else
return " uM[ " + s + " ] " ;
} ;
auto getWall = [ ] ( string s , int coord ) {
if ( wall_via_texture )
return " getWall( " + s + " , " + its ( coord ) + " ) " ;
else
return " uWall " + string ( coord ? " Y " : " X " ) + " [ " + s + " ] " ;
} ;
auto getWallstart = [ ] ( string s ) {
if ( wall_via_texture )
return " getWallstart( " + s + " ) " ;
else
return " uWallstart[ " + s + " ] " ;
} ;
2020-05-08 19:14:31 +00:00
2021-07-09 08:09:31 +00:00
currentmap - > wall_offset ( centerover ) ; /* so raywall is not empty and deg is not zero */
2020-06-03 13:11:20 +00:00
2020-05-08 19:14:31 +00:00
deg = 0 ;
2020-05-09 16:32:16 +00:00
auto samples = hybrid : : gen_sample_list ( ) ;
for ( int i = 0 ; i < isize ( samples ) - 1 ; i + + )
deg = max ( deg , samples [ i + 1 ] . first - samples [ i ] . first ) ;
2020-05-08 19:14:31 +00:00
2019-10-26 15:03:10 +00:00
last_geometry = geometry ;
2019-10-21 22:37:57 +00:00
if ( ! our_raycaster ) {
2019-11-08 14:34:51 +00:00
bool asonov = hr : : asonov : : in ( ) ;
2019-11-09 11:12:16 +00:00
bool use_reflect = reflect_val & & ! nil & & ! levellines ;
2020-05-08 19:14:31 +00:00
2020-11-14 12:53:19 +00:00
bool many_cell_types = need_many_cell_types ( ) ;
2019-10-21 22:37:57 +00:00
string vsh =
2019-11-14 20:21:17 +00:00
" attribute mediump vec4 aPosition; \n "
2020-12-26 20:12:34 +00:00
" uniform mediump mat4 uProjection; \n "
2019-11-14 20:21:17 +00:00
" varying mediump vec4 at; \n "
2019-10-21 22:37:57 +00:00
" void main() { \n "
2020-12-26 20:12:34 +00:00
" gl_Position = aPosition; at = uProjection * aPosition; \n "
2019-10-21 22:37:57 +00:00
" } \n " ;
2020-06-03 13:11:20 +00:00
irays = isize ( cgi . raywall ) ;
2020-01-15 17:39:35 +00:00
string rays = its ( irays ) ;
2019-10-26 22:58:02 +00:00
2019-10-21 22:37:57 +00:00
string fsh =
2019-11-14 20:21:17 +00:00
" varying mediump vec4 at; \n "
" uniform mediump int uLength; \n "
" uniform mediump float uIPD; \n "
" uniform mediump mat4 uStart; \n "
" uniform mediump vec2 uStartid; \n "
" uniform mediump sampler2D tConnections; \n "
" uniform mediump sampler2D tWallcolor; \n "
2020-07-07 20:16:38 +00:00
" uniform mediump sampler2D tVolumetric; \n "
2019-11-14 20:21:17 +00:00
" uniform mediump sampler2D tTexture; \n "
" uniform mediump sampler2D tTextureMap; \n "
" uniform mediump vec4 uFogColor; \n "
" uniform mediump float uLinearSightRange, uExpStart, uExpDecay; \n " ;
2021-05-17 12:21:14 +00:00
if ( wall_via_texture ) {
fsh + =
" uniform mediump sampler2D tWall; \n "
" uniform mediump float uInvLengthWall; \n "
" mediump vec4 getWall(mediump int x, mediump int coord) { \n "
2021-06-01 16:01:48 +00:00
" mediump vec4 result; \n "
" mediump vec4 v = texture2D(tWall, vec2((float(x)+.5) * uInvLengthWall, (float(coord)+.5) / 4.)); \n "
2021-07-07 21:33:34 +00:00
" for(int j=0; j<4; j++) result[j] = (v[j] - .5) * " + to_glsl ( ray_scale ) + " ; \n "
2021-05-17 12:21:14 +00:00
" return result; \n "
" } \n "
" mediump int getWallstart(mediump int x) { \n "
2021-06-01 16:01:48 +00:00
" mediump vec4 v = texture2D(tWall, vec2((float(x)+.5) * uInvLengthWall, 0.625)); \n "
2021-05-17 12:21:14 +00:00
" return int(v[0] / uInvLengthWall); \n "
" } \n " ;
}
else fsh + =
" uniform mediump vec4 uWallX[ " + rays + " ]; \n "
" uniform mediump vec4 uWallY[ " + rays + " ]; \n "
" uniform mediump int uWallstart[ " + its ( isize ( cgi . wallstart ) ) + " ]; \n " ;
if ( m_via_texture ) {
fsh + =
" uniform mediump sampler2D tM; \n "
" uniform mediump float uInvLengthM; \n "
" mediump mat4 getM(mediump int x) { \n "
2021-06-01 16:01:48 +00:00
" mediump mat4 result; \n "
2021-05-17 12:21:14 +00:00
" for(int i=0; i<4; i++) { \n "
2021-06-01 16:01:48 +00:00
" mediump vec4 v = texture2D(tM, vec2((float(x)+.5) * uInvLengthM, (float(i)+.5) / 4.)); \n "
2021-07-07 21:33:34 +00:00
" for(int j=0; j<4; j++) result[j][i] = (v[j] - .5) * " + to_glsl ( ray_scale ) + " ; \n "
2021-05-17 12:21:14 +00:00
" } \n "
" return result; \n "
" } \n " ;
}
else fsh + =
" uniform mediump mat4 uM[ " + its ( gms_limit ) + " ]; \n " ;
2019-10-22 08:52:17 +00:00
2020-01-15 17:39:35 +00:00
# ifdef GLES_ONLY
2021-06-01 16:02:18 +00:00
if ( ! wall_via_texture ) {
fsh + = build_getter ( " mediump vec4 " , " uWallX " , irays ) ;
fsh + = build_getter ( " mediump vec4 " , " uWallY " , irays ) ;
fsh + = build_getter ( " mediump int " , " uWallstart " , deg + 1 ) ;
}
2021-05-17 12:21:14 +00:00
if ( ! m_via_texture )
fsh + = build_getter ( " mediump mat4 " , " uM " , gms_limit ) ;
2020-01-15 17:39:35 +00:00
# endif
2019-10-28 16:33:17 +00:00
if ( prod ) fsh + =
2019-11-14 20:21:17 +00:00
" uniform mediump float uPLevel; \n "
" uniform mediump mat4 uLP; \n " ;
2019-10-28 16:33:17 +00:00
2020-11-14 12:53:19 +00:00
if ( many_cell_types ) fsh + =
2020-05-08 19:14:31 +00:00
" uniform int uWallOffset, uSides; \n " ;
2019-11-02 09:40:22 +00:00
2020-05-08 19:14:31 +00:00
int flat1 = 0 , flat2 = deg ;
if ( prod | | rotspace ) flat2 - = 2 ;
2020-10-15 14:33:52 +00:00
# if CAP_BT
2019-12-14 11:05:01 +00:00
if ( hyperbolic & & bt : : in ( ) ) {
2019-11-14 20:21:17 +00:00
fsh + = " uniform mediump float uBLevel; \n " ;
2019-12-14 11:05:01 +00:00
flat1 = bt : : dirs_outer ( ) ;
flat2 - = bt : : dirs_inner ( ) ;
2019-11-02 09:40:22 +00:00
}
2020-10-15 14:33:52 +00:00
# endif
2020-05-08 19:18:47 +00:00
if ( hyperbolic ) fsh + =
2019-10-21 22:37:57 +00:00
2020-01-15 17:39:35 +00:00
" mediump mat4 xpush(float x) { return mat4( "
2019-10-21 22:37:57 +00:00
" cosh(x), 0., 0., sinh(x), \n "
" 0., 1., 0., 0., \n "
" 0., 0., 1., 0., \n "
" sinh(x), 0., 0., cosh(x) "
2019-11-02 09:40:22 +00:00
" );} \n " ;
2020-05-08 19:18:47 +00:00
if ( sphere ) fsh + =
" mediump mat4 xpush(float x) { return mat4( "
" cos(x), 0., 0., sin(x), \n "
" 0., 1., 0., 0., \n "
" 0., 0., 1., 0., \n "
" -sin(x), 0., 0., cos(x) "
" );} \n " ;
2019-11-02 09:40:22 +00:00
if ( IN_ODS ) fsh + =
2019-10-21 22:37:57 +00:00
2020-01-15 17:39:35 +00:00
" mediump mat4 xzspin(float x) { return mat4( "
2019-10-21 22:37:57 +00:00
" cos(x), 0., sin(x), 0., \n "
" 0., 1., 0., 0., \n "
" -sin(x), 0., cos(x), 0., \n "
" 0., 0., 0., 1. "
" );} \n "
2020-01-15 17:39:35 +00:00
" mediump mat4 yzspin(float x) { return mat4( "
2019-10-21 22:37:57 +00:00
" 1., 0., 0., 0., \n "
" 0., cos(x), sin(x), 0., \n "
" 0., -sin(x), cos(x), 0., \n "
" 0., 0., 0., 1. "
2019-10-22 08:52:17 +00:00
" );} \n " ;
2019-10-21 22:37:57 +00:00
2020-11-14 12:53:19 +00:00
if ( many_cell_types ) {
2020-05-08 19:18:47 +00:00
fsh + = " int walloffset, sides; \n " ;
}
else {
fsh + = " const int walloffset = 0; \n "
2020-06-03 13:11:20 +00:00
" const int sides = " + its ( centerover - > type + ( WDIM = = 2 ? 2 : 0 ) ) + " ; \n " ;
2020-05-08 19:18:47 +00:00
}
2019-10-22 10:07:38 +00:00
fsh + =
2020-01-15 17:39:35 +00:00
" mediump vec2 map_texture(mediump vec4 pos, int which) { \n " ;
2019-10-23 16:52:57 +00:00
if ( nil ) fsh + = " if(which == 2 || which == 5) pos.z = 0.; \n " ;
2019-12-14 11:05:01 +00:00
else if ( hyperbolic & & bt : : in ( ) ) fsh + =
2019-11-02 09:40:22 +00:00
" pos = vec4(-log(pos.w-pos.x), pos.y, pos.z, 1); \n "
" pos.yz *= exp(pos.x); \n " ;
2020-05-08 19:18:47 +00:00
else if ( hyperbolic | | sphere ) fsh + =
2019-10-22 10:07:38 +00:00
" pos /= pos.w; \n " ;
2019-10-28 16:33:17 +00:00
else if ( prod ) fsh + =
" pos = vec4(pos.x/pos.z, pos.y/pos.z, pos.w, 0); \n " ;
2019-10-22 10:07:38 +00:00
fsh + =
2021-05-17 12:21:14 +00:00
" int s = " + getWallstart ( " which " ) + " ; \n "
" int e = " + getWallstart ( " which+1 " ) + " ; \n "
2019-11-03 12:36:40 +00:00
" for(int ix=0; ix<16; ix++) { \n "
" int i = s+ix; if(i >= e) break; \n "
2021-05-17 12:21:14 +00:00
" mediump vec2 v = vec2(dot( " + getWall ( " i " , 0 ) + " , pos), dot( " + getWall ( " i " , 1 ) + " , pos)); \n "
2019-10-26 08:32:44 +00:00
" if(v.x >= 0. && v.y >= 0. && v.x + v.y <= 1.) return vec2(v.x+v.y, v.x-v.y); \n "
2019-10-22 10:07:38 +00:00
" } \n "
2019-10-26 08:32:44 +00:00
" return vec2(1, 1); \n "
2019-10-22 10:07:38 +00:00
" } \n " ;
2021-01-31 14:27:58 +00:00
2021-02-07 19:39:39 +00:00
bool eyes = is_eyes ( ) ;
2020-05-08 19:18:47 +00:00
2021-02-07 19:39:39 +00:00
bool stepbased = is_stepbased ( ) ;
2019-10-22 10:07:38 +00:00
2019-10-22 08:52:17 +00:00
string fmain = " void main() { \n " ;
2019-10-27 00:23:20 +00:00
if ( use_reflect ) fmain + = " bool depthtoset = true; \n " ;
2019-10-22 08:52:17 +00:00
if ( IN_ODS ) fmain + =
2020-01-15 17:39:35 +00:00
" mediump float lambda = at[0]; \n " // -PI to PI
" mediump float phi; \n "
" mediump float eye; \n "
2019-10-21 22:37:57 +00:00
" if(at.y < 0.) { phi = at.y + PI/2.; eye = uIPD / 2.; } \n " // right
" else { phi = at.y - PI/2.; eye = -uIPD / 2.; } \n "
2020-01-15 17:39:35 +00:00
" mediump mat4 vw = uStart * xzspin(-lambda) * xpush(eye) * yzspin(phi); \n "
" mediump vec4 at0 = vec4(0., 0., 1., 0.); \n " ;
2019-10-22 08:52:17 +00:00
2020-11-01 20:20:54 +00:00
else {
fmain + =
" mediump mat4 vw = uStart; \n "
" mediump vec4 at0 = at; \n "
" gl_FragColor = vec4(0,0,0,1); \n "
" mediump float left = 1.; \n "
" at0.y = -at.y; \n "
" at0.w = 0.; \n " ;
if ( panini_alpha ) fmain + =
" mediump float hr = at0.x*at0.x; \n "
" mediump float alpha = " + to_glsl ( panini_alpha ) + " ; \n "
" mediump float A = 1. + hr; \n "
" mediump float B = -2.*hr*alpha; \n "
" mediump float C = 1. - hr*alpha*alpha; \n "
" B /= A; C /= A; \n "
" mediump float hz = B / 2. + sqrt(C + B*B/4.); \n "
" if(abs(hz) > 1e-3) { "
" at0.xyz *= hz+alpha; \n "
" at0.z = hz; \n } "
" else at0.z = 0.; \n "
2021-03-21 10:28:10 +00:00
" \n "
;
else if ( stereo_alpha ) fmain + =
" mediump float hr = at0.x*at0.x+at0.y*at0.y; \n "
" mediump float alpha = " + to_glsl ( stereo_alpha ) + " ; \n "
" mediump float A = 1. + hr; \n "
" mediump float B = -2.*hr*alpha; \n "
" mediump float C = 1. - hr*alpha*alpha; \n "
" B /= A; C /= A; \n "
" mediump float hz = B / 2. + sqrt(C + B*B/4.); \n "
" if(abs(hz) > 1e-3) { "
" at0.xyz *= hz+alpha; \n "
" at0.z = hz; \n } "
" else at0.z = 0.; \n "
" \n "
2020-11-01 20:20:54 +00:00
;
fmain + =
" at0.xyz = at0.xyz / length(at0.xyz); \n " ;
2021-01-31 14:27:58 +00:00
if ( eyes ) fmain + = " at0.xyz /= uAbsUnit; \n " ;
2020-11-01 20:20:54 +00:00
}
2019-10-22 08:52:17 +00:00
2020-01-15 17:39:35 +00:00
if ( hyperbolic ) fsh + = " mediump float len(mediump vec4 x) { return x[3]; } \n " ;
2020-05-08 19:18:47 +00:00
else if ( sphere & & rotspace ) fsh + = " mediump float len(mediump vec4 x) { return 1. + x . x * x . x + x . y * x . y - x . z * x . z - x . w * x . w ; } \ n " ;
2020-05-09 08:41:15 +00:00
else if ( sl2 ) fsh + = " mediump float len(mediump vec4 x) { return 1. + x . x * x . x + x . y * x . y ; } \ n " ;
2020-05-08 19:18:47 +00:00
else if ( sphere ) fsh + = " mediump float len(mediump vec4 x) { return 1. - x [ 3 ] ; } \ n " ;
2020-01-15 17:39:35 +00:00
else fsh + = " mediump float len(mediump vec4 x) { return length(x.xyz); } \n " ;
2019-10-22 08:52:17 +00:00
2021-01-31 14:27:58 +00:00
ld s = 1 ;
2021-02-01 10:21:51 +00:00
# if CAP_VR
2021-01-31 14:27:58 +00:00
if ( eyes ) s * = vrhr : : absolute_unit_in_meters ;
2021-02-01 10:21:51 +00:00
# endif
2021-01-31 14:27:58 +00:00
2020-05-08 19:18:47 +00:00
if ( stepbased ) fmain + =
2021-01-31 14:27:58 +00:00
" const mediump float maxstep = " + fts ( maxstep_current ( ) * s ) + " ; \n "
" const mediump float minstep = " + fts ( minstep * s ) + " ; \n "
" mediump float next = maxstep; \n " ;
2019-10-23 16:52:57 +00:00
2019-10-28 16:33:17 +00:00
if ( prod ) {
string sgn = in_h2xe ( ) ? " - " : " + " ;
fmain + =
2020-01-15 17:39:35 +00:00
" mediump vec4 position = vw * vec4(0., 0., 1., 0.); \n "
" mediump vec4 at1 = uLP * at0; \n " ;
2019-11-28 23:50:47 +00:00
if ( in_e2xe ( ) ) fmain + =
2020-01-15 17:39:35 +00:00
" mediump float zpos = log(position.z); \n " ;
2019-11-28 23:50:47 +00:00
else fmain + =
2020-01-15 17:39:35 +00:00
" mediump float zpos = log(position.z*position.z " + sgn + " position.x*position.x " + sgn + " position.y*position.y)/2.; \n " ;
2021-02-01 20:26:25 +00:00
if ( eyes ) fmain + =
" vw *= exp(-zpos); \n " ;
else fmain + =
2019-10-28 16:33:17 +00:00
" position *= exp(-zpos); \n "
2020-01-15 17:39:35 +00:00
" mediump float zspeed = at1.z; \n "
" mediump float xspeed = length(at1.xy); \n "
" mediump vec4 tangent = vw * exp(-zpos) * vec4(at1.xy, 0, 0) / xspeed; \n " ;
2019-10-28 16:33:17 +00:00
}
2021-01-31 14:27:58 +00:00
else if ( ! eyes ) {
fmain + =
" mediump vec4 position = vw * vec4(0., 0., 0., 1.); \n "
" mediump vec4 tangent = vw * at0; \n " ;
}
if ( eyes ) {
fsh + = " mediump uniform mat4 uEyeShift; \n " ;
fsh + = " mediump uniform float uAbsUnit; \n " ;
}
2020-05-08 19:14:31 +00:00
2020-05-09 08:41:15 +00:00
if ( stretch : : in ( ) ) {
2020-08-08 14:08:51 +00:00
if ( stretch : : mstretch ) {
fsh + = " mediump uniform mat4 uITOA; \n " ;
fsh + = " mediump uniform mat4 uATOI; \n " ;
2020-08-22 22:10:59 +00:00
fsh + = " mediump uniform mat4 uToOrig; \n " ;
fsh + = " mediump uniform mat4 uFromOrig; \n " ;
fsh + = " mediump mat4 toOrig; \n " ;
fsh + = " mediump mat4 fromOrig; \n " ;
fmain + =
" toOrig = uToOrig; \n "
" fromOrig = uFromOrig; \n " ;
fmain + =
" tangent = s_itranslate(toOrig * position) * toOrig * tangent; \n " ;
2020-08-08 14:08:51 +00:00
fmain + =
" tangent = uITOA * tangent; \n " ;
2020-08-22 22:10:59 +00:00
fmain + =
" tangent = fromOrig * s_translate(toOrig * position) * tangent; \n " ;
2020-08-08 14:08:51 +00:00
}
2020-08-22 22:10:59 +00:00
else {
fmain + =
" tangent = s_itranslate(position) * tangent; \n " ;
2020-08-08 14:08:51 +00:00
fmain + =
" tangent[2] /= " + to_glsl ( stretch : : not_squared ( ) ) + " ; \n " ;
2020-08-22 22:10:59 +00:00
fmain + =
" tangent = s_translate(position) * tangent; \n " ;
}
2020-05-08 19:18:47 +00:00
}
2020-11-14 12:53:19 +00:00
if ( many_cell_types ) fmain + = " walloffset = uWallOffset; sides = uSides; \n " ;
2019-10-28 16:33:17 +00:00
fmain + =
2020-01-15 17:39:35 +00:00
" mediump float go = 0.; \n "
" mediump vec2 cid = uStartid; \n "
2019-10-25 13:18:31 +00:00
" for(int iter=0; iter< " + its ( max_iter_current ( ) ) + " ; iter++) { \n " ;
2019-10-22 20:42:48 +00:00
2019-10-23 16:52:57 +00:00
fmain + =
2020-01-15 17:39:35 +00:00
" mediump float dist = 100.; \n " ;
2019-10-22 20:42:48 +00:00
fmain + =
" int which = -1; \n " ;
2019-11-28 23:50:47 +00:00
2021-02-01 20:26:35 +00:00
if ( in_e2xe ( ) & & ! eyes ) fmain + = " tangent.w = position.w = 0.; \n " ;
2019-10-22 20:42:48 +00:00
if ( IN_ODS ) fmain + =
2019-10-21 22:37:57 +00:00
" if(go == 0.) { \n "
2020-01-15 17:39:35 +00:00
" mediump float best = len(position); \n "
2020-05-08 19:14:31 +00:00
" for(int i=0; i<sides; i++) { \n "
2021-05-17 12:21:14 +00:00
" mediump float cand = len( " + getM ( " i " ) + " * position); \n "
2019-10-21 22:37:57 +00:00
" if(cand < best - .001) { dist = 0.; best = cand; which = i; } \n "
" } \n "
2019-10-22 20:42:48 +00:00
" } \n " ;
2019-10-22 08:52:17 +00:00
2020-05-08 19:18:47 +00:00
if ( ! stepbased ) {
2019-10-22 20:42:48 +00:00
fmain + =
2019-10-28 16:33:17 +00:00
" if(which == -1) { \n " ;
2021-07-07 21:34:15 +00:00
fmain + = " for(int i= " + its ( flat1 ) + " ; i< " + ( prod ? " sides-2 " : ( WDIM = = 2 | | is_subcube_based ( variation ) ) ? " sides " : its ( flat2 ) ) + " ; i++) { \n " ;
2020-06-03 13:11:20 +00:00
2020-10-15 14:37:43 +00:00
// fmain += "int woi = walloffset+i;\n";
2019-10-22 20:42:48 +00:00
2019-10-28 16:33:17 +00:00
if ( in_h2xe ( ) ) fmain + =
2021-05-17 12:21:14 +00:00
" mediump float v = ((position - " + getM ( " woi " ) + " * position)[2] / ( " + getM ( " woi " ) + " * tangent - tangent)[2]); \n "
2019-10-28 16:33:17 +00:00
" if(v > 1. || v < -1.) continue; \n "
2020-01-15 17:39:35 +00:00
" mediump float d = atanh(v); \n "
" mediump vec4 next_tangent = position * sinh(d) + tangent * cosh(d); \n "
2021-05-17 12:21:14 +00:00
" if(next_tangent[2] < ( " + getM ( " woi " ) + " * next_tangent)[2]) continue; \n "
2019-10-28 16:33:17 +00:00
" d /= xspeed; \n " ;
else if ( in_s2xe ( ) ) fmain + =
2021-05-17 12:21:14 +00:00
" mediump float v = ((position - " + getM ( " woi " ) + " * position)[2] / ( " + getM ( " woi " ) + " * tangent - tangent)[2]); \n "
2020-01-15 17:39:35 +00:00
" mediump float d = atan(v); \n "
" mediump vec4 next_tangent = tangent * cos(d) - position * sin(d); \n "
2021-05-17 12:21:14 +00:00
" if(next_tangent[2] > ( " + getM ( " woi " ) + " * next_tangent)[2]) continue; \n "
2019-10-28 16:33:17 +00:00
" d /= xspeed; \n " ;
2019-11-28 23:50:47 +00:00
else if ( in_e2xe ( ) ) fmain + =
2021-05-17 12:21:14 +00:00
" mediump float deno = dot(position, tangent) - dot( " + getM ( " woi " ) + " *position, " + getM ( " woi " ) + " *tangent); \n "
2019-11-28 23:50:47 +00:00
" if(deno < 1e-6 && deno > -1e-6) continue; \n "
2021-05-17 12:21:14 +00:00
" mediump float d = (dot( " + getM ( " woi " ) + " *position, " + getM ( " woi " ) + " *position) - dot(position, position)) / 2. / deno; \n "
2019-11-28 23:50:47 +00:00
" if(d < 0.) continue; \n "
2020-01-15 17:39:35 +00:00
" mediump vec4 next_position = position + d * tangent; \n "
2021-05-17 12:21:14 +00:00
" if(dot(next_position, tangent) < dot( " + getM ( " woi " ) + " *next_position, " + getM ( " woi " ) + " *tangent)) continue; \n "
2019-11-28 23:50:47 +00:00
" d /= xspeed; \n " ;
2019-10-28 16:33:17 +00:00
else if ( hyperbolic ) fmain + =
2021-05-17 12:21:14 +00:00
" mediump float v = ((position - " + getM ( " woi " ) + " * position)[3] / ( " + getM ( " woi " ) + " * tangent - tangent)[3]); \n "
2019-10-22 20:42:48 +00:00
" if(v > 1. || v < -1.) continue; \n "
2020-01-15 17:39:35 +00:00
" mediump float d = atanh(v); \n "
" mediump vec4 next_tangent = position * sinh(d) + tangent * cosh(d); \n "
2021-05-17 12:21:14 +00:00
" if(next_tangent[3] < ( " + getM ( " woi " ) + " * next_tangent)[3]) continue; \n " ;
2020-05-08 19:18:47 +00:00
else if ( sphere ) fmain + =
2021-05-17 12:21:14 +00:00
" mediump float v = ((position - " + getM ( " woi " ) + " * position)[3] / ( " + getM ( " woi " ) + " * tangent - tangent)[3]); \n "
2020-05-08 19:18:47 +00:00
" mediump float d = atan(v); \n "
" mediump vec4 next_tangent = -position * sin(d) + tangent * cos(d); \n "
2021-05-17 12:21:14 +00:00
" if(next_tangent[3] > ( " + getM ( " woi " ) + " * next_tangent)[3]) continue; \n " ;
2019-10-22 20:42:48 +00:00
else fmain + =
2021-05-17 12:21:14 +00:00
" mediump float deno = dot(position, tangent) - dot( " + getM ( " woi " ) + " *position, " + getM ( " woi " ) + " *tangent); \n "
2019-10-22 20:42:48 +00:00
" if(deno < 1e-6 && deno > -1e-6) continue; \n "
2021-05-17 12:21:14 +00:00
" mediump float d = (dot( " + getM ( " woi " ) + " *position, " + getM ( " woi " ) + " *position) - dot(position, position)) / 2. / deno; \n "
2019-10-22 20:42:48 +00:00
" if(d < 0.) continue; \n "
2020-01-15 17:39:35 +00:00
" mediump vec4 next_position = position + d * tangent; \n "
2021-05-17 12:21:14 +00:00
" if(dot(next_position, tangent) < dot( " + getM ( " woi " ) + " *next_position, " + getM ( " woi " ) + " *tangent)) continue; \n " ;
2020-10-15 14:37:43 +00:00
replace_str ( fmain , " [woi] " , " [walloffset+i] " ) ;
2021-05-17 12:21:14 +00:00
replace_str ( fmain , " (woi) " , " (walloffset+i) " ) ;
2019-10-22 20:42:48 +00:00
fmain + =
" if(d < dist) { dist = d; which = i; } \n "
" } \n " ;
2020-05-27 23:50:00 +00:00
if ( hyperbolic & & reg3 : : ultra_mirror_in ( ) ) {
2021-07-12 09:07:22 +00:00
fmain + = " for(int i= " + its ( S7 * 2 ) + " ; i< " + its ( S7 * 2 + isize ( cgi . heptshape - > vertices_only ) ) + " ; i++) { \n " ;
2021-05-17 12:21:14 +00:00
fmain + = " mat4 uMi = " + getM ( " i " ) + " ; " ;
2020-05-27 23:50:00 +00:00
fmain + =
2021-05-17 12:21:14 +00:00
" mediump float v = ((position - uMi * position)[3] / (uMi * tangent - tangent)[3]); \n "
2020-05-27 23:50:00 +00:00
" if(v > 1. || v < -1.) continue; \n "
" mediump float d = atanh(v); \n "
" mediump vec4 next_tangent = position * sinh(d) + tangent * cosh(d); \n "
2021-05-17 12:21:14 +00:00
" if(next_tangent[3] < (uMi * next_tangent)[3]) continue; \n "
2020-05-27 23:50:00 +00:00
" if(d < dist) { dist = d; which = i; } \n "
" } \n " ;
}
2019-11-02 09:40:22 +00:00
// 20: get to horosphere +uBLevel (take smaller root)
// 21: get to horosphere -uBLevel (take larger root)
2019-12-14 11:05:01 +00:00
if ( hyperbolic & & bt : : in ( ) ) {
2019-11-02 09:40:22 +00:00
fmain + =
" for(int i=20; i<22; i++) { \n "
2020-01-15 17:39:35 +00:00
" mediump float sgn = i == 20 ? -1. : 1.; \n "
" mediump vec4 zpos = xpush(uBLevel*sgn) * position; \n "
" mediump vec4 ztan = xpush(uBLevel*sgn) * tangent; \n "
" mediump float Mp = zpos.w - zpos.x; \n "
" mediump float Mt = ztan.w - ztan.x; \n "
" mediump float a = (Mp*Mp-Mt*Mt); \n "
" mediump float b = Mp/a; \n "
" mediump float c = (1.+Mt*Mt) / a; \n "
2019-11-02 09:40:22 +00:00
" if(b*b < c) continue; \n "
" if(sgn < 0. && Mt > 0.) continue; \n "
2020-01-15 17:39:35 +00:00
" mediump float zsgn = (Mt > 0. ? -sgn : sgn); \n "
" mediump float u = sqrt(b*b-c)*zsgn + b; \n "
" mediump float v = -(Mp*u-1.) / Mt; \n "
" mediump float d = asinh(v); \n "
2019-11-02 09:40:22 +00:00
" if(d < 0. && abs(log(position.w*position.w-position.x*position.x)) < uBLevel) continue; \n "
" if(d < dist) { dist = d; which = i; } \n "
" } \n " ;
}
2019-10-28 16:33:17 +00:00
if ( prod ) fmain + =
2020-05-08 19:14:31 +00:00
" if(zspeed > 0.) { mediump float d = (uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = sides-1; }} \n "
" if(zspeed < 0.) { mediump float d = (-uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = sides-2; }} \n " ;
2019-10-28 16:33:17 +00:00
fmain + = " } \n " ;
2019-10-23 16:52:57 +00:00
fmain + =
" if(dist < 0.) { dist = 0.; } \n " ;
fmain + =
2019-10-26 08:54:26 +00:00
" if(which == -1 && dist == 0.) return; " ;
2019-10-22 20:42:48 +00:00
}
2020-05-09 08:41:15 +00:00
2019-10-22 08:52:17 +00:00
// shift d units
2019-10-27 00:23:20 +00:00
if ( use_reflect ) fmain + =
" bool reflect = false; \n " ;
2019-10-28 16:33:17 +00:00
2021-02-01 20:26:25 +00:00
if ( in_h2xe ( ) & & ! stepbased ) fmain + =
2020-01-15 17:39:35 +00:00
" mediump float ch = cosh(dist*xspeed); mediump float sh = sinh(dist*xspeed); \n "
" mediump vec4 v = position * ch + tangent * sh; \n "
2019-10-28 16:33:17 +00:00
" tangent = tangent * ch + position * sh; \n "
" position = v; \n "
" zpos += dist * zspeed; \n " ;
2021-02-01 20:26:25 +00:00
else if ( in_s2xe ( ) & & ! stepbased ) fmain + =
2020-01-15 17:39:35 +00:00
" mediump float ch = cos(dist*xspeed); mediump float sh = sin(dist*xspeed); \n "
" mediump vec4 v = position * ch + tangent * sh; \n "
2019-10-28 16:33:17 +00:00
" tangent = tangent * ch - position * sh; \n "
" position = v; \n "
" zpos += dist * zspeed; \n " ;
2021-02-01 20:26:25 +00:00
else if ( in_e2xe ( ) & & ! stepbased ) fmain + =
2019-11-28 23:50:47 +00:00
" position = position + tangent * dist * xspeed; \n "
" zpos += dist * zspeed; \n " ;
2020-05-08 19:18:47 +00:00
else if ( hyperbolic & & ! stepbased ) fmain + =
2020-01-15 17:39:35 +00:00
" mediump float ch = cosh(dist); mediump float sh = sinh(dist); \n "
" mediump vec4 v = position * ch + tangent * sh; \n "
2019-10-21 22:37:57 +00:00
" tangent = tangent * ch + position * sh; \n "
2019-10-22 08:52:17 +00:00
" position = v; \n " ;
2020-05-08 19:18:47 +00:00
else if ( sphere & & ! stepbased ) fmain + =
" mediump float ch = cos(dist); mediump float sh = sin(dist); \n "
" mediump vec4 v = position * ch + tangent * sh; \n "
" tangent = tangent * ch - position * sh; \n "
" position = v; \n " ;
else if ( stepbased ) {
bool use_christoffel = true ;
2019-10-23 16:52:57 +00:00
2019-11-02 10:51:44 +00:00
if ( sol & & nih ) fsh + =
2020-01-15 17:39:35 +00:00
" mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) { \n "
2019-11-02 10:51:44 +00:00
" return vec4(-(vel.z*tra.x + vel.x*tra.z)*log(2.), (vel.z*tra.y + vel.y * tra.z)*log(3.), vel.x*tra.x * exp(2.*log(2.)*pos.z)*log(2.) - vel.y * tra.y * exp(-2.*log(3.)*pos.z)*log(3.), 0.); \n "
" } \n " ;
else if ( nih ) fsh + =
2020-01-15 17:39:35 +00:00
" mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) { \n "
2019-11-02 10:51:44 +00:00
" return vec4((vel.z*tra.x + vel.x*tra.z)*log(2.), (vel.z*tra.y + vel.y * tra.z)*log(3.), -vel.x*tra.x * exp(-2.*log(2.)*pos.z)*log(2.) - vel.y * tra.y * exp(-2.*log(3.)*pos.z)*log(3.), 0.); \n "
" } \n " ;
else if ( sol ) fsh + =
2020-01-15 17:39:35 +00:00
" mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) { \n "
2019-10-23 16:52:57 +00:00
" return vec4(-vel.z*tra.x - vel.x*tra.z, vel.z*tra.y + vel.y * tra.z, vel.x*tra.x * exp(2.*pos.z) - vel.y * tra.y * exp(-2.*pos.z), 0.); \n "
" } \n " ;
2020-05-31 01:31:05 +00:00
else if ( nil ) {
fsh + =
2020-01-15 17:39:35 +00:00
" mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) { \n "
" mediump float x = pos.x; \n "
2019-10-23 16:52:57 +00:00
" return vec4(x*vel.y*tra.y - 0.5*dot(vel.yz,tra.zy), -.5*x*dot(vel.yx,tra.xy) + .5 * dot(vel.zx,tra.xz), -.5*(x*x-1.)*dot(vel.yx,tra.xy)+.5*x*dot(vel.zx,tra.xz), 0.); \n "
// " return vec4(0.,0.,0.,0.);\n"
" } \n " ;
2020-05-31 01:31:05 +00:00
use_christoffel = false ;
}
2020-08-08 14:08:51 +00:00
else if ( sl2 | | stretch : : in ( ) ) {
if ( sl2 ) {
fsh + = " mediump mat4 s_translate(vec4 h) { \n "
" return mat4(h.w,h.z,h.y,h.x,-h.z,h.w,-h.x,h.y,h.y,-h.x,h.w,-h.z,h.x,h.y,h.z,h.w); \n "
" } \n " ;
}
else {
fsh + = " mediump mat4 s_translate(vec4 h) { \n "
" return mat4(h.w,h.z,-h.y,-h.x,-h.z,h.w,h.x,-h.y,h.y,-h.x,h.w,-h.z,h.x,h.y,h.z,h.w); \n "
" } \n " ;
}
2020-05-08 19:18:47 +00:00
fsh + = " mediump mat4 s_itranslate(vec4 h) { \n "
" h.xyz = -h.xyz; return s_translate(h); \n "
" } \n " ;
2020-08-08 14:08:51 +00:00
if ( stretch : : mstretch ) {
fsh + = " mediump vec4 christoffel(mediump vec4 pos, mediump vec4 vel, mediump vec4 tra) { \n "
2020-08-22 22:10:59 +00:00
" vel = s_itranslate(toOrig * pos) * toOrig * vel; \n "
" tra = s_itranslate(toOrig * pos) * toOrig * tra; \n "
" return fromOrig * s_translate(toOrig * pos) * vec4( \n " ;
2020-08-08 14:08:51 +00:00
for ( int i = 0 ; i < 3 ; i + + ) {
auto & c = stretch : : ms_christoffel ;
fsh + = " 0. " ;
for ( int j = 0 ; j < 3 ; j + + )
for ( int k = 0 ; k < 3 ; k + + )
if ( c [ i ] [ j ] [ k ] )
fsh + = " + vel[ " + its ( j ) + " ]*tra[ " + its ( k ) + " ]* " + to_glsl ( c [ i ] [ j ] [ k ] ) ;
fsh + = " , \n " ;
}
fsh + = " 0); \n "
" } \n " ;
}
else
use_christoffel = false ;
2020-05-08 19:18:47 +00:00
}
else use_christoffel = false ;
2020-04-11 22:40:15 +00:00
2020-05-08 19:18:47 +00:00
if ( use_christoffel ) fsh + = " mediump vec4 get_acc(mediump vec4 pos, mediump vec4 vel) { \n "
2020-04-11 22:40:15 +00:00
" return christoffel(pos, vel, vel); \n "
" } \n " ;
2019-10-23 16:52:57 +00:00
2019-12-14 11:28:45 +00:00
if ( sn : : in ( ) & & ! asonov ) fsh + = " uniform mediump float uBinaryWidth; \n " ;
2019-10-23 16:52:57 +00:00
fmain + =
" dist = next < minstep ? 2.*next : next; \n " ;
2020-08-08 14:08:51 +00:00
if ( nil & & ! use_christoffel ) fsh + =
2020-01-15 17:39:35 +00:00
" mediump vec4 translate(mediump vec4 a, mediump vec4 b) { \n "
2019-10-23 21:09:49 +00:00
" return vec4(a[0] + b[0], a[1] + b[1], a[2] + b[2] + a[0] * b[1], b[3]); \n "
" } \n "
2020-01-15 17:39:35 +00:00
" mediump vec4 translatev(mediump vec4 a, mediump vec4 t) { \n "
2019-10-23 21:09:49 +00:00
" return vec4(t[0], t[1], t[2] + a[0] * t[1], 0.); \n "
" } \n "
2020-01-15 17:39:35 +00:00
" mediump vec4 itranslate(mediump vec4 a, mediump vec4 b) { \n "
2019-10-23 21:09:49 +00:00
" return vec4(-a[0] + b[0], -a[1] + b[1], -a[2] + b[2] - a[0] * (b[1]-a[1]), b[3]); \n "
" } \n "
2020-01-15 17:39:35 +00:00
" mediump vec4 itranslatev(mediump vec4 a, mediump vec4 t) { \n "
2019-10-23 21:09:49 +00:00
" return vec4(t[0], t[1], t[2] - a[0] * t[1], 0.); \n "
" } \n " ;
2020-08-08 14:08:51 +00:00
// if(nil) fmain += "tangent = translate(position, itranslate(position, tangent));\n";
2019-10-23 21:09:49 +00:00
2020-05-08 19:18:47 +00:00
if ( use_christoffel ) fmain + =
2020-04-11 22:40:15 +00:00
" mediump vec4 vel = tangent * dist; \n "
" mediump vec4 acc1 = get_acc(position, vel); \n "
" mediump vec4 acc2 = get_acc(position + vel / 2., vel + acc1/2.); \n "
" mediump vec4 acc3 = get_acc(position + vel / 2. + acc1/4., vel + acc2/2.); \n "
" mediump vec4 acc4 = get_acc(position + vel + acc2/2., vel + acc3/2.); \n "
" mediump vec4 nposition = position + vel + (acc1+acc2+acc3)/6.; \n " ;
2020-08-08 14:08:51 +00:00
if ( ( sl2 | | stretch : : in ( ) ) & & use_christoffel ) {
if ( sl2 ) fmain + =
" nposition = nposition / sqrt(dot(position.zw, position.zw) - dot(nposition.xy, nposition.xy)); \n " ;
else if ( stretch : : in ( ) ) fmain + =
" nposition = nposition / sqrt(dot(nposition, nposition)); \n " ;
}
2020-05-08 19:18:47 +00:00
2020-08-08 14:08:51 +00:00
if ( ( sl2 | | stretch : : in ( ) ) & & ! use_christoffel ) {
2020-07-28 14:46:23 +00:00
ld SV = stretch : : not_squared ( ) ;
ld mul = ( sphere ? 1 : - 1 ) - 1 / SV / SV ;
fmain + =
" vec4 vel = s_itranslate(position) * tangent * dist; \n "
2020-08-08 14:08:51 +00:00
" vec4 vel1 = vel; vel1.z *= " + to_glsl ( stretch : : not_squared ( ) ) + " ; \n "
" mediump float vlen = length(vel1.xyz); \n "
2020-07-28 14:46:23 +00:00
" if(vel.z<0.) vlen=-vlen; \n "
2020-08-08 14:08:51 +00:00
" float z_part = vel1.z/vlen; \n "
2020-07-28 14:46:23 +00:00
" float x_part = sqrt(1.-z_part*z_part); \n "
" const float SV = " + to_glsl ( SV ) + " ; \n "
" float rparam = x_part / z_part / SV; \n "
" float beta = atan2(vel.y,vel.x); \n "
" if(vlen<0.) beta += PI; \n "
" mediump vec4 nposition, ntangent; \n " ;
if ( sl2 ) fmain + =
" if(rparam > 1.) { \n "
" float cr = 1./sqrt(rparam*rparam-1.); \n "
" float sr = rparam*cr; \n "
" float z = cr * " + to_glsl ( mul ) + " ; \n "
" float a = vlen / length(vec2(sr, cr/SV)); \n "
" float k = -a; \n "
" float u = z*a; \n "
" float xy = sr * sinh(k); \n "
" float zw = cr * sinh(k); \n "
" nposition = vec4( "
" -xy*cos(u+beta), "
" -xy*sin(u+beta), "
" zw*cos(u)-cosh(k)*sin(u), "
" zw*sin(u)+cosh(k)*cos(u) "
" ); \n "
" ntangent = vec4( "
" -sr*cosh(k)*k*cos(u+beta) + u*xy*sin(u+beta), "
" -sr*cosh(k)*k*sin(u+beta) - u*xy*cos(u+beta), "
" k*cr*cosh(k)*cos(u)-zw*sin(u)*u-k*sinh(k)*sin(u)-u*cosh(k)*cos(u), "
" k*cr*cosh(k)*sin(u)+u*zw*cos(u)+k*sinh(k)*cos(u)-u*cosh(k)*sin(u) "
" ); \n "
" } \n "
" else { \n "
" float r = atanh(rparam); \n "
" float cr = cosh(r); \n "
" float sr = sinh(r); \n "
" float z = cr * " + to_glsl ( mul ) + " ; \n "
" float a = vlen / length(vec2(sr, cr/SV)); \n "
" float k = -a; \n "
" float u = z*a; \n "
" float xy = sr * sin(k); \n "
" float zw = cr * sin(k); \n "
" ntangent = vec4( "
" -sr*cos(k)*k*cos(u+beta) + u*xy*sin(u+beta), "
" -sr*cos(k)*k*sin(u+beta) - u*xy*cos(u+beta), "
" k*cr*cos(k)*cos(u)-zw*sin(u)*u+k*sin(k)*sin(u)-u*cos(k)*cos(u), "
" k*cr*cos(k)*sin(u)+zw*cos(u)*u-k*sin(k)*cos(u)-u*cos(k)*sin(u) "
" ); \n "
" nposition = vec4( "
" -xy * cos(u+beta), "
" -xy * sin(u+beta), "
" zw * cos(u) - cos(k) * sin(u), "
" zw * sin(u) + cos(k)*cos(u) "
" ); \n "
" } \n " ;
else fmain + =
" if(true) { \n "
" float r = atan(rparam); \n "
" float cr = cos(r); \n "
" float sr = sin(r); \n "
" float z = cr * " + to_glsl ( mul ) + " ; \n "
" float a = vlen / length(vec2(sr, cr/SV)); \n "
" float k = a; \n "
" float u = z*a; \n "
" float xy = sr * sin(k); \n "
" float zw = cr * sin(k); \n "
" ntangent = vec4( "
" sr*cos(k)*k*cos(u+beta) - u*xy*sin(u+beta), "
" sr*cos(k)*k*sin(u+beta) + u*xy*cos(u+beta), "
" k*cr*cos(k)*cos(u)-zw*sin(u)*u+k*sin(k)*sin(u)-u*cos(k)*cos(u), "
" k*cr*cos(k)*sin(u)+zw*cos(u)*u-k*sin(k)*cos(u)-u*cos(k)*sin(u) "
" ); \n "
" nposition = vec4( "
" xy * cos(u+beta), "
" xy * sin(u+beta), "
" zw * cos(u) - cos(k) * sin(u), "
" zw * sin(u) + cos(k)*cos(u) "
" ); \n "
" } \n " ;
fmain + =
2020-08-08 14:08:51 +00:00
" ntangent = ntangent / dist; \n "
" ntangent = s_translate(position) * ntangent; \n "
" nposition = s_translate(position) * nposition; \n " ;
2020-07-28 14:46:23 +00:00
}
2021-02-01 21:51:24 +00:00
if ( nil & & ! use_christoffel & & ! eyes ) {
2019-10-23 21:09:49 +00:00
fmain + =
2020-01-15 17:39:35 +00:00
" mediump vec4 xp, xt; \n "
" mediump vec4 back = itranslatev(position, tangent); \n "
2019-10-23 21:09:49 +00:00
" if(back.x == 0. && back.y == 0.) { \n "
" xp = vec4(0., 0., back.z*dist, 1.); \n "
" xt = back; \n "
" } \n "
" else if(abs(back.z) == 0.) { \n "
" xp = vec4(back.x*dist, back.y*dist, back.x*back.y*dist*dist/2., 1.); \n "
" xt = vec4(back.x, back.y, dist*back.x*back.y, 0.); \n "
" } \n "
" else if(abs(back.z) < 1e-1) { \n "
2020-01-15 17:39:35 +00:00
// we use the midpoint method here, because the formulas below cause glitches due to mediump float precision
" mediump vec4 acc = christoffel(vec4(0,0,0,1), back, back); \n "
" mediump vec4 pos2 = back * dist / 2.; \n "
" mediump vec4 tan2 = back + acc * dist / 2.; \n "
" mediump vec4 acc2 = christoffel(pos2, tan2, tan2); \n "
2019-10-23 21:09:49 +00:00
" xp = vec4(0,0,0,1) + back * dist + acc2 / 2. * dist * dist; \n "
" xt = back + acc * dist; \n "
" } \n "
" else { \n "
2020-01-15 17:39:35 +00:00
" mediump float alpha = atan2(back.y, back.x); \n "
" mediump float w = back.z * dist; \n "
" mediump float c = length(back.xy) / back.z; \n "
2019-10-23 21:09:49 +00:00
" xp = vec4(2.*c*sin(w/2.) * cos(w/2.+alpha), 2.*c*sin(w/2.)*sin(w/2.+alpha), w*(1.+(c*c/2.)*((1.-sin(w)/w)+(1.-cos(w))/w * sin(w+2.*alpha))), 1.); \n "
" xt = back.z * vec4( "
" c*cos(alpha+w), "
" c*sin(alpha+w), "
" 1. + c*c*2.*sin(w/2.)*sin(alpha+w)*cos(alpha+w/2.), "
" 0.); \n "
" } \n "
2020-01-15 17:39:35 +00:00
" mediump vec4 nposition = translate(position, xp); \n " ;
2019-10-23 21:09:49 +00:00
}
2019-10-23 16:52:57 +00:00
2019-11-08 14:01:03 +00:00
if ( asonov ) {
2019-11-14 20:21:17 +00:00
fsh + = " uniform mediump mat4 uStraighten; \n " ;
2020-01-15 17:39:35 +00:00
fmain + = " mediump vec4 sp = uStraighten * nposition; \n " ;
2019-11-08 14:01:03 +00:00
}
2020-05-08 19:18:47 +00:00
2021-01-31 14:27:58 +00:00
if ( eyes ) {
fmain + =
2021-02-01 20:26:25 +00:00
" mediump float t = go + dist; \n " ;
fmain + = prod ?
" mediump vec4 v = at1 * t; \n " :
" mediump vec4 v = at0 * t; \n " ;
2021-01-31 14:27:58 +00:00
fmain + =
2021-02-01 20:26:25 +00:00
" v[3] = 1.; \n "
2021-02-01 21:51:24 +00:00
" mediump vec4 azeq = uEyeShift * v; \n " ;
if ( nil ) fmain + =
" mediump float alpha = atan2(azeq.y, azeq.x); \n "
" mediump float w = azeq.z; \n "
" mediump float c = length(azeq.xy) / azeq.z; \n "
" mediump vec4 xp = vec4(2.*c*sin(w/2.) * cos(w/2.+alpha), 2.*c*sin(w/2.)*sin(w/2.+alpha), w*(1.+(c*c/2.)*((1.-sin(w)/w)+(1.-cos(w))/w * sin(w+2.*alpha))), 1.); \n "
" mediump vec4 orig_position = vw * vec4(0., 0., 0., 1.); \n "
" mediump vec4 nposition = translate(orig_position, xp); \n " ;
else if ( prod ) {
2021-02-01 20:26:25 +00:00
fmain + =
" mediump float alen_xy = length(azeq.xy); \n " ;
fmain + = " mediump float nzpos = zpos + azeq.z; \n " ;
if ( in_h2xe ( ) ) {
fmain + = " azeq.xy *= sinh(alen_xy) / alen_xy; \n " ;
fmain + = " azeq.z = cosh(alen_xy); \n " ;
}
else if ( in_s2xe ( ) ) {
fmain + = " azeq.xy *= sin (alen_xy) / alen_xy; \n " ;
fmain + = " azeq.z = cos(alen_xy); \n " ;
}
else {
/* euclid */
fmain + = " azeq.z = 1.; \n " ;
}
fmain + = " azeq.w = 0.; \n " ;
fmain + =
2021-01-31 14:27:58 +00:00
" mediump vec4 nposition = vw * azeq; \n " ;
2021-02-01 20:26:25 +00:00
}
else {
fmain + =
" mediump float alen = length(azeq.xyz); \n " ;
if ( hyperbolic ) fmain + =
" azeq *= sinh(alen) / alen; \n "
" azeq[3] = cosh(alen); \n " ;
else if ( sphere ) fmain + =
" azeq *= sin(alen) / alen; \n "
" azeq[3] = cos(alen); \n " ;
else /* euclid */ fmain + =
" azeq[3] = 1; \n " ;
fmain + =
" mediump vec4 nposition = vw * azeq; \n " ;
}
2021-01-31 14:27:58 +00:00
}
else if ( hyperbolic ) {
2020-05-08 19:18:47 +00:00
fmain + =
" mediump float ch = cosh(dist); mediump float sh = sinh(dist); \n "
" mediump vec4 v = position * ch + tangent * sh; \n "
" mediump vec4 ntangent = tangent * ch + position * sh; \n "
" mediump vec4 nposition = v; \n " ;
}
2021-01-31 14:27:58 +00:00
else if ( sphere & & ! stretch : : in ( ) ) {
2020-05-08 19:18:47 +00:00
fmain + =
" mediump float ch = cos(dist); mediump float sh = sin(dist); \n "
" mediump vec4 v = position * ch + tangent * sh; \n "
" mediump vec4 ntangent = tangent * ch - position * sh; \n "
" mediump vec4 nposition = v; \n " ;
}
2021-02-01 20:26:25 +00:00
bool reg = hyperbolic | | sphere | | euclid | | sl2 | | prod ;
2019-10-23 16:52:57 +00:00
2020-05-08 19:18:47 +00:00
if ( reg ) {
fsh + = " mediump float len_h(vec4 h) { return 1. - h[3]; } \n " ;
2021-02-01 20:26:25 +00:00
string s = ( rotspace | | prod ) ? " -2 " : " " ;
2020-05-08 19:18:47 +00:00
fmain + =
" mediump float best = len(nposition); \n "
" for(int i=0; i<sides " + s + " ; i++) { \n "
2021-05-17 12:21:14 +00:00
" mediump float cand = len( " + getM ( " walloffset+i " ) + " * nposition); \n "
2020-05-08 19:18:47 +00:00
" if(cand < best) { best = cand; which = i; } \n "
" } \n " ;
if ( rotspace ) fmain + =
" if(which == -1) { \n "
" best = len_h(nposition); \n "
2021-05-17 12:21:14 +00:00
" mediump float cand1 = len_h( " + getM ( " walloffset+sides-2 " ) + " *nposition); \n "
2020-05-08 19:18:47 +00:00
" if(cand1 < best) { best = cand1; which = sides-2; } \n "
2021-05-17 12:21:14 +00:00
" mediump float cand2 = len_h( " + getM ( " walloffset+sides-1 " ) + " *nposition); \n "
2020-05-08 19:18:47 +00:00
" if(cand2 < best) { best = cand2; which = sides-1; } \n "
" } \n " ;
2021-02-01 20:26:25 +00:00
if ( prod ) {
fmain + =
" if(nzpos > uPLevel) which = sides-1; \n "
" if(nzpos <-uPLevel) which = sides-2; \n " ;
}
2020-05-08 19:18:47 +00:00
}
2021-02-01 21:51:24 +00:00
if ( nil ) fmain + =
" mediump float rz = (abs(nposition.x) > abs(nposition.y) ? -nposition.x*nposition.y : 0.) + nposition.z; \n " ;
2019-10-23 16:52:57 +00:00
fmain + =
" if(next >= minstep) { \n " ;
2021-03-21 10:29:20 +00:00
string hnilw = to_glsl ( nilv : : nilwidth / 2 ) ;
string hnilw2 = to_glsl ( nilv : : nilwidth * nilv : : nilwidth / 2 ) ;
2019-10-23 16:52:57 +00:00
2020-05-08 19:18:47 +00:00
if ( reg ) fmain + = " if(which != -1) { \n " ;
else if ( asonov ) fmain + =
2019-11-08 14:01:03 +00:00
" if(abs(sp.x) > 1. || abs(sp.y) > 1. || abs(sp.z) > 1.) { \n " ;
else if ( nih ) fmain + =
2019-11-02 10:51:44 +00:00
" if(abs(nposition.x) > uBinaryWidth || abs(nposition.y) > uBinaryWidth || abs(nposition.z) > .5) { \n " ;
else if ( sol ) fmain + =
2019-10-23 16:52:57 +00:00
" if(abs(nposition.x) > uBinaryWidth || abs(nposition.y) > uBinaryWidth || abs(nposition.z) > log(2.)/2.) { \n " ;
else fmain + =
2021-03-21 10:29:20 +00:00
" if(abs(nposition.x) > " + hnilw + " || abs(nposition.y) > " + hnilw + " || abs(rz) > " + hnilw2 + " ) { \n " ;
2019-10-23 16:52:57 +00:00
fmain + =
" next = dist / 2.; continue; \n "
" } \n "
" if(next < maxstep) next = next / 2.; \n "
" } \n "
" else { \n " ;
2019-12-14 11:28:45 +00:00
if ( sn : : in ( ) ) {
2019-11-08 14:01:03 +00:00
if ( asonov ) fmain + =
" if(sp.x > 1.) which = 4; \n "
" if(sp.y > 1.) which = 5; \n "
" if(sp.x <-1.) which = 10; \n "
" if(sp.y <-1.) which = 11; \n "
" if(sp.z > 1.) { \n "
2020-01-15 17:39:35 +00:00
" mediump float best = 999.; \n "
2019-11-08 14:01:03 +00:00
" for(int i=0; i<4; i++) { \n "
2021-05-17 12:21:14 +00:00
" mediump float cand = len(uStraighten * " + getM ( " i " ) + " * position); \n "
2019-11-08 14:01:03 +00:00
" if(cand < best) { best = cand; which = i;} \n "
" } \n "
" } \n "
" if(sp.z < -1.) { \n "
2020-01-15 17:39:35 +00:00
" mediump float best = 999.; \n "
2019-11-08 14:01:03 +00:00
" for(int i=6; i<10; i++) { \n "
2021-05-17 12:21:14 +00:00
" mediump float cand = len(uStraighten * " + getM ( " i " ) + " * position); \n "
2019-11-08 14:01:03 +00:00
" if(cand < best) { best = cand; which = i;} \n "
" } \n "
" } \n " ;
else if ( sol & & ! nih ) fmain + =
2019-10-23 16:52:57 +00:00
" if(nposition.x > uBinaryWidth) which = 0; \n "
" if(nposition.x <-uBinaryWidth) which = 4; \n "
" if(nposition.y > uBinaryWidth) which = 1; \n "
2019-11-02 10:51:44 +00:00
" if(nposition.y <-uBinaryWidth) which = 5; \n " ;
if ( nih ) fmain + =
" if(nposition.x > uBinaryWidth) which = 0; \n "
" if(nposition.x <-uBinaryWidth) which = 2; \n "
" if(nposition.y > uBinaryWidth) which = 1; \n "
" if(nposition.y <-uBinaryWidth) which = 3; \n " ;
if ( sol & & nih ) fmain + =
" if(nposition.z > .5) which = nposition.x > 0. ? 5 : 4; \n "
" if(nposition.z <-.5) which = nposition.y > uBinaryWidth/3. ? 8 : nposition.y < -uBinaryWidth/3. ? 6 : 7; \n " ;
if ( nih & & ! sol ) fmain + =
" if(nposition.z > .5) which = 4; \n "
" if(nposition.z < -.5) which = (nposition.y > uBinaryWidth/3. ? 9 : nposition.y < -uBinaryWidth/3. ? 5 : 7) + (nposition.x>0.?1:0); \n " ;
2019-11-08 14:01:03 +00:00
if ( sol & & ! nih & & ! asonov ) fmain + =
2019-10-23 16:52:57 +00:00
" if(nposition.z > log(2.)/2.) which = nposition.x > 0. ? 3 : 2; \n "
" if(nposition.z <-log(2.)/2.) which = nposition.y > 0. ? 7 : 6; \n " ;
2019-11-02 10:51:44 +00:00
}
2020-05-08 19:18:47 +00:00
else if ( nil ) fmain + =
2021-03-21 10:29:20 +00:00
" if(nposition.x > " + hnilw + " ) which = 3; \n "
" if(nposition.x <- " + hnilw + " ) which = 0; \n "
" if(nposition.y > " + hnilw + " ) which = 4; \n "
" if(nposition.y <- " + hnilw + " ) which = 1; \n "
" if(rz > " + hnilw2 + " ) which = 5; \n "
" if(rz <- " + hnilw2 + " ) which = 2; \n " ;
2019-10-23 16:52:57 +00:00
fmain + =
" next = maxstep; \n "
" } \n " ;
2020-05-08 19:18:47 +00:00
if ( use_christoffel ) fmain + =
2020-04-11 22:40:15 +00:00
" tangent = tangent + (acc1+2.*acc2+2.*acc3+acc4)/(6.*dist); \n " ;
2021-02-01 21:51:24 +00:00
else if ( nil & & ! eyes ) fmain + =
2020-05-08 19:18:47 +00:00
" tangent = translatev(position, xt); \n " ;
2021-01-31 14:27:58 +00:00
else if ( ! eyes )
fmain + =
2020-05-08 19:18:47 +00:00
" tangent = ntangent; \n " ;
2020-08-08 14:08:51 +00:00
2021-01-31 14:27:58 +00:00
if ( ! eyes ) fmain + =
2020-08-08 14:08:51 +00:00
" position = nposition; \n " ;
2021-01-31 14:27:58 +00:00
else fmain + = " vec4 position = nposition; \n " ;
2020-08-08 14:08:51 +00:00
if ( ( stretch : : in ( ) | | sl2 ) & & use_christoffel ) {
fmain + =
2020-08-22 22:10:59 +00:00
" tangent = s_itranslate(toOrig * position) * toOrig * tangent; \n "
2020-08-08 14:08:51 +00:00
" tangent[3] = 0.; \n " ;
if ( stretch : : mstretch )
fmain + =
" float nvelsquared = dot(tangent.xyz, (uATOI * tangent).xyz); \n " ;
else
fmain + =
" float nvelsquared = tangent.x * tangent.x + tangent.y * tangent.y + "
+ to_glsl ( stretch : : squared ( ) ) + " * tangent.z * tangent.z; \n " ;
fmain + =
" tangent /= sqrt(nvelsquared); \n "
2020-08-22 22:10:59 +00:00
" tangent = fromOrig * s_translate(toOrig * position) * tangent; \n " ;
2020-08-08 14:08:51 +00:00
}
2019-10-22 20:42:48 +00:00
}
2019-10-22 08:52:17 +00:00
else fmain + =
" position = position + tangent * dist; \n " ;
2019-10-22 20:42:48 +00:00
2021-01-31 14:27:58 +00:00
if ( ! eyes ) {
if ( hyperbolic ) fmain + =
" position /= sqrt(position.w*position.w - dot(position.xyz, position.xyz)); \n "
" tangent -= dot(vec4(-position.xyz, position.w), tangent) * position; \n "
" tangent /= sqrt(dot(tangent.xyz, tangent.xyz) - tangent.w*tangent.w); \n " ;
if ( in_h2xe ( ) ) fmain + =
" position /= sqrt(position.z*position.z - dot(position.xy, position.xy)); \n "
" tangent -= dot(vec3(-position.xy, position.z), tangent.xyz) * position; \n "
" tangent /= sqrt(dot(tangent.xy, tangent.xy) - tangent.z*tangent.z); \n " ;
}
2020-10-26 11:02:24 +00:00
2019-12-14 11:05:01 +00:00
if ( hyperbolic & & bt : : in ( ) ) {
2019-11-02 09:40:22 +00:00
fmain + =
" if(which == 20) { \n "
2020-01-15 17:39:35 +00:00
" mediump float best = 999.; \n "
2019-11-02 09:40:22 +00:00
" for(int i= " + its ( flat2 ) + " ; i< " + its ( S7 ) + " ; i++) { \n "
2021-05-17 12:21:14 +00:00
" mediump float cand = len( " + getM ( " i " ) + " * position); \n "
2019-11-02 09:40:22 +00:00
" if(cand < best) { best = cand; which = i; } \n "
" } \n "
" } \n "
" if(which == 21) { \n "
2020-01-15 17:39:35 +00:00
" mediump float best = 999.; \n "
2019-11-02 09:40:22 +00:00
" for(int i=0; i< " + its ( flat1 ) + " ; i++) { \n "
2021-05-17 12:21:14 +00:00
" mediump float cand = len( " + getM ( " i " ) + " * position); \n "
2019-11-02 09:40:22 +00:00
" if(cand < best) { best = cand; which = i; } \n "
" } \n "
// "gl_FragColor = vec4(.5 + .5 * sin((go+dist)*100.), 1, float(which)/3., 1); return;\n"
" } \n " ;
}
2019-10-23 16:52:57 +00:00
2020-07-07 20:16:38 +00:00
if ( volumetric : : on ) fmain + =
" if(dist > 0. && go < " + to_glsl ( hard_limit ) + " ) { \n "
" if(dist > " + to_glsl ( hard_limit ) + " - go) dist = " + to_glsl ( hard_limit ) + " - go; \n "
" mediump vec4 col = texture2D(tVolumetric, cid); \n "
" mediump float factor = col.w; col.w = 1.; \n "
2020-07-08 10:43:30 +00:00
" mediump float frac = exp(-(factor + 1. / uExpDecay) * dist); \n "
" gl_FragColor += left * (1.-frac) * col; \n "
" left *= frac; \n "
2020-07-07 20:16:38 +00:00
" } \n ; " ;
fmain + = " go = go + dist; \n " ;
2019-11-02 09:40:22 +00:00
2019-10-22 20:42:48 +00:00
fmain + = " if(which == -1) continue; \n " ;
2020-07-07 20:16:38 +00:00
2021-02-01 20:26:25 +00:00
if ( prod & & eyes ) fmain + = " position.w = -nzpos; \n " ;
else if ( prod ) fmain + = " position.w = -zpos ; \ n " ;
2019-10-28 16:33:17 +00:00
2020-05-27 23:50:00 +00:00
if ( reg3 : : ultra_mirror_in ( ) ) fmain + =
" if(which >= " + its ( S7 ) + " ) { "
2021-05-17 12:21:14 +00:00
" tangent = " + getM ( " which " ) + " * tangent; \n "
2020-05-27 23:50:00 +00:00
" continue; \n "
" } \n " ;
2019-10-22 08:52:17 +00:00
// apply wall color
fmain + =
2020-01-15 17:39:35 +00:00
" mediump vec2 u = cid + vec2(float(which) / float(uLength), 0); \n "
" mediump vec4 col = texture2D(tWallcolor, u); \n "
2019-11-03 12:36:06 +00:00
" if(col[3] > 0.0) { \n " ;
2021-01-31 14:27:58 +00:00
if ( eyes )
2021-02-07 19:41:47 +00:00
fmain + = " mediump float gou = go / uAbsUnit; \n " ;
2021-01-31 14:27:58 +00:00
else
2021-02-07 19:41:47 +00:00
fmain + = " mediump float gou = go; \n " ;
2019-11-08 13:59:19 +00:00
if ( hard_limit < NO_LIMIT )
2021-01-31 14:27:58 +00:00
fmain + = " if(gou > " + to_glsl ( hard_limit ) + " ) { gl_FragDepth = 1.; return; } \n " ;
2019-11-03 12:36:06 +00:00
if ( ! ( levellines & & disable_texture ) ) fmain + =
2020-05-08 19:14:31 +00:00
" mediump vec2 inface = map_texture(position, which+walloffset); \n "
2020-01-15 17:39:35 +00:00
" mediump vec3 tmap = texture2D(tTextureMap, u).rgb; \n "
2019-10-26 08:54:26 +00:00
" if(tmap.z == 0.) col.xyz *= min(1., (1.-inface.x)/ tmap.x); \n "
2019-10-26 08:32:44 +00:00
" else { \n "
2020-01-15 17:39:35 +00:00
" mediump vec2 inface2 = tmap.xy + tmap.z * inface; \n "
2019-10-26 08:32:44 +00:00
" col.xyz *= texture2D(tTexture, inface2).rgb; \n "
2019-11-03 12:36:06 +00:00
" } \n " ;
2020-07-07 20:16:38 +00:00
if ( volumetric : : on )
2021-01-31 14:27:58 +00:00
fmain + = " mediump float d = uExpStart * exp(-gou / uExpDecay); \n " ;
2020-07-07 20:16:38 +00:00
else
fmain + =
2021-01-31 14:27:58 +00:00
" mediump float d = max(1. - gou / uLinearSightRange, uExpStart * exp(-gou / uExpDecay)); \n " ;
2020-07-07 20:16:38 +00:00
2020-07-08 10:43:30 +00:00
if ( ! volumetric : : on ) fmain + =
2019-10-26 13:33:57 +00:00
" col.xyz = col.xyz * d + uFogColor.xyz * (1.-d); \n " ;
2019-10-23 16:52:57 +00:00
if ( nil ) fmain + =
2019-10-26 08:32:44 +00:00
" if(abs(abs(position.x)-abs(position.y)) < .005) col.xyz /= 2.; \n " ;
2019-10-23 16:52:57 +00:00
2019-10-26 08:55:19 +00:00
if ( use_reflect ) fmain + =
" if(col.w == 1.) { \n "
2020-05-09 16:30:36 +00:00
" col.w = " + to_glsl ( 1 - reflect_val ) + " ; \n "
2019-10-26 08:55:19 +00:00
" reflect = true; \n "
" } \n " ;
2019-10-26 12:11:44 +00:00
ld vnear = glhr : : vnear_default ;
ld vfar = glhr : : vfar_default ;
2019-10-23 16:52:57 +00:00
fmain + =
2019-10-27 00:23:20 +00:00
" gl_FragColor.xyz += left * col.xyz * col.w; \n " ;
if ( use_reflect ) fmain + =
" if(reflect && depthtoset) { \n " ;
else fmain + =
2019-10-26 12:11:44 +00:00
" if(col.w == 1.) { \n " ;
2021-01-31 14:27:58 +00:00
if ( hyperbolic & & ! eyes ) fmain + =
2020-11-01 20:39:18 +00:00
" mediump vec4 t = at0 * sinh(go); \n " ;
2019-10-26 12:11:44 +00:00
else fmain + =
2020-11-01 20:39:18 +00:00
" mediump vec4 t = at0 * go; \n " ;
fmain + =
" t.w = 1.; \n " ;
2019-10-27 00:23:20 +00:00
2019-11-03 12:36:06 +00:00
if ( levellines ) {
2021-01-31 14:27:58 +00:00
if ( hyperbolic & & ! eyes )
2019-11-03 12:36:06 +00:00
fmain + = " gl_FragColor.xyz *= 0.5 + 0.5 * cos(z/cosh(go) * uLevelLines * 2. * PI); \n " ;
else
fmain + = " gl_FragColor.xyz *= 0.5 + 0.5 * cos(z * uLevelLines * 2. * PI); \n " ;
2019-11-14 20:21:17 +00:00
fsh + = " uniform mediump float uLevelLines; \n " ;
2019-11-03 12:36:06 +00:00
}
2020-11-01 20:39:18 +00:00
if ( panini_alpha )
fmain + = panini_shader ( ) ;
2019-11-03 12:36:06 +00:00
2021-03-21 10:28:10 +00:00
else if ( stereo_alpha )
fmain + = stereo_shader ( ) ;
2020-01-15 17:39:35 +00:00
# ifndef GLES_ONLY
2019-10-26 12:11:44 +00:00
fmain + =
2020-11-01 20:39:18 +00:00
" gl_FragDepth = ( " + to_glsl ( - vnear - vfar ) + " +t.w* " + to_glsl ( 2 * vnear * vfar ) + " /t.z)/ " + to_glsl ( vnear - vfar ) + " ; \n "
2019-10-27 00:23:20 +00:00
" gl_FragDepth = (gl_FragDepth + 1.) / 2.; \n " ;
2020-01-15 17:39:35 +00:00
# endif
2019-10-27 00:23:20 +00:00
if ( ! use_reflect ) fmain + =
" return; \n " ;
else fmain + =
" depthtoset = false; \n " ;
fmain + =
2019-10-26 12:11:44 +00:00
" } \n "
2019-10-26 08:54:26 +00:00
" left *= (1. - col.w); \n "
2019-10-22 08:52:17 +00:00
" } \n " ;
2019-10-27 00:23:20 +00:00
if ( use_reflect ) {
2021-07-09 18:35:44 +00:00
if ( prod ) fmain + = " if(reflect && which >= sides-2) { zspeed = -zspeed; continue; } \n " ;
2019-12-14 11:05:01 +00:00
if ( hyperbolic & & bt : : in ( ) ) fmain + =
2019-11-02 09:40:22 +00:00
" if(reflect && (which < " + its ( flat1 ) + " || which >= " + its ( flat2 ) + " )) { \n "
2020-01-15 17:39:35 +00:00
" mediump float x = -log(position.w - position.x); \n "
" mediump vec4 xtan = xpush(-x) * tangent; \n "
" mediump float diag = (position.y*position.y+position.z*position.z)/2.; \n "
" mediump vec4 normal = vec4(1.-diag, -position.y, -position.z, -diag); \n "
" mediump float mdot = dot(xtan.xyz, normal.xyz) - xtan.w * normal.w; \n "
2019-11-02 09:40:22 +00:00
" xtan = xtan - normal * mdot * 2.; \n "
" tangent = xpush(x) * xtan; \n "
" continue; \n "
" } \n " ;
2019-11-09 11:12:16 +00:00
if ( asonov ) {
fmain + =
" if(reflect) { \n "
" if(which == 4 || which == 10) tangent = refl(tangent, position.z, uReflectX); \n "
" else if(which == 5 || which == 11) tangent = refl(tangent, position.z, uReflectY); \n "
" else tangent.z = -tangent.z; \n "
" } \n " ;
fsh + =
2019-11-14 20:21:17 +00:00
" uniform mediump vec4 uReflectX, uReflectY; \n "
2020-01-15 17:39:35 +00:00
" mediump vec4 refl(mediump vec4 t, float z, mediump vec4 r) { \n "
2019-11-09 11:12:16 +00:00
" t.x *= exp(z); t.y /= exp(z); \n "
" t -= dot(t, r) * r; \n "
" t.x /= exp(z); t.y *= exp(z); \n "
" return t; \n "
" } \n " ;
}
else if ( sol & & ! nih & & ! asonov ) fmain + =
2019-10-27 00:23:20 +00:00
" if(reflect) { \n "
" if(which == 0 || which == 4) tangent.x = -tangent.x; \n "
" else if(which == 1 || which == 5) tangent.y = -tangent.y; \n "
" else tangent.z = -tangent.z; \n "
" continue; \n "
" } \n " ;
2019-11-02 10:51:44 +00:00
else if ( nih ) fmain + =
" if(reflect) { \n "
" if(which == 0 || which == 2) tangent.x = -tangent.x; \n "
" else if(which == 1 || which == 3) tangent.y = -tangent.y; \n "
" else tangent.z = -tangent.z; \n "
" continue; \n "
" } \n " ;
2021-07-09 18:12:35 +00:00
else {
fmain + =
2019-10-27 00:23:20 +00:00
" if(reflect) { \n "
2021-07-09 18:12:35 +00:00
" tangent = " + getM ( " uMirrorShift+walloffset+which " ) + " * tangent; \n "
2019-10-27 00:23:20 +00:00
" continue; \n "
" } \n " ;
2021-07-09 18:12:35 +00:00
fsh + = " uniform int uMirrorShift; \n " ;
}
2019-10-27 00:23:20 +00:00
}
2019-10-22 08:52:17 +00:00
// next cell
fmain + =
2020-01-15 17:39:35 +00:00
" mediump vec4 connection = texture2D(tConnections, u); \n "
2019-10-28 16:33:17 +00:00
" cid = connection.xy; \n " ;
if ( prod ) fmain + =
2020-05-08 19:14:31 +00:00
" if(which == sides-2) { zpos += uPLevel+uPLevel; } \n "
" if(which == sides-1) { zpos -= uPLevel+uPLevel; } \n " ;
2019-10-28 16:33:17 +00:00
fmain + =
2019-10-25 22:01:12 +00:00
" int mid = int(connection.z * 1024.); \n "
2021-05-17 12:21:14 +00:00
" mediump mat4 m = " + getM ( " mid " ) + " * " + getM ( " walloffset+which " ) + " ; \n " ;
2021-01-31 14:27:58 +00:00
if ( eyes )
fmain + = " vw = m * vw; \n " ;
else fmain + =
2020-01-15 17:39:35 +00:00
" position = m * position; \n "
2020-08-22 22:10:59 +00:00
" tangent = m * tangent; \n " ;
if ( stretch : : mstretch ) fmain + =
" m = s_itranslate(m*vec4(0,0,0,1)) * m; "
" fromOrig = m * fromOrig; \n "
" m[0][1] = -m[0][1]; m[1][0] = -m[1][0]; \n " // inverse
" toOrig = toOrig * m; \n " ;
2019-10-22 08:52:17 +00:00
2020-11-14 12:53:19 +00:00
if ( many_cell_types ) {
2020-05-08 19:14:31 +00:00
fmain + =
2021-07-07 21:33:34 +00:00
" walloffset = int(connection.w * " + to_glsl ( max_wall_offset ) + " ); \n "
" sides = int(connection.w * " + to_glsl ( max_wall_offset * max_celltype ) + " ) - " + its ( max_celltype ) + " * walloffset; \n " ;
2020-05-08 19:14:31 +00:00
// fmain += "if(sides != 8) { gl_FragColor = vec4(.5,float(sides)/8.,.5,1); return; }";
}
2019-10-22 08:52:17 +00:00
fmain + =
2019-10-26 12:11:44 +00:00
" } \n "
2019-10-27 00:23:20 +00:00
" gl_FragColor.xyz += left * uFogColor.xyz; \n " ;
2020-01-15 17:39:35 +00:00
# ifndef GLES_ONLY
2019-10-27 00:23:20 +00:00
if ( use_reflect ) fmain + =
" if(depthtoset) gl_FragDepth = 1.; \n " ;
else fmain + =
" gl_FragDepth = 1.; \n " ;
2020-01-15 17:39:35 +00:00
# endif
2019-10-27 00:23:20 +00:00
fmain + =
2019-10-21 22:37:57 +00:00
" } " ;
2019-10-22 08:52:17 +00:00
fsh + = fmain ;
2020-03-29 15:35:42 +00:00
callhooks ( hooks_rayshader , vsh , fsh ) ;
2019-10-21 22:37:57 +00:00
our_raycaster = make_shared < raycaster > ( vsh , fsh ) ;
}
full_enable ( our_raycaster ) ;
}
2021-02-18 14:47:45 +00:00
void bind_array ( vector < array < float , 4 > > & v , GLint t , GLuint & tx , int id , int length ) {
2019-10-22 08:52:17 +00:00
if ( t = = - 1 ) println ( hlog , " bind to nothing " ) ;
2019-10-21 22:37:57 +00:00
glUniform1i ( t , id ) ;
if ( tx = = 0 ) glGenTextures ( 1 , & tx ) ;
glActiveTexture ( GL_TEXTURE0 + id ) ;
2020-10-15 14:37:43 +00:00
GLERR ( " activeTexture " ) ;
2019-10-25 22:01:12 +00:00
glBindTexture ( GL_TEXTURE_2D , tx ) ;
2020-10-15 14:37:43 +00:00
GLERR ( " bindTexture " ) ;
2019-10-21 22:37:57 +00:00
2019-10-25 22:01:12 +00:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
2020-10-15 14:37:43 +00:00
GLERR ( " texParameteri " ) ;
2019-10-21 22:37:57 +00:00
2020-10-15 14:37:43 +00:00
# ifdef GLES_ONLY
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , length , isize ( v ) / length , 0 , GL_RGBA , GL_FLOAT , & v [ 0 ] ) ;
# else
2019-10-26 15:03:29 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , 0x8814 /* GL_RGBA32F */ , length , isize ( v ) / length , 0 , GL_RGBA , GL_FLOAT , & v [ 0 ] ) ;
2020-10-15 14:37:43 +00:00
# endif
2019-10-21 22:37:57 +00:00
GLERR ( " bind_array " ) ;
}
2019-10-25 22:01:12 +00:00
void uniform2 ( GLint id , array < float , 2 > fl ) {
glUniform2f ( id , fl [ 0 ] , fl [ 1 ] ) ;
2019-10-25 13:05:17 +00:00
}
2019-12-06 13:14:27 +00:00
color_t color_out_of_range = 0x0F0800FF ;
2019-10-25 22:17:58 +00:00
2020-07-03 12:54:50 +00:00
transmatrix get_ms ( cell * c , int a , bool mirror ) {
int z = a ? 1 : - 1 ;
if ( c - > type = = 3 ) {
hyperpoint h =
project_on_triangle (
hybrid : : get_corner ( c , a , 0 , z ) ,
hybrid : : get_corner ( c , a , 1 , z ) ,
hybrid : : get_corner ( c , a , 2 , z )
) ;
transmatrix T = rspintox ( h ) ;
if ( mirror ) T = T * MirrorX ;
return T * xpush ( - 2 * hdist0 ( h ) ) * spintox ( h ) ;
}
else {
hyperpoint h = Hypc ;
for ( int a = 0 ; a < c - > type ; a + + ) {
hyperpoint corner = hybrid : : get_corner ( c , a , 0 , z ) ;
h + = corner ;
}
h = normalize ( h ) ;
ld d = hdist0 ( h ) ;
if ( h [ 2 ] > 0 ) d = - d ;
if ( mirror ) return MirrorZ * zpush ( 2 * d ) ;
return zpush ( 2 * d ) ;
}
}
2020-11-14 12:53:19 +00:00
int nesting ;
2021-07-09 18:12:35 +00:00
transmatrix mirrorize ( transmatrix T ) {
T = inverse ( T ) ;
hyperpoint h = tC0 ( T ) ;
ld d = hdist0 ( h ) ;
return rspintox ( h ) * xpush ( d / 2 ) * MirrorX * xpush ( - d / 2 ) * spintox ( h ) ;
}
2021-02-18 14:47:45 +00:00
struct raycast_map {
2021-03-09 13:09:58 +00:00
int saved_frameid ;
2021-02-18 14:47:45 +00:00
vector < cell * > lst ;
map < cell * , int > ids ;
vector < transmatrix > ms ;
2021-07-09 18:12:35 +00:00
int length , per_row , rows , mirror_shift ;
2021-02-18 14:47:45 +00:00
vector < array < float , 4 > > connections , wallcolor , texturemap , volumetric ;
void apply_shape ( ) {
length = 4096 ;
per_row = length / deg ;
rows = next_p2 ( ( isize ( lst ) + per_row - 1 ) / per_row ) ;
int q = length * rows ;
connections . resize ( q ) ;
wallcolor . resize ( q ) ;
texturemap . resize ( q ) ;
volumetric . resize ( q ) ;
}
2021-07-09 18:12:35 +00:00
2021-02-18 14:47:45 +00:00
void generate_initial_ms ( cell * cs ) {
auto sa = hybrid : : gen_sample_list ( ) ;
ms . clear ( ) ;
ms . resize ( sa . back ( ) . first , Id ) ;
for ( auto & p : sa ) {
int id = p . first ;
cell * c = p . second ;
if ( ! c ) continue ;
for ( int j = 0 ; j < c - > type ; j + + )
2021-07-09 17:33:01 +00:00
ms [ id + j ] = currentmap - > ray_iadj ( c , j ) ;
2021-02-18 14:47:45 +00:00
if ( WDIM = = 2 ) for ( int a : { 0 , 1 } ) {
ms [ id + c - > type + a ] = get_ms ( c , a , false ) ;
}
}
// println(hlog, ms);
2021-07-09 18:12:35 +00:00
mirror_shift = isize ( ms ) ;
2021-02-18 14:47:45 +00:00
if ( ! sol & & ! nil & & ( reflect_val | | reg3 : : ultra_mirror_in ( ) ) ) {
2021-07-09 18:12:35 +00:00
ms . resize ( mirror_shift * 2 ) ;
2021-02-18 14:47:45 +00:00
2021-07-09 18:12:35 +00:00
for ( auto & p : sa ) {
int id = p . first ;
cell * c = p . second ;
if ( ! c ) continue ;
for ( int j = 0 ; j < c - > type ; j + + )
ms [ mirror_shift + id + j ] = mirrorize ( ms [ id + j ] ) ;
if ( WDIM = = 2 ) for ( int a : { 0 , 1 } ) {
ms [ mirror_shift + id + c - > type + a ] = get_ms ( c , a , true ) ;
2021-02-18 14:47:45 +00:00
}
2021-07-09 18:12:35 +00:00
}
2021-02-18 14:47:45 +00:00
if ( reg3 : : ultra_mirror_in ( ) ) {
for ( auto v : cgi . ultra_mirrors )
ms . push_back ( v ) ;
}
}
if ( prod ) {
for ( auto p : sa ) {
int id = p . first ;
if ( id = = 0 ) continue ;
ms [ id - 2 ] = Id ;
ms [ id - 1 ] = Id ;
}
}
}
void generate_cell_listing ( cell * cs ) {
manual_celllister cl ;
cl . add ( cs ) ;
bool optimize = ! isWall3 ( cs ) ;
// vector<int> legaldir = { -1 };
for ( int i = 0 ; i < isize ( cl . lst ) ; i + + ) {
cell * c = cl . lst [ i ] ;
if ( racing : : on & & i > 0 & & c - > wall = = waBarrier ) continue ;
if ( optimize & & isWall3 ( c ) ) continue ;
forCellIdCM ( c2 , d , c ) {
// if(reflect_val == 0 && !((1<<d) & legaldir[i])) continue;
if ( rays_generate ) setdist ( c2 , 7 , c ) ;
/* if(!cl.listed(c2))
legaldir . push_back ( legaldir [ i ] & ~ ( 1 < < ( ( d + 3 ) % 6 ) ) ) ; */
cl . add ( c2 ) ;
if ( isize ( cl . lst ) > = max_cells ) goto finish ;
}
}
finish :
lst = cl . lst ;
ids . clear ( ) ;
for ( int i = 0 ; i < isize ( lst ) ; i + + ) ids [ lst [ i ] ] = i ;
}
array < float , 2 > enc ( int i , int a ) {
array < float , 2 > res ;
res [ 0 ] = ( ( i % per_row ) * deg + a + .5 ) / length ;
res [ 1 ] = ( ( i / per_row ) + .5 ) / rows ;
return res ;
}
void generate_connections ( cell * c , int id ) {
auto & vmap = volumetric : : vmap ;
if ( volumetric : : on ) {
celldrawer dd ;
dd . c = c ;
dd . setcolors ( ) ;
int u = ( id / per_row * length ) + ( id % per_row * deg ) ;
color_t vcolor ;
if ( vmap . count ( c ) )
vcolor = vmap [ c ] ;
else
vcolor = ( backcolor < < 8 ) ;
volumetric [ u ] = glhr : : acolor ( vcolor ) ;
}
forCellIdEx ( c1 , i , c ) {
int u = ( id / per_row * length ) + ( id % per_row * deg ) + i ;
if ( ! ids . count ( c1 ) ) {
wallcolor [ u ] = glhr : : acolor ( color_out_of_range | 0xFF ) ;
texturemap [ u ] = glhr : : makevertex ( 0.1 , 0 , 0 ) ;
continue ;
}
auto code = enc ( ids [ c1 ] , 0 ) ;
connections [ u ] [ 0 ] = code [ 0 ] ;
connections [ u ] [ 1 ] = code [ 1 ] ;
if ( isWall3 ( c1 ) ) {
celldrawer dd ;
dd . c = c1 ;
dd . setcolors ( ) ;
shiftmatrix Vf ;
dd . set_land_floor ( Vf ) ;
color_t wcol = darkena ( dd . wcol , 0 , 0xFF ) ;
int dv = get_darkval ( c1 , c - > c . spin ( i ) ) ;
float p = 1 - dv / 16. ;
wallcolor [ u ] = glhr : : acolor ( wcol ) ;
for ( int a : { 0 , 1 , 2 } ) wallcolor [ u ] [ a ] * = p ;
if ( qfi . fshape ) {
texturemap [ u ] = floor_texture_map [ qfi . fshape - > id ] ;
}
else
texturemap [ u ] = glhr : : makevertex ( 0.1 , 0 , 0 ) ;
}
else {
color_t col = transcolor ( c , c1 , winf [ c - > wall ] . color ) | transcolor ( c1 , c , winf [ c1 - > wall ] . color ) ;
if ( col = = 0 )
wallcolor [ u ] = glhr : : acolor ( 0 ) ;
else {
int dv = get_darkval ( c1 , c - > c . spin ( i ) ) ;
float p = 1 - dv / 16. ;
wallcolor [ u ] = glhr : : acolor ( col ) ;
for ( int a : { 0 , 1 , 2 } ) wallcolor [ u ] [ a ] * = p ;
texturemap [ u ] = glhr : : makevertex ( 0.001 , 0 , 0 ) ;
}
}
2021-07-09 08:09:31 +00:00
int wo = currentmap - > wall_offset ( c ) ;
2021-02-18 14:47:45 +00:00
if ( wo > = irays ) {
println ( hlog , " wo= " , wo , " irays = " , irays ) ;
reset_raycaster ( ) ;
return ;
}
transmatrix T = currentmap - > iadj ( c , i ) * inverse ( ms [ wo + i ] ) ;
2021-04-30 17:45:22 +00:00
if ( in_e2xe ( ) & & i > = c - > type - 2 )
T = Id ;
2021-02-18 14:47:45 +00:00
for ( int k = 0 ; k < = isize ( ms ) ; k + + ) {
2021-07-13 15:38:59 +00:00
if ( k < isize ( ms ) & & ! eqmatrix ( ms [ k ] , T , 1e-5 ) ) continue ;
2021-02-18 14:47:45 +00:00
if ( k = = isize ( ms ) ) ms . push_back ( T ) ;
connections [ u ] [ 2 ] = ( k + .5 ) / 1024. ;
break ;
}
2021-07-09 08:09:31 +00:00
auto wo1 = currentmap - > wall_offset ( c1 ) ;
if ( wo1 > = max_wall_offset )
println ( hlog , " error: wall_offset " , wo1 , " exceeds " , max_wall_offset ) ;
2021-07-07 21:33:34 +00:00
if ( c1 - > type > = max_celltype )
println ( hlog , " error: type " + its ( c1 - > type ) + " exceeds " , max_celltype ) ;
2021-07-09 08:09:31 +00:00
connections [ u ] [ 3 ] = ( wo1 * 1. / max_wall_offset ) + ( c1 - > type + ( WDIM = = 2 ? 2 : 0 ) + .5 ) * 1. / max_wall_offset / max_celltype ;
2021-02-18 14:47:45 +00:00
}
if ( WDIM = = 2 ) for ( int a : { 0 , 1 } ) {
celldrawer dd ;
dd . c = c ;
dd . setcolors ( ) ;
shiftmatrix Vf ;
dd . set_land_floor ( Vf ) ;
int u = ( id / per_row * length ) + ( id % per_row * deg ) + c - > type + a ;
wallcolor [ u ] = glhr : : acolor ( darkena ( dd . fcol , 0 , 0xFF ) ) ;
if ( qfi . fshape )
texturemap [ u ] = floor_texture_map [ qfi . fshape - > id ] ;
else
texturemap [ u ] = glhr : : makevertex ( 0.1 , 0 , 0 ) ;
}
}
void generate_connections ( ) {
int id = 0 ;
for ( cell * c : lst )
generate_connections ( c , id + + ) ;
}
bool gms_exceeded ( ) {
2021-06-01 16:02:58 +00:00
if ( m_via_texture ) return false ;
2021-02-18 14:47:45 +00:00
return isize ( ms ) > gms_array_size ;
}
void assign_uniforms ( raycaster * o ) {
2021-05-17 12:21:29 +00:00
if ( ! o ) return ;
2021-02-18 14:47:45 +00:00
glUniform1i ( o - > uLength , length ) ;
GLERR ( " uniform mediump length " ) ;
2021-05-17 12:21:14 +00:00
if ( m_via_texture ) {
int mlength = next_p2 ( isize ( ms ) ) ;
vector < array < float , 4 > > m_map ;
m_map . resize ( 4 * mlength ) ;
for ( int i = 0 ; i < isize ( ms ) ; i + + )
for ( int a = 0 ; a < 4 ; a + + )
2021-07-09 18:33:33 +00:00
for ( int b = 0 ; b < 4 ; b + + ) {
if ( MDIM = = 3 & & ( a = = 3 | | b = = 3 ) ) m_map [ i + a * mlength ] [ b ] = .5 ;
else m_map [ i + a * mlength ] [ b ] = ms [ i ] [ a ] [ b ] / ray_scale + .5 ;
}
2021-05-17 12:21:14 +00:00
bind_array ( m_map , o - > tM , txM , 7 , mlength ) ;
glUniform1f ( o - > uInvLengthM , 1. / mlength ) ;
}
else {
vector < glhr : : glmatrix > gms ;
for ( auto & m : ms ) gms . push_back ( glhr : : tmtogl_transpose3 ( m ) ) ;
glUniformMatrix4fv ( o - > uM , isize ( gms ) , 0 , gms [ 0 ] . as_array ( ) ) ;
}
2021-02-18 14:47:45 +00:00
bind_array ( wallcolor , o - > tWallcolor , txWallcolor , 4 , length ) ;
bind_array ( connections , o - > tConnections , txConnections , 3 , length ) ;
bind_array ( texturemap , o - > tTextureMap , txTextureMap , 5 , length ) ;
if ( volumetric : : on ) bind_array ( volumetric , o - > tVolumetric , txVolumetric , 6 , length ) ;
2021-07-09 18:12:35 +00:00
if ( o - > uMirrorShift ! = - 1 ) {
glUniform1i ( o - > uMirrorShift , mirror_shift ) ;
}
2021-02-18 14:47:45 +00:00
}
void create_all ( cell * cs ) {
2021-03-09 13:09:58 +00:00
saved_frameid = frameid ;
2021-02-18 14:47:45 +00:00
generate_initial_ms ( cs ) ;
generate_cell_listing ( cs ) ;
apply_shape ( ) ;
generate_connections ( ) ;
}
bool need_to_create ( cell * cs ) {
2021-03-09 13:09:58 +00:00
if ( ! fixed_map & & frameid ! = saved_frameid ) return true ;
2021-02-18 14:47:45 +00:00
return ! ids . count ( cs ) ;
}
} ;
unique_ptr < raycast_map > rmap ;
2021-05-12 18:19:45 +00:00
bool reset_rmap = false ;
2021-02-18 14:47:45 +00:00
2021-04-07 00:32:38 +00:00
EX void reset_raycaster ( ) {
2021-05-12 18:19:45 +00:00
our_raycaster = nullptr ;
reset_rmap = true ;
2021-04-07 00:32:38 +00:00
rots : : saved_matrices_ray = { } ;
}
2021-02-18 14:47:45 +00:00
2021-04-30 17:45:34 +00:00
EX void reset_raycaster_map ( ) {
rmap = nullptr ;
}
2019-10-25 12:50:48 +00:00
EX void cast ( ) {
2020-11-14 12:53:19 +00:00
// may call itself recursively in case of bugs -- just in case...
dynamicval < int > dn ( nesting , nesting + 1 ) ;
if ( nesting > 10 ) return ;
2020-06-03 15:40:16 +00:00
if ( isize ( cgi . raywall ) > irays ) reset_raycaster ( ) ;
2020-11-14 12:53:19 +00:00
2019-10-21 22:37:57 +00:00
enable_raycaster ( ) ;
2020-11-14 12:53:19 +00:00
auto & o = our_raycaster ;
if ( need_many_cell_types ( ) & & o - > uWallOffset = = - 1 ) {
reset_raycaster ( ) ;
cast ( ) ;
return ;
}
2019-10-23 21:10:50 +00:00
2019-10-25 12:50:48 +00:00
if ( comparison_mode )
2019-10-23 21:10:50 +00:00
glColorMask ( GL_TRUE , GL_FALSE , GL_FALSE , GL_TRUE ) ;
2019-10-21 22:37:57 +00:00
vector < glvertex > screen = {
glhr : : makevertex ( - 1 , - 1 , 1 ) ,
glhr : : makevertex ( - 1 , + 1 , 1 ) ,
glhr : : makevertex ( + 1 , - 1 , 1 ) ,
glhr : : makevertex ( - 1 , + 1 , 1 ) ,
glhr : : makevertex ( + 1 , - 1 , 1 ) ,
glhr : : makevertex ( + 1 , + 1 , 1 )
} ;
2019-11-16 02:04:01 +00:00
ld d = current_display - > eyewidth ( ) ;
if ( vid . stereo_mode = = sLR ) d = 2 * d - 1 ;
else d = - d ;
2019-10-21 22:37:57 +00:00
auto & cd = current_display ;
2019-11-16 02:04:01 +00:00
cd - > set_viewport ( global_projection ) ;
cd - > set_mask ( global_projection ) ;
2020-12-26 20:12:34 +00:00
2020-12-27 16:37:39 +00:00
# if CAP_VR
2021-01-31 14:27:58 +00:00
if ( o - > uEyeShift ! = - 1 ) {
2021-02-01 21:51:24 +00:00
transmatrix T = vrhr : : eyeshift ;
if ( nonisotropic )
T = inverse ( NLP ) * T ;
glUniformMatrix4fv ( o - > uEyeShift , 1 , 0 , glhr : : tmtogl_transpose3 ( T ) . as_array ( ) ) ;
2021-01-31 14:27:58 +00:00
glUniform1f ( o - > uAbsUnit , vrhr : : absolute_unit_in_meters ) ;
}
2020-12-30 13:20:30 +00:00
if ( vrhr : : rendering_eye ( ) ) {
2020-12-26 20:13:32 +00:00
glUniformMatrix4fv ( o - > uProjection , 1 , 0 , glhr : : tmtogl_transpose3 ( vrhr : : eyeproj ) . as_array ( ) ) ;
}
2020-12-27 16:37:39 +00:00
# else
2021-01-31 14:28:14 +00:00
if ( 0 ) ;
2020-12-27 16:37:39 +00:00
# endif
2020-12-26 20:13:32 +00:00
else {
transmatrix proj = Id ;
proj = eupush ( - global_projection * d , 0 ) * proj ;
proj = euscale ( cd - > tanfov / ( vid . stereo_mode = = sLR ? 2 : 1 ) , cd - > tanfov * cd - > ysize / cd - > xsize ) * proj ;
proj = eupush ( - ( ( cd - > xcenter - cd - > xtop ) * 2. / cd - > xsize - 1 ) , - ( ( cd - > ycenter - cd - > ytop ) * 2. / cd - > ysize - 1 ) ) * proj ;
glUniformMatrix4fv ( o - > uProjection , 1 , 0 , glhr : : tmtogl_transpose3 ( proj ) . as_array ( ) ) ;
}
2019-10-21 22:37:57 +00:00
2020-03-29 15:35:42 +00:00
if ( ! callhandlers ( false , hooks_rayset , o ) ) {
2019-10-28 16:33:17 +00:00
2019-11-13 23:26:50 +00:00
cell * cs = centerover ;
2019-10-28 16:33:17 +00:00
2020-07-27 16:49:04 +00:00
transmatrix T = cview ( ) . T ;
2019-11-16 02:04:01 +00:00
if ( global_projection )
T = xpush ( vid . ipd * global_projection / 2 ) * T ;
2019-11-14 16:20:55 +00:00
if ( nonisotropic ) T = NLP * T ;
2019-10-28 16:33:17 +00:00
T = inverse ( T ) ;
2019-11-14 18:33:55 +00:00
virtualRebase ( cs , T ) ;
2019-10-28 16:33:17 +00:00
2020-07-03 12:55:16 +00:00
int ray_fixes = 0 ;
2020-08-22 22:11:37 +00:00
transmatrix msm = stretch : : mstretch_matrix ;
2020-07-03 12:55:16 +00:00
back :
for ( int a = 0 ; a < cs - > type ; a + + )
2021-07-09 17:33:01 +00:00
if ( hdist0 ( currentmap - > ray_iadj ( cs , a ) * tC0 ( T ) ) < hdist0 ( tC0 ( T ) ) ) {
2020-07-03 12:55:16 +00:00
T = currentmap - > iadj ( cs , a ) * T ;
2020-08-22 22:11:37 +00:00
if ( o - > uToOrig ! = - 1 ) {
transmatrix HT = currentmap - > adj ( cs , a ) ;
HT = stretch : : itranslate ( tC0 ( HT ) ) * HT ;
msm = HT * msm ;
}
2020-07-03 12:55:16 +00:00
cs = cs - > move ( a ) ;
ray_fixes + + ;
2021-04-07 00:33:28 +00:00
if ( ray_fixes > 100 ) {
println ( hlog , " major ray error " ) ;
return ;
}
2020-07-03 12:55:16 +00:00
goto back ;
}
2021-04-07 00:33:28 +00:00
if ( ray_fixes ) println ( hlog , " ray error x " , ray_fixes ) ;
2020-07-03 12:55:16 +00:00
2019-10-28 16:33:17 +00:00
glUniformMatrix4fv ( o - > uStart , 1 , 0 , glhr : : tmtogl_transpose3 ( T ) . as_array ( ) ) ;
2019-11-14 16:20:55 +00:00
if ( o - > uLP ! = - 1 ) glUniformMatrix4fv ( o - > uLP , 1 , 0 , glhr : : tmtogl_transpose3 ( inverse ( NLP ) ) . as_array ( ) ) ;
2019-11-14 20:21:17 +00:00
GLERR ( " uniform mediump startid " ) ;
2019-10-21 22:37:57 +00:00
glUniform1f ( o - > uIPD , vid . ipd ) ;
2019-11-14 20:21:17 +00:00
GLERR ( " uniform mediump IPD " ) ;
2020-05-08 19:14:31 +00:00
2020-08-08 14:08:51 +00:00
if ( o - > uITOA ! = - 1 ) {
glUniformMatrix4fv ( o - > uITOA , 1 , 0 , glhr : : tmtogl_transpose3 ( stretch : : m_itoa ) . as_array ( ) ) ;
glUniformMatrix4fv ( o - > uATOI , 1 , 0 , glhr : : tmtogl_transpose3 ( stretch : : m_atoi ) . as_array ( ) ) ;
}
2020-08-22 22:10:59 +00:00
if ( o - > uToOrig ! = - 1 ) {
glUniformMatrix4fv ( o - > uToOrig , 1 , 0 , glhr : : tmtogl_transpose3 ( msm ) . as_array ( ) ) ;
glUniformMatrix4fv ( o - > uFromOrig , 1 , 0 , glhr : : tmtogl_transpose3 ( inverse ( msm ) ) . as_array ( ) ) ;
}
2020-08-08 14:08:51 +00:00
2020-05-08 19:14:31 +00:00
if ( o - > uWallOffset ! = - 1 ) {
2021-07-09 08:09:31 +00:00
glUniform1i ( o - > uWallOffset , currentmap - > wall_offset ( cs ) ) ;
2020-06-03 13:44:34 +00:00
glUniform1i ( o - > uSides , cs - > type + ( WDIM = = 2 ? 2 : 0 ) ) ;
2020-05-08 19:14:31 +00:00
}
2020-02-07 18:13:18 +00:00
2019-10-22 10:07:38 +00:00
vector < glvertex > wallx , wally ;
for ( auto & m : cgi . raywall ) {
wallx . push_back ( glhr : : pointtogl ( m [ 0 ] ) ) ;
wally . push_back ( glhr : : pointtogl ( m [ 1 ] ) ) ;
}
2021-05-17 12:21:14 +00:00
if ( wall_via_texture ) {
int wlength = next_p2 ( isize ( wallx ) ) ;
vector < array < float , 4 > > w_map ;
w_map . resize ( 4 * wlength ) ;
ld minval = 9 , maxval = - 9 ;
for ( int i = 0 ; i < isize ( wallx ) ; i + + ) {
for ( int a = 0 ; a < 4 ; a + + ) {
2021-07-07 21:33:34 +00:00
w_map [ i ] [ a ] = wallx [ i ] [ a ] / ray_scale + .5 ;
w_map [ i + wlength ] [ a ] = wally [ i ] [ a ] / ray_scale + .5 ;
2021-05-17 12:21:14 +00:00
minval = min < ld > ( minval , w_map [ i ] [ a ] ) ;
minval = min < ld > ( minval , w_map [ i + wlength ] [ a ] ) ;
maxval = max < ld > ( maxval , w_map [ i ] [ a ] ) ;
maxval = max < ld > ( maxval , w_map [ i + wlength ] [ a ] ) ;
}
}
// println(hlog, "wallrange = ", tie(minval, maxval), " wallx = ", isize(wallx), " wallstart = ", isize(cgi.wallstart));
for ( int i = 0 ; i < isize ( cgi . wallstart ) ; i + + )
w_map [ i + 2 * wlength ] [ 0 ] = ( cgi . wallstart [ i ] + .5 ) / wlength ;
bind_array ( w_map , o - > tWall , txWall , 8 , wlength ) ;
glUniform1f ( o - > uInvLengthWall , 1. / wlength ) ;
}
else {
vector < GLint > wallstart ;
for ( auto i : cgi . wallstart ) wallstart . push_back ( i ) ;
glUniform1iv ( o - > uWallstart , isize ( wallstart ) , & wallstart [ 0 ] ) ;
glUniform4fv ( o - > uWallX , isize ( wallx ) , & wallx [ 0 ] [ 0 ] ) ;
glUniform4fv ( o - > uWallY , isize ( wally ) , & wally [ 0 ] [ 0 ] ) ;
}
2019-10-22 10:07:38 +00:00
2019-11-03 12:36:06 +00:00
if ( o - > uLevelLines ! = - 1 )
glUniform1f ( o - > uLevelLines , levellines ) ;
2019-10-22 20:42:48 +00:00
if ( o - > uBinaryWidth ! = - 1 )
2019-11-02 10:51:44 +00:00
glUniform1f ( o - > uBinaryWidth , vid . binary_width / 2 * ( nih ? 1 : log ( 2 ) ) ) ;
2021-03-30 09:41:52 +00:00
# if CAP_SOLV
2019-11-08 14:01:03 +00:00
if ( o - > uStraighten ! = - 1 ) {
2019-11-08 14:35:23 +00:00
glUniformMatrix4fv ( o - > uStraighten , 1 , 0 , glhr : : tmtogl_transpose ( asonov : : straighten ) . as_array ( ) ) ;
2019-11-08 14:01:03 +00:00
}
2019-11-09 11:12:16 +00:00
if ( o - > uReflectX ! = - 1 ) {
auto h = glhr : : pointtogl ( tangent_length ( spin ( 90 * degree ) * asonov : : ty , 2 ) ) ;
glUniform4fv ( o - > uReflectX , 1 , & h [ 0 ] ) ;
h = glhr : : pointtogl ( tangent_length ( spin ( 90 * degree ) * asonov : : tx , 2 ) ) ;
glUniform4fv ( o - > uReflectY , 1 , & h [ 0 ] ) ;
}
2021-03-30 09:41:52 +00:00
# endif
2019-10-28 16:33:17 +00:00
if ( o - > uPLevel ! = - 1 )
glUniform1f ( o - > uPLevel , cgi . plevel / 2 ) ;
2020-10-15 14:33:52 +00:00
# if CAP_BT
2019-11-02 09:40:22 +00:00
if ( o - > uBLevel ! = - 1 )
2019-12-14 11:05:01 +00:00
glUniform1f ( o - > uBLevel , log ( bt : : expansion ( ) ) / 2 ) ;
2020-10-15 14:33:52 +00:00
# endif
2019-10-28 16:33:17 +00:00
2020-07-07 20:16:38 +00:00
if ( o - > uLinearSightRange ! = - 1 )
glUniform1f ( o - > uLinearSightRange , sightranges [ geometry ] ) ;
2019-10-25 13:05:17 +00:00
glUniform1f ( o - > uExpDecay , exp_decay_current ( ) ) ;
2020-07-07 20:16:38 +00:00
2019-10-25 13:05:17 +00:00
glUniform1f ( o - > uExpStart , exp_start ) ;
2019-10-26 13:33:57 +00:00
auto cols = glhr : : acolor ( darkena ( backcolor , 0 , 0xFF ) ) ;
2020-07-08 10:43:30 +00:00
if ( o - > uFogColor ! = - 1 )
glUniform4f ( o - > uFogColor , cols [ 0 ] , cols [ 1 ] , cols [ 2 ] , cols [ 3 ] ) ;
2021-02-18 14:47:45 +00:00
2021-05-12 18:19:45 +00:00
if ( reset_rmap ) rmap = nullptr , reset_rmap = false ;
2021-02-18 14:47:45 +00:00
if ( ! rmap ) rmap = ( unique_ptr < raycast_map > ) new raycast_map ;
2020-03-29 15:35:42 +00:00
2021-02-18 14:47:45 +00:00
if ( rmap - > need_to_create ( cs ) ) {
rmap - > create_all ( cs ) ;
if ( rmap - > gms_exceeded ( ) ) {
2021-06-01 16:02:58 +00:00
if ( isize ( rmap - > ms ) > gms_limit | | can_via_texture ) {
m_via_texture = true ;
wall_via_texture = true ;
println ( hlog , " enabling m_via_texture " ) ;
reset_raycaster ( ) ;
cast ( ) ;
}
else {
gms_array_size = isize ( rmap - > ms ) ;
println ( hlog , " changing gms_array_size to " , gms_array_size ) ;
reset_raycaster ( ) ;
cast ( ) ;
}
2021-02-18 14:47:45 +00:00
return ;
}
rmap - > assign_uniforms ( & * o ) ;
}
GLERR ( " uniform mediump start " ) ;
2021-05-17 12:21:29 +00:00
if ( ! o ) { cast ( ) ; return ; }
2021-02-18 14:47:45 +00:00
uniform2 ( o - > uStartid , rmap - > enc ( rmap - > ids [ cs ] , 0 ) ) ;
2020-03-29 15:35:42 +00:00
}
2019-10-26 13:33:57 +00:00
2020-10-15 14:37:43 +00:00
# if CAP_VERTEXBUFFER
glhr : : bindbuffer_vertex ( screen ) ;
glVertexAttribPointer ( hr : : aPosition , 4 , GL_FLOAT , GL_FALSE , sizeof ( glvertex ) , 0 ) ;
# else
2019-10-21 22:37:57 +00:00
glVertexAttribPointer ( hr : : aPosition , 4 , GL_FLOAT , GL_FALSE , sizeof ( glvertex ) , & screen [ 0 ] ) ;
2020-10-15 14:37:43 +00:00
# endif
2019-10-26 12:11:44 +00:00
if ( ray : : comparison_mode )
glhr : : set_depthtest ( false ) ;
else {
glhr : : set_depthtest ( true ) ;
glhr : : set_depthwrite ( true ) ;
}
2019-10-21 22:37:57 +00:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
2019-10-26 08:32:44 +00:00
glActiveTexture ( GL_TEXTURE0 + 0 ) ;
glBindTexture ( GL_TEXTURE_2D , floor_textures - > renderedTexture ) ;
2020-10-15 14:37:43 +00:00
GLERR ( " bind " ) ;
2019-10-21 22:37:57 +00:00
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
GLERR ( " finish " ) ;
}
2020-07-07 20:16:38 +00:00
EX namespace volumetric {
EX bool on ;
EX map < cell * , color_t > vmap ;
int intensity = 16 ;
EX void enable ( ) {
if ( ! on ) {
on = true ;
reset_raycaster ( ) ;
}
}
EX void random_fog ( ) {
enable ( ) ;
for ( cell * c : currentmap - > allcells ( ) )
vmap [ c ] = ( ( rand ( ) % 0x1000000 ) < < 8 ) | intensity ;
}
EX void menu ( ) {
cmode = sm : : SIDE | sm : : MAYDARK ;
gamescreen ( 0 ) ;
dialog : : init ( XLAT ( " volumetric raycasting " ) ) ;
2020-07-12 18:54:29 +00:00
if ( ! cheater ) {
dialog : : addItem ( XLAT ( " enable the cheat mode for additional options " ) , ' X ' ) ;
dialog : : add_action ( enable_cheat ) ;
dialog : : addBack ( ) ;
dialog : : display ( ) ;
return ;
}
2020-07-07 20:16:38 +00:00
dialog : : addBoolItem ( XLAT ( " active " ) , on , ' a ' ) ;
dialog : : add_action ( [ & ] {
on = ! on ;
reset_raycaster ( ) ;
} ) ;
dialog : : addSelItem ( XLAT ( " intensity of random coloring " ) , its ( intensity ) , ' i ' ) ;
dialog : : add_action ( [ ] {
dialog : : editNumber ( intensity , 0 , 255 , 5 , 15 , " " , " " ) ;
dialog : : reaction = random_fog ;
} ) ;
dialog : : addItem ( XLAT ( " color randomly " ) , ' r ' ) ;
dialog : : add_action ( random_fog ) ;
dialog : : addColorItem ( " color cell under cursor " , vmap . count ( centerover ) ? vmap [ centerover ] : 0 , ' c ' ) ;
dialog : : add_action ( [ & ] {
enable ( ) ;
dialog : : openColorDialog ( vmap [ centerover ] ) ;
dialog : : dialogflags | = sm : : SIDE ;
} ) ;
dialog : : addColorItem ( " color cell under player " , vmap . count ( cwt . at ) ? vmap [ cwt . at ] : 0 , ' p ' ) ;
dialog : : add_action ( [ & ] {
enable ( ) ;
dialog : : openColorDialog ( vmap [ cwt . at ] ) ;
dialog : : dialogflags | = sm : : SIDE ;
} ) ;
dialog : : addBreak ( 150 ) ;
dialog : : addHelp ( " This fills all the cells with glowing fog, for cool visualizations " ) ;
dialog : : addBreak ( 150 ) ;
dialog : : addBack ( ) ;
dialog : : display ( ) ;
}
EX }
2019-10-25 12:50:48 +00:00
EX void configure ( ) {
cmode = sm : : SIDE | sm : : MAYDARK ;
gamescreen ( 0 ) ;
dialog : : init ( XLAT ( " raycasting configuration " ) ) ;
dialog : : addBoolItem ( XLAT ( " available in current geometry " ) , available ( ) , 0 ) ;
dialog : : addBoolItem ( XLAT ( " use raycasting? " ) , want_use = = 2 ? true : in_use , ' u ' ) ;
if ( want_use = = 1 ) dialog : : lastItem ( ) . value = XLAT ( " SMART " ) ;
dialog : : add_action ( [ ] {
want_use + + ; want_use % = 3 ;
} ) ;
dialog : : addBoolItem_action ( XLAT ( " comparison mode " ) , comparison_mode , ' c ' ) ;
2019-10-25 13:05:17 +00:00
dialog : : addSelItem ( XLAT ( " exponential range " ) , fts ( exp_decay_current ( ) ) , ' r ' ) ;
dialog : : add_action ( [ & ] {
2019-11-08 14:00:09 +00:00
dialog : : editNumber ( exp_decay_current ( ) , 0 , 40 , 0.25 , 5 , XLAT ( " exponential range " ) ,
2019-10-25 13:05:17 +00:00
XLAT ( " brightness formula: max(1-d/sightrange, s*exp(-d/r)) " )
) ;
} ) ;
dialog : : addSelItem ( XLAT ( " exponential start " ) , fts ( exp_start ) , ' s ' ) ;
dialog : : add_action ( [ & ] {
dialog : : editNumber ( exp_start , 0 , 1 , 0.1 , 1 , XLAT ( " exponential start " ) ,
XLAT ( " brightness formula: max(1-d/sightrange, s*exp(-d/r)) \n " )
) ;
} ) ;
2019-11-08 13:59:19 +00:00
if ( hard_limit < NO_LIMIT )
dialog : : addSelItem ( XLAT ( " hard limit " ) , fts ( hard_limit ) , ' H ' ) ;
else
dialog : : addBoolItem ( XLAT ( " hard limit " ) , false , ' H ' ) ;
dialog : : add_action ( [ & ] {
if ( hard_limit > = NO_LIMIT ) hard_limit = 10 ;
dialog : : editNumber ( hard_limit , 0 , 100 , 1 , 10 , XLAT ( " hard limit " ) , " " ) ;
dialog : : reaction = reset_raycaster ;
dialog : : extra_options = [ ] {
dialog : : addItem ( " no limit " , ' N ' ) ;
dialog : : add_action ( [ ] { hard_limit = NO_LIMIT ; reset_raycaster ( ) ; } ) ;
} ;
} ) ;
2019-10-27 00:23:20 +00:00
if ( ! nil ) {
dialog : : addSelItem ( XLAT ( " reflective walls " ) , fts ( reflect_val ) , ' R ' ) ;
dialog : : add_action ( [ & ] {
dialog : : editNumber ( reflect_val , 0 , 1 , 0.1 , 0 , XLAT ( " reflective walls " ) , " " ) ;
dialog : : reaction = reset_raycaster ;
} ) ;
}
2019-10-25 13:18:31 +00:00
2021-02-07 19:39:39 +00:00
if ( is_stepbased ( ) ) {
2019-10-25 22:43:15 +00:00
dialog : : addSelItem ( XLAT ( " max step " ) , fts ( maxstep_current ( ) ) , ' x ' ) ;
dialog : : add_action ( [ ] {
2021-02-07 19:39:39 +00:00
auto & ms = maxstep_current ( ) ;
dialog : : editNumber ( maxstep_current ( ) , 1e-6 , 1 , .1 ,
& ms = = & maxstep_pro ? .05 :
& ms = = & maxstep_nil ? .1 : .5 ,
XLAT ( " max step " ) , " affects the precision of solving the geodesic equation in Solv " ) ;
2019-10-25 22:43:15 +00:00
dialog : : scaleLog ( ) ;
dialog : : bound_low ( 1e-9 ) ;
dialog : : reaction = reset_raycaster ;
} ) ;
dialog : : addSelItem ( XLAT ( " min step " ) , fts ( minstep ) , ' n ' ) ;
dialog : : add_action ( [ ] {
2019-10-26 13:42:38 +00:00
dialog : : editNumber ( minstep , 1e-6 , 1 , 0.1 , 0.001 , XLAT ( " min step " ) , " how precisely should we find out when do cross the cell boundary " ) ;
2019-10-25 22:43:15 +00:00
dialog : : scaleLog ( ) ;
dialog : : bound_low ( 1e-9 ) ;
dialog : : reaction = reset_raycaster ;
} ) ;
}
2020-07-07 20:16:38 +00:00
2021-05-24 09:42:46 +00:00
dialog : : addBoolItem ( XLAT ( " volumetric raycasting " ) , volumetric : : on , ' v ' ) ;
2020-07-07 20:16:38 +00:00
dialog : : add_action_push ( volumetric : : menu ) ;
2019-10-25 13:18:31 +00:00
dialog : : addSelItem ( XLAT ( " iterations " ) , its ( max_iter_current ( ) ) , ' s ' ) ;
dialog : : add_action ( [ & ] {
2019-10-26 13:42:38 +00:00
dialog : : editNumber ( max_iter_current ( ) , 0 , 600 , 1 , 60 , XLAT ( " iterations " ) , " in H3/H2xE/E3 this is the number of cell boundaries; in nonisotropic, the number of simulation steps " ) ;
2019-10-25 22:43:15 +00:00
dialog : : reaction = reset_raycaster ;
2019-10-25 13:18:31 +00:00
} ) ;
2019-10-25 22:12:30 +00:00
dialog : : addSelItem ( XLAT ( " max cells " ) , its ( max_cells ) , ' s ' ) ;
dialog : : add_action ( [ & ] {
dialog : : editNumber ( max_cells , 16 , 131072 , 0.1 , 4096 , XLAT ( " max cells " ) , " " ) ;
dialog : : scaleLog ( ) ;
dialog : : extra_options = [ ] {
dialog : : addBoolItem_action ( " generate " , rays_generate , ' G ' ) ;
2019-10-25 22:17:58 +00:00
dialog : : addColorItem ( XLAT ( " out-of-range color " ) , color_out_of_range , ' X ' ) ;
dialog : : add_action ( [ ] {
dialog : : openColorDialog ( color_out_of_range ) ;
dialog : : dialogflags | = sm : : SIDE ;
} ) ;
2019-10-25 22:12:30 +00:00
} ;
} ) ;
2020-05-16 08:55:38 +00:00
2020-11-14 12:53:19 +00:00
if ( gms_array_size > gms_limit & & ray : : in_use ) {
2020-05-16 08:55:38 +00:00
dialog : : addBreak ( 100 ) ;
2020-11-14 12:53:19 +00:00
dialog : : addHelp ( XLAT ( " unfortunately this honeycomb is too complex for the current implementation (%1>%2) " , its ( gms_array_size ) , its ( gms_limit ) ) ) ;
2020-05-16 08:55:38 +00:00
}
2019-11-03 12:36:06 +00:00
edit_levellines ( ' L ' ) ;
2019-10-25 13:05:17 +00:00
2019-10-25 12:50:48 +00:00
dialog : : addBack ( ) ;
dialog : : display ( ) ;
}
2019-10-25 22:12:40 +00:00
# if CAP_COMMANDLINE
int readArgs ( ) {
using namespace arg ;
if ( 0 ) ;
else if ( argis ( " -ray-do " ) ) {
PHASEFROM ( 2 ) ;
want_use = 2 ;
}
else if ( argis ( " -ray-dont " ) ) {
PHASEFROM ( 2 ) ;
want_use = 0 ;
}
else if ( argis ( " -ray-smart " ) ) {
PHASEFROM ( 2 ) ;
want_use = 1 ;
}
2020-05-08 19:20:33 +00:00
else if ( argis ( " -ray-range " ) ) {
PHASEFROM ( 2 ) ;
2020-07-03 12:55:16 +00:00
shift_arg_formula ( exp_start , reset_raycaster ) ;
shift_arg_formula ( exp_decay_current ( ) , reset_raycaster ) ;
2020-05-27 23:50:53 +00:00
}
else if ( argis ( " -ray-hard " ) ) {
PHASEFROM ( 2 ) ;
shift_arg_formula ( hard_limit ) ;
2020-05-08 19:20:33 +00:00
}
2019-11-02 21:31:50 +00:00
else if ( argis ( " -ray-out " ) ) {
PHASEFROM ( 2 ) ; shift ( ) ; color_out_of_range = arghex ( ) ;
}
2019-10-28 16:33:54 +00:00
else if ( argis ( " -ray-comp " ) ) {
PHASEFROM ( 2 ) ;
comparison_mode = true ;
}
2020-05-08 19:20:33 +00:00
else if ( argis ( " -ray-sol " ) ) {
PHASEFROM ( 2 ) ;
shift ( ) ; max_iter_sol = argi ( ) ;
shift_arg_formula ( maxstep_sol , reset_raycaster ) ;
reset_raycaster ( ) ;
}
2020-07-03 12:55:16 +00:00
else if ( argis ( " -ray-iter " ) ) {
PHASEFROM ( 2 ) ;
shift ( ) ; max_iter_current ( ) = argi ( ) ;
}
2020-08-22 22:11:47 +00:00
else if ( argis ( " -ray-step " ) ) {
PHASEFROM ( 2 ) ;
println ( hlog , " maxstep_current() is " , maxstep_current ( ) ) ;
shift_arg_formula ( maxstep_current ( ) ) ;
}
2019-10-25 22:12:40 +00:00
else if ( argis ( " -ray-cells " ) ) {
PHASEFROM ( 2 ) ; shift ( ) ;
rays_generate = true ;
max_cells = argi ( ) ;
}
2019-10-27 00:23:20 +00:00
else if ( argis ( " -ray-reflect " ) ) {
PHASEFROM ( 2 ) ;
2020-07-03 12:55:16 +00:00
shift_arg_formula ( reflect_val , reset_raycaster ) ;
2019-10-27 00:23:20 +00:00
}
2019-10-25 22:12:40 +00:00
else if ( argis ( " -ray-cells-no " ) ) {
PHASEFROM ( 2 ) ; shift ( ) ;
rays_generate = false ;
max_cells = argi ( ) ;
}
2020-07-08 10:43:30 +00:00
else if ( argis ( " -ray-random " ) ) {
start_game ( ) ;
shift ( ) ; volumetric : : intensity = argi ( ) ;
volumetric : : random_fog ( ) ;
}
else if ( argis ( " -ray-cursor " ) ) {
start_game ( ) ;
volumetric : : enable ( ) ;
shift ( ) ; volumetric : : vmap [ centerover ] = arghex ( ) ;
}
2019-10-25 22:12:40 +00:00
else return 1 ;
return 0 ;
}
2021-02-23 04:33:35 +00:00
auto hook = addHook ( hooks_args , 100 , readArgs )
+ addHook ( hooks_clearmemory , 40 , [ ] { rmap = { } ; } ) ;
2019-11-23 22:51:52 +00:00
# endif
# if CAP_CONFIG
2019-11-16 00:40:14 +00:00
void addconfig ( ) {
2021-02-01 00:45:10 +00:00
param_f ( exp_start , " ray_exp_start " ) ;
param_f ( exp_decay_exp , " ray_exp_decay_exp " ) ;
param_f ( maxstep_sol , " ray_maxstep_sol " ) ;
param_f ( maxstep_nil , " ray_maxstep_nil " ) ;
param_f ( minstep , " ray_minstep " ) ;
param_f ( reflect_val , " ray_reflect_val " ) ;
param_f ( hard_limit , " ray_hard_limit " ) ;
2019-11-16 00:40:14 +00:00
addsaver ( want_use , " ray_want_use " ) ;
2021-02-18 14:48:00 +00:00
param_f ( exp_decay_poly , " ray_exp_decay_poly " ) ;
2019-11-16 00:40:14 +00:00
addsaver ( max_iter_iso , " ray_max_iter_iso " ) ;
addsaver ( max_iter_sol , " ray_max_iter_sol " ) ;
addsaver ( max_cells , " ray_max_cells " ) ;
addsaver ( rays_generate , " ray_generate " ) ;
2021-02-18 14:47:45 +00:00
param_b ( fixed_map , " ray_fixed_map " ) ;
2019-11-16 00:40:14 +00:00
}
2019-11-23 22:51:52 +00:00
auto hookc = addHook ( hooks_configfile , 100 , addconfig ) ;
2019-10-25 22:12:40 +00:00
# endif
2019-11-23 22:51:52 +00:00
2019-11-03 13:19:11 +00:00
# endif
2019-10-25 22:12:40 +00:00
2020-03-21 09:49:07 +00:00
# if !CAP_RAY
2019-11-03 13:19:11 +00:00
EX always_false in_use ;
EX always_false comparison_mode ;
EX void reset_raycaster ( ) { }
EX void cast ( ) { }
# endif
2019-10-25 12:50:48 +00:00
EX }
2019-10-21 22:37:57 +00:00
}