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 {
2019-10-25 12:50:48 +00:00
EX namespace ray {
2019-11-03 13:19:11 +00:00
# if MAXMDIM >= 4
2019-10-25 12:50:48 +00:00
/** texture IDs */
2019-10-26 08:32:44 +00:00
GLuint txConnections = 0 , txWallcolor = 0 , txTextureMap = 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 ;
2019-10-25 13:05:17 +00:00
EX ld exp_start = 1 , exp_decay_exp = 4 , exp_decay_poly = 10 ;
2019-10-25 22:43:15 +00:00
EX ld maxstep_sol = .02 ;
EX ld maxstep_nil = .1 ;
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 ;
2019-10-25 13:18:31 +00:00
EX int max_iter_sol = 600 , max_iter_iso = 60 ;
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 ( ) {
2019-11-02 10:51:44 +00:00
return ( solnih | | hyperbolic ) ? 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 ( ) {
2019-10-25 21:24:31 +00:00
if ( nonisotropic ) return max_iter_sol ;
else return max_iter_iso ;
}
2019-10-25 22:43:15 +00:00
ld & maxstep_current ( ) {
2019-11-02 10:51:44 +00:00
if ( solnih ) return maxstep_sol ;
2019-10-25 22:43:15 +00:00
else return maxstep_nil ;
}
2019-10-21 22:37:57 +00:00
# define IN_ODS 0
2019-10-26 15:03:10 +00:00
eGeometry last_geometry ;
2019-10-25 12:50:48 +00:00
/** is the raycaster available? */
EX bool available ( ) {
2019-11-09 10:18:52 +00:00
if ( noGUI ) return false ;
if ( ! vid . usingGL ) return false ;
2019-10-25 12:50:48 +00:00
if ( WDIM = = 2 ) return false ;
2019-11-02 09:40:22 +00:00
if ( hyperbolic & & pmodel = = mdPerspective & & ! penrose )
2019-10-25 12:50:48 +00:00
return true ;
2019-11-23 19:39:38 +00:00
if ( nil & & S7 = = 8 )
return false ;
2019-11-02 10:51:44 +00:00
if ( ( solnih | | nil ) & & pmodel = = mdGeodesic )
2019-10-25 12:50:48 +00:00
return true ;
if ( euclid & & pmodel = = mdPerspective & & ! binarytiling )
return true ;
2019-10-28 16:33:17 +00:00
if ( prod & & PURE )
return true ;
2019-10-25 12:50:48 +00:00
return false ;
}
/** do we want to use the raycaster? */
EX bool requested ( ) {
if ( ! want_use ) return false ;
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 ;
return racing : : on | | quotient ;
}
2019-10-21 22:37:57 +00:00
struct raycaster : glhr : : GLprogram {
2019-11-16 02:04:01 +00:00
GLint uStart , uStartid , uM , uLength , uFovX , uFovY , uIPD , uShift ;
2019-10-22 10:07:38 +00:00
GLint uWallstart , uWallX , uWallY ;
2019-10-26 08:32:44 +00:00
GLint tConnections , tWallcolor , tTextureMap ;
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 ;
2019-10-21 22:37:57 +00:00
raycaster ( string vsh , string fsh ) : GLprogram ( vsh , fsh ) {
println ( hlog , " assigning " ) ;
uStart = glGetUniformLocation ( _program , " uStart " ) ;
uStartid = glGetUniformLocation ( _program , " uStartid " ) ;
uM = glGetUniformLocation ( _program , " uM " ) ;
uLength = glGetUniformLocation ( _program , " uLength " ) ;
uFovX = glGetUniformLocation ( _program , " uFovX " ) ;
uFovY = glGetUniformLocation ( _program , " uFovY " ) ;
2019-11-16 02:04:01 +00:00
uShift = glGetUniformLocation ( _program , " uShift " ) ;
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 " ) ;
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
2019-11-16 02:04:01 +00:00
uShift = glGetUniformLocation ( _program , " uShift " ) ;
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 " ) ;
2019-10-21 22:37:57 +00:00
}
} ;
shared_ptr < raycaster > our_raycaster ;
2019-10-26 15:02:20 +00:00
EX void reset_raycaster ( ) { our_raycaster = nullptr ; } ;
2019-10-25 22:43:15 +00:00
2019-10-28 16:33:17 +00:00
int deg ;
2019-10-21 22:37:57 +00:00
void enable_raycaster ( ) {
2019-10-26 15:03:10 +00:00
if ( geometry ! = last_geometry ) reset_raycaster ( ) ;
last_geometry = geometry ;
2019-10-28 16:33:17 +00:00
deg = S7 ; if ( prod ) deg + = 2 ;
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 ;
2019-10-26 08:55:19 +00:00
2019-10-21 22:37:57 +00:00
string vsh =
2019-11-14 20:21:17 +00:00
" attribute mediump vec4 aPosition; \n "
2019-11-16 02:04:01 +00:00
" uniform mediump float uFovX, uFovY, uShift; \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 "
2019-11-16 02:04:01 +00:00
" gl_Position = aPosition; at = aPosition; at.x += uShift; \n "
2019-10-21 22:37:57 +00:00
# if IN_ODS
" at[0] *= PI; at[1] *= PI; \n "
# else
" at[0] *= uFovX; at[1] *= uFovY; \n "
# endif
" } \n " ;
2019-10-26 22:58:02 +00:00
string rays = its ( isize ( cgi . raywall ) ) ;
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 mat4 uM[84]; \n "
" uniform mediump mat4 uTest; \n "
" uniform mediump vec2 uStartid; \n "
" uniform mediump sampler2D tConnections; \n "
" uniform mediump sampler2D tWallcolor; \n "
" uniform mediump sampler2D tTexture; \n "
" uniform mediump sampler2D tTextureMap; \n "
" uniform mediump vec4 uWallX[ " + rays + " ]; \n "
" uniform mediump vec4 uWallY[ " + rays + " ]; \n "
" uniform mediump vec4 uFogColor; \n "
" uniform mediump int uWallstart[ " + its ( deg + 1 ) + " ]; \n "
" uniform mediump float uLinearSightRange, uExpStart, uExpDecay; \n " ;
2019-10-22 08:52:17 +00:00
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
2019-11-02 09:40:22 +00:00
int flat1 = 0 , flat2 = S7 ;
if ( hyperbolic & & binarytiling ) {
2019-11-14 20:21:17 +00:00
fsh + = " uniform mediump float uBLevel; \n " ;
2019-11-02 09:40:22 +00:00
flat1 = binary : : dirs_outer ( ) ;
flat2 - = binary : : dirs_inner ( ) ;
}
if ( IN_ODS | | hyperbolic ) fsh + =
2019-10-21 22:37:57 +00:00
" mat4 xpush(float x) { return mat4( "
" 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 " ;
if ( IN_ODS ) fsh + =
2019-10-21 22:37:57 +00:00
" mat4 xzspin(float x) { return mat4( "
" cos(x), 0., sin(x), 0., \n "
" 0., 1., 0., 0., \n "
" -sin(x), 0., cos(x), 0., \n "
" 0., 0., 0., 1. "
" );} \n "
" mat4 yzspin(float x) { return mat4( "
" 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
2019-10-22 10:07:38 +00:00
fsh + =
" vec2 map_texture(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-11-02 09:40:22 +00:00
else if ( hyperbolic & & binarytiling ) fsh + =
" pos = vec4(-log(pos.w-pos.x), pos.y, pos.z, 1); \n "
" pos.yz *= exp(pos.x); \n " ;
2019-10-28 16:33:17 +00:00
else if ( hyperbolic ) 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 + =
" int s = uWallstart[which]; \n "
" int e = uWallstart[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 "
2019-10-22 10:07:38 +00:00
" vec2 v = vec2(dot(uWallX[i], pos), dot(uWallY[i], 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 " ;
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 + =
2019-10-21 22:37:57 +00:00
" float lambda = at[0]; \n " // -PI to PI
" float phi; \n "
" float eye; \n "
" if(at.y < 0.) { phi = at.y + PI/2.; eye = uIPD / 2.; } \n " // right
" else { phi = at.y - PI/2.; eye = -uIPD / 2.; } \n "
" mat4 vw = uStart * xzspin(-lambda) * xpush(eye) * yzspin(phi); \n "
2019-10-22 08:52:17 +00:00
" vec4 at0 = vec4(0., 0., 1., 0.); \n " ;
else fmain + =
2019-10-21 22:37:57 +00:00
" mat4 vw = uStart; \n "
2019-10-22 08:52:17 +00:00
" vec4 at0 = at; \n "
2019-10-26 08:54:26 +00:00
" gl_FragColor = vec4(0,0,0,1); \n "
" float left = 1.; \n "
2019-10-22 08:52:17 +00:00
" at0.y = -at.y; \n "
2019-10-21 22:37:57 +00:00
" at0.w = 0.; \n "
2019-10-22 08:52:17 +00:00
" at0.xyz = at0.xyz / length(at0.xyz); \n " ;
if ( hyperbolic ) fsh + = " float len(vec4 x) { return x[3]; } \n " ;
else fsh + = " float len(vec4 x) { return length(x.xyz); } \n " ;
2019-10-23 16:52:57 +00:00
if ( nonisotropic ) fmain + =
2019-10-25 22:43:15 +00:00
" const float maxstep = " + fts ( maxstep_current ( ) ) + " ; \n "
" const float minstep = " + fts ( minstep ) + " ; \n "
2019-10-23 16:52:57 +00:00
" float next = maxstep; \n " ;
2019-10-28 16:33:17 +00:00
if ( prod ) {
string sgn = in_h2xe ( ) ? " - " : " + " ;
fmain + =
" vec4 position = vw * vec4(0., 0., 1., 0.); \n "
2019-11-28 23:50:47 +00:00
" vec4 at1 = uLP * at0; \n " ;
if ( in_e2xe ( ) ) fmain + =
" float zpos = log(position.z); \n " ;
else fmain + =
" float zpos = log(position.z*position.z " + sgn + " position.x*position.x " + sgn + " position.y*position.y)/2.; \n " ;
fmain + =
2019-10-28 16:33:17 +00:00
" position *= exp(-zpos); \n "
" float zspeed = at1.z; \n "
" float xspeed = length(at1.xy); \n "
" vec4 tangent = vw * exp(-zpos) * vec4(at1.xy, 0, 0) / xspeed; \n " ;
}
else fmain + =
2019-10-22 08:52:17 +00:00
" vec4 position = vw * vec4(0., 0., 0., 1.); \n "
2019-10-28 16:33:17 +00:00
" vec4 tangent = vw * at0; \n " ;
fmain + =
2019-10-22 08:52:17 +00:00
" float go = 0.; \n "
2019-10-25 22:01:12 +00:00
" 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 + =
2019-10-22 20:42:48 +00:00
" float dist = 100.; \n " ;
fmain + =
" int which = -1; \n " ;
2019-11-28 23:50:47 +00:00
if ( in_e2xe ( ) ) 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 "
2019-10-22 08:52:17 +00:00
" float best = len(position); \n "
2019-10-26 07:25:55 +00:00
" for(int i=0; i< " + its ( S7 ) + " ; i++) { \n "
2019-10-22 08:52:17 +00:00
" float cand = len(uM[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
2019-10-23 16:52:57 +00:00
if ( ! nonisotropic ) {
2019-10-22 20:42:48 +00:00
fmain + =
2019-10-28 16:33:17 +00:00
" if(which == -1) { \n " ;
2019-11-02 09:40:22 +00:00
fmain + = " for(int i= " + its ( flat1 ) + " ; i< " + its ( flat2 ) + " ; i++) { \n " ;
2019-10-22 20:42:48 +00:00
2019-10-28 16:33:17 +00:00
if ( in_h2xe ( ) ) fmain + =
" float v = ((position - uM[i] * position)[2] / (uM[i] * tangent - tangent)[2]); \n "
" if(v > 1. || v < -1.) continue; \n "
" float d = atanh(v); \n "
" vec4 next_tangent = position * sinh(d) + tangent * cosh(d); \n "
" if(next_tangent[2] < (uM[i] * next_tangent)[2]) continue; \n "
" d /= xspeed; \n " ;
else if ( in_s2xe ( ) ) fmain + =
" float v = ((position - uM[i] * position)[2] / (uM[i] * tangent - tangent)[2]); \n "
" float d = atan(v); \n "
" vec4 next_tangent = tangent * cos(d) - position * sin(d); \n "
" if(next_tangent[2] > (uM[i] * next_tangent)[2]) continue; \n "
" d /= xspeed; \n " ;
2019-11-28 23:50:47 +00:00
else if ( in_e2xe ( ) ) fmain + =
" float deno = dot(position, tangent) - dot(uM[i]*position, uM[i]*tangent); \n "
" if(deno < 1e-6 && deno > -1e-6) continue; \n "
" float d = (dot(uM[i]*position, uM[i]*position) - dot(position, position)) / 2. / deno; \n "
" if(d < 0.) continue; \n "
" vec4 next_position = position + d * tangent; \n "
" if(dot(next_position, tangent) < dot(uM[i]*next_position, uM[i]*tangent)) continue; \n "
" d /= xspeed; \n " ;
2019-10-28 16:33:17 +00:00
else if ( hyperbolic ) fmain + =
2019-10-22 20:42:48 +00:00
" float v = ((position - uM[i] * position)[3] / (uM[i] * tangent - tangent)[3]); \n "
" if(v > 1. || v < -1.) continue; \n "
" float d = atanh(v); \n "
" vec4 next_tangent = position * sinh(d) + tangent * cosh(d); \n "
" if(next_tangent[3] < (uM[i] * next_tangent)[3]) continue; \n " ;
else fmain + =
" float deno = dot(position, tangent) - dot(uM[i]*position, uM[i]*tangent); \n "
" if(deno < 1e-6 && deno > -1e-6) continue; \n "
" float d = (dot(uM[i]*position, uM[i]*position) - dot(position, position)) / 2. / deno; \n "
" if(d < 0.) continue; \n "
" vec4 next_position = position + d * tangent; \n "
" if(dot(next_position, tangent) < dot(uM[i]*next_position, uM[i]*tangent)) continue; \n " ;
fmain + =
" 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)
if ( hyperbolic & & binarytiling ) {
fmain + =
" for(int i=20; i<22; i++) { \n "
" float sgn = i == 20 ? -1. : 1.; \n "
" vec4 zpos = xpush(uBLevel*sgn) * position; \n "
" vec4 ztan = xpush(uBLevel*sgn) * tangent; \n "
" float Mp = zpos.w - zpos.x; \n "
" float Mt = ztan.w - ztan.x; \n "
" float a = (Mp*Mp-Mt*Mt); \n "
" float b = Mp/a; \n "
" float c = (1.+Mt*Mt) / a; \n "
" if(b*b < c) continue; \n "
" if(sgn < 0. && Mt > 0.) continue; \n "
" float zsgn = (Mt > 0. ? -sgn : sgn); \n "
" float u = sqrt(b*b-c)*zsgn + b; \n "
" float v = -(Mp*u-1.) / Mt; \n "
" float d = asinh(v); \n "
" 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 + =
" if(zspeed > 0.) { float d = (uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = " + its ( S7 ) + " +1; }} \n "
" if(zspeed < 0.) { float d = (-uPLevel - zpos) / zspeed; if(d < dist) { dist = d; which = " + its ( S7 ) + " ; }} \n " ;
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
}
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
if ( in_h2xe ( ) ) fmain + =
" float ch = cosh(dist*xspeed); float sh = sinh(dist*xspeed); \n "
" vec4 v = position * ch + tangent * sh; \n "
" tangent = tangent * ch + position * sh; \n "
" position = v; \n "
" zpos += dist * zspeed; \n " ;
else if ( in_s2xe ( ) ) fmain + =
" float ch = cos(dist*xspeed); float sh = sin(dist*xspeed); \n "
" vec4 v = position * ch + tangent * sh; \n "
" tangent = tangent * ch - position * sh; \n "
" position = v; \n "
" zpos += dist * zspeed; \n " ;
2019-11-28 23:50:47 +00:00
else if ( in_e2xe ( ) ) fmain + =
" position = position + tangent * dist * xspeed; \n "
" zpos += dist * zspeed; \n " ;
2019-10-28 16:33:17 +00:00
else if ( hyperbolic ) fmain + =
2019-10-21 22:37:57 +00:00
" float ch = cosh(dist); float sh = sinh(dist); \n "
" vec4 v = position * ch + tangent * sh; \n "
" tangent = tangent * ch + position * sh; \n "
2019-10-22 08:52:17 +00:00
" position = v; \n " ;
2019-10-23 16:52:57 +00:00
else if ( nonisotropic ) {
2019-11-02 10:51:44 +00:00
if ( sol & & nih ) fsh + =
" vec4 christoffel(vec4 pos, vec4 vel, vec4 tra) { \n "
" 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 + =
" vec4 christoffel(vec4 pos, vec4 vel, vec4 tra) { \n "
" 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 + =
2019-10-23 16:52:57 +00:00
" vec4 christoffel(vec4 pos, vec4 vel, vec4 tra) { \n "
" 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 " ;
else fsh + =
" vec4 christoffel(vec4 pos, vec4 vel, vec4 tra) { \n "
" float x = pos.x; \n "
" 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 " ;
2019-11-14 20:21:17 +00:00
if ( solnih & & ! asonov ) fsh + = " uniform mediump float uBinaryWidth; \n " ;
2019-10-23 16:52:57 +00:00
fmain + =
" dist = next < minstep ? 2.*next : next; \n " ;
2019-10-23 21:09:49 +00:00
if ( nil ) fsh + =
" vec4 translate(vec4 a, vec4 b) { \n "
" return vec4(a[0] + b[0], a[1] + b[1], a[2] + b[2] + a[0] * b[1], b[3]); \n "
" } \n "
" vec4 translatev(vec4 a, vec4 t) { \n "
" return vec4(t[0], t[1], t[2] + a[0] * t[1], 0.); \n "
" } \n "
" vec4 itranslate(vec4 a, vec4 b) { \n "
" return vec4(-a[0] + b[0], -a[1] + b[1], -a[2] + b[2] - a[0] * (b[1]-a[1]), b[3]); \n "
" } \n "
" vec4 itranslatev(vec4 a, vec4 t) { \n "
" return vec4(t[0], t[1], t[2] - a[0] * t[1], 0.); \n "
" } \n " ;
if ( nil ) fmain + = " tangent = translate(position, itranslate(position, tangent)); \n " ;
2019-11-02 10:51:44 +00:00
if ( solnih ) fmain + =
2019-10-22 20:42:48 +00:00
" vec4 acc = christoffel(position, tangent, tangent); \n "
" vec4 pos2 = position + tangent * dist / 2.; \n "
" vec4 tan2 = tangent + acc * dist / 2.; \n "
" vec4 acc2 = christoffel(pos2, tan2, tan2); \n "
2019-10-23 16:52:57 +00:00
" vec4 nposition = position + tangent * dist + acc2 / 2. * dist * dist; \n " ;
2019-10-26 08:55:19 +00:00
2019-10-23 21:09:49 +00:00
if ( nil ) {
fmain + =
" vec4 xp, xt; \n "
" vec4 back = itranslatev(position, tangent); \n "
" 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 "
// we use the midpoint method here, because the formulas below cause glitches due to float precision
" vec4 acc = christoffel(vec4(0,0,0,1), back, back); \n "
" vec4 pos2 = back * dist / 2.; \n "
" vec4 tan2 = back + acc * dist / 2.; \n "
" vec4 acc2 = christoffel(pos2, tan2, tan2); \n "
" xp = vec4(0,0,0,1) + back * dist + acc2 / 2. * dist * dist; \n "
" xt = back + acc * dist; \n "
" } \n "
" else { \n "
" float alpha = atan2(back.y, back.x); \n "
" float w = back.z * dist; \n "
" float c = length(back.xy) / back.z; \n "
" 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 "
" vec4 nposition = translate(position, xp); \n " ;
}
2019-10-23 16:52:57 +00:00
if ( nil ) fmain + =
" float rz = (abs(nposition.x) > abs(nposition.y) ? -nposition.x*nposition.y : 0.) + nposition.z; \n " ;
2019-11-08 14:01:03 +00:00
if ( asonov ) {
2019-11-14 20:21:17 +00:00
fsh + = " uniform mediump mat4 uStraighten; \n " ;
2019-11-08 14:01:03 +00:00
fmain + = " vec4 sp = uStraighten * nposition; \n " ;
}
2019-10-23 16:52:57 +00:00
fmain + =
" if(next >= minstep) { \n " ;
2019-11-08 14:01:03 +00:00
if ( asonov ) fmain + =
" 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 + =
" if(abs(nposition.x) > .5 || abs(nposition.y) > .5 || abs(rz) > .5) { \n " ;
fmain + =
" next = dist / 2.; continue; \n "
" } \n "
" if(next < maxstep) next = next / 2.; \n "
" } \n "
" else { \n " ;
2019-11-02 10:51:44 +00:00
if ( solnih ) {
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 "
" float best = 999.; \n "
" for(int i=0; i<4; i++) { \n "
" float cand = len(uStraighten * uM[i] * position); \n "
" if(cand < best) { best = cand; which = i;} \n "
" } \n "
" } \n "
" if(sp.z < -1.) { \n "
" float best = 999.; \n "
" for(int i=6; i<10; i++) { \n "
" float cand = len(uStraighten * uM[i] * position); \n "
" 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
}
2019-10-23 16:52:57 +00:00
else fmain + =
" if(nposition.x > .5) which = 3; \n "
" if(nposition.x <-.5) which = 0; \n "
" if(nposition.y > .5) which = 4; \n "
" if(nposition.y <-.5) which = 1; \n "
" if(rz > .5) which = 5; \n "
" if(rz <-.5) which = 2; \n " ;
fmain + =
" next = maxstep; \n "
" } \n " ;
2019-10-23 21:09:49 +00:00
if ( nil ) fmain + =
" tangent = translatev(position, xt); \n " ;
2019-10-23 16:52:57 +00:00
fmain + =
2019-10-23 21:09:49 +00:00
" position = nposition; \n " ;
if ( ! nil ) fmain + =
2019-10-22 20:42:48 +00:00
" tangent = tangent + acc * dist; \n " ;
}
2019-10-22 08:52:17 +00:00
else fmain + =
" position = position + tangent * dist; \n " ;
2019-11-08 13:59:44 +00:00
# if CAP_FIX_RAYCAST
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 " ;
# endif
2019-10-22 20:42:48 +00:00
2019-11-02 09:40:22 +00:00
if ( hyperbolic & & binarytiling ) {
fmain + =
" if(which == 20) { \n "
" float best = 999.; \n "
" for(int i= " + its ( flat2 ) + " ; i< " + its ( S7 ) + " ; i++) { \n "
" float cand = len(uM[i] * position); \n "
" if(cand < best) { best = cand; which = i; } \n "
" } \n "
" } \n "
" if(which == 21) { \n "
" float best = 999.; \n "
" for(int i=0; i< " + its ( flat1 ) + " ; i++) { \n "
" float cand = len(uM[i] * position); \n "
" 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
2019-11-02 09:40:22 +00:00
fmain + = " go = go + dist; \n " ;
2019-10-22 20:42:48 +00:00
fmain + = " if(which == -1) continue; \n " ;
2019-11-02 09:40:22 +00:00
2019-10-28 16:33:17 +00:00
if ( prod ) fmain + = " position.w = -zpos; \n " ;
2019-10-22 08:52:17 +00:00
// apply wall color
fmain + =
2019-10-25 22:01:12 +00:00
" vec2 u = cid + vec2(float(which) / float(uLength), 0); \n "
" vec4 col = texture2D(tWallcolor, u); \n "
2019-11-03 12:36:06 +00:00
" if(col[3] > 0.0) { \n " ;
2019-11-08 13:59:19 +00:00
if ( hard_limit < NO_LIMIT )
fmain + = " if(go > float( " + fts ( hard_limit ) + " )) { gl_FragDepth = 1.; return; } \n " ;
2019-11-03 12:36:06 +00:00
if ( ! ( levellines & & disable_texture ) ) fmain + =
2019-10-22 10:07:38 +00:00
" vec2 inface = map_texture(position, which); \n "
2019-10-26 08:32:44 +00:00
" 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 "
" vec2 inface2 = tmap.xy + tmap.z * inface; \n "
" col.xyz *= texture2D(tTexture, inface2).rgb; \n "
2019-11-03 12:36:06 +00:00
" } \n " ;
fmain + =
2019-10-26 13:33:57 +00:00
" float d = max(1. - go / uLinearSightRange, uExpStart * exp(-go / uExpDecay)); \n "
" 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 "
2019-10-27 00:23:20 +00:00
" col.w = float( " + fts ( 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 " ;
if ( hyperbolic ) fmain + =
" float z = at0.z * sinh(go); \n "
" float w = 1.; \n " ;
else fmain + =
" float z = at0.z * go; \n "
" float w = 1.; \n " ;
2019-10-27 00:23:20 +00:00
2019-11-03 12:36:06 +00:00
if ( levellines ) {
if ( hyperbolic )
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
}
2019-10-26 12:11:44 +00:00
fmain + =
" gl_FragDepth = (-float( " + fts ( vnear + vfar ) + " )+w*float( " + fts ( 2 * vnear * vfar ) + " )/z)/float( " + fts ( vnear - vfar ) + " ); \n "
2019-10-27 00:23:20 +00:00
" gl_FragDepth = (gl_FragDepth + 1.) / 2.; \n " ;
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 ) {
2019-10-28 16:33:17 +00:00
if ( prod ) fmain + = " if(reflect && which >= " + its ( S7 ) + " ) { zspeed = -zspeed; continue; } \n " ;
2019-11-02 09:40:22 +00:00
if ( hyperbolic & & binarytiling ) fmain + =
" if(reflect && (which < " + its ( flat1 ) + " || which >= " + its ( flat2 ) + " )) { \n "
" float x = -log(position.w - position.x); \n "
" vec4 xtan = xpush(-x) * tangent; \n "
" float diag = (position.y*position.y+position.z*position.z)/2.; \n "
" vec4 normal = vec4(1.-diag, -position.y, -position.z, -diag); \n "
" float mdot = dot(xtan.xyz, normal.xyz) - xtan.w * normal.w; \n "
" 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 "
2019-11-09 11:12:16 +00:00
" vec4 refl(vec4 t, float z, vec4 r) { \n "
" 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 " ;
2019-10-27 00:23:20 +00:00
else fmain + =
" if(reflect) { \n "
2019-10-28 16:33:17 +00:00
" tangent = uM[ " + its ( deg ) + " +which] * tangent; \n "
2019-10-27 00:23:20 +00:00
" continue; \n "
" } \n " ;
}
2019-10-22 08:52:17 +00:00
// next cell
fmain + =
2019-10-25 22:01:12 +00:00
" vec4 connection = texture2D(tConnections, u); \n "
2019-10-28 16:33:17 +00:00
" cid = connection.xy; \n " ;
if ( prod ) fmain + =
" if(which == " + its ( S7 ) + " ) { zpos += uPLevel+uPLevel; continue; } \n "
" if(which == " + its ( S7 ) + " +1) { zpos -= uPLevel+uPLevel; continue; } \n " ;
fmain + =
2019-10-25 22:01:12 +00:00
" int mid = int(connection.z * 1024.); \n "
2019-10-25 13:11:44 +00:00
" position = uM[mid] * uM[which] * position; \n "
2019-10-28 16:33:17 +00:00
" tangent = uM[mid] * uM[which] * tangent; \n " ;
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 " ;
if ( use_reflect ) fmain + =
" if(depthtoset) gl_FragDepth = 1.; \n " ;
else fmain + =
" gl_FragDepth = 1.; \n " ;
fmain + =
2019-10-21 22:37:57 +00:00
" } " ;
2019-10-22 08:52:17 +00:00
fsh + = fmain ;
2019-10-21 22:37:57 +00:00
our_raycaster = make_shared < raycaster > ( vsh , fsh ) ;
}
full_enable ( our_raycaster ) ;
}
2019-10-25 22:01:12 +00:00
int length , per_row , rows ;
2019-10-21 22:37:57 +00:00
2019-10-22 08:52:17 +00:00
void bind_array ( vector < array < float , 4 > > & v , GLint t , GLuint & tx , int id ) {
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 ) ;
2019-10-25 22:01:12 +00:00
glBindTexture ( GL_TEXTURE_2D , tx ) ;
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 ) ;
2019-10-21 22:37:57 +00:00
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 ] ) ;
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-10-25 22:01:12 +00:00
array < float , 2 > enc ( int i , int a ) {
array < float , 2 > res ;
2019-10-28 16:33:17 +00:00
res [ 0 ] = ( ( i % per_row ) * deg + a + .5 ) / length ;
2019-10-25 22:01:12 +00:00
res [ 1 ] = ( ( i / per_row ) + .5 ) / rows ;
return res ;
} ;
2019-10-25 13:18:31 +00:00
2019-10-25 22:17:58 +00:00
color_t color_out_of_range = 0xFF0080FF ;
2019-10-25 12:50:48 +00:00
EX void cast ( ) {
2019-10-21 22:37:57 +00:00
enable_raycaster ( ) ;
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
auto & o = our_raycaster ;
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 ;
glUniform1f ( o - > uShift , - global_projection * 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 ) ;
glUniform1f ( o - > uFovX , cd - > tanfov / ( vid . stereo_mode = = sLR ? 2 : 1 ) ) ;
2019-10-21 22:37:57 +00:00
glUniform1f ( o - > uFovY , cd - > tanfov * cd - > ysize / cd - > xsize ) ;
2019-10-28 16:33:17 +00:00
deg = S7 ;
if ( prod ) deg + = 2 ;
2019-10-25 22:01:12 +00:00
length = 4096 ;
2019-10-28 16:33:17 +00:00
per_row = length / deg ;
2019-10-25 22:01:12 +00:00
vector < cell * > lst ;
2019-11-13 23:26:50 +00:00
cell * cs = centerover ;
2019-10-28 16:33:17 +00:00
transmatrix T = cview ( ) ;
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
2019-10-25 22:12:30 +00:00
if ( true ) {
manual_celllister cl ;
2019-10-28 16:33:17 +00:00
cl . add ( cs ) ;
2019-11-02 09:41:42 +00:00
bool optimize = ! isWall3 ( cs ) ;
2019-10-25 22:12:30 +00:00
for ( int i = 0 ; i < isize ( cl . lst ) ; i + + ) {
cell * c = cl . lst [ i ] ;
2019-10-25 22:27:31 +00:00
if ( racing : : on & & i > 0 & & c - > wall = = waBarrier ) continue ;
2019-11-02 09:41:42 +00:00
if ( optimize & & isWall3 ( c ) ) continue ;
2019-10-25 22:12:30 +00:00
forCellCM ( c2 , c ) {
if ( rays_generate ) setdist ( c2 , 7 , c ) ;
cl . add ( c2 ) ;
if ( isize ( cl . lst ) > = max_cells ) goto finish ;
}
}
finish :
lst = cl . lst ;
}
2019-10-21 22:37:57 +00:00
2019-10-25 22:01:12 +00:00
rows = next_p2 ( ( isize ( lst ) + per_row - 1 ) / per_row ) ;
2019-10-22 08:52:17 +00:00
2019-10-21 22:37:57 +00:00
map < cell * , int > ids ;
for ( int i = 0 ; i < isize ( lst ) ; i + + ) ids [ lst [ i ] ] = i ;
glUniform1i ( o - > uLength , length ) ;
2019-11-14 20:21:17 +00:00
GLERR ( " uniform mediump length " ) ;
2019-10-21 22:37:57 +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 start " ) ;
2019-10-26 12:17:50 +00:00
uniform2 ( o - > uStartid , enc ( ids [ cs ] , 0 ) ) ;
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 " ) ;
2019-10-28 16:33:17 +00:00
2019-10-21 22:37:57 +00:00
vector < transmatrix > ms ;
2019-11-13 23:27:59 +00:00
for ( int j = 0 ; j < S7 ; j + + ) ms . push_back ( currentmap - > iadj ( cwt . at , j ) ) ;
2019-10-28 16:33:17 +00:00
if ( prod ) ms . push_back ( Id ) ;
if ( prod ) ms . push_back ( Id ) ;
2019-10-27 00:23:20 +00:00
if ( ! sol & & ! nil & & reflect_val ) {
for ( int j = 0 ; j < S7 ; j + + ) {
transmatrix T = inverse ( ms [ j ] ) ;
hyperpoint h = tC0 ( T ) ;
ld d = hdist0 ( h ) ;
transmatrix U = rspintox ( h ) * xpush ( d / 2 ) * MirrorX * xpush ( - d / 2 ) * spintox ( h ) ;
ms . push_back ( U ) ;
}
}
2019-10-25 22:01:12 +00:00
vector < array < float , 4 > > connections ( length * rows ) ;
vector < array < float , 4 > > wallcolor ( length * rows ) ;
2019-10-26 08:32:44 +00:00
vector < array < float , 4 > > texturemap ( length * rows ) ;
2019-10-25 22:01:12 +00:00
2019-10-21 22:37:57 +00:00
if ( 1 ) for ( cell * c : lst ) {
int id = ids [ c ] ;
forCellIdEx ( c1 , i , c ) {
2019-10-28 16:33:17 +00:00
int u = ( id / per_row * length ) + ( id % per_row * deg ) + i ;
2019-10-21 22:37:57 +00:00
if ( ! ids . count ( c1 ) ) {
2019-10-26 07:14:38 +00:00
wallcolor [ u ] = glhr : : acolor ( color_out_of_range | 0xFF ) ;
2019-10-26 08:32:44 +00:00
texturemap [ u ] = glhr : : makevertex ( 0.1 , 0 , 0 ) ;
2019-10-21 22:37:57 +00:00
continue ;
}
2019-10-25 22:01:12 +00:00
auto code = enc ( ids [ c1 ] , 0 ) ;
connections [ u ] [ 0 ] = code [ 0 ] ;
connections [ u ] [ 1 ] = code [ 1 ] ;
2019-10-21 22:37:57 +00:00
if ( isWall3 ( c1 ) ) {
2019-10-25 10:44:41 +00:00
celldrawer dd ;
2019-11-25 19:05:52 +00:00
dd . c = c1 ;
2019-10-25 10:44:41 +00:00
dd . setcolors ( ) ;
2019-10-26 08:32:44 +00:00
transmatrix Vf ;
dd . set_land_floor ( Vf ) ;
2019-10-25 10:44:41 +00:00
color_t wcol = darkena ( dd . wcol , 0 , 0xFF ) ;
2019-10-26 07:14:38 +00:00
int dv = get_darkval ( c1 , c - > c . spin ( i ) ) ;
float p = 1 - dv / 16. ;
2019-10-21 22:37:57 +00:00
wallcolor [ u ] = glhr : : acolor ( wcol ) ;
2019-10-26 07:14:38 +00:00
for ( int a : { 0 , 1 , 2 } ) wallcolor [ u ] [ a ] * = p ;
2019-10-26 08:32:44 +00:00
if ( qfi . fshape ) {
texturemap [ u ] = floor_texture_map [ qfi . fshape - > id ] ;
}
else
texturemap [ u ] = glhr : : makevertex ( 0.1 , 0 , 0 ) ;
2019-10-21 22:37:57 +00:00
}
2019-10-26 08:54:26 +00:00
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 ) ;
}
}
2019-10-28 16:33:17 +00:00
if ( prod & & i > = S7 ) {
connections [ u ] [ 2 ] = ( S7 + .5 ) / 1024. ;
continue ;
}
2019-11-13 23:27:59 +00:00
transmatrix T = currentmap - > iadj ( c , i ) * inverse ( ms [ i ] ) ;
2019-10-21 22:37:57 +00:00
for ( int k = 0 ; k < = isize ( ms ) ; k + + ) {
if ( k < isize ( ms ) & & ! eqmatrix ( ms [ k ] , T ) ) continue ;
if ( k = = isize ( ms ) ) ms . push_back ( T ) ;
2019-10-25 22:01:12 +00:00
connections [ u ] [ 2 ] = ( k + .5 ) / 1024. ;
2019-10-21 22:37:57 +00:00
break ;
}
}
}
2019-10-22 10:07:38 +00:00
vector < GLint > wallstart ;
for ( auto i : cgi . wallstart ) wallstart . push_back ( i ) ;
glUniform1iv ( o - > uWallstart , isize ( wallstart ) , & wallstart [ 0 ] ) ;
vector < glvertex > wallx , wally ;
for ( auto & m : cgi . raywall ) {
wallx . push_back ( glhr : : pointtogl ( m [ 0 ] ) ) ;
wally . push_back ( glhr : : pointtogl ( m [ 1 ] ) ) ;
}
glUniform4fv ( o - > uWallX , isize ( wallx ) , & wallx [ 0 ] [ 0 ] ) ;
glUniform4fv ( o - > uWallY , isize ( wally ) , & wally [ 0 ] [ 0 ] ) ;
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 ) ) ) ;
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 ] ) ;
}
2019-10-28 16:33:17 +00:00
if ( o - > uPLevel ! = - 1 )
glUniform1f ( o - > uPLevel , cgi . plevel / 2 ) ;
2019-11-02 09:40:22 +00:00
if ( o - > uBLevel ! = - 1 )
glUniform1f ( o - > uBLevel , log ( binary : : expansion ( ) ) / 2 ) ;
2019-10-28 16:33:17 +00:00
2019-10-25 13:05:17 +00:00
glUniform1f ( o - > uLinearSightRange , sightranges [ geometry ] ) ;
glUniform1f ( o - > uExpDecay , exp_decay_current ( ) ) ;
glUniform1f ( o - > uExpStart , exp_start ) ;
2019-10-22 20:42:48 +00:00
2019-10-21 22:37:57 +00:00
vector < glhr : : glmatrix > gms ;
2019-10-28 16:33:17 +00:00
for ( auto & m : ms ) gms . push_back ( glhr : : tmtogl_transpose3 ( m ) ) ;
2019-10-21 22:37:57 +00:00
glUniformMatrix4fv ( o - > uM , isize ( gms ) , 0 , gms [ 0 ] . as_array ( ) ) ;
bind_array ( wallcolor , o - > tWallcolor , txWallcolor , 4 ) ;
bind_array ( connections , o - > tConnections , txConnections , 3 ) ;
2019-10-26 08:32:44 +00:00
bind_array ( texturemap , o - > tTextureMap , txTextureMap , 5 ) ;
2019-10-21 22:37:57 +00:00
2019-10-26 13:33:57 +00:00
auto cols = glhr : : acolor ( darkena ( backcolor , 0 , 0xFF ) ) ;
glUniform4f ( o - > uFogColor , cols [ 0 ] , cols [ 1 ] , cols [ 2 ] , cols [ 3 ] ) ;
2019-10-21 22:37:57 +00:00
glVertexAttribPointer ( hr : : aPosition , 4 , GL_FLOAT , GL_FALSE , sizeof ( glvertex ) , & screen [ 0 ] ) ;
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 ) ;
2019-10-21 22:37:57 +00:00
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
GLERR ( " finish " ) ;
}
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
2019-10-25 22:43:15 +00:00
if ( nonisotropic ) {
dialog : : addSelItem ( XLAT ( " max step " ) , fts ( maxstep_current ( ) ) , ' x ' ) ;
dialog : : add_action ( [ ] {
2019-10-26 13:42:38 +00:00
dialog : : editNumber ( maxstep_current ( ) , 1e-6 , 1 , 0.1 , sol ? 0.03 : 0.1 , 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 ;
} ) ;
}
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
} ;
} ) ;
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 ;
}
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 ;
}
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 ) ;
shift_arg_formula ( reflect_val ) ;
}
2019-10-25 22:12:40 +00:00
else if ( argis ( " -ray-cells-no " ) ) {
PHASEFROM ( 2 ) ; shift ( ) ;
rays_generate = false ;
max_cells = argi ( ) ;
}
else return 1 ;
return 0 ;
}
2019-11-23 22:51:52 +00:00
auto hook = addHook ( hooks_args , 100 , readArgs ) ;
# endif
# if CAP_CONFIG
2019-11-16 00:40:14 +00:00
void addconfig ( ) {
addparam ( exp_start , " ray_exp_start " ) ;
addparam ( exp_decay_exp , " ray_exp_decay_exp " ) ;
addparam ( maxstep_sol , " ray_maxstep_sol " ) ;
addparam ( maxstep_nil , " ray_maxstep_nil " ) ;
addparam ( minstep , " ray_minstep " ) ;
addparam ( reflect_val , " ray_reflect_val " ) ;
addparam ( hard_limit , " ray_hard_limit " ) ;
addsaver ( want_use , " ray_want_use " ) ;
addsaver ( exp_decay_poly , " ray_exp_decay_poly " ) ;
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 " ) ;
}
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
2019-11-03 13:19:11 +00:00
# if MAXMDIM == 3
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
}