Created
January 27, 2024 22:03
-
-
Save ingenieroariel/d8a85739ea01735cc71670f5e1832122 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local mouseSpeed = 0.5 | |
local touchSpeed = 0.1 | |
local maxFov = 90 | |
local minFov = 0.01 | |
local maxPitch = 85 | |
local minPitch = -85 | |
local camera = { | |
vid = nil, | |
yaw = 0, | |
pitch = 0, | |
fov = maxFov, | |
fovDirty = false, | |
} | |
function camera:rebuild() | |
camtag_model(self.vid, 0.01, 100.0, self.fov, VRESW/VRESH, true, false) | |
self.fovDirty = false | |
end | |
local mouse = { | |
devid = nil, | |
buttons = {}, | |
lastSample = {}, | |
} | |
local touchscreen = { | |
devid = nil, | |
touches = {}, | |
nTouches = 0, | |
} | |
local sphere | |
local shader = {} | |
local v = [[ | |
#version 140 | |
uniform mat4 modelview; | |
uniform mat4 projection; | |
attribute vec4 vertex; | |
attribute vec2 texcoord; | |
varying vec2 texco; | |
void main() { | |
texco = texcoord; | |
gl_Position = (projection * modelview) * vertex; | |
} | |
]] | |
local fragment_shader = [[ | |
#version 140 | |
#extension GL_EXT_gpu_shader4 : require | |
#define EPSILON 0.0000000000000001 | |
#define PI2 6.28318530717958647693 | |
#define PI 3.1415926535897932384626433832795 | |
#define NUM_BASE_CELLS 122 | |
#define NUM_ICOSA_FACES 20 | |
#define NUM_DIGITS 15 | |
#define M_AP7_ROT_RADS 0.333473172251832115336090755351601070065900389 | |
#define M_SQRT7 2.6457513110645905905016157536392604257102 | |
#define RES0_U_GNOMONIC 0.38196601125010500003 | |
#define M_SQRT3_2 0.8660254037844386467637231707529361834714 | |
#define M_SIN60 M_SQRT3_2 | |
#define CENTER_DIGIT 0 | |
#define K_AXES_DIGIT 1 | |
#define J_AXES_DIGIT 2 | |
#define JK_AXES_DIGIT 3 | |
#define I_AXES_DIGIT 4 | |
#define IK_AXES_DIGIT 5 | |
#define IJ_AXES_DIGIT 6 | |
#define INVALID_DIGIT 7 | |
struct CellIndex { | |
int resolution; | |
int baseCell; | |
int digits[NUM_DIGITS]; | |
}; | |
struct FIJK { | |
int face; | |
ivec3 coord; | |
}; | |
struct D { | |
FIJK homeFijk; | |
bool isPentagon; | |
ivec2 cwOffsetPent; | |
}; | |
struct R { | |
int baseCell; | |
int ccwRot60; | |
}; | |
/** @brief CoordIJK unit vectors corresponding to the 7 H3 digits. | |
*/ | |
const ivec3 UV[7] = ivec3[7]( | |
ivec3(0, 0, 0), | |
ivec3(0, 0, 1), | |
ivec3(0, 1, 0), | |
ivec3(0, 1, 1), | |
ivec3(1, 0, 0), | |
ivec3(1, 0, 1), | |
ivec3(1, 1, 0) | |
); | |
const int R60CCW[7] = int[7]( | |
CENTER_DIGIT, | |
IK_AXES_DIGIT, | |
JK_AXES_DIGIT, | |
K_AXES_DIGIT, | |
IJ_AXES_DIGIT, | |
I_AXES_DIGIT, | |
J_AXES_DIGIT | |
); | |
const int R60CW[7] = int[7]( | |
CENTER_DIGIT, | |
JK_AXES_DIGIT, | |
IJ_AXES_DIGIT, | |
J_AXES_DIGIT, | |
IK_AXES_DIGIT, | |
K_AXES_DIGIT, | |
I_AXES_DIGIT | |
); | |
/** @brief icosahedron face centers in lat/lng radians */ | |
const vec2 FCG[NUM_ICOSA_FACES] = vec2[NUM_ICOSA_FACES]( | |
vec2(0.803582649718989942, 1.248397419617396099), | |
vec2(1.307747883455638156, 2.536945009877921159), | |
vec2(1.054751253523952054, -1.347517358900396623), | |
vec2(0.600191595538186799, -0.450603909469755746), | |
vec2(0.491715428198773866, 0.401988202911306943), | |
vec2(0.172745327415618701, 1.678146885280433686), | |
vec2(0.605929321571350690, 2.953923329812411617), | |
vec2(0.427370518328979641, -1.888876200336285401), | |
vec2(-0.079066118549212831, -0.733429513380867741), | |
vec2(-0.230961644455383637, 0.506495587332349035), | |
vec2(0.079066118549212831, 2.408163140208925497), | |
vec2(0.230961644455383637, -2.635097066257444203), | |
vec2(-0.172745327415618701, -1.463445768309359553), | |
vec2(-0.605929321571350690, -0.187669323777381622), | |
vec2(-0.427370518328979641, 1.252716453253507838), | |
vec2(-0.600191595538186799, 2.690988744120037492), | |
vec2(-0.491715428198773866, -2.739604450678486295), | |
vec2(-0.803582649718989942, -1.893195233972397139), | |
vec2(-1.307747883455638156, -0.604647643711872080), | |
vec2(-1.054751253523952054, 1.794075294689396615) | |
); | |
/** @brief icosahedron face centers in x/y/z on the unit sphere */ | |
const vec3 FCP[NUM_ICOSA_FACES] = vec3[NUM_ICOSA_FACES]( | |
vec3(0.2199307791404606, 0.6583691780274996, 0.7198475378926182), | |
vec3(-0.2139234834501421, 0.1478171829550703, 0.9656017935214205), | |
vec3(0.1092625278784797, -0.4811951572873210, 0.8697775121287253), | |
vec3(0.7428567301586791, -0.3593941678278028, 0.5648005936517033), | |
vec3(0.8112534709140969, 0.3448953237639384, 0.4721387736413930), | |
vec3(-0.1055498149613921, 0.9794457296411413, 0.1718874610009365), | |
vec3(-0.8075407579970092, 0.1533552485898818, 0.5695261994882688), | |
vec3(-0.2846148069787907, -0.8644080972654206, 0.4144792552473539), | |
vec3(0.7405621473854482, -0.6673299564565524, -0.0789837646326737), | |
vec3(0.8512303986474293, 0.4722343788582681, -0.2289137388687808), | |
vec3(-0.7405621473854481, 0.6673299564565524, 0.0789837646326737), | |
vec3(-0.8512303986474292, -0.4722343788582682, 0.2289137388687808), | |
vec3(0.1055498149613919, -0.9794457296411413, -0.1718874610009365), | |
vec3(0.8075407579970092, -0.1533552485898819, -0.5695261994882688), | |
vec3(0.2846148069787908, 0.8644080972654204, -0.4144792552473539), | |
vec3(-0.7428567301586791, 0.3593941678278027, -0.5648005936517033), | |
vec3(-0.8112534709140971, -0.3448953237639382, -0.4721387736413930), | |
vec3(-0.2199307791404607, -0.6583691780274996, -0.7198475378926182), | |
vec3(0.2139234834501420, -0.1478171829550704, -0.9656017935214205), | |
vec3(-0.1092625278784796, 0.4811951572873210, -0.8697775121287253) | |
); | |
/** @brief icosahedron face ijk axes as azimuth in radians from face center to | |
* vertex 0/1/2 respectively | |
*/ | |
const vec3 FARC[NUM_ICOSA_FACES] = vec3[NUM_ICOSA_FACES]( | |
vec3(5.619958268523939882, 3.525563166130744542, | |
1.431168063737548730), | |
vec3(5.760339081714187279, 3.665943979320991689, | |
1.571548876927796127), | |
vec3(0.780213654393430055, 4.969003859179821079, | |
2.874608756786625655), | |
vec3(0.430469363979999913, 4.619259568766391033, | |
2.524864466373195467), | |
vec3(6.130269123335111400, 4.035874020941915804, | |
1.941478918548720291), | |
vec3(2.692877706530642877, 0.598482604137447119, | |
4.787272808923838195), | |
vec3(2.982963003477243874, 0.888567901084048369, | |
5.077358105870439581), | |
vec3(3.532912002790141181, 1.438516900396945656, | |
5.627307105183336758), | |
vec3(3.494305004259568154, 1.399909901866372864, | |
5.588700106652763840), | |
vec3(3.003214169499538391, 0.908819067106342928, | |
5.097609271892733906), | |
vec3(5.930472956509811562, 3.836077854116615875, | |
1.741682751723420374), | |
vec3(0.138378484090254847, 4.327168688876645809, | |
2.232773586483450311), | |
vec3(0.448714947059150361, 4.637505151845541521, | |
2.543110049452346120), | |
vec3(0.158629650112549365, 4.347419854898940135, | |
2.253024752505744869), | |
vec3(5.891865957979238535, 3.797470855586042958, | |
1.703075753192847583), | |
vec3(2.711123289609793325, 0.616728187216597771, | |
4.805518392002988683), | |
vec3(3.294508837434268316, 1.200113735041072948, | |
5.388903939827463911), | |
vec3(3.804819692245439833, 1.710424589852244509, | |
5.899214794638635174), | |
vec3(3.664438879055192436, 1.570043776661997111, | |
5.758833981448388027), | |
vec3(2.361378999196363184, 0.266983896803167583, | |
4.455774101589558636) | |
); | |
const R FIBC[NUM_ICOSA_FACES * 3 * 3 * 3] = R[NUM_ICOSA_FACES * 3 * 3 * 3]( | |
R(16, 0), R(18, 0), R(24, 0), | |
R(33, 0), R(30, 0), R(32, 3), | |
R(49, 1), R(48, 3), R(50, 3), | |
R(8, 0), R(5, 5), R(10, 5), | |
R(22, 0), R(16, 0), R(18, 0), | |
R(41, 1), R(33, 0), R(30, 0), | |
R(4, 0), R(0, 5), R(2, 5), | |
R(15, 1), R(8, 0), R(5, 5), | |
R(31, 1), R(22, 0), R(16, 0), | |
R(2, 0), R(6, 0), R(14, 0), | |
R(10, 0), R(11, 0), R(17, 3), | |
R(24, 1), R(23, 3), R(25, 3), | |
R(0, 0), R(1, 5), R(9, 5), | |
R(5, 0), R(2, 0), R(6, 0), | |
R(18, 1), R(10, 0), R(11, 0), | |
R(4, 1), R(3, 5), R(7, 5), | |
R(8, 1), R(0, 0), R(1, 5), | |
R(16, 1), R(5, 0), R(2, 0), | |
R(7, 0), R(21, 0), R(38, 0), | |
R(9, 0), R(19, 0), R(34, 3), | |
R(14, 1), R(20, 3), R(36, 3), | |
R(3, 0), R(13, 5), R(29, 5), | |
R(1, 0), R(7, 0), R(21, 0), | |
R(6, 1), R(9, 0), R(19, 0), | |
R(4, 2), R(12, 5), R(26, 5), | |
R(0, 1), R(3, 0), R(13, 5), | |
R(2, 1), R(1, 0), R(7, 0), | |
R(26, 0), R(42, 0), R(58, 0), | |
R(29, 0), R(43, 0), R(62, 3), | |
R(38, 1), R(47, 3), R(64, 3), | |
R(12, 0), R(28, 5), R(44, 5), | |
R(13, 0), R(26, 0), R(42, 0), | |
R(21, 1), R(29, 0), R(43, 0), | |
R(4, 3), R(15, 5), R(31, 5), | |
R(3, 1), R(12, 0), R(28, 5), | |
R(7, 1), R(13, 0), R(26, 0), | |
R(31, 0), R(41, 0), R(49, 0), | |
R(44, 0), R(53, 0), R(61, 3), | |
R(58, 1), R(65, 3), R(75, 3), | |
R(15, 0), R(22, 5), R(33, 5), | |
R(28, 0), R(31, 0), R(41, 0), | |
R(42, 1), R(44, 0), R(53, 0), | |
R(4, 4), R(8, 5), R(16, 5), | |
R(12, 1), R(15, 0), R(22, 5), | |
R(26, 1), R(28, 0), R(31, 0), | |
R(50, 0), R(48, 0), R(49, 3), | |
R(32, 0), R(30, 3), R(33, 3), | |
R(24, 3), R(18, 3), R(16, 3), | |
R(70, 0), R(67, 0), R(66, 3), | |
R(52, 3), R(50, 0), R(48, 0), | |
R(37, 3), R(32, 0), R(30, 3), | |
R(83, 0), R(87, 3), R(85, 3), | |
R(74, 3), R(70, 0), R(67, 0), | |
R(57, 1), R(52, 3), R(50, 0), | |
R(25, 0), R(23, 0), R(24, 3), | |
R(17, 0), R(11, 3), R(10, 3), | |
R(14, 3), R(6, 3), R(2, 3), | |
R(45, 0), R(39, 0), R(37, 3), | |
R(35, 3), R(25, 0), R(23, 0), | |
R(27, 3), R(17, 0), R(11, 3), | |
R(63, 0), R(59, 3), R(57, 3), | |
R(56, 3), R(45, 0), R(39, 0), | |
R(46, 3), R(35, 3), R(25, 0), | |
R(36, 0), R(20, 0), R(14, 3), | |
R(34, 0), R(19, 3), R(9, 3), | |
R(38, 3), R(21, 3), R(7, 3), | |
R(55, 0), R(40, 0), R(27, 3), | |
R(54, 3), R(36, 0), R(20, 0), | |
R(51, 3), R(34, 0), R(19, 3), | |
R(72, 0), R(60, 3), R(46, 3), | |
R(73, 3), R(55, 0), R(40, 0), | |
R(71, 3), R(54, 3), R(36, 0), | |
R(64, 0), R(47, 0), R(38, 3), | |
R(62, 0), R(43, 3), R(29, 3), | |
R(58, 3), R(42, 3), R(26, 3), | |
R(84, 0), R(69, 0), R(51, 3), | |
R(82, 3), R(64, 0), R(47, 0), | |
R(76, 3), R(62, 0), R(43, 3), | |
R(97, 0), R(89, 3), R(71, 3), | |
R(98, 3), R(84, 0), R(69, 0), | |
R(96, 3), R(82, 3), R(64, 0), | |
R(75, 0), R(65, 0), R(58, 3), | |
R(61, 0), R(53, 3), R(44, 3), | |
R(49, 3), R(41, 3), R(31, 3), | |
R(94, 0), R(86, 0), R(76, 3), | |
R(81, 3), R(75, 0), R(65, 0), | |
R(66, 3), R(61, 0), R(53, 3), | |
R(107, 0), R(104, 3), R(96, 3), | |
R(101, 3), R(94, 0), R(86, 0), | |
R(85, 3), R(81, 3), R(75, 0), | |
R(57, 0), R(59, 0), R(63, 3), | |
R(74, 0), R(78, 3), R(79, 3), | |
R(83, 3), R(92, 3), R(95, 3), | |
R(37, 0), R(39, 3), R(45, 3), | |
R(52, 0), R(57, 0), R(59, 0), | |
R(70, 3), R(74, 0), R(78, 3), | |
R(24, 0), R(23, 3), R(25, 3), | |
R(32, 3), R(37, 0), R(39, 3), | |
R(50, 3), R(52, 0), R(57, 0), | |
R(46, 0), R(60, 0), R(72, 3), | |
R(56, 0), R(68, 3), R(80, 3), | |
R(63, 3), R(77, 3), R(90, 3), | |
R(27, 0), R(40, 3), R(55, 3), | |
R(35, 0), R(46, 0), R(60, 0), | |
R(45, 3), R(56, 0), R(68, 3), | |
R(14, 0), R(20, 3), R(36, 3), | |
R(17, 3), R(27, 0), R(40, 3), | |
R(25, 3), R(35, 0), R(46, 0), | |
R(71, 0), R(89, 0), R(97, 3), | |
R(73, 0), R(91, 3), R(103, 3), | |
R(72, 3), R(88, 3), R(105, 3), | |
R(51, 0), R(69, 3), R(84, 3), | |
R(54, 0), R(71, 0), R(89, 0), | |
R(55, 3), R(73, 0), R(91, 3), | |
R(38, 0), R(47, 3), R(64, 3), | |
R(34, 3), R(51, 0), R(69, 3), | |
R(36, 3), R(54, 0), R(71, 0), | |
R(96, 0), R(104, 0), R(107, 3), | |
R(98, 0), R(110, 3), R(115, 3), | |
R(97, 3), R(111, 3), R(119, 3), | |
R(76, 0), R(86, 3), R(94, 3), | |
R(82, 0), R(96, 0), R(104, 0), | |
R(84, 3), R(98, 0), R(110, 3), | |
R(58, 0), R(65, 3), R(75, 3), | |
R(62, 3), R(76, 0), R(86, 3), | |
R(64, 3), R(82, 0), R(96, 0), | |
R(85, 0), R(87, 0), R(83, 3), | |
R(101, 0), R(102, 3), R(100, 3), | |
R(107, 3), R(112, 3), R(114, 3), | |
R(66, 0), R(67, 3), R(70, 3), | |
R(81, 0), R(85, 0), R(87, 0), | |
R(94, 3), R(101, 0), R(102, 3), | |
R(49, 0), R(48, 3), R(50, 3), | |
R(61, 3), R(66, 0), R(67, 3), | |
R(75, 3), R(81, 0), R(85, 0), | |
R(95, 0), R(92, 0), R(83, 0), | |
R(79, 0), R(78, 0), R(74, 3), | |
R(63, 1), R(59, 3), R(57, 3), | |
R(109, 0), R(108, 0), R(100, 5), | |
R(93, 1), R(95, 0), R(92, 0), | |
R(77, 1), R(79, 0), R(78, 0), | |
R(117, 4), R(118, 5), R(114, 5), | |
R(106, 1), R(109, 0), R(108, 0), | |
R(90, 1), R(93, 1), R(95, 0), | |
R(90, 0), R(77, 0), R(63, 0), | |
R(80, 0), R(68, 0), R(56, 3), | |
R(72, 1), R(60, 3), R(46, 3), | |
R(106, 0), R(93, 0), R(79, 5), | |
R(99, 1), R(90, 0), R(77, 0), | |
R(88, 1), R(80, 0), R(68, 0), | |
R(117, 3), R(109, 5), R(95, 5), | |
R(113, 1), R(106, 0), R(93, 0), | |
R(105, 1), R(99, 1), R(90, 0), | |
R(105, 0), R(88, 0), R(72, 0), | |
R(103, 0), R(91, 0), R(73, 3), | |
R(97, 1), R(89, 3), R(71, 3), | |
R(113, 0), R(99, 0), R(80, 5), | |
R(116, 1), R(105, 0), R(88, 0), | |
R(111, 1), R(103, 0), R(91, 0), | |
R(117, 2), R(106, 5), R(90, 5), | |
R(121, 1), R(113, 0), R(99, 0), | |
R(119, 1), R(116, 1), R(105, 0), | |
R(119, 0), R(111, 0), R(97, 0), | |
R(115, 0), R(110, 0), R(98, 3), | |
R(107, 1), R(104, 3), R(96, 3), | |
R(121, 0), R(116, 0), R(103, 5), | |
R(120, 1), R(119, 0), R(111, 0), | |
R(112, 1), R(115, 0), R(110, 0), | |
R(117, 1), R(113, 5), R(105, 5), | |
R(118, 1), R(121, 0), R(116, 0), | |
R(114, 1), R(120, 1), R(119, 0), | |
R(114, 0), R(112, 0), R(107, 0), | |
R(100, 0), R(102, 0), R(101, 3), | |
R(83, 1), R(87, 3), R(85, 3), | |
R(118, 0), R(120, 0), R(115, 5), | |
R(108, 1), R(114, 0), R(112, 0), | |
R(92, 1), R(100, 0), R(102, 0), | |
R(117, 0), R(121, 5), R(119, 5), | |
R(109, 1), R(118, 0), R(120, 0), | |
R(95, 1), R(108, 1), R(114, 0) | |
); | |
const D baseCellData[NUM_BASE_CELLS] = D[NUM_BASE_CELLS]( | |
D(FIJK(1, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(2, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(1, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(2, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(0, ivec3(2, 0, 0)), true, ivec2(-1, -1)), | |
D(FIJK(1, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(1, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(2, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(0, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(2, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(1, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(1, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(3, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(3, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(11, ivec3(2, 0, 0)), true, ivec2(2, 6)), | |
D(FIJK(4, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(0, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(6, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(0, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(2, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(7, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(2, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(0, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(6, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(10, ivec3(2, 0, 0)), true, ivec2(1, 5)), | |
D(FIJK(6, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(3, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(11, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(4, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(3, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(0, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(4, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(5, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(0, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(7, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(11, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(7, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(10, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(12, ivec3(2, 0, 0)), true, ivec2(3, 7)), | |
D(FIJK(6, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(7, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(4, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(3, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(3, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(4, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(6, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(11, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(8, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(5, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(14, ivec3(2, 0, 0)), true, ivec2(0, 9)), | |
D(FIJK(5, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(12, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(10, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(4, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(12, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(7, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(11, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(10, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(13, ivec3(2, 0, 0)), true, ivec2(4, 8)), | |
D(FIJK(10, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(11, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(9, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(8, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(6, ivec3(2, 0, 0)), true, ivec2(11, 15)), | |
D(FIJK(8, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(9, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(14, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(5, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(16, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(8, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(5, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(12, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(7, ivec3(2, 0, 0)), true, ivec2(12, 16)), | |
D(FIJK(12, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(10, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(9, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(13, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(16, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(15, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(15, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(16, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(14, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(13, ivec3(1, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(5, ivec3(2, 0, 0)), true, ivec2(10, 19)), | |
D(FIJK(8, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(14, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(9, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(14, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(17, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(12, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(16, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(17, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(15, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(16, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(9, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(15, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(13, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(8, ivec3(2, 0, 0)), true, ivec2(13, 17)), | |
D(FIJK(13, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(17, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(19, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(14, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(19, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(17, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(13, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(17, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(16, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(9, ivec3(2, 0, 0)), true, ivec2(14, 18)), | |
D(FIJK(15, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(15, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(18, ivec3(0, 1, 1)), false, ivec2(0, 0)), | |
D(FIJK(18, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(19, ivec3(0, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(17, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(19, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(18, ivec3(0, 1, 0)), false, ivec2(0, 0)), | |
D(FIJK(18, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(19, ivec3(2, 0, 0)), true, ivec2(-1, -1)), | |
D(FIJK(19, ivec3(1, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(18, ivec3(0, 0, 0)), false, ivec2(0, 0)), | |
D(FIJK(19, ivec3(1, 0, 1)), false, ivec2(0, 0)), | |
D(FIJK(18, ivec3(1, 0, 0)), false, ivec2(0, 0)) | |
); | |
highp float pointSquareDist(in vec3 v1, in vec3 v2) { | |
vec3 delta = v1 - v2; | |
return dot(delta, delta); | |
} | |
void geoToVec3d(in vec2 g, out vec3 v) { | |
highp float r = cos(g.x); | |
v = vec3( | |
cos(g.y) * r, | |
sin(g.y) * r, | |
sin(g.x) | |
); | |
} | |
void geoToClosestFace(in vec2 g, out int face, out highp float sqd) { | |
vec3 v3d; | |
geoToVec3d(g, v3d); | |
face = 0; | |
sqd = 5.; | |
for (int f=0; f<NUM_ICOSA_FACES; ++f) { | |
highp float sqdT = pointSquareDist(FCP[f], v3d); | |
if (sqdT < sqd) { | |
face = f; | |
sqd = sqdT; | |
} | |
} | |
} | |
highp float posAngleRads(in float rads) { | |
float tmp = (rads < 0.) ? rads + 2. * PI : rads; | |
if (rads >= 2. * PI) tmp -= 2. * PI; | |
return tmp; | |
} | |
highp float geoAzimuthRads(in vec2 p1, in vec2 p2) { | |
return atan( | |
cos(p2.x) * sin(p2.y - p1.y), | |
cos(p1.x) * sin(p2.x) - | |
sin(p1.x) * cos(p2.x) * cos(p2.y - p1.y) | |
); | |
} | |
void geoToHex2d(in vec2 g, in int res, out int face, out vec2 v) { | |
highp float sqd; | |
geoToClosestFace(g, face, sqd); | |
highp float r = acos(1. - sqd / 2.); | |
if (r < EPSILON) { | |
v = vec2(0.); | |
return; | |
} | |
highp float theta = posAngleRads( | |
FARC[face][0] - | |
posAngleRads( | |
geoAzimuthRads(FCG[face], g) | |
) | |
); | |
if (mod(res, 2) == 1) | |
theta = posAngleRads(theta - M_AP7_ROT_RADS); | |
r = tan(r); | |
r /= RES0_U_GNOMONIC; | |
for (int i=0; i<res; ++i) r *= M_SQRT7; | |
v = vec2( | |
r * cos(theta), | |
r * sin(theta) | |
); | |
} | |
void ijkNormalize(inout ivec3 c) { | |
if (c.x < 0) { | |
c.y -= c.x; | |
c.z -= c.x; | |
c.x = 0; | |
} | |
if (c.y < 0) { | |
c.x -= c.y; | |
c.z -= c.y; | |
c.y = 0; | |
} | |
if (c.z < 0) { | |
c.x -= c.z; | |
c.y -= c.z; | |
c.z = 0; | |
} | |
int m = int(min(c.x, int(min(c.y, c.z)))); | |
if (m > 0) { | |
c -= ivec3(m); | |
} | |
} | |
void hex2dToCoordIJK(in vec2 v, out ivec3 h) { | |
highp float a1, a2; | |
highp float x1, x2; | |
int m1, m2; | |
highp float r1, r2; | |
h.z = 0; | |
a1 = abs(v.x); | |
a2 = abs(v.y); | |
x2 = a2 / M_SIN60; | |
x1 = a1 + x2 / 2.; | |
m1 = int(x1); | |
m2 = int(x2); | |
r1 = x1 - float(m1); | |
r2 = x2 - float(m2); | |
if (r1 < 0.5) { | |
if (r1 < 1. / 3.) { | |
if (r2 < (1. + r1) / 2.) { | |
h.x = m1; | |
h.y = m2; | |
} else { | |
h.x = m1; | |
h.y = m2 + 1; | |
} | |
} else { | |
if (r2 < (1. - r1)) { | |
h.y = m2; | |
} else { | |
h.y = m2 + 1; | |
} | |
if ((1. - r1) <= r2 && r2 < (2. * r1)) { | |
h.x = m1 + 1; | |
} else { | |
h.x = m1; | |
} | |
} | |
} else { | |
if (r1 < 2. / 3.) { | |
if (r2 < (1. - r1)) { | |
h.y = m2; | |
} else { | |
h.y = m2 + 1; | |
} | |
if ((2. * r1 - 1.) < r2 && r2 < (1. - r1)) { | |
h.x = m1; | |
} else { | |
h.x = m1 + 1; | |
} | |
} else { | |
if (r2 < (r1 / 2.)) { | |
h.x = m1 + 1; | |
h.y = m2; | |
} else { | |
h.x = m1 + 1; | |
h.y = m2 + 1; | |
} | |
} | |
} | |
if (v.x < 0.) { | |
if (mod(h.y, 2) == 0) { | |
int axisi = h.y / 2; | |
int diff = h.x - axisi; | |
h.x = h.x - 2 * diff; | |
} else { | |
int axisi = (h.y + 1) / 2; | |
int diff = h.x - axisi; | |
h.x = h.x - (2 * diff + 1); | |
} | |
} | |
if (v.y < 0.) { | |
h.x = h.x - (2 * h.y + 1) / 2; | |
h.y = -1 * h.y; | |
} | |
ijkNormalize(h); | |
} | |
void upAp7(inout ivec3 ijk) { | |
int i = ijk.x - ijk.z; | |
int j = ijk.y - ijk.z; | |
ijk = ivec3( | |
int(floor(float(3 * i - j) / 7. + 0.5)), | |
int(floor(float(i + 2 * j) / 7. + 0.5)), | |
0 | |
); | |
ijkNormalize(ijk); | |
} | |
void upAp7r(inout ivec3 ijk) { | |
int i = ijk.x - ijk.z; | |
int j = ijk.y - ijk.z; | |
ijk = ivec3( | |
int(floor(float(2 * i + j) / 7. + 0.5)), | |
int(floor(float(3 * j - i) / 7. + 0.5)), | |
0 | |
); | |
ijkNormalize(ijk); | |
} | |
void downAp7(inout ivec3 ijk) { | |
ivec3 iVec = ivec3(3, 0, 1); | |
ivec3 jVec = ivec3(1, 3, 0); | |
ivec3 kVec = ivec3(0, 1, 3); | |
iVec *= ijk.x; | |
jVec *= ijk.y; | |
kVec *= ijk.z; | |
ijk = iVec + jVec + kVec; | |
ijkNormalize(ijk); | |
} | |
void downAp7r(inout ivec3 ijk) { | |
ivec3 iVec = ivec3(3, 1, 0); | |
ivec3 jVec = ivec3(0, 3, 1); | |
ivec3 kVec = ivec3(1, 0, 3); | |
iVec *= ijk.x; | |
jVec *= ijk.y; | |
kVec *= ijk.z; | |
ijk = iVec + jVec + kVec; | |
ijkNormalize(ijk); | |
} | |
int unitIjkToDigit(in ivec3 ijk) { | |
ivec3 c = ijk; | |
ijkNormalize(c); | |
int digit = -1; | |
for (int i=0; i<7; ++i) { | |
if (c == UV[i]) { | |
digit = i; | |
break; | |
} | |
} | |
return digit; | |
} | |
int h3LeadingNonZeroDigit(in CellIndex h) { | |
for (int r=0; r<h.resolution; ++r) { | |
if (h.digits[r] > 0) return h.digits[r]; | |
} | |
return 0; | |
} | |
void h3Rotate60ccw(inout CellIndex h) { | |
for (int r=0; r<h.resolution; ++r) { | |
h.digits[r] = R60CCW[ h.digits[r] ]; | |
} | |
} | |
void h3Rotate60cw(inout CellIndex h) { | |
for (int r=0; r<h.resolution; ++r) { | |
h.digits[r] = R60CW[ h.digits[r] ]; | |
} | |
} | |
bool baseCellIsCwOffset(in int baseCell, in int testFace) { | |
return baseCellData[baseCell].cwOffsetPent.x == testFace || | |
baseCellData[baseCell].cwOffsetPent.y == testFace; | |
} | |
void geoToFaceIjk(in vec2 g, in int res, out FIJK h) { | |
vec2 v; | |
geoToHex2d(g, res, h.face, v); | |
hex2dToCoordIJK(v, h.coord); | |
} | |
CellIndex faceIjkToCellIndex(in FIJK fijk, in int res) { | |
CellIndex result = CellIndex( | |
res, | |
0, | |
int[NUM_DIGITS](0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | |
); | |
if (res == 0) { | |
result.baseCell = FIBC[ | |
fijk.face * 27 + | |
fijk.coord.x * 9 + | |
fijk.coord.y * 3 + | |
fijk.coord.z | |
].baseCell; | |
return result; | |
} | |
FIJK fijkBC = fijk; | |
ivec3 ijk = fijkBC.coord; | |
for (int r=res-1; r >= 0; --r) { | |
ivec3 lastIJK = ijk; | |
ivec3 lastCenter; | |
if (mod(r + 1, 2) == 1) { | |
upAp7(ijk); | |
lastCenter = ijk; | |
downAp7(lastCenter); | |
} else { | |
upAp7r(ijk); | |
lastCenter = ijk; | |
downAp7r(lastCenter); | |
} | |
ivec3 diff = lastIJK - lastCenter; | |
ijkNormalize(diff); | |
result.digits[r] = unitIjkToDigit(diff); | |
} | |
fijkBC.coord = ijk; | |
R baseCellRotation = FIBC[ | |
fijkBC.face * 27 + | |
fijkBC.coord.x * 9 + | |
fijkBC.coord.y * 3 + | |
fijkBC.coord.z | |
]; | |
int baseCell = baseCellRotation.baseCell; | |
int numRots = baseCellRotation.ccwRot60; | |
result.baseCell = baseCell; | |
if (baseCellData[baseCell].isPentagon) { | |
if (h3LeadingNonZeroDigit(result) == K_AXES_DIGIT) { | |
if(baseCellIsCwOffset(baseCell, fijkBC.face)) { | |
h3Rotate60cw(result); | |
} else { | |
h3Rotate60ccw(result); | |
} | |
} | |
} else { | |
for (int i=0; i<numRots; ++i) { | |
h3Rotate60ccw(result); | |
} | |
} | |
return result; | |
} | |
CellIndex latLngToCellIndex(in vec2 g, in int res) { | |
FIJK fijk; | |
geoToFaceIjk(g, res, fijk); | |
return faceIjkToCellIndex(fijk, res); | |
} | |
const int LUT_WIDTH = 2048; | |
const int LUT_HEIGHTS[6] = int[6](1, 1, 3, 21, 141, 985); | |
vec4 sampleCellValue(in sampler2D s2D, in CellIndex c) { | |
ivec2 dims = textureSize2D(s2D, 0); | |
if (c.resolution > 5) return vec4(0); | |
int idx = 0; | |
int mult = 1; | |
for (int i=c.resolution-1; i>=0; --i) { | |
idx += c.digits[i] * mult; | |
mult *= 7; | |
} | |
idx += c.baseCell * mult; | |
int xCoord = idx % dims.x; | |
int yCoord = idx / dims.x; | |
return texelFetch2D(s2D, ivec2(xCoord, yCoord), 0); | |
} | |
int texelToIdx(in vec4 t) { | |
return | |
((int(t.b * 255) << 8) | int(t.a * 255)) * 2048 + | |
((int(t.r * 255) << 8) | int(t.g * 255)); | |
} | |
vec4 sampleCellValueDense(in sampler2D s2D, in CellIndex c) { | |
int idx = texelToIdx(texelFetch2D(s2D, ivec2( | |
c.baseCell, | |
0. | |
), 0)); | |
if (idx == 0) return vec4(0); | |
for (int r=0; r<c.resolution-1; ++r) { | |
idx += c.digits[r]; | |
int x = idx % 2048; | |
int y = idx / 2048; | |
idx = texelToIdx(texelFetch2D(s2D, ivec2(x, y), 0)); | |
if (idx == 0) return vec4(0); | |
} | |
idx += c.digits[c.resolution-1]; | |
return texelFetch2D(s2D, ivec2(idx % 2048, idx / 2048), 0); | |
} | |
uniform sampler2D map_tu0; | |
uniform sampler2D map_tu1; | |
uniform highp float zoom; | |
varying vec2 texco; | |
void main() { | |
vec2 g = vec2( | |
(1 - texco.y) * PI - 0.5 * PI, | |
(1 - texco.x) * PI2 - PI | |
); | |
vec4 tex = texture2D(map_tu0, vec2(1 - texco.x, texco.y)); | |
int resolution = 8; | |
CellIndex cell = latLngToCellIndex(g, resolution); | |
vec4 hCol = sampleCellValueDense(map_tu1, cell); | |
gl_FragColor = vec4(tex.rgb * (1 - hCol.a) + hCol.rgb * hCol.a, 1.); | |
} | |
]] | |
function shader.get() | |
local s = build_shader(v, fragment_shader, "geopoints") | |
return s | |
end | |
function geopointvis() | |
shader = shader.get() | |
shader_uniform(shader, "zoom", "f", 0) | |
sphere = build_sphere(5, 40, 40, 2) | |
image_framesetsize(sphere, 2, FRAMESET_MULTITEXTURE) | |
show_image(sphere) | |
image_shader(sphere, shader) | |
local img = load_image("./earthmap10k.jpg") | |
set_image_as_frame(sphere, img, 0) | |
delete_image(img) | |
local data_tex = load_image("./h3_res8_dense.png") | |
image_texfilter(data_tex, FILTER_NONE) | |
set_image_as_frame(sphere, data_tex, 1) | |
delete_image(data_tex) | |
image_color(WORLDID, 50, 50, 50, 0) | |
camera.vid = null_surface(1, 1) | |
move3d_model(camera.vid, 0, 0, -10.0) | |
camera:rebuild() | |
end | |
function geopointvis_clock_pulse(tick) | |
local t = tick/CLOCKRATE | |
if camera.fovDirty then | |
camera:rebuild() | |
end | |
rotate3d_model(sphere, 0, camera.pitch, camera.yaw, 1/CLOCKRATE) | |
end | |
function geopointvis_input(input) | |
if input.kind == "analog" then | |
if mouse.devid and mouse.devid ~= input.devid then | |
return | |
end | |
local sample = input.samples[1] | |
if not mouse.buttons[1] and not mouse.buttons[2] then | |
mouse.lastSample[input.subid] = sample | |
return | |
end | |
local delta | |
if input.relative then | |
delta = sample | |
else | |
delta = sample - mouse.lastSample[input.subid] | |
end | |
mouse.lastSample[input.subid] = sample | |
if mouse.buttons[1] then | |
local panSpeed = mouseSpeed * ( | |
0.001 + 0.999*(camera.fov - minFov)/(maxFov - minFov) | |
) | |
if input.subid == 0 then | |
camera.yaw = ( | |
camera.yaw + delta * panSpeed | |
) % 360 | |
elseif input.subid == 1 then | |
camera.pitch = math.max( | |
minPitch, | |
math.min( | |
maxPitch, | |
camera.pitch + delta * panSpeed | |
) | |
) | |
end | |
elseif mouse.buttons[2] then | |
if input.subid == 1 then | |
local zoomSpeed = mouseSpeed * (0.1 + 0.9*(camera.fov - minFov)/(maxFov - minFov)) | |
camera.fov = math.max( | |
minFov, | |
math.min( | |
maxFov, | |
camera.fov + delta * zoomSpeed | |
) | |
) | |
camera.fovDirty = true | |
shader_uniform(shader, "zoom", "f", 1 - (camera.fov - minFov)/(maxFov - minFov)) | |
end | |
end | |
elseif input.kind == "touch" then | |
if touchscreen.devid == nil then | |
touchscreen.devid = input.devid | |
elseif touchscreen.devid ~= input.devid then | |
return | |
end | |
-- Recount on finger addition or removal | |
local alreadyDetected = touchscreen.touches[input.subid] ~= nil | |
if alreadyDetected ~= input.active then | |
touchscreen.nTouches = input.active and 1 or 0 | |
for _,_ in pairs(touchscreen.touches) do | |
touchscreen.nTouches = touchscreen.nTouches + 1 | |
end | |
end | |
if not input.active then | |
touchscreen.touches[input.subid] = nil | |
touchscreen.nTouches = touchscreen.nTouches - 1 | |
if touchscreen.nTouches < 2 then | |
touchscreen.lastDist = nil | |
end | |
return | |
end | |
local touch = touchscreen.touches[input.subid] | |
if touchscreen.nTouches == 1 and touch then | |
local deltaX = input.x - touch[1] | |
local deltaY = input.y - touch[2] | |
local panSpeed = touchSpeed * ( | |
0.001 + 0.999*(camera.fov - minFov)/(maxFov - minFov) | |
) | |
camera.yaw = ( | |
camera.yaw + deltaX * panSpeed | |
) % 360 | |
camera.pitch = math.max( | |
minPitch, | |
math.min( | |
maxPitch, | |
camera.pitch + deltaY * panSpeed | |
) | |
) | |
elseif touchscreen.nTouches == 2 and touch then | |
local delta = input.y - touch[2] | |
local zoomSpeed = touchSpeed * (0.1 + 0.9*(camera.fov - minFov)/(maxFov - minFov)) | |
camera.fov = math.max( | |
minFov, | |
math.min( | |
maxFov, | |
camera.fov - delta * zoomSpeed | |
) | |
) | |
camera.fovDirty = true | |
shader_uniform(shader, "zoom", "f", 1 - (camera.fov - minFov)/(maxFov - minFov)) | |
end | |
touchscreen.touches[input.subid] = {input.x, input.y} | |
elseif input.kind == "digital" then | |
if input.mouse then | |
if input.active then | |
mouse.devid = input.devid | |
elseif mouse.devid == input.devid then | |
mouse.devid = nil | |
else | |
return | |
end | |
mouse.buttons[input.subid] = input.active | |
elseif input.keyboard then | |
if input.keysym == 27 then | |
shutdown() | |
end | |
end | |
end | |
end | |
function geopointvis_display_state(disp) | |
if disp == "reset" then | |
resize_video_canvas(VRESW, VRESH) | |
camera:rebuild() | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment