diff --git a/examples/al-cuts-fits-hips.html b/examples/al-cuts-fits-hips.html index 7969e0c8..69f94307 100644 --- a/examples/al-cuts-fits-hips.html +++ b/examples/al-cuts-fits-hips.html @@ -15,7 +15,7 @@ aladin.setBaseImageLayer(dss); - dss.setCuts(2, 10000); + dss.setCuts(2, 100, 'jpeg'); }); diff --git a/src/core/src/shaders.rs b/src/core/src/shaders.rs index 2b45860c..024c45af 100644 --- a/src/core/src/shaders.rs +++ b/src/core/src/shaders.rs @@ -3,1680 +3,135 @@ use std::collections::HashMap; pub fn get_all() -> HashMap<&'static str, &'static str> { let mut out = HashMap::new(); out.insert( - r"moc_base.frag", + r"hips_rasterizer_raster.vert", r#"#version 300 es - -precision lowp float; -out vec4 color; - -uniform vec4 u_color; - -void main() { - color = u_color; -}"#, - ); - out.insert( - r"hips_rasterizer_i32.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler2DArray; - -uniform sampler2DArray tex; - -in vec3 frag_uv_start; -in vec3 frag_uv_end; -in float frag_blending_factor; - -out vec4 out_frag_color; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} - -uniform float opacity; - -void main() { - vec3 uv0 = frag_uv_start; - vec3 uv1 = frag_uv_end; - uv0.y = 1.0 - uv0.y; - uv1.y = 1.0 - uv1.y; - - vec4 color_start = uvw2c_i32(uv0); - vec4 color_end = uvw2c_i32(uv1); - - out_frag_color = mix(color_start, color_end, frag_blending_factor); - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"hips_raytracer_i16.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler2DArray; -precision mediump int; - -uniform sampler2DArray tex; - -in vec3 frag_pos; -in vec2 out_clip_pos; -out vec4 out_frag_color; - -struct Tile { - int uniq; // Healpix cell - int texture_idx; // Index in the texture buffer - float start_time; // Absolute time that the load has been done in ms - float empty; -}; - -uniform Tile textures_tiles[12]; - -uniform float opacity; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} -const float TWICE_PI = 6.28318530718; -const float PI = 3.141592653589793; -const float FOUR_OVER_PI = 1.27323954474; -const float TRANSITION_Z = 0.66666666666; -const float TRANSITION_Z_INV = 1.5; - -int quarter(vec2 p) { - int x_neg = int(p.x < 0.0); - int y_neg = int(p.y < 0.0); - int q = (x_neg + y_neg) | (y_neg << 1); - return q; -} - -float xpm1(vec2 p) { - bool x_neg = (p.x < 0.0); - bool y_neg = (p.y < 0.0); - float lon = atan(abs(p.y), abs(p.x)); - float x02 = lon * FOUR_OVER_PI; - if (x_neg != y_neg) { // Could be replaced by a sign copy from (x_neg ^ y_neg) << 32 - return 1.0 - x02; - } else { - return x02 - 1.0; - } -} - -float one_minus_z_pos(vec3 p) { - float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 - - if (d2 < 1e-1) { // <=> dec > 84.27 deg - return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); - } - return 1.0f - p.z; -} - -float one_minus_z_neg(vec3 p) { - float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 - if (d2 < 1e-1f) { // <=> dec < -84.27 deg - return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); - } - return p.z + 1.0; -} - -int ij2z(int i, int j) { - int i4 = i | (j << 2); - - int j4 = (i4 ^ (i4 >> 1)) & 0x22222222; - int i5 = i4 ^ j4 ^ (j4 << 1); - - return i5; -} - -struct HashDxDy { - int idx; - float dx; - float dy; -}; - -uniform sampler2D ang2pixd; -HashDxDy hash_with_dxdy2(vec2 radec) { - vec2 aa = vec2(radec.x/TWICE_PI + 1.0, (radec.y/PI) + 0.5); - vec3 v = texture(ang2pixd, aa).rgb; - return HashDxDy( - int(v.x * 255.0), - v.y, - v.z - ); -} -HashDxDy hash_with_dxdy(int depth, vec3 p) { - - int nside = 1 << depth; - float half_nside = float(nside) * 0.5; - - float x_pm1 = xpm1(p.xy); - int q = quarter(p.xy); - - int d0h = 0; - vec2 p_proj = vec2(0.0); - if (p.z > TRANSITION_Z) { - float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_pos(p)); - p_proj = vec2(x_pm1 * sqrt_3_one_min_z, 2.0 - sqrt_3_one_min_z); - d0h = q; - } else if (p.z < -TRANSITION_Z) { - float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_neg(p)); - p_proj = vec2(x_pm1 * sqrt_3_one_min_z, sqrt_3_one_min_z); - d0h = q + 8; - } else { - float y_pm1 = p.z * TRANSITION_Z_INV; - int q01 = int(x_pm1 > y_pm1); // 0/1 - int q12 = int(x_pm1 >= -y_pm1); // 0\1 - int q03 = 1 - q12; // 1\0 - int q1 = q01 & q12; // = 1 if q1, 0 else - p_proj = vec2( - x_pm1 - float(q01 + q12 - 1), - y_pm1 + float(q01 + q03) - ); - d0h = ((q01 + q03) << 2) + ((q + q1) & 3); - } - - float x = (half_nside * (p_proj.x + p_proj.y)); - float y = (half_nside * (p_proj.y - p_proj.x)); - int i = int(x); - int j = int(y); - - return HashDxDy( - (d0h << (depth << 1)) + ij2z(i, j), - x - float(i), - y - float(j) - ); -} -vec3 xyz2uv(vec3 xyz) { - HashDxDy result = hash_with_dxdy(0, xyz.zxy); - - int idx = result.idx; - vec2 offset = vec2(result.dy, result.dx); - Tile tile = textures_tiles[idx]; - - return vec3(offset, float(tile.texture_idx)); -} - -void main() { - vec3 uv = xyz2uv(normalize(frag_pos)); - - uv.y = 1.0 - uv.y; - vec4 c = uvw2c_i16(uv); - - - out_frag_color = c; - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"catalogs_mercator.vert", - r#"#version 300 es -precision lowp float; -layout (location = 0) in vec2 offset; -layout (location = 1) in vec2 uv; -layout (location = 2) in vec3 center; - -uniform float current_time; -uniform mat3 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -out vec2 out_uv; -out vec3 out_p; - -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; - -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); -} - -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); -} - -vec2 w2c_ait(vec3 p) { - float r = length(p.zx); - float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) - w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma - float y2d = p.y / w; - - float x2d = 0.0; - if (abs(p.x) < 5e-3) { - float x_over_r = p.x/r; - x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; - } else { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; - } - - return vec2(x2d * 0.5, y2d) / SQRT_2; -} -const float eps = 1.25e-8; -const int n_iter = 100; - -float newton_solve(float z) { - float cte = PI * z; - float x = 2.0 * asin(z); - float f = x + sin(x) - cte; - int i = 0; - while (abs(f) > eps && i < n_iter) { - x -= f / (1.0 + cos(x)); - f = x + sin(x) - cte; - i += 1; - } - - return 0.5 * x; -} - -vec2 w2c_mol(vec3 p) { - float g = newton_solve(p.y); - - float sg = sin(g); - float cg = cos(g); - return vec2((atan(-p.x, p.z) * cg) / PI, sg); -} -vec2 w2c_tan(vec3 p) { - p.z = max(p.z, 1e-2); - return vec2(-p.x, p.y) / (p.z*PI); -} -vec2 w2c_stg(vec3 p) { - float w = (1.0 + p.z) * 0.5; - return vec2(-p.x, p.y) / (PI * w); -} -vec2 w2c_zea(vec3 p) { - float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] - return vec2(-p.x, p.y) * 0.5 / w; -} -vec2 w2c_mer(vec3 p) { - return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; -} - -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -uniform int u_proj; - -vec2 proj(vec3 p) { - if (u_proj == 0) { - return w2c_tan(p); - } else if (u_proj == 1) { - return w2c_stg(p); - } else if (u_proj == 2) { - return w2c_sin(p); - } else if (u_proj == 3) { - return w2c_zea(p); - } else if (u_proj == 4) { - return w2c_ait(p); - } else if (u_proj == 5) { - return w2c_mol(p); - } else { - return w2c_mer(p); - } -} - - -void main() { - vec3 p = inv_model * center; - - vec2 center_pos_clip_space = world2clip_mercator(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); - - out_uv = uv; - out_p = p; -}"#, - ); - out.insert( - r"colormaps_colormap.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler2D; - -in vec2 out_uv; -out vec4 color; - -uniform sampler2D texture_fbo; -uniform float alpha; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} - -void main() { - float opacity = texture(texture_fbo, out_uv).r; - - float o = smoothstep(0.0, 0.1, opacity); - - color = colormap_f(opacity); - color.a = o * alpha; -}"#, - ); - out.insert( - r"catalogs_aitoff.vert", - r#"#version 300 es -precision lowp float; -layout (location = 0) in vec2 offset; -layout (location = 1) in vec2 uv; -layout (location = 2) in vec3 center; - -uniform float current_time; -uniform mat3 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -out vec2 out_uv; -out vec3 out_p; - -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; - -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); -} - -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); -} - -vec2 w2c_ait(vec3 p) { - float r = length(p.zx); - float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) - w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma - float y2d = p.y / w; - - float x2d = 0.0; - if (abs(p.x) < 5e-3) { - float x_over_r = p.x/r; - x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; - } else { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; - } - - return vec2(x2d * 0.5, y2d) / SQRT_2; -} -const float eps = 1.25e-8; -const int n_iter = 100; - -float newton_solve(float z) { - float cte = PI * z; - float x = 2.0 * asin(z); - float f = x + sin(x) - cte; - int i = 0; - while (abs(f) > eps && i < n_iter) { - x -= f / (1.0 + cos(x)); - f = x + sin(x) - cte; - i += 1; - } - - return 0.5 * x; -} - -vec2 w2c_mol(vec3 p) { - float g = newton_solve(p.y); - - float sg = sin(g); - float cg = cos(g); - return vec2((atan(-p.x, p.z) * cg) / PI, sg); -} -vec2 w2c_tan(vec3 p) { - p.z = max(p.z, 1e-2); - return vec2(-p.x, p.y) / (p.z*PI); -} -vec2 w2c_stg(vec3 p) { - float w = (1.0 + p.z) * 0.5; - return vec2(-p.x, p.y) / (PI * w); -} -vec2 w2c_zea(vec3 p) { - float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] - return vec2(-p.x, p.y) * 0.5 / w; -} -vec2 w2c_mer(vec3 p) { - return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; -} - -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -uniform int u_proj; - -vec2 proj(vec3 p) { - if (u_proj == 0) { - return w2c_tan(p); - } else if (u_proj == 1) { - return w2c_stg(p); - } else if (u_proj == 2) { - return w2c_sin(p); - } else if (u_proj == 3) { - return w2c_zea(p); - } else if (u_proj == 4) { - return w2c_ait(p); - } else if (u_proj == 5) { - return w2c_mol(p); - } else { - return w2c_mer(p); - } -} - -void main() { - vec3 p = inv_model * center; - - vec2 center_pos_clip_space = world2clip_aitoff(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); - - out_uv = uv; - out_p = p; -}"#, - ); - out.insert( - r"hips_raytracer_backcolor.frag", - r#"#version 300 es -precision lowp float; -precision mediump int; - -out vec4 out_frag_color; - -uniform vec3 color; - -void main() { - out_frag_color = vec4(color, 1.0); -}"#, - ); - out.insert( - r"line_base.frag", - r#"#version 300 es - precision highp float; -out vec4 color; -in vec2 l; +layout (location = 0) in vec3 xyz; +layout (location = 1) in vec3 uv_start; +layout (location = 2) in vec3 uv_end; +layout (location = 3) in float time_tile_received; -uniform vec4 u_color; -uniform float u_thickness; -uniform float u_width; -uniform float u_height; +out vec3 frag_uv_start; +out vec3 frag_uv_end; +out float frag_blending_factor; -void main() { - if (l.x > 0.05) { - discard; - } else { - color = u_color; +uniform mat3 inv_model; +uniform vec2 ndc_to_clip; +uniform float czf; +uniform float current_time; - float dist = abs((u_thickness + 2.0) * l.y); - - float half_thickness = (u_thickness + 2.0) * 0.5; - color.a = color.a * (1.0 - smoothstep(half_thickness - 1.0, half_thickness, dist)); - } -}"#, - ); - out.insert( - r"hips_rasterizer_f32.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler2DArray; - -uniform sampler2DArray tex; - -in vec3 frag_uv_start; -in vec3 frag_uv_end; -in float frag_blending_factor; - -out vec4 out_frag_color; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} - -uniform float opacity; - -void main() { - vec3 uv0 = frag_uv_start; - vec3 uv1 = frag_uv_end; - uv0.y = 1.0 - uv0.y; - uv1.y = 1.0 - uv1.y; - - vec4 color_start = uvw2c_f32(uv0); - vec4 color_end = uvw2c_f32(uv1); - - out_frag_color = mix(color_start, color_end, frag_blending_factor); - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"hips_raytracer_rgba.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler2DArray; -precision mediump int; - -uniform sampler2DArray tex; - -in vec2 out_clip_pos; -in vec3 frag_pos; -out vec4 out_frag_color; - -struct Tile { - int uniq; // Healpix cell - int texture_idx; // Index in the texture buffer - float start_time; // Absolute time that the load has been done in ms - float empty; -}; - -uniform Tile textures_tiles[12]; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} -const float TWICE_PI = 6.28318530718; const float PI = 3.141592653589793; -const float FOUR_OVER_PI = 1.27323954474; -const float TRANSITION_Z = 0.66666666666; -const float TRANSITION_Z_INV = 1.5; +const float SQRT_2 = 1.41421356237309504880168872420969808; -int quarter(vec2 p) { - int x_neg = int(p.x < 0.0); - int y_neg = int(p.y < 0.0); - int q = (x_neg + y_neg) | (y_neg << 1); - return q; +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); } -float xpm1(vec2 p) { - bool x_neg = (p.x < 0.0); - bool y_neg = (p.y < 0.0); - float lon = atan(abs(p.y), abs(p.x)); - float x02 = lon * FOUR_OVER_PI; - if (x_neg != y_neg) { // Could be replaced by a sign copy from (x_neg ^ y_neg) << 32 - return 1.0 - x02; +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); +} + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 5e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; } else { - return x02 - 1.0; + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; } + + return vec2(x2d * 0.5, y2d) / SQRT_2; } +const float eps = 1.25e-8; +const int n_iter = 100; -float one_minus_z_pos(vec3 p) { - float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 - - if (d2 < 1e-1) { // <=> dec > 84.27 deg - return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); +float newton_solve(float z) { + float cte = PI * z; + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; } - return 1.0f - p.z; + + return 0.5 * x; } -float one_minus_z_neg(vec3 p) { - float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 - if (d2 < 1e-1f) { // <=> dec < -84.27 deg - return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); - } - return p.z + 1.0; +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} +vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); + return vec2(-p.x, p.y) / (p.z*PI); +} +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} +vec2 w2c_zea(vec3 p) { + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; } -int ij2z(int i, int j) { - int i4 = i | (j << 2); +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); - int j4 = (i4 ^ (i4 >> 1)) & 0x22222222; - int i5 = i4 ^ j4 ^ (j4 << 1); + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); - return i5; + return vec3(dc * ts, ds, dc * tc); } -struct HashDxDy { - int idx; - float dx; - float dy; -}; +uniform int u_proj; -uniform sampler2D ang2pixd; -HashDxDy hash_with_dxdy2(vec2 radec) { - vec2 aa = vec2(radec.x/TWICE_PI + 1.0, (radec.y/PI) + 0.5); - vec3 v = texture(ang2pixd, aa).rgb; - return HashDxDy( - int(v.x * 255.0), - v.y, - v.z - ); -} -HashDxDy hash_with_dxdy(int depth, vec3 p) { - - int nside = 1 << depth; - float half_nside = float(nside) * 0.5; - - float x_pm1 = xpm1(p.xy); - int q = quarter(p.xy); - - int d0h = 0; - vec2 p_proj = vec2(0.0); - if (p.z > TRANSITION_Z) { - float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_pos(p)); - p_proj = vec2(x_pm1 * sqrt_3_one_min_z, 2.0 - sqrt_3_one_min_z); - d0h = q; - } else if (p.z < -TRANSITION_Z) { - float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_neg(p)); - p_proj = vec2(x_pm1 * sqrt_3_one_min_z, sqrt_3_one_min_z); - d0h = q + 8; +vec2 proj(vec3 p) { + if (u_proj == 0) { + return w2c_tan(p); + } else if (u_proj == 1) { + return w2c_stg(p); + } else if (u_proj == 2) { + return w2c_sin(p); + } else if (u_proj == 3) { + return w2c_zea(p); + } else if (u_proj == 4) { + return w2c_ait(p); + } else if (u_proj == 5) { + return w2c_mol(p); } else { - float y_pm1 = p.z * TRANSITION_Z_INV; - int q01 = int(x_pm1 > y_pm1); // 0/1 - int q12 = int(x_pm1 >= -y_pm1); // 0\1 - int q03 = 1 - q12; // 1\0 - int q1 = q01 & q12; // = 1 if q1, 0 else - p_proj = vec2( - x_pm1 - float(q01 + q12 - 1), - y_pm1 + float(q01 + q03) - ); - d0h = ((q01 + q03) << 2) + ((q + q1) & 3); + return w2c_mer(p); } - - float x = (half_nside * (p_proj.x + p_proj.y)); - float y = (half_nside * (p_proj.y - p_proj.x)); - int i = int(x); - int j = int(y); - - return HashDxDy( - (d0h << (depth << 1)) + ij2z(i, j), - x - float(i), - y - float(j) - ); } -vec3 xyz2uv(vec3 xyz) { - HashDxDy result = hash_with_dxdy(0, xyz.zxy); - - int idx = result.idx; - vec2 offset = vec2(result.dy, result.dx); - Tile tile = textures_tiles[idx]; - - return vec3(offset, float(tile.texture_idx)); -} - -uniform float opacity; -uniform vec4 no_tile_color; void main() { - vec3 uv = xyz2uv(normalize(frag_pos)); - vec4 c = uvw2c_rgba(uv); + vec3 p_w = inv_model * xyz; + vec2 p_clip = proj(p_w); - out_frag_color = c; - out_frag_color = vec4(c.rgb, opacity * c.a); + vec2 p_ndc = p_clip / (ndc_to_clip * czf); + gl_Position = vec4(p_ndc, 0.0, 1.0); + + frag_uv_start = uv_start; + frag_uv_end = uv_end; + frag_blending_factor = min((current_time - time_tile_received) / 200.0, 1.0); }"#, ); out.insert( @@ -1945,9 +400,436 @@ void main() { }"#, ); out.insert( - r"catalogs_ortho.vert", + r"hips3d_raster.vert", r#"#version 300 es precision lowp float; + +layout (location = 0) in vec2 lonlat; +layout (location = 1) in vec3 uv; + +out vec3 frag_uv; + +uniform mat3 inv_model; +uniform vec2 ndc_to_clip; +uniform float czf; + +const float PI = 3.141592653589793; +const float SQRT_2 = 1.41421356237309504880168872420969808; + +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); +} + +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); +} + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 5e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; + } else { + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; + } + + return vec2(x2d * 0.5, y2d) / SQRT_2; +} +const float eps = 1.25e-8; +const int n_iter = 100; + +float newton_solve(float z) { + float cte = PI * z; + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; + } + + return 0.5 * x; +} + +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} +vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); + return vec2(-p.x, p.y) / (p.z*PI); +} +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} +vec2 w2c_zea(vec3 p) { + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; +} + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +uniform int u_proj; + +vec2 proj(vec3 p) { + if (u_proj == 0) { + return w2c_tan(p); + } else if (u_proj == 1) { + return w2c_stg(p); + } else if (u_proj == 2) { + return w2c_sin(p); + } else if (u_proj == 3) { + return w2c_zea(p); + } else if (u_proj == 4) { + return w2c_ait(p); + } else if (u_proj == 5) { + return w2c_mol(p); + } else { + return w2c_mer(p); + } +} + +void main() { + vec3 p_xyz = lonlat2xyz(lonlat); + vec3 p_w = inv_model * p_xyz; + vec2 p_clip = proj(p_w.xyz); + + vec2 p_ndc = p_clip / (ndc_to_clip * czf); + gl_Position = vec4(p_ndc, 0.0, 1.0); + + frag_uv = uv; +}"#, + ); + out.insert( + r"hips_raytracer_backcolor.vert", + r#"#version 300 es +precision lowp float; +precision mediump int; + +layout (location = 0) in vec2 pos_clip_space; + +uniform vec2 ndc_to_clip; +uniform float czf; + +void main() { + gl_Position = vec4(pos_clip_space / (ndc_to_clip * czf), 0.0, 1.0); +}"#, + ); + out.insert( + r"hips_rasterizer_u8.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler2DArray; + +uniform sampler2DArray tex; + +in vec3 frag_uv_start; +in vec3 frag_uv_end; +in float frag_blending_factor; + +out vec4 out_frag_color; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} + +uniform float opacity; + +void main() { + vec3 uv0 = frag_uv_start; + vec3 uv1 = frag_uv_end; + uv0.y = 1.0 - uv0.y; + uv1.y = 1.0 - uv1.y; + + vec4 color_start = uvw2c_u8(uv0); + vec4 color_end = uvw2c_u8(uv1); + + out_frag_color = mix(color_start, color_end, frag_blending_factor); + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + out.insert( + r"hips_raytracer_backcolor.frag", + r#"#version 300 es +precision lowp float; +precision mediump int; + +out vec4 out_frag_color; + +uniform vec3 color; + +void main() { + out_frag_color = vec4(color, 1.0); +}"#, + ); + out.insert( + r"catalogs_tan.vert", + r#"#version 300 es +precision lowp float; + layout (location = 0) in vec2 offset; layout (location = 1) in vec2 uv; layout (location = 2) in vec3 center; @@ -2067,54 +949,13 @@ vec2 proj(vec3 p) { void main() { vec3 p = inv_model * center; - vec2 center_pos_clip_space = world2clip_orthographic(p); + vec2 center_pos_clip_space = world2clip_gnomonic(p); vec2 pos_clip_space = center_pos_clip_space; gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); out_uv = uv; out_p = p; -}"#, - ); - out.insert( - r"fits_base.vert", - r#"#version 300 es -precision highp float; -precision highp int; - -layout (location = 0) in vec2 ndc_pos; -layout (location = 1) in vec2 uv; - -out vec2 frag_uv; - -void main() { - gl_Position = vec4(ndc_pos, 0.0, 1.0); - frag_uv = uv; -}"#, - ); - out.insert( - r"hips_raytracer_raytracer.vert", - r#"#version 300 es -precision lowp float; -precision mediump int; - -layout (location = 0) in vec2 pos_clip_space; -layout (location = 1) in vec3 pos_world_space; - -out vec2 out_clip_pos; -out vec3 frag_pos; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform mat3 model; - -void main() { - vec2 uv = pos_clip_space * 0.5 + 0.5; - - frag_pos = model * pos_world_space; - - gl_Position = vec4(pos_clip_space / (ndc_to_clip * czf), 0.0, 1.0); - out_clip_pos = pos_clip_space; }"#, ); out.insert( @@ -2144,7 +985,1167 @@ void main() { }"#, ); out.insert( - r"hips3d_u8.frag", + r"catalogs_arc.vert", + r#"#version 300 es +precision lowp float; +layout (location = 0) in vec2 offset; +layout (location = 1) in vec2 uv; +layout (location = 2) in vec3 center; + +uniform float current_time; +uniform mat3 inv_model; + +uniform vec2 ndc_to_clip; +uniform float czf; +uniform vec2 kernel_size; + +out vec2 out_uv; +out vec3 out_p; + +const float PI = 3.141592653589793; +const float SQRT_2 = 1.41421356237309504880168872420969808; + +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); +} + +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); +} + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 5e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; + } else { + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; + } + + return vec2(x2d * 0.5, y2d) / SQRT_2; +} +const float eps = 1.25e-8; +const int n_iter = 100; + +float newton_solve(float z) { + float cte = PI * z; + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; + } + + return 0.5 * x; +} + +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} +vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); + return vec2(-p.x, p.y) / (p.z*PI); +} +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} +vec2 w2c_zea(vec3 p) { + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; +} + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +uniform int u_proj; + +vec2 proj(vec3 p) { + if (u_proj == 0) { + return w2c_tan(p); + } else if (u_proj == 1) { + return w2c_stg(p); + } else if (u_proj == 2) { + return w2c_sin(p); + } else if (u_proj == 3) { + return w2c_zea(p); + } else if (u_proj == 4) { + return w2c_ait(p); + } else if (u_proj == 5) { + return w2c_mol(p); + } else { + return w2c_mer(p); + } +} + +void main() { + vec3 p = inv_model * center; + + vec2 center_pos_clip_space = world2clip_arc(p); + + vec2 pos_clip_space = center_pos_clip_space; + gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); + + out_uv = uv; + out_p = p; +}"#, + ); + out.insert( + r"moc_base.frag", + r#"#version 300 es + +precision lowp float; +out vec4 color; + +uniform vec4 u_color; + +void main() { + color = u_color; +}"#, + ); + out.insert( + r"colormaps_colormap.vert", + r#"#version 300 es +precision lowp float; +precision lowp sampler2D; + +layout (location = 0) in vec2 position; +layout (location = 1) in vec2 uv; + +out vec2 out_uv; + +void main() { + gl_Position = vec4(position, 0.f, 1.f); + out_uv = uv; +}"#, + ); + out.insert( + r"fits_base.vert", + r#"#version 300 es +precision highp float; +precision highp int; + +layout (location = 0) in vec2 ndc_pos; +layout (location = 1) in vec2 uv; + +out vec2 frag_uv; + +void main() { + gl_Position = vec4(ndc_pos, 0.0, 1.0); + frag_uv = uv; +}"#, + ); + out.insert( + r"hips3d_red.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler3D; +precision lowp isampler3D; +precision lowp usampler3D; + +uniform sampler3D tex; + +in vec3 frag_uv; + +out vec4 out_frag_color; +uniform float opacity; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} + +void main() { + vec3 uv = vec3(frag_uv.xyz); + vec4 color = uvw2c_ra(uv); + + out_frag_color = color; + out_frag_color.a = opacity * out_frag_color.a; +}"#, + ); + out.insert( + r"catalogs_ortho.frag", + r#"#version 300 es +precision lowp float; + +in vec2 out_uv; +in vec3 out_p; + +out vec4 color; + +uniform sampler2D kernel_texture; +uniform float max_density; // max number of sources in a kernel sized HEALPix cell at the current depth +uniform float fov; +uniform float strength; +void main() { + if (out_p.z < 0.f) { + discard; + } + + color = texture(kernel_texture, out_uv) / max(log2(fov*100.0), 1.0); + color.r *= strength; +}"#, + ); + out.insert( + r"hips_rasterizer_i16.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler2DArray; + +uniform sampler2DArray tex; + +in vec3 frag_uv_start; +in vec3 frag_uv_end; +in float frag_blending_factor; + +out vec4 out_frag_color; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} + +uniform float opacity; + +void main() { + vec3 uv0 = frag_uv_start; + vec3 uv1 = frag_uv_end; + uv0.y = 1.0 - uv0.y; + uv1.y = 1.0 - uv1.y; + + vec4 color_start = uvw2c_i16(uv0); + vec4 color_end = uvw2c_i16(uv1); + + out_frag_color = mix(color_start, color_end, frag_blending_factor); + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + out.insert( + r"line_inst_lonlat.vert", + r#"#version 300 es +precision highp float; +layout (location = 0) in vec2 p_a_lonlat; +layout (location = 1) in vec2 p_b_lonlat; +layout (location = 2) in vec2 vertex; + +uniform mat3 u_2world; +uniform vec2 ndc_to_clip; +uniform float czf; +uniform float u_width; +uniform float u_height; +uniform float u_thickness; + +out vec2 l; + +const float PI = 3.141592653589793; +const float SQRT_2 = 1.41421356237309504880168872420969808; + +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); +} + +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); +} + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 5e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; + } else { + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; + } + + return vec2(x2d * 0.5, y2d) / SQRT_2; +} +const float eps = 1.25e-8; +const int n_iter = 100; + +float newton_solve(float z) { + float cte = PI * z; + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; + } + + return 0.5 * x; +} + +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} +vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); + return vec2(-p.x, p.y) / (p.z*PI); +} +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} +vec2 w2c_zea(vec3 p) { + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; +} + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +uniform int u_proj; + +vec2 proj(vec3 p) { + if (u_proj == 0) { + return w2c_tan(p); + } else if (u_proj == 1) { + return w2c_stg(p); + } else if (u_proj == 2) { + return w2c_sin(p); + } else if (u_proj == 3) { + return w2c_zea(p); + } else if (u_proj == 4) { + return w2c_ait(p); + } else if (u_proj == 5) { + return w2c_mol(p); + } else { + return w2c_mer(p); + } +} + +void main() { + vec3 p_a_xyz = lonlat2xyz(p_a_lonlat); + vec3 p_b_xyz = lonlat2xyz(p_b_lonlat); + vec3 p_a_w = u_2world * p_a_xyz; + vec3 p_b_w = u_2world * p_b_xyz; + vec2 p_a_clip = proj(p_a_w); + vec2 p_b_clip = proj(p_b_w); + + vec2 da = p_a_clip - p_b_clip; + + vec2 p_a_ndc = p_a_clip / (ndc_to_clip * czf); + vec2 p_b_ndc = p_b_clip / (ndc_to_clip * czf); + + vec2 x_b = p_b_ndc - p_a_ndc; + vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); + + float ndc2pix = 2.0 / u_width; + + vec2 p_ndc_x = x_b * vertex.x; + vec2 p_ndc_y = (u_thickness + 2.0) * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix; + + vec2 p_ndc = p_a_ndc + p_ndc_x + p_ndc_y; + gl_Position = vec4(p_ndc, 0.f, 1.f); + + l = vec2(dot(da, da), vertex.y); +}"#, + ); + out.insert( + r"hips_rasterizer_rgba.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler2DArray; + +uniform sampler2DArray tex; + +in vec3 frag_uv_start; +in vec3 frag_uv_end; +in float frag_blending_factor; + +out vec4 out_frag_color; +uniform float opacity; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} + +void main() { + vec4 color_start = uvw2c_rgba(frag_uv_start); + vec4 color_end = uvw2c_rgba(frag_uv_end); + + out_frag_color = mix(color_start, color_end, frag_blending_factor); + out_frag_color.a = opacity * out_frag_color.a; +}"#, + ); + out.insert( + r"image_base.vert", + r#"#version 300 es +precision highp float; + +layout (location = 0) in vec2 ndc_pos; +layout (location = 1) in vec2 uv; + +out vec2 frag_uv; + +void main() { + gl_Position = vec4(ndc_pos, 0.0, 1.0); + frag_uv = uv; +}"#, + ); + out.insert( + r"hips3d_f32.frag", r#"#version 300 es precision lowp float; precision lowp sampler3D; @@ -2403,37 +2404,39 @@ void main() { vec3 uv = vec3(frag_uv.xyz); uv.y = 1.0 - uv.y; - vec4 color = uvw2c_u8(uv); + vec4 color = uvw2c_f32(uv); out_frag_color = color; out_frag_color.a = out_frag_color.a * opacity; }"#, ); out.insert( - r"colormaps_colormap.vert", + r"line_base.vert", r#"#version 300 es -precision lowp float; -precision lowp sampler2D; +precision highp float; +layout (location = 0) in vec2 ndc_pos; -layout (location = 0) in vec2 position; -layout (location = 1) in vec2 uv; - -out vec2 out_uv; +out float l; void main() { - gl_Position = vec4(position, 0.f, 1.f); - out_uv = uv; + gl_Position = vec4( + ndc_pos, + 0.0, + 1.0 + ); }"#, ); out.insert( - r"hips_raytracer_rgba2cmap.frag", + r"hips_raytracer_u8.frag", r#"#version 300 es precision lowp float; precision lowp sampler2DArray; -precision lowp sampler2DArray; +precision lowp usampler2DArray; precision lowp isampler2DArray; precision mediump int; +uniform sampler2DArray tex; + in vec3 frag_pos; in vec2 out_clip_pos; out vec4 out_frag_color; @@ -2448,7 +2451,6 @@ struct Tile { uniform Tile textures_tiles[12]; uniform float opacity; -uniform sampler2DArray tex; uniform float scale; uniform float offset; @@ -2812,7 +2814,10 @@ vec3 xyz2uv(vec3 xyz) { void main() { vec3 uv = xyz2uv(normalize(frag_pos)); - vec4 c = uvw2cmap_rgba(uv); + + uv.y = 1.0 - uv.y; + vec4 c = uvw2c_u8(uv); + out_frag_color = c; out_frag_color.a = out_frag_color.a * opacity; @@ -3215,23 +3220,32 @@ void main() { }"#, ); out.insert( - r"line_base.vert", + r"line_inst_ndc.vert", r#"#version 300 es precision highp float; -layout (location = 0) in vec2 ndc_pos; +layout (location = 0) in vec2 p_a; +layout (location = 1) in vec2 p_b; +layout (location = 2) in vec2 vertex; -out float l; +out vec2 l; + +uniform float u_width; +uniform float u_height; +uniform float u_thickness; void main() { - gl_Position = vec4( - ndc_pos, - 0.0, - 1.0 - ); + vec2 x_b = p_b - p_a; + vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); + + float ndc2pix = 2.0 / u_width; + + vec2 p = p_a + x_b * vertex.x + (u_thickness + 2.0) * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix; + gl_Position = vec4(p, 0.f, 1.f); + l = vec2(0.0, vertex.y); }"#, ); out.insert( - r"fits_i16.frag", + r"fits_i32.frag", r#"#version 300 es precision lowp float; precision lowp sampler2D; @@ -3431,1028 +3445,8 @@ void main() { vec2 uv = frag_uv; uv.y = 1.0 - uv.y; - out_frag_color = uv2c_i16(frag_uv); + out_frag_color = uv2c_i32(frag_uv); out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"hips3d_raster.vert", - r#"#version 300 es -precision lowp float; - -layout (location = 0) in vec2 lonlat; -layout (location = 1) in vec3 uv; - -out vec3 frag_uv; - -uniform mat3 inv_model; -uniform vec2 ndc_to_clip; -uniform float czf; - -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; - -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); -} - -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); -} - -vec2 w2c_ait(vec3 p) { - float r = length(p.zx); - float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) - w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma - float y2d = p.y / w; - - float x2d = 0.0; - if (abs(p.x) < 5e-3) { - float x_over_r = p.x/r; - x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; - } else { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; - } - - return vec2(x2d * 0.5, y2d) / SQRT_2; -} -const float eps = 1.25e-8; -const int n_iter = 100; - -float newton_solve(float z) { - float cte = PI * z; - float x = 2.0 * asin(z); - float f = x + sin(x) - cte; - int i = 0; - while (abs(f) > eps && i < n_iter) { - x -= f / (1.0 + cos(x)); - f = x + sin(x) - cte; - i += 1; - } - - return 0.5 * x; -} - -vec2 w2c_mol(vec3 p) { - float g = newton_solve(p.y); - - float sg = sin(g); - float cg = cos(g); - return vec2((atan(-p.x, p.z) * cg) / PI, sg); -} -vec2 w2c_tan(vec3 p) { - p.z = max(p.z, 1e-2); - return vec2(-p.x, p.y) / (p.z*PI); -} -vec2 w2c_stg(vec3 p) { - float w = (1.0 + p.z) * 0.5; - return vec2(-p.x, p.y) / (PI * w); -} -vec2 w2c_zea(vec3 p) { - float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] - return vec2(-p.x, p.y) * 0.5 / w; -} -vec2 w2c_mer(vec3 p) { - return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; -} - -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -uniform int u_proj; - -vec2 proj(vec3 p) { - if (u_proj == 0) { - return w2c_tan(p); - } else if (u_proj == 1) { - return w2c_stg(p); - } else if (u_proj == 2) { - return w2c_sin(p); - } else if (u_proj == 3) { - return w2c_zea(p); - } else if (u_proj == 4) { - return w2c_ait(p); - } else if (u_proj == 5) { - return w2c_mol(p); - } else { - return w2c_mer(p); - } -} - -void main() { - vec3 p_xyz = lonlat2xyz(lonlat); - vec3 p_w = inv_model * p_xyz; - vec2 p_clip = proj(p_w.xyz); - - vec2 p_ndc = p_clip / (ndc_to_clip * czf); - gl_Position = vec4(p_ndc, 0.0, 1.0); - - frag_uv = uv; -}"#, - ); - out.insert( - r"line_inst_ndc.vert", - r#"#version 300 es -precision highp float; -layout (location = 0) in vec2 p_a; -layout (location = 1) in vec2 p_b; -layout (location = 2) in vec2 vertex; - -out vec2 l; - -uniform float u_width; -uniform float u_height; -uniform float u_thickness; - -void main() { - vec2 x_b = p_b - p_a; - vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); - - float ndc2pix = 2.0 / u_width; - - vec2 p = p_a + x_b * vertex.x + (u_thickness + 2.0) * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix; - gl_Position = vec4(p, 0.f, 1.f); - l = vec2(0.0, vertex.y); -}"#, - ); - out.insert( - r"hips_raytracer_backcolor.vert", - r#"#version 300 es -precision lowp float; -precision mediump int; - -layout (location = 0) in vec2 pos_clip_space; - -uniform vec2 ndc_to_clip; -uniform float czf; - -void main() { - gl_Position = vec4(pos_clip_space / (ndc_to_clip * czf), 0.0, 1.0); -}"#, - ); - out.insert( - r"moc_base.vert", - r#"#version 300 es -precision highp float; -layout (location = 0) in vec2 lonlat; - -uniform mat3 u_2world; -uniform vec2 ndc_to_clip; -uniform float czf; - -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; - -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); -} - -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); -} - -vec2 w2c_ait(vec3 p) { - float r = length(p.zx); - float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) - w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma - float y2d = p.y / w; - - float x2d = 0.0; - if (abs(p.x) < 5e-3) { - float x_over_r = p.x/r; - x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; - } else { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; - } - - return vec2(x2d * 0.5, y2d) / SQRT_2; -} -const float eps = 1.25e-8; -const int n_iter = 100; - -float newton_solve(float z) { - float cte = PI * z; - float x = 2.0 * asin(z); - float f = x + sin(x) - cte; - int i = 0; - while (abs(f) > eps && i < n_iter) { - x -= f / (1.0 + cos(x)); - f = x + sin(x) - cte; - i += 1; - } - - return 0.5 * x; -} - -vec2 w2c_mol(vec3 p) { - float g = newton_solve(p.y); - - float sg = sin(g); - float cg = cos(g); - return vec2((atan(-p.x, p.z) * cg) / PI, sg); -} -vec2 w2c_tan(vec3 p) { - p.z = max(p.z, 1e-2); - return vec2(-p.x, p.y) / (p.z*PI); -} -vec2 w2c_stg(vec3 p) { - float w = (1.0 + p.z) * 0.5; - return vec2(-p.x, p.y) / (PI * w); -} -vec2 w2c_zea(vec3 p) { - float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] - return vec2(-p.x, p.y) * 0.5 / w; -} -vec2 w2c_mer(vec3 p) { - return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; -} - -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -uniform int u_proj; - -vec2 proj(vec3 p) { - if (u_proj == 0) { - return w2c_tan(p); - } else if (u_proj == 1) { - return w2c_stg(p); - } else if (u_proj == 2) { - return w2c_sin(p); - } else if (u_proj == 3) { - return w2c_zea(p); - } else if (u_proj == 4) { - return w2c_ait(p); - } else if (u_proj == 5) { - return w2c_mol(p); - } else { - return w2c_mer(p); - } -} - -void main() { - vec3 p_xyz = lonlat2xyz(lonlat); - vec3 p_w = u_2world * p_xyz; - vec2 p_clip = proj(p_w); - - vec2 p_ndc = p_clip / (ndc_to_clip * czf); - gl_Position = vec4(p_ndc, 0.f, 1.f); -}"#, - ); - out.insert( - r"hips3d_i32.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler3D; -precision lowp isampler3D; -precision lowp usampler3D; - -uniform sampler3D tex; - -in vec3 frag_uv; - -out vec4 out_frag_color; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} - -uniform float opacity; - -void main() { - vec3 uv = vec3(frag_uv.xyz); - uv.y = 1.0 - uv.y; - - vec4 color = uvw2c_i32(uv); - - out_frag_color = color; - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"line_inst_lonlat.vert", - r#"#version 300 es -precision highp float; -layout (location = 0) in vec2 p_a_lonlat; -layout (location = 1) in vec2 p_b_lonlat; -layout (location = 2) in vec2 vertex; - -uniform mat3 u_2world; -uniform vec2 ndc_to_clip; -uniform float czf; -uniform float u_width; -uniform float u_height; -uniform float u_thickness; - -out vec2 l; - -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; - -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); -} - -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); -} - -vec2 w2c_ait(vec3 p) { - float r = length(p.zx); - float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) - w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma - float y2d = p.y / w; - - float x2d = 0.0; - if (abs(p.x) < 5e-3) { - float x_over_r = p.x/r; - x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; - } else { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; - } - - return vec2(x2d * 0.5, y2d) / SQRT_2; -} -const float eps = 1.25e-8; -const int n_iter = 100; - -float newton_solve(float z) { - float cte = PI * z; - float x = 2.0 * asin(z); - float f = x + sin(x) - cte; - int i = 0; - while (abs(f) > eps && i < n_iter) { - x -= f / (1.0 + cos(x)); - f = x + sin(x) - cte; - i += 1; - } - - return 0.5 * x; -} - -vec2 w2c_mol(vec3 p) { - float g = newton_solve(p.y); - - float sg = sin(g); - float cg = cos(g); - return vec2((atan(-p.x, p.z) * cg) / PI, sg); -} -vec2 w2c_tan(vec3 p) { - p.z = max(p.z, 1e-2); - return vec2(-p.x, p.y) / (p.z*PI); -} -vec2 w2c_stg(vec3 p) { - float w = (1.0 + p.z) * 0.5; - return vec2(-p.x, p.y) / (PI * w); -} -vec2 w2c_zea(vec3 p) { - float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] - return vec2(-p.x, p.y) * 0.5 / w; -} -vec2 w2c_mer(vec3 p) { - return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; -} - -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -uniform int u_proj; - -vec2 proj(vec3 p) { - if (u_proj == 0) { - return w2c_tan(p); - } else if (u_proj == 1) { - return w2c_stg(p); - } else if (u_proj == 2) { - return w2c_sin(p); - } else if (u_proj == 3) { - return w2c_zea(p); - } else if (u_proj == 4) { - return w2c_ait(p); - } else if (u_proj == 5) { - return w2c_mol(p); - } else { - return w2c_mer(p); - } -} - -void main() { - vec3 p_a_xyz = lonlat2xyz(p_a_lonlat); - vec3 p_b_xyz = lonlat2xyz(p_b_lonlat); - vec3 p_a_w = u_2world * p_a_xyz; - vec3 p_b_w = u_2world * p_b_xyz; - vec2 p_a_clip = proj(p_a_w); - vec2 p_b_clip = proj(p_b_w); - - vec2 da = p_a_clip - p_b_clip; - - vec2 p_a_ndc = p_a_clip / (ndc_to_clip * czf); - vec2 p_b_ndc = p_b_clip / (ndc_to_clip * czf); - - vec2 x_b = p_b_ndc - p_a_ndc; - vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); - - float ndc2pix = 2.0 / u_width; - - vec2 p_ndc_x = x_b * vertex.x; - vec2 p_ndc_y = (u_thickness + 2.0) * y_b * vertex.y * vec2(1.0, u_width/u_height) * ndc2pix; - - vec2 p_ndc = p_a_ndc + p_ndc_x + p_ndc_y; - gl_Position = vec4(p_ndc, 0.f, 1.f); - - l = vec2(dot(da, da), vertex.y); -}"#, - ); - out.insert( - r"hips_rasterizer_raster.vert", - r#"#version 300 es -precision highp float; - -layout (location = 0) in vec3 xyz; -layout (location = 1) in vec3 uv_start; -layout (location = 2) in vec3 uv_end; -layout (location = 3) in float time_tile_received; - -out vec3 frag_uv_start; -out vec3 frag_uv_end; -out float frag_blending_factor; - -uniform mat3 inv_model; -uniform vec2 ndc_to_clip; -uniform float czf; -uniform float current_time; - -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; - -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); -} - -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); -} - -vec2 w2c_ait(vec3 p) { - float r = length(p.zx); - float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) - w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma - float y2d = p.y / w; - - float x2d = 0.0; - if (abs(p.x) < 5e-3) { - float x_over_r = p.x/r; - x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; - } else { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; - } - - return vec2(x2d * 0.5, y2d) / SQRT_2; -} -const float eps = 1.25e-8; -const int n_iter = 100; - -float newton_solve(float z) { - float cte = PI * z; - float x = 2.0 * asin(z); - float f = x + sin(x) - cte; - int i = 0; - while (abs(f) > eps && i < n_iter) { - x -= f / (1.0 + cos(x)); - f = x + sin(x) - cte; - i += 1; - } - - return 0.5 * x; -} - -vec2 w2c_mol(vec3 p) { - float g = newton_solve(p.y); - - float sg = sin(g); - float cg = cos(g); - return vec2((atan(-p.x, p.z) * cg) / PI, sg); -} -vec2 w2c_tan(vec3 p) { - p.z = max(p.z, 1e-2); - return vec2(-p.x, p.y) / (p.z*PI); -} -vec2 w2c_stg(vec3 p) { - float w = (1.0 + p.z) * 0.5; - return vec2(-p.x, p.y) / (PI * w); -} -vec2 w2c_zea(vec3 p) { - float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] - return vec2(-p.x, p.y) * 0.5 / w; -} -vec2 w2c_mer(vec3 p) { - return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; -} - -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -uniform int u_proj; - -vec2 proj(vec3 p) { - if (u_proj == 0) { - return w2c_tan(p); - } else if (u_proj == 1) { - return w2c_stg(p); - } else if (u_proj == 2) { - return w2c_sin(p); - } else if (u_proj == 3) { - return w2c_zea(p); - } else if (u_proj == 4) { - return w2c_ait(p); - } else if (u_proj == 5) { - return w2c_mol(p); - } else { - return w2c_mer(p); - } -} - -void main() { - vec3 p_w = inv_model * xyz; - vec2 p_clip = proj(p_w); - - vec2 p_ndc = p_clip / (ndc_to_clip * czf); - gl_Position = vec4(p_ndc, 0.0, 1.0); - - frag_uv_start = uv_start; - frag_uv_end = uv_end; - frag_blending_factor = min((current_time - time_tile_received) / 200.0, 1.0); -}"#, - ); - out.insert( - r"image_base.vert", - r#"#version 300 es -precision highp float; - -layout (location = 0) in vec2 ndc_pos; -layout (location = 1) in vec2 uv; - -out vec2 frag_uv; - -void main() { - gl_Position = vec4(ndc_pos, 0.0, 1.0); - frag_uv = uv; -}"#, - ); - out.insert( - r"catalogs_ortho.frag", - r#"#version 300 es -precision lowp float; - -in vec2 out_uv; -in vec3 out_p; - -out vec4 color; - -uniform sampler2D kernel_texture; -uniform float max_density; // max number of sources in a kernel sized HEALPix cell at the current depth -uniform float fov; -uniform float strength; -void main() { - if (out_p.z < 0.f) { - discard; - } - - color = texture(kernel_texture, out_uv) / max(log2(fov*100.0), 1.0); - color.r *= strength; -}"#, - ); - out.insert( - r"catalogs_catalog.frag", - r#"#version 300 es -precision lowp float; - -in vec2 out_uv; -in vec3 out_p; - -out vec4 color; - -uniform sampler2D kernel_texture; -uniform float max_density; // max number of sources in a kernel sized HEALPix cell at the current depth -uniform float fov; -uniform float strength; -void main() { - color = texture(kernel_texture, out_uv) / max(log2(fov*100.0), 1.0); - color.r *= strength; -}"#, - ); - out.insert( - r"catalogs_healpix.vert", - r#"#version 300 es -precision lowp float; -layout (location = 0) in vec2 offset; -layout (location = 1) in vec2 uv; -layout (location = 2) in vec3 center; - -uniform float current_time; -uniform mat3 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -out vec2 out_uv; -out vec3 out_p; - -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; - -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); -} - -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); -} - -vec2 w2c_ait(vec3 p) { - float r = length(p.zx); - float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) - w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma - float y2d = p.y / w; - - float x2d = 0.0; - if (abs(p.x) < 5e-3) { - float x_over_r = p.x/r; - x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; - } else { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; - } - - return vec2(x2d * 0.5, y2d) / SQRT_2; -} -const float eps = 1.25e-8; -const int n_iter = 100; - -float newton_solve(float z) { - float cte = PI * z; - float x = 2.0 * asin(z); - float f = x + sin(x) - cte; - int i = 0; - while (abs(f) > eps && i < n_iter) { - x -= f / (1.0 + cos(x)); - f = x + sin(x) - cte; - i += 1; - } - - return 0.5 * x; -} - -vec2 w2c_mol(vec3 p) { - float g = newton_solve(p.y); - - float sg = sin(g); - float cg = cos(g); - return vec2((atan(-p.x, p.z) * cg) / PI, sg); -} -vec2 w2c_tan(vec3 p) { - p.z = max(p.z, 1e-2); - return vec2(-p.x, p.y) / (p.z*PI); -} -vec2 w2c_stg(vec3 p) { - float w = (1.0 + p.z) * 0.5; - return vec2(-p.x, p.y) / (PI * w); -} -vec2 w2c_zea(vec3 p) { - float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] - return vec2(-p.x, p.y) * 0.5 / w; -} -vec2 w2c_mer(vec3 p) { - return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; -} - -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -uniform int u_proj; - -vec2 proj(vec3 p) { - if (u_proj == 0) { - return w2c_tan(p); - } else if (u_proj == 1) { - return w2c_stg(p); - } else if (u_proj == 2) { - return w2c_sin(p); - } else if (u_proj == 3) { - return w2c_zea(p); - } else if (u_proj == 4) { - return w2c_ait(p); - } else if (u_proj == 5) { - return w2c_mol(p); - } else { - return w2c_mer(p); - } -} - - -void main() { - vec3 p = inv_model * center; - - vec2 center_pos_clip_space = world2clip_healpix(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); - - out_uv = uv; - out_p = p; }"#, ); out.insert( @@ -4661,7 +3655,7 @@ void main() { }"#, ); out.insert( - r"catalogs_arc.vert", + r"catalogs_ortho.vert", r#"#version 300 es precision lowp float; layout (location = 0) in vec2 offset; @@ -4779,10 +3773,11 @@ vec2 proj(vec3 p) { } } + void main() { vec3 p = inv_model * center; - vec2 center_pos_clip_space = world2clip_arc(p); + vec2 center_pos_clip_space = world2clip_orthographic(p); vec2 pos_clip_space = center_pos_clip_space; gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); @@ -4792,552 +3787,28 @@ void main() { }"#, ); out.insert( - r"hips_rasterizer_rgba.frag", + r"hips_raytracer_raytracer.vert", r#"#version 300 es precision lowp float; -precision lowp sampler2DArray; +precision mediump int; -uniform sampler2DArray tex; +layout (location = 0) in vec2 pos_clip_space; +layout (location = 1) in vec3 pos_world_space; -in vec3 frag_uv_start; -in vec3 frag_uv_end; -in float frag_blending_factor; +out vec2 out_clip_pos; +out vec3 frag_pos; -out vec4 out_frag_color; -uniform float opacity; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} +uniform vec2 ndc_to_clip; +uniform float czf; +uniform mat3 model; void main() { - vec4 color_start = uvw2c_rgba(frag_uv_start); - vec4 color_end = uvw2c_rgba(frag_uv_end); + vec2 uv = pos_clip_space * 0.5 + 0.5; - out_frag_color = mix(color_start, color_end, frag_blending_factor); - out_frag_color.a = opacity * out_frag_color.a; -}"#, - ); - out.insert( - r"hips_rasterizer_i16.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler2DArray; + frag_pos = model * pos_world_space; -uniform sampler2DArray tex; - -in vec3 frag_uv_start; -in vec3 frag_uv_end; -in float frag_blending_factor; - -out vec4 out_frag_color; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} - -uniform float opacity; - -void main() { - vec3 uv0 = frag_uv_start; - vec3 uv1 = frag_uv_end; - uv0.y = 1.0 - uv0.y; - uv1.y = 1.0 - uv1.y; - - vec4 color_start = uvw2c_i16(uv0); - vec4 color_end = uvw2c_i16(uv1); - - out_frag_color = mix(color_start, color_end, frag_blending_factor); - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"passes_post_vertex_100es.vert", - r#"#version 300 es -precision mediump float; - -layout (location = 0) in vec2 a_pos; -out vec2 v_tc; - -void main() { - gl_Position = vec4(a_pos * 2. - 1., 0.0, 1.0); - v_tc = a_pos; + gl_Position = vec4(pos_clip_space / (ndc_to_clip * czf), 0.0, 1.0); + out_clip_pos = pos_clip_space; }"#, ); out.insert( @@ -5626,743 +4097,7 @@ void main() { }"#, ); out.insert( - r"fits_i32.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler2D; -precision mediump int; - -out vec4 out_frag_color; -in vec2 frag_uv; - -uniform sampler2D tex; -uniform float opacity; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uv2c_f32(vec2 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uv2c_i32(vec2 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uv2c_i16(vec2 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uv2c_u8(vec2 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} - -void main() { - vec2 uv = frag_uv; - uv.y = 1.0 - uv.y; - - out_frag_color = uv2c_i32(frag_uv); - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"hips3d_red.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler3D; -precision lowp isampler3D; -precision lowp usampler3D; - -uniform sampler3D tex; - -in vec3 frag_uv; - -out vec4 out_frag_color; -uniform float opacity; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} - -void main() { - vec3 uv = vec3(frag_uv.xyz); - vec4 color = uvw2c_ra(uv); - - out_frag_color = color; - out_frag_color.a = opacity * out_frag_color.a; -}"#, - ); - out.insert( - r"hips3d_f32.frag", - r#"#version 300 es -precision lowp float; -precision lowp sampler3D; - -uniform sampler3D tex; - -in vec3 frag_uv; - -out vec4 out_frag_color; - -uniform float scale; -uniform float offset; -uniform float blank; -uniform float min_value; -uniform float max_value; -uniform int H; -uniform float reversed; - -uniform sampler2D colormaps; -uniform float num_colormaps; -uniform float colormap_id; - -vec4 colormap_f(float x) { - float id = (colormap_id + 0.5) / num_colormaps; - return texture(colormaps, vec2(x, id)); -} -float linear_f(float x, float min_value, float max_value) { - return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); -} - -float sqrt_f(float x, float min_value, float max_value) { - float a = linear_f(x, min_value, max_value); - return sqrt(a); -} - -float log_f(float x, float min_value, float max_value) { - float y = linear_f(x, min_value, max_value); - float a = 1000.0; - return log(a*y + 1.0)/log(a); -} - -float asinh_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return asinh(10.0*d)/3.0; -} - -float pow2_f(float x, float min_value, float max_value) { - float d = linear_f(x, min_value, max_value); - return d*d; -} - -float transfer_func(int H, float x, float min_value, float max_value) { - if (H == 0) { - return linear_f(x, min_value, max_value); - } else if (H == 1) { - return sqrt_f(x, min_value, max_value); - } else if (H == 2) { - return log_f(x, min_value, max_value); - } else if (H == 3) { - return asinh_f(x, min_value, max_value); - } else { - return pow2_f(x, min_value, max_value); - } -} - -uniform float k_gamma; -uniform float k_saturation; -uniform float k_contrast; -uniform float k_brightness; -uniform float k_exposure; - -vec4 apply_gamma(vec4 ic, float g) { - float new_r = pow(ic.r, g); - float new_g = pow(ic.g, g); - float new_b = pow(ic.b, g); - - return vec4(new_r, new_g, new_b, ic.a); -} - -vec4 apply_saturation(vec4 color, float value) { - const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); - vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); - - return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); -} - -vec4 apply_contrast(vec4 color, float value) { - return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); -} - -vec4 apply_brightness(vec4 color, float value) { - return vec4(color.rgb + value, color.a); -} - -vec4 apply_exposure(vec4 color, float value) { - return vec4((1.0 + value) * color.rgb, color.a); -} - -vec4 apply_tonal(vec4 color) { - return apply_gamma( - apply_saturation( - apply_contrast( - apply_brightness(color, k_brightness), - k_contrast - ), - k_saturation - ), - k_gamma - ); -} -vec3 rgb2hsv(vec3 c) { - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) { - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -highp float decode_f32(highp vec4 rgba) { - highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; - highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; - if (abs(Exponent + 127.0) < 1e-3) { - return 0.0; - } - highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); - highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); - return Result; -} - -int decode_i32(vec4 rgba) { - int r = int(rgba.r * 255.0 + 0.5); - int g = int(rgba.g * 255.0 + 0.5); - int b = int(rgba.b * 255.0 + 0.5); - int a = int(rgba.a * 255.0 + 0.5); - - int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer - - return value; -} - -int decode_i16(vec2 rg) { - int r = int(rg.r * 255.0 + 0.5); - int g = int(rg.g * 255.0 + 0.5); - - int value = (r << 8) | g; // Combine into a 16-bit integer - - if (value >= 32768) { - value -= 65536; - } - - return value; -} - -uint decode_u8(float r) { - uint value = uint(r * 255.0 + 0.5); - return value; -} - - - - -vec4 uvw2c_r(vec3 uv) { - vec2 va = texture(tex, uv).ra; - - va.x = transfer_func(H, va.x, min_value, max_value); - - va.x = mix(va.x, 1.0 - va.x, reversed); - - vec4 c = colormap_f(va.x); - return apply_tonal(c); -} - -vec4 uvw2c_rgba(vec3 uv) { - vec4 c = texture(tex, uv).rgba; - - c.r = transfer_func(H, c.r, min_value, max_value); - c.g = transfer_func(H, c.g, min_value, max_value); - c.b = transfer_func(H, c.b, min_value, max_value); - - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 uvw2c_ra(vec3 uv) { - vec2 c = texture(tex, uv).rg; - - c.r = transfer_func(H, c.r, min_value, max_value); - - c.r = mix(c.r, 1.0 - c.r, reversed); - - vec3 color = colormap_f(c.r).rgb; - - return apply_tonal(vec4(color, c.g)); -} - -vec4 uvw2cmap_rgba(vec3 uv) { - float v = texture(tex, uv).r; - v = transfer_func(H, v, min_value, max_value); - vec4 c = colormap_f(v); - c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); - - return apply_tonal(c); -} - -vec4 val2c_f32(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); - return apply_tonal(new_color); -} - -vec4 val2c(float x) { - float alpha = x * scale + offset; - alpha = transfer_func(H, alpha, min_value, max_value); - - alpha = mix(alpha, 1.0 - alpha, reversed); - - vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); - return apply_tonal(new_color); -} - -vec4 uvw2c_f32(vec3 uv) { - float val = decode_f32(texture(tex, uv).rgba*255.0); - return val2c_f32(val); -} - -vec4 uvw2c_i32(vec3 uv) { - float val = float(decode_i32(texture(tex, uv).rgba)); - return val2c(val); -} - -vec4 uvw2c_i16(vec3 uv) { - float val = float(decode_i16(texture(tex, uv).rg)); - return val2c(val); -} - -vec4 uvw2c_u8(vec3 uv) { - float val = float(decode_u8(texture(tex, uv).r)); - return val2c(val); -} - -uniform float opacity; - -void main() { - vec3 uv = vec3(frag_uv.xyz); - uv.y = 1.0 - uv.y; - - vec4 color = uvw2c_f32(uv); - - out_frag_color = color; - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"hips_rasterizer_u8.frag", + r"hips_rasterizer_i32.frag", r#"#version 300 es precision lowp float; precision lowp sampler2DArray; @@ -6625,11 +4360,966 @@ void main() { uv0.y = 1.0 - uv0.y; uv1.y = 1.0 - uv1.y; - vec4 color_start = uvw2c_u8(uv0); - vec4 color_end = uvw2c_u8(uv1); + vec4 color_start = uvw2c_i32(uv0); + vec4 color_end = uvw2c_i32(uv1); out_frag_color = mix(color_start, color_end, frag_blending_factor); out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + out.insert( + r"hips_raytracer_rgba.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler2DArray; +precision mediump int; + +uniform sampler2DArray tex; + +in vec2 out_clip_pos; +in vec3 frag_pos; +out vec4 out_frag_color; + +struct Tile { + int uniq; // Healpix cell + int texture_idx; // Index in the texture buffer + float start_time; // Absolute time that the load has been done in ms + float empty; +}; + +uniform Tile textures_tiles[12]; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} +const float TWICE_PI = 6.28318530718; +const float PI = 3.141592653589793; +const float FOUR_OVER_PI = 1.27323954474; +const float TRANSITION_Z = 0.66666666666; +const float TRANSITION_Z_INV = 1.5; + +int quarter(vec2 p) { + int x_neg = int(p.x < 0.0); + int y_neg = int(p.y < 0.0); + int q = (x_neg + y_neg) | (y_neg << 1); + return q; +} + +float xpm1(vec2 p) { + bool x_neg = (p.x < 0.0); + bool y_neg = (p.y < 0.0); + float lon = atan(abs(p.y), abs(p.x)); + float x02 = lon * FOUR_OVER_PI; + if (x_neg != y_neg) { // Could be replaced by a sign copy from (x_neg ^ y_neg) << 32 + return 1.0 - x02; + } else { + return x02 - 1.0; + } +} + +float one_minus_z_pos(vec3 p) { + float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 + + if (d2 < 1e-1) { // <=> dec > 84.27 deg + return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); + } + return 1.0f - p.z; +} + +float one_minus_z_neg(vec3 p) { + float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 + if (d2 < 1e-1f) { // <=> dec < -84.27 deg + return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); + } + return p.z + 1.0; +} + +int ij2z(int i, int j) { + int i4 = i | (j << 2); + + int j4 = (i4 ^ (i4 >> 1)) & 0x22222222; + int i5 = i4 ^ j4 ^ (j4 << 1); + + return i5; +} + +struct HashDxDy { + int idx; + float dx; + float dy; +}; + +uniform sampler2D ang2pixd; +HashDxDy hash_with_dxdy2(vec2 radec) { + vec2 aa = vec2(radec.x/TWICE_PI + 1.0, (radec.y/PI) + 0.5); + vec3 v = texture(ang2pixd, aa).rgb; + return HashDxDy( + int(v.x * 255.0), + v.y, + v.z + ); +} +HashDxDy hash_with_dxdy(int depth, vec3 p) { + + int nside = 1 << depth; + float half_nside = float(nside) * 0.5; + + float x_pm1 = xpm1(p.xy); + int q = quarter(p.xy); + + int d0h = 0; + vec2 p_proj = vec2(0.0); + if (p.z > TRANSITION_Z) { + float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_pos(p)); + p_proj = vec2(x_pm1 * sqrt_3_one_min_z, 2.0 - sqrt_3_one_min_z); + d0h = q; + } else if (p.z < -TRANSITION_Z) { + float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_neg(p)); + p_proj = vec2(x_pm1 * sqrt_3_one_min_z, sqrt_3_one_min_z); + d0h = q + 8; + } else { + float y_pm1 = p.z * TRANSITION_Z_INV; + int q01 = int(x_pm1 > y_pm1); // 0/1 + int q12 = int(x_pm1 >= -y_pm1); // 0\1 + int q03 = 1 - q12; // 1\0 + int q1 = q01 & q12; // = 1 if q1, 0 else + p_proj = vec2( + x_pm1 - float(q01 + q12 - 1), + y_pm1 + float(q01 + q03) + ); + d0h = ((q01 + q03) << 2) + ((q + q1) & 3); + } + + float x = (half_nside * (p_proj.x + p_proj.y)); + float y = (half_nside * (p_proj.y - p_proj.x)); + int i = int(x); + int j = int(y); + + return HashDxDy( + (d0h << (depth << 1)) + ij2z(i, j), + x - float(i), + y - float(j) + ); +} +vec3 xyz2uv(vec3 xyz) { + HashDxDy result = hash_with_dxdy(0, xyz.zxy); + + int idx = result.idx; + vec2 offset = vec2(result.dy, result.dx); + Tile tile = textures_tiles[idx]; + + return vec3(offset, float(tile.texture_idx)); +} + +uniform float opacity; +uniform vec4 no_tile_color; + +void main() { + vec3 uv = xyz2uv(normalize(frag_pos)); + vec4 c = uvw2c_rgba(uv); + + out_frag_color = c; + out_frag_color = vec4(c.rgb, opacity * c.a); +}"#, + ); + out.insert( + r"catalogs_mercator.vert", + r#"#version 300 es +precision lowp float; +layout (location = 0) in vec2 offset; +layout (location = 1) in vec2 uv; +layout (location = 2) in vec3 center; + +uniform float current_time; +uniform mat3 inv_model; + +uniform vec2 ndc_to_clip; +uniform float czf; +uniform vec2 kernel_size; + +out vec2 out_uv; +out vec3 out_p; + +const float PI = 3.141592653589793; +const float SQRT_2 = 1.41421356237309504880168872420969808; + +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); +} + +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); +} + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 5e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; + } else { + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; + } + + return vec2(x2d * 0.5, y2d) / SQRT_2; +} +const float eps = 1.25e-8; +const int n_iter = 100; + +float newton_solve(float z) { + float cte = PI * z; + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; + } + + return 0.5 * x; +} + +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} +vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); + return vec2(-p.x, p.y) / (p.z*PI); +} +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} +vec2 w2c_zea(vec3 p) { + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; +} + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +uniform int u_proj; + +vec2 proj(vec3 p) { + if (u_proj == 0) { + return w2c_tan(p); + } else if (u_proj == 1) { + return w2c_stg(p); + } else if (u_proj == 2) { + return w2c_sin(p); + } else if (u_proj == 3) { + return w2c_zea(p); + } else if (u_proj == 4) { + return w2c_ait(p); + } else if (u_proj == 5) { + return w2c_mol(p); + } else { + return w2c_mer(p); + } +} + + +void main() { + vec3 p = inv_model * center; + + vec2 center_pos_clip_space = world2clip_mercator(p); + + vec2 pos_clip_space = center_pos_clip_space; + gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); + + out_uv = uv; + out_p = p; +}"#, + ); + out.insert( + r"colormaps_colormap.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler2D; + +in vec2 out_uv; +out vec4 color; + +uniform sampler2D texture_fbo; +uniform float alpha; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} + +void main() { + float opacity = texture(texture_fbo, out_uv).r; + + float o = smoothstep(0.0, 0.1, opacity); + + color = colormap_f(opacity); + color.a = o * alpha; +}"#, + ); + out.insert( + r"catalogs_healpix.vert", + r#"#version 300 es +precision lowp float; +layout (location = 0) in vec2 offset; +layout (location = 1) in vec2 uv; +layout (location = 2) in vec3 center; + +uniform float current_time; +uniform mat3 inv_model; + +uniform vec2 ndc_to_clip; +uniform float czf; +uniform vec2 kernel_size; + +out vec2 out_uv; +out vec3 out_p; + +const float PI = 3.141592653589793; +const float SQRT_2 = 1.41421356237309504880168872420969808; + +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); +} + +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); +} + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 5e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; + } else { + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; + } + + return vec2(x2d * 0.5, y2d) / SQRT_2; +} +const float eps = 1.25e-8; +const int n_iter = 100; + +float newton_solve(float z) { + float cte = PI * z; + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; + } + + return 0.5 * x; +} + +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} +vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); + return vec2(-p.x, p.y) / (p.z*PI); +} +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} +vec2 w2c_zea(vec3 p) { + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; +} + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +uniform int u_proj; + +vec2 proj(vec3 p) { + if (u_proj == 0) { + return w2c_tan(p); + } else if (u_proj == 1) { + return w2c_stg(p); + } else if (u_proj == 2) { + return w2c_sin(p); + } else if (u_proj == 3) { + return w2c_zea(p); + } else if (u_proj == 4) { + return w2c_ait(p); + } else if (u_proj == 5) { + return w2c_mol(p); + } else { + return w2c_mer(p); + } +} + + +void main() { + vec3 p = inv_model * center; + + vec2 center_pos_clip_space = world2clip_healpix(p); + + vec2 pos_clip_space = center_pos_clip_space; + gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); + + out_uv = uv; + out_p = p; +}"#, + ); + out.insert( + r"hips3d_i32.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler3D; +precision lowp isampler3D; +precision lowp usampler3D; + +uniform sampler3D tex; + +in vec3 frag_uv; + +out vec4 out_frag_color; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} + +uniform float opacity; + +void main() { + vec3 uv = vec3(frag_uv.xyz); + uv.y = 1.0 - uv.y; + + vec4 color = uvw2c_i32(uv); + + out_frag_color = color; + out_frag_color.a = out_frag_color.a * opacity; }"#, ); out.insert( @@ -6838,14 +5528,1458 @@ void main() { }"#, ); out.insert( - r"hips_raytracer_u8.frag", + r"fits_i16.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler2D; +precision mediump int; + +out vec4 out_frag_color; +in vec2 frag_uv; + +uniform sampler2D tex; +uniform float opacity; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uv2c_f32(vec2 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uv2c_i32(vec2 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uv2c_i16(vec2 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uv2c_u8(vec2 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} + +void main() { + vec2 uv = frag_uv; + uv.y = 1.0 - uv.y; + + out_frag_color = uv2c_i16(frag_uv); + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + out.insert( + r"hips_rasterizer_f32.frag", r#"#version 300 es precision lowp float; precision lowp sampler2DArray; -precision lowp usampler2DArray; + +uniform sampler2DArray tex; + +in vec3 frag_uv_start; +in vec3 frag_uv_end; +in float frag_blending_factor; + +out vec4 out_frag_color; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} + +uniform float opacity; + +void main() { + vec3 uv0 = frag_uv_start; + vec3 uv1 = frag_uv_end; + uv0.y = 1.0 - uv0.y; + uv1.y = 1.0 - uv1.y; + + vec4 color_start = uvw2c_f32(uv0); + vec4 color_end = uvw2c_f32(uv1); + + out_frag_color = mix(color_start, color_end, frag_blending_factor); + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + out.insert( + r"catalogs_mollweide.vert", + r#"#version 300 es +precision lowp float; +layout (location = 0) in vec2 offset; +layout (location = 1) in vec2 uv; +layout (location = 2) in vec3 center; + +uniform float current_time; +uniform mat3 inv_model; + +uniform vec2 ndc_to_clip; +uniform float czf; +uniform vec2 kernel_size; + +out vec2 out_uv; +out vec3 out_p; + +const float PI = 3.141592653589793; +const float SQRT_2 = 1.41421356237309504880168872420969808; + +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); +} + +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); +} + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 5e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; + } else { + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; + } + + return vec2(x2d * 0.5, y2d) / SQRT_2; +} +const float eps = 1.25e-8; +const int n_iter = 100; + +float newton_solve(float z) { + float cte = PI * z; + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; + } + + return 0.5 * x; +} + +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} +vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); + return vec2(-p.x, p.y) / (p.z*PI); +} +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} +vec2 w2c_zea(vec3 p) { + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; +} + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +uniform int u_proj; + +vec2 proj(vec3 p) { + if (u_proj == 0) { + return w2c_tan(p); + } else if (u_proj == 1) { + return w2c_stg(p); + } else if (u_proj == 2) { + return w2c_sin(p); + } else if (u_proj == 3) { + return w2c_zea(p); + } else if (u_proj == 4) { + return w2c_ait(p); + } else if (u_proj == 5) { + return w2c_mol(p); + } else { + return w2c_mer(p); + } +} + + +void main() { + vec3 p = inv_model * center; + + vec2 center_pos_clip_space = world2clip_mollweide(p); + + vec2 pos_clip_space = center_pos_clip_space; + gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); + + out_uv = uv; + out_p = p; +}"#, + ); + out.insert( + r"moc_base.vert", + r#"#version 300 es +precision highp float; +layout (location = 0) in vec2 lonlat; + +uniform mat3 u_2world; +uniform vec2 ndc_to_clip; +uniform float czf; + +const float PI = 3.141592653589793; +const float SQRT_2 = 1.41421356237309504880168872420969808; + +vec2 w2c_sin(vec3 p) { + vec2 q = vec2(-p.x, p.y); + return p.z >= 0.f ? q : normalize(q); +} + +vec2 w2c_sin_no_backface(vec3 p) { + return vec2(-p.x, p.y); +} + +vec2 w2c_ait(vec3 p) { + float r = length(p.zx); + float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) + w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma + float y2d = p.y / w; + + float x2d = 0.0; + if (abs(p.x) < 5e-3) { + float x_over_r = p.x/r; + x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; + } else { + w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) + x2d = sign(-p.x) * w; + } + + return vec2(x2d * 0.5, y2d) / SQRT_2; +} +const float eps = 1.25e-8; +const int n_iter = 100; + +float newton_solve(float z) { + float cte = PI * z; + float x = 2.0 * asin(z); + float f = x + sin(x) - cte; + int i = 0; + while (abs(f) > eps && i < n_iter) { + x -= f / (1.0 + cos(x)); + f = x + sin(x) - cte; + i += 1; + } + + return 0.5 * x; +} + +vec2 w2c_mol(vec3 p) { + float g = newton_solve(p.y); + + float sg = sin(g); + float cg = cos(g); + return vec2((atan(-p.x, p.z) * cg) / PI, sg); +} +vec2 w2c_tan(vec3 p) { + p.z = max(p.z, 1e-2); + return vec2(-p.x, p.y) / (p.z*PI); +} +vec2 w2c_stg(vec3 p) { + float w = (1.0 + p.z) * 0.5; + return vec2(-p.x, p.y) / (PI * w); +} +vec2 w2c_zea(vec3 p) { + float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] + return vec2(-p.x, p.y) * 0.5 / w; +} +vec2 w2c_mer(vec3 p) { + return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; +} + +vec3 lonlat2xyz(vec2 lonlat) { + float t = lonlat.x; + float tc = cos(t); + float ts = sin(t); + + float d = lonlat.y; + float dc = cos(d); + float ds = sin(d); + + return vec3(dc * ts, ds, dc * tc); +} + +uniform int u_proj; + +vec2 proj(vec3 p) { + if (u_proj == 0) { + return w2c_tan(p); + } else if (u_proj == 1) { + return w2c_stg(p); + } else if (u_proj == 2) { + return w2c_sin(p); + } else if (u_proj == 3) { + return w2c_zea(p); + } else if (u_proj == 4) { + return w2c_ait(p); + } else if (u_proj == 5) { + return w2c_mol(p); + } else { + return w2c_mer(p); + } +} + +void main() { + vec3 p_xyz = lonlat2xyz(lonlat); + vec3 p_w = u_2world * p_xyz; + vec2 p_clip = proj(p_w); + + vec2 p_ndc = p_clip / (ndc_to_clip * czf); + gl_Position = vec4(p_ndc, 0.f, 1.f); +}"#, + ); + out.insert( + r"catalogs_catalog.frag", + r#"#version 300 es +precision lowp float; + +in vec2 out_uv; +in vec3 out_p; + +out vec4 color; + +uniform sampler2D kernel_texture; +uniform float max_density; // max number of sources in a kernel sized HEALPix cell at the current depth +uniform float fov; +uniform float strength; +void main() { + color = texture(kernel_texture, out_uv) / max(log2(fov*100.0), 1.0); + color.r *= strength; +}"#, + ); + out.insert( + r"line_base.frag", + r#"#version 300 es + +precision highp float; + +out vec4 color; +in vec2 l; + +uniform vec4 u_color; +uniform float u_thickness; +uniform float u_width; +uniform float u_height; + +void main() { + if (l.x > 0.05) { + discard; + } else { + color = u_color; + + float dist = abs((u_thickness + 2.0) * l.y); + + float half_thickness = (u_thickness + 2.0) * 0.5; + color.a = color.a * (1.0 - smoothstep(half_thickness - 1.0, half_thickness, dist)); + } +}"#, + ); + out.insert( + r"passes_post_vertex_100es.vert", + r#"#version 300 es +precision mediump float; + +layout (location = 0) in vec2 a_pos; +out vec2 v_tc; + +void main() { + gl_Position = vec4(a_pos * 2. - 1., 0.0, 1.0); + v_tc = a_pos; +}"#, + ); + out.insert( + r"hips3d_u8.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler3D; + +uniform sampler3D tex; + +in vec3 frag_uv; + +out vec4 out_frag_color; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} + +uniform float opacity; + +void main() { + vec3 uv = vec3(frag_uv.xyz); + uv.y = 1.0 - uv.y; + + vec4 color = uvw2c_u8(uv); + + out_frag_color = color; + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + out.insert( + r"hips_raytracer_rgba2cmap.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler2DArray; +precision lowp sampler2DArray; precision lowp isampler2DArray; precision mediump int; +in vec3 frag_pos; +in vec2 out_clip_pos; +out vec4 out_frag_color; + +struct Tile { + int uniq; // Healpix cell + int texture_idx; // Index in the texture buffer + float start_time; // Absolute time that the load has been done in ms + float empty; +}; + +uniform Tile textures_tiles[12]; + +uniform float opacity; +uniform sampler2DArray tex; + +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; + +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; + +vec4 colormap_f(float x) { + float id = (colormap_id + 0.5) / num_colormaps; + return texture(colormaps, vec2(x, id)); +} +float linear_f(float x, float min_value, float max_value) { + return clamp((x - min_value)/(max_value - min_value), 0.0, 1.0); +} + +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} + +float log_f(float x, float min_value, float max_value) { + float y = linear_f(x, min_value, max_value); + float a = 1000.0; + return log(a*y + 1.0)/log(a); +} + +float asinh_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return asinh(10.0*d)/3.0; +} + +float pow2_f(float x, float min_value, float max_value) { + float d = linear_f(x, min_value, max_value); + return d*d; +} + +float transfer_func(int H, float x, float min_value, float max_value) { + if (H == 0) { + return linear_f(x, min_value, max_value); + } else if (H == 1) { + return sqrt_f(x, min_value, max_value); + } else if (H == 2) { + return log_f(x, min_value, max_value); + } else if (H == 3) { + return asinh_f(x, min_value, max_value); + } else { + return pow2_f(x, min_value, max_value); + } +} + +uniform float k_gamma; +uniform float k_saturation; +uniform float k_contrast; +uniform float k_brightness; +uniform float k_exposure; + +vec4 apply_gamma(vec4 ic, float g) { + float new_r = pow(ic.r, g); + float new_g = pow(ic.g, g); + float new_b = pow(ic.b, g); + + return vec4(new_r, new_g, new_b, ic.a); +} + +vec4 apply_saturation(vec4 color, float value) { + const vec3 luminosity_factor = vec3(0.2126, 0.7152, 0.0722); + vec3 grayscale = vec3(dot(color.rgb, luminosity_factor)); + + return vec4(mix(grayscale, color.rgb, 1.0 + value), color.a); +} + +vec4 apply_contrast(vec4 color, float value) { + return vec4(0.5 + (1.0 + value) * (color.rgb - 0.5), color.a); +} + +vec4 apply_brightness(vec4 color, float value) { + return vec4(color.rgb + value, color.a); +} + +vec4 apply_exposure(vec4 color, float value) { + return vec4((1.0 + value) * color.rgb, color.a); +} + +vec4 apply_tonal(vec4 color) { + return apply_gamma( + apply_saturation( + apply_contrast( + apply_brightness(color, k_brightness), + k_contrast + ), + k_saturation + ), + k_gamma + ); +} +vec3 rgb2hsv(vec3 c) { + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) { + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} +highp float decode_f32(highp vec4 rgba) { + highp float Sign = 1.0 - step(128.0,rgba[0])*2.0; + highp float Exponent = 2.0 * mod(rgba[0],128.0) + step(128.0,rgba[1]) - 127.0; + if (abs(Exponent + 127.0) < 1e-3) { + return 0.0; + } + highp float Mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 +rgba[3] + float(0x800000); + highp float Result = Sign * exp2(Exponent) * (Mantissa * exp2(-23.0 )); + return Result; +} + +int decode_i32(vec4 rgba) { + int r = int(rgba.r * 255.0 + 0.5); + int g = int(rgba.g * 255.0 + 0.5); + int b = int(rgba.b * 255.0 + 0.5); + int a = int(rgba.a * 255.0 + 0.5); + + int value = (r << 24) | (g << 16) | (b << 8) | a; // Combine into a 16-bit integer + + return value; +} + +int decode_i16(vec2 rg) { + int r = int(rg.r * 255.0 + 0.5); + int g = int(rg.g * 255.0 + 0.5); + + int value = (r << 8) | g; // Combine into a 16-bit integer + + if (value >= 32768) { + value -= 65536; + } + + return value; +} + +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; +} + + + + +vec4 uvw2c_r(vec3 uv) { + vec2 va = texture(tex, uv).ra; + + va.x = transfer_func(H, va.x, min_value, max_value); + + va.x = mix(va.x, 1.0 - va.x, reversed); + + vec4 c = colormap_f(va.x); + return apply_tonal(c); +} + +vec4 uvw2c_rgba(vec3 uv) { + vec4 c = texture(tex, uv).rgba; + + c.r = transfer_func(H, c.r, min_value, max_value); + c.g = transfer_func(H, c.g, min_value, max_value); + c.b = transfer_func(H, c.b, min_value, max_value); + + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 uvw2c_ra(vec3 uv) { + vec2 c = texture(tex, uv).rg; + + c.r = transfer_func(H, c.r, min_value, max_value); + + c.r = mix(c.r, 1.0 - c.r, reversed); + + vec3 color = colormap_f(c.r).rgb; + + return apply_tonal(vec4(color, c.g)); +} + +vec4 uvw2cmap_rgba(vec3 uv) { + float v = texture(tex, uv).r; + v = transfer_func(H, v, min_value, max_value); + vec4 c = colormap_f(v); + c.rgb = mix(c.rgb, 1.0 - c.rgb, reversed); + + return apply_tonal(c); +} + +vec4 val2c_f32(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(isinf(x))); + return apply_tonal(new_color); +} + +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); + + alpha = mix(alpha, 1.0 - alpha, reversed); + + vec4 new_color = mix(colormap_f(alpha), vec4(0.0), float(x == blank || isnan(x))); + return apply_tonal(new_color); +} + +vec4 uvw2c_f32(vec3 uv) { + float val = decode_f32(texture(tex, uv).rgba*255.0); + return val2c_f32(val); +} + +vec4 uvw2c_i32(vec3 uv) { + float val = float(decode_i32(texture(tex, uv).rgba)); + return val2c(val); +} + +vec4 uvw2c_i16(vec3 uv) { + float val = float(decode_i16(texture(tex, uv).rg)); + return val2c(val); +} + +vec4 uvw2c_u8(vec3 uv) { + float val = float(decode_u8(texture(tex, uv).r)); + return val2c(val); +} +const float TWICE_PI = 6.28318530718; +const float PI = 3.141592653589793; +const float FOUR_OVER_PI = 1.27323954474; +const float TRANSITION_Z = 0.66666666666; +const float TRANSITION_Z_INV = 1.5; + +int quarter(vec2 p) { + int x_neg = int(p.x < 0.0); + int y_neg = int(p.y < 0.0); + int q = (x_neg + y_neg) | (y_neg << 1); + return q; +} + +float xpm1(vec2 p) { + bool x_neg = (p.x < 0.0); + bool y_neg = (p.y < 0.0); + float lon = atan(abs(p.y), abs(p.x)); + float x02 = lon * FOUR_OVER_PI; + if (x_neg != y_neg) { // Could be replaced by a sign copy from (x_neg ^ y_neg) << 32 + return 1.0 - x02; + } else { + return x02 - 1.0; + } +} + +float one_minus_z_pos(vec3 p) { + float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 + + if (d2 < 1e-1) { // <=> dec > 84.27 deg + return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); + } + return 1.0f - p.z; +} + +float one_minus_z_neg(vec3 p) { + float d2 = dot(p.xy, p.xy); // z = sqrt(1 - d2) AND sqrt(1 - x) = 1 - x / 2 - x^2 / 8 - x^3 / 16 - 5 x^4/128 - 7 * x^5/256 + if (d2 < 1e-1f) { // <=> dec < -84.27 deg + return d2 * (0.5 + d2 * (0.125 + d2 * (0.0625 + d2 * (0.0390625 + d2 * 0.02734375)))); + } + return p.z + 1.0; +} + +int ij2z(int i, int j) { + int i4 = i | (j << 2); + + int j4 = (i4 ^ (i4 >> 1)) & 0x22222222; + int i5 = i4 ^ j4 ^ (j4 << 1); + + return i5; +} + +struct HashDxDy { + int idx; + float dx; + float dy; +}; + +uniform sampler2D ang2pixd; +HashDxDy hash_with_dxdy2(vec2 radec) { + vec2 aa = vec2(radec.x/TWICE_PI + 1.0, (radec.y/PI) + 0.5); + vec3 v = texture(ang2pixd, aa).rgb; + return HashDxDy( + int(v.x * 255.0), + v.y, + v.z + ); +} +HashDxDy hash_with_dxdy(int depth, vec3 p) { + + int nside = 1 << depth; + float half_nside = float(nside) * 0.5; + + float x_pm1 = xpm1(p.xy); + int q = quarter(p.xy); + + int d0h = 0; + vec2 p_proj = vec2(0.0); + if (p.z > TRANSITION_Z) { + float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_pos(p)); + p_proj = vec2(x_pm1 * sqrt_3_one_min_z, 2.0 - sqrt_3_one_min_z); + d0h = q; + } else if (p.z < -TRANSITION_Z) { + float sqrt_3_one_min_z = sqrt(3.0 * one_minus_z_neg(p)); + p_proj = vec2(x_pm1 * sqrt_3_one_min_z, sqrt_3_one_min_z); + d0h = q + 8; + } else { + float y_pm1 = p.z * TRANSITION_Z_INV; + int q01 = int(x_pm1 > y_pm1); // 0/1 + int q12 = int(x_pm1 >= -y_pm1); // 0\1 + int q03 = 1 - q12; // 1\0 + int q1 = q01 & q12; // = 1 if q1, 0 else + p_proj = vec2( + x_pm1 - float(q01 + q12 - 1), + y_pm1 + float(q01 + q03) + ); + d0h = ((q01 + q03) << 2) + ((q + q1) & 3); + } + + float x = (half_nside * (p_proj.x + p_proj.y)); + float y = (half_nside * (p_proj.y - p_proj.x)); + int i = int(x); + int j = int(y); + + return HashDxDy( + (d0h << (depth << 1)) + ij2z(i, j), + x - float(i), + y - float(j) + ); +} +vec3 xyz2uv(vec3 xyz) { + HashDxDy result = hash_with_dxdy(0, xyz.zxy); + + int idx = result.idx; + vec2 offset = vec2(result.dy, result.dx); + Tile tile = textures_tiles[idx]; + + return vec3(offset, float(tile.texture_idx)); +} + +void main() { + vec3 uv = xyz2uv(normalize(frag_pos)); + vec4 c = uvw2cmap_rgba(uv); + + out_frag_color = c; + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + out.insert( + r"hips_raytracer_i16.frag", + r#"#version 300 es +precision lowp float; +precision lowp sampler2DArray; +precision mediump int; + uniform sampler2DArray tex; in vec3 frag_pos; @@ -7227,144 +7361,11 @@ void main() { vec3 uv = xyz2uv(normalize(frag_pos)); uv.y = 1.0 - uv.y; - vec4 c = uvw2c_u8(uv); + vec4 c = uvw2c_i16(uv); out_frag_color = c; out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"catalogs_tan.vert", - r#"#version 300 es -precision lowp float; - -layout (location = 0) in vec2 offset; -layout (location = 1) in vec2 uv; -layout (location = 2) in vec3 center; - -uniform float current_time; -uniform mat3 inv_model; - -uniform vec2 ndc_to_clip; -uniform float czf; -uniform vec2 kernel_size; - -out vec2 out_uv; -out vec3 out_p; - -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; - -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); -} - -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); -} - -vec2 w2c_ait(vec3 p) { - float r = length(p.zx); - float w = sqrt((r * (r + p.z)) * 0.5f); // = cos(b) cos(l/2) - w = sqrt((1.0 + w) * 0.5f); // = 1 / gamma - float y2d = p.y / w; - - float x2d = 0.0; - if (abs(p.x) < 5e-3) { - float x_over_r = p.x/r; - x2d = -p.x * (1.0 - x_over_r*x_over_r/21.0) / w; - } else { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; - } - - return vec2(x2d * 0.5, y2d) / SQRT_2; -} -const float eps = 1.25e-8; -const int n_iter = 100; - -float newton_solve(float z) { - float cte = PI * z; - float x = 2.0 * asin(z); - float f = x + sin(x) - cte; - int i = 0; - while (abs(f) > eps && i < n_iter) { - x -= f / (1.0 + cos(x)); - f = x + sin(x) - cte; - i += 1; - } - - return 0.5 * x; -} - -vec2 w2c_mol(vec3 p) { - float g = newton_solve(p.y); - - float sg = sin(g); - float cg = cos(g); - return vec2((atan(-p.x, p.z) * cg) / PI, sg); -} -vec2 w2c_tan(vec3 p) { - p.z = max(p.z, 1e-2); - return vec2(-p.x, p.y) / (p.z*PI); -} -vec2 w2c_stg(vec3 p) { - float w = (1.0 + p.z) * 0.5; - return vec2(-p.x, p.y) / (PI * w); -} -vec2 w2c_zea(vec3 p) { - float w = sqrt(0.5 + 0.5 * p.z); // <=> sqrt[(1 + x) / 2] - return vec2(-p.x, p.y) * 0.5 / w; -} -vec2 w2c_mer(vec3 p) { - return vec2(atan(-p.x, p.z), atanh(p.y)) / PI; -} - -vec3 lonlat2xyz(vec2 lonlat) { - float t = lonlat.x; - float tc = cos(t); - float ts = sin(t); - - float d = lonlat.y; - float dc = cos(d); - float ds = sin(d); - - return vec3(dc * ts, ds, dc * tc); -} - -uniform int u_proj; - -vec2 proj(vec3 p) { - if (u_proj == 0) { - return w2c_tan(p); - } else if (u_proj == 1) { - return w2c_stg(p); - } else if (u_proj == 2) { - return w2c_sin(p); - } else if (u_proj == 3) { - return w2c_zea(p); - } else if (u_proj == 4) { - return w2c_ait(p); - } else if (u_proj == 5) { - return w2c_mol(p); - } else { - return w2c_mer(p); - } -} - - -void main() { - vec3 p = inv_model * center; - - vec2 center_pos_clip_space = world2clip_gnomonic(p); - - vec2 pos_clip_space = center_pos_clip_space; - gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); - - out_uv = uv; - out_p = p; }"#, ); out.insert( @@ -7768,7 +7769,7 @@ void main() { }"#, ); out.insert( - r"catalogs_mollweide.vert", + r"catalogs_aitoff.vert", r#"#version 300 es precision lowp float; layout (location = 0) in vec2 offset; @@ -7886,11 +7887,10 @@ vec2 proj(vec3 p) { } } - void main() { vec3 p = inv_model * center; - vec2 center_pos_clip_space = world2clip_mollweide(p); + vec2 center_pos_clip_space = world2clip_aitoff(p); vec2 pos_clip_space = center_pos_clip_space; gl_Position = vec4((pos_clip_space / (ndc_to_clip * czf)) + offset * kernel_size , 0.f, 1.f); diff --git a/src/css/aladin.css b/src/css/aladin.css index ddcecb2e..438182b0 100644 --- a/src/css/aladin.css +++ b/src/css/aladin.css @@ -1117,6 +1117,14 @@ otherwise it fits its content options. If those are too big the select can go ou left: 0.2rem; } +.aladin-link { + color: white; +} + +.aladin-link:hover { + color: greenyellow; +} + .aladin-simbadPointer-control { position: absolute; top: 7.8rem; diff --git a/src/js/Aladin.js b/src/js/Aladin.js index 34eee9ed..acca5f52 100644 --- a/src/js/Aladin.js +++ b/src/js/Aladin.js @@ -1831,7 +1831,7 @@ export let Aladin = (function () { // Do not use proxy with CORS headers until we solve that: https://github.com/MattiasBuelens/wasm-streams/issues/20 //url = Utils.handleCORSNotSameOrigin(url).href; - let imageOptions = {...options, successCallback, errorCallback}; + let imageOptions = {...options, imgFormat: 'fits', successCallback, errorCallback}; let image = new Image(url, imageOptions); return image; diff --git a/src/js/ColorCfg.js b/src/js/ColorCfg.js index b4dcfdc3..480cef2c 100644 --- a/src/js/ColorCfg.js +++ b/src/js/ColorCfg.js @@ -59,9 +59,9 @@ } this.maxCut = { - webp: 1.0, - jpeg: 1.0, - png: 1.0, + webp: 255.0, + jpeg: 255.0, + png: 255.0, fits: undefined // wait the default value coming from the properties }; if (options && Number.isFinite(options.maxCut)) { @@ -95,6 +95,16 @@ } } + let minCut = this.minCut[this.imgFormat] + if (this.imgFormat !== "fits") { + minCut /= 255.0 + } + + let maxCut = this.maxCut[this.imgFormat] + if (this.imgFormat !== "fits") { + maxCut /= 255.0 + } + // Reset the whole meta object return { blendCfg: blend, @@ -107,8 +117,8 @@ kContrast: this.kContrast, stretch: this.stretch, - minCut: this.minCut[this.imgFormat], - maxCut: this.maxCut[this.imgFormat], + minCut, + maxCut, reversed: this.reversed, cmapName: this.colormap, } @@ -121,7 +131,7 @@ this.setColormap(options.colormap, options) - this.setCuts(options.minCut, options.maxCut) + this.setCuts(options.minCut, options.maxCut, options.cutFormat) this.setBrightness(options.brightness) this.setSaturation(options.saturation) @@ -249,18 +259,20 @@ }; // Sets the cuts for the current image format - ColorCfg.prototype.setCuts = function(minCut, maxCut) { + ColorCfg.prototype.setCuts = function(minCut, maxCut, imgFormat) { + imgFormat = imgFormat || this.imgFormat; + if (minCut instanceof Object) { // Mincut is given in the form of an javascript object with all the formats - this.minCut = minCut + this.minCut = {...this.minCut, ...minCut}; } else if (minCut !== null && minCut !== undefined) { - this.minCut[this.imgFormat] = minCut; + this.minCut[imgFormat] = minCut; } if (maxCut instanceof Object) { - this.maxCut = maxCut; + this.maxCut = {...this.maxCut, ...maxCut}; } else if (maxCut !== null && maxCut !== undefined) { - this.maxCut[this.imgFormat] = maxCut; + this.maxCut[imgFormat] = maxCut; } }; diff --git a/src/js/HiPS.js b/src/js/HiPS.js index 8b3bb91a..ca8294af 100644 --- a/src/js/HiPS.js +++ b/src/js/HiPS.js @@ -31,7 +31,6 @@ import { HiPSProperties } from "./HiPSProperties.js"; import { Aladin } from "./Aladin.js"; import { CooFrameEnum } from "./CooFrameEnum.js"; import { Utils } from "./Utils" -import { SpectraDisplayer } from "./SpectraDisplayer.js"; let PropertyParser = {}; // Utilitary functions for parsing the properties and giving default values @@ -733,9 +732,16 @@ export let HiPS = (function () { * * @param {number} minCut - The low cut value to set for the HiPS. * @param {number} maxCut - The high cut value to set for the HiPS. + * @param {string} [imgFormat] - The image format for which one wants to set the cuts. By default, the format used is the current imageFormat */ - HiPS.prototype.setCuts = function (minCut, maxCut) { - this.setOptions({minCut, maxCut}) + HiPS.prototype.setCuts = function (minCut, maxCut, imgFormat) { + imgFormat = imgFormat?.toLowerCase(); + + if (imgFormat === "jpg") { + imgFormat = "jpeg"; + } + + this.setOptions({minCut, maxCut, cutFormat: imgFormat}) }; /** diff --git a/src/js/Image.js b/src/js/Image.js index dd78a4bf..4c44c855 100644 --- a/src/js/Image.js +++ b/src/js/Image.js @@ -402,6 +402,7 @@ export let Image = (function () { // Set the automatic computed cuts let [minCut, maxCut] = self.getCuts(); + minCut = minCut || imageParams.min_cut; maxCut = maxCut || imageParams.max_cut; self.setCuts( diff --git a/src/js/View.js b/src/js/View.js index f076ee4b..e007049b 100644 --- a/src/js/View.js +++ b/src/js/View.js @@ -1300,7 +1300,7 @@ export let View = (function () { if (!view.throttledTouchPadZoom) { view.throttledTouchPadZoom = () => { - const factor = Utils.detectTrackPad(e) ? 1.06 : 1.2; + const factor = Utils.detectTrackPad(e) ? 1.07 : 1.2; const currZoomFactor = view.zoom.isZooming ? view.zoom.finalZoom : view.zoomFactor; let newZoomFactor = view.delta > 0 ? currZoomFactor * factor : currZoomFactor / factor; diff --git a/src/js/gui/Box/HiPSSettingsBox.js b/src/js/gui/Box/HiPSSettingsBox.js index 15f6b0d3..0e876640 100644 --- a/src/js/gui/Box/HiPSSettingsBox.js +++ b/src/js/gui/Box/HiPSSettingsBox.js @@ -219,11 +219,6 @@ import { TogglerActionButton } from "../Button/Toggler.js"; value: 0.0, change: (e) => { let minCut = +e.target.value - let imgFormat = self.options.layer.imgFormat; - if (imgFormat !== "fits") { - minCut /= 255.0; - } - self.options.layer.setCuts(minCut, self.options.layer.getColorCfg().getCuts()[1]) } }, @@ -238,12 +233,6 @@ import { TogglerActionButton } from "../Button/Toggler.js"; value: 1.0, change: (e) => { let maxCut = +e.target.value - - let imgFormat = self.options.layer.imgFormat; - if (imgFormat !== "fits") { - maxCut /= 255.0; - } - self.options.layer.setCuts(self.options.layer.getColorCfg().getCuts()[0], maxCut) } }] @@ -302,10 +291,6 @@ import { TogglerActionButton } from "../Button/Toggler.js"; let reversed = colorCfg.getReversed(); let [minCut, maxCut] = colorCfg.getCuts(); - if (layer.imgFormat !== "fits") { - minCut = Math.round(minCut * 255); - maxCut = Math.round(maxCut * 255); - } this.pixelSettingsContent.set('mincut', +minCut.toFixed(4)) this.pixelSettingsContent.set('maxcut', +maxCut.toFixed(4)) this.pixelSettingsContent.set('stretch', stretch) diff --git a/src/js/gui/Box/StackBox.js b/src/js/gui/Box/StackBox.js index f4b070e5..2ff537eb 100644 --- a/src/js/gui/Box/StackBox.js +++ b/src/js/gui/Box/StackBox.js @@ -781,6 +781,21 @@ export class OverlayStackBox extends Box { }) ); layout = layout.concat(this._createSurveysList()); + let self = this; + const moreHiPSLink = document.createElement("a"); + moreHiPSLink.href = "#"; + moreHiPSLink.classList.add('aladin-link'); + moreHiPSLink.textContent = "More..."; + moreHiPSLink.title = "Open the survey browser" + moreHiPSLink.addEventListener("click", (e) => { + e.preventDefault(); + if (!self.hipsBrowser) + self.hipsBrowser = new HiPSBrowserBox(aladin); + + self.hipsBrowser._show({ position: { anchor: "center center" } }); + }); + layout.push(moreHiPSLink) + return Layout.vertical({ layout }); }