diff --git a/README.md b/README.md index 4b19f6ed..28b2e0ad 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# [Aladin Lite](https://aladin.u-strasbg.fr/AladinLite) +# [Aladin Lite](https://aladin.cds.unistra.fr/AladinLite) **An astronomical HiPS visualizer in the browser** Aladin Lite logo @@ -8,14 +8,14 @@ See [A&A 578, A114 (2015)](https://arxiv.org/abs/1505.02291) and [IVOA HiPS Reco Aladin Lite is built to be easily embeddable in any web page. It powers astronomical portals like [ESASky](https://sky.esa.int/), [ESO Science Archive portal](http://archive.eso.org/scienceportal/) and [ALMA Portal](https://almascience.eso.org/asax/). -More details on [Aladin Lite documentation page](http://aladin.u-strasbg.fr/AladinLite/doc/). +More details on [Aladin Lite documentation page](http://aladin.cds.unistra.fr/AladinLite/doc/). A new [API technical documentation](https://cds-astro.github.io/aladin-lite/) is now available. [![Run tests](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml/badge.svg)](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml) [![API Documentation](https://img.shields.io/badge/API-documentation-blue.svg)](https://cds-astro.github.io/aladin-lite) [![Release page](https://img.shields.io/badge/Release-download-yellow.svg)](https://aladin.cds.unistra.fr/AladinLite/doc/release/) -Try Aladin Lite [here](https://aladin.u-strasbg.fr/AladinLite). +Try Aladin Lite [here](https://aladin.cds.unistra.fr/AladinLite). Aladin Lite is made possible thanks to pure Rust core libraries: * [cdshealpix](https://github.com/cds-astro/cds-healpix-rust) - for HEALPix projection and unprojection to/from sky coordinates diff --git a/package.json b/package.json index 187c47da..780dfa46 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "homepage": "https://aladin.u-strasbg.fr/", + "homepage": "https://aladin.cds.unistra.fr/", "name": "aladin-lite", "type": "module", "version": "3.7.2-beta", diff --git a/src/core/src/app.rs b/src/core/src/app.rs index 224c69ac..0aa5e10a 100644 --- a/src/core/src/app.rs +++ b/src/core/src/app.rs @@ -87,6 +87,7 @@ pub struct App { time_start_dragging: Time, time_mouse_high_vel: Time, dragging: bool, + vel_history: Vec, prev_cam_position: Vector3, //prev_center: Vector3, @@ -208,6 +209,7 @@ impl App { let browser_features_support = BrowserFeaturesSupport::new(); + let vel_history = vec![]; Ok(App { gl, //ui, @@ -244,6 +246,7 @@ impl App { time_start_dragging, time_mouse_high_vel, dragging, + vel_history, prev_cam_position, out_of_fov, @@ -1538,7 +1541,16 @@ impl App { let dx = crate::math::vector::dist2(&from_mouse_pos, &to_mouse_pos).sqrt(); self.dist_dragging += dx; + //let now = Time::now(); + //let dragging_duration = (now - self.time_start_dragging).as_secs(); + //let dragging_vel = self.dist_dragging / dragging_duration; + + // 1. Use smoothed velocity instead of instantaneous velocity let dv = dx / (Time::now() - self.camera.get_time_of_last_move()).as_secs(); + self.vel_history.push(dv); + if self.vel_history.len() > 5 { + self.vel_history.remove(0); + } if dv > 10000.0 { self.time_mouse_high_vel = Time::now(); @@ -1587,15 +1599,18 @@ impl App { } let now = Time::now(); - let dragging_duration = (now - self.time_start_dragging).as_secs(); - let dragging_vel = self.dist_dragging / dragging_duration; + let avg_vel = self.vel_history.iter().copied().sum::() / self.vel_history.len() as f32; - // Detect if there has been a recent acceleration - // It is also possible that the dragging time is too short and if it is the case, trigger the inertia - let recent_acceleration = (Time::now() - self.time_mouse_high_vel).as_secs() < 0.1 - || (Time::now() - self.time_start_dragging).as_secs() < 0.1; + // 2. Clamp minimum + maximum velocities + let min_vel = 1000.0; // tweak - if dragging_vel < 2000.0 && !recent_acceleration { + // 3. Better condition for “recent acceleration” + let t_since_drag = (now - self.time_start_dragging).as_secs(); + let t_since_accel = (now - self.time_mouse_high_vel).as_secs(); + + let inertia_trigger = + avg_vel > min_vel || ((t_since_drag < 0.15) || (t_since_accel < 0.15)); + if !inertia_trigger { return; } @@ -1605,10 +1620,8 @@ impl App { let center = self.camera.get_center(); let axis = self.prev_cam_position.cross(*center).normalize(); - //let delta_time = ((now - time_of_last_move).0 as f64).max(1.0); let delta_angle = math::vector::angle3(&self.prev_cam_position, center).to_radians(); - let ampl = delta_angle * (dragging_vel as f64) * 5e-3; - //let ampl = (dragging_vel * 0.01) as f64; + let ampl = (delta_angle * avg_vel as f64) * 5e-3; self.inertia = Some(Inertia::new(ampl.to_radians(), axis, self.north_up)) } diff --git a/src/core/src/inertia.rs b/src/core/src/inertia.rs index 8cc98d1a..44f13a19 100644 --- a/src/core/src/inertia.rs +++ b/src/core/src/inertia.rs @@ -27,6 +27,7 @@ impl Inertia { } } + /* pub fn apply(&mut self, camera: &mut CameraViewPort, proj: &ProjectionType, _dt: DeltaTime) { let t = ((Time::now() - self.time_start).as_millis() / 1000.0) as f64; // Undamped angular frequency of the oscillator @@ -46,6 +47,24 @@ impl Inertia { let fov = start_fov * (1_f32 - alpha) + goal_fov * alpha;*/ camera.apply_axis_rotation(&self.axis, self.speed.to_angle(), proj); + if self.north_up { + camera.set_position_angle(0.0.to_angle(), proj); + } + }*/ + + pub fn apply(&mut self, camera: &mut CameraViewPort, proj: &ProjectionType, _dt: DeltaTime) { + let t = ((Time::now() - self.time_start).as_millis() / 1000.0) as f64; + // Initial angular velocity + let v0 = self.ampl * 0.5; + + // Friction coefficient (tweak this) + let damping = 2.5; + + // Exponential decay of angular velocity + self.speed = (v0 * (-damping * t).exp()).min(3.0); + + camera.apply_axis_rotation(&self.axis, self.speed.to_angle(), proj); + if self.north_up { camera.set_position_angle(0.0.to_angle(), proj); } diff --git a/src/core/src/shaders.rs b/src/core/src/shaders.rs index 024c45af..05133497 100644 --- a/src/core/src/shaders.rs +++ b/src/core/src/shaders.rs @@ -3,135 +3,264 @@ use std::collections::HashMap; pub fn get_all() -> HashMap<&'static str, &'static str> { let mut out = HashMap::new(); out.insert( - r"hips_rasterizer_raster.vert", + 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; -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 vec2 l; -out vec3 frag_uv_start; -out vec3 frag_uv_end; -out float frag_blending_factor; +uniform float u_width; +uniform float u_height; +uniform float u_thickness; -uniform mat3 inv_model; -uniform vec2 ndc_to_clip; -uniform float czf; -uniform float current_time; +void main() { + vec2 x_b = p_b - p_a; + vec2 y_b = normalize(vec2(-x_b.y, x_b.x)); -const float PI = 3.141592653589793; -const float SQRT_2 = 1.41421356237309504880168872420969808; + float ndc2pix = 2.0 / u_width; -vec2 w2c_sin(vec3 p) { - vec2 q = vec2(-p.x, p.y); - return p.z >= 0.f ? q : normalize(q); + 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#"#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); } -vec2 w2c_sin_no_backface(vec3 p) { - return vec2(-p.x, p.y); +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); } -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 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 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; +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 { - w = sqrt((r*r - r*p.z) * 2.0) / w; // = 2 * gamma * cos(b) sin(l/2) - x2d = sign(-p.x) * w; + 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 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; + return value; } -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; +uint decode_u8(float r) { + uint value = uint(r * 255.0 + 0.5); + return value; } -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); + + +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); } -uniform int u_proj; +vec4 val2c(float x) { + float alpha = x * scale + offset; + alpha = transfer_func(H, alpha, min_value, max_value); -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); - } + 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() { - vec3 p_w = inv_model * xyz; - vec2 p_clip = proj(p_w); + vec2 uv = frag_uv; + uv.y = 1.0 - uv.y; - vec2 p_ndc = p_clip / (ndc_to_clip * czf); - gl_Position = vec4(p_ndc, 0.0, 1.0); + out_frag_color = uv2c_i16(frag_uv); + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + out.insert( + r"hips_raytracer_backcolor.vert", + r#"#version 300 es +precision lowp float; +precision mediump int; - frag_uv_start = uv_start; - frag_uv_end = uv_end; - frag_blending_factor = min((current_time - time_tile_received) / 200.0, 1.0); +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"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( @@ -400,16 +529,144 @@ void main() { }"#, ); out.insert( - r"hips3d_raster.vert", + 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; -layout (location = 0) in vec2 lonlat; -layout (location = 1) in vec3 uv; - -out vec3 frag_uv; - +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; @@ -516,43 +773,25 @@ vec2 proj(vec3 p) { void main() { vec3 p_xyz = lonlat2xyz(lonlat); - vec3 p_w = inv_model * p_xyz; - vec2 p_clip = proj(p_w.xyz); + 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.0, 1.0); - - frag_uv = uv; + gl_Position = vec4(p_ndc, 0.f, 1.f); }"#, ); out.insert( - r"hips_raytracer_backcolor.vert", + r"fits_f32.frag", 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; +precision highp float; +precision highp sampler2D; +precision highp int; out vec4 out_frag_color; +in vec2 frag_uv; + +uniform sampler2D tex; +uniform float opacity; uniform float scale; uniform float offset; @@ -654,21 +893,6 @@ vec4 apply_tonal(vec4 color) { 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; @@ -712,49 +936,6 @@ uint decode_u8(float r) { -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; @@ -776,343 +957,32 @@ vec4 val2c(float x) { return apply_tonal(new_color); } -vec4 uvw2c_f32(vec3 uv) { +vec4 uv2c_f32(vec2 uv) { float val = decode_f32(texture(tex, uv).rgba*255.0); return val2c_f32(val); } -vec4 uvw2c_i32(vec3 uv) { +vec4 uv2c_i32(vec2 uv) { float val = float(decode_i32(texture(tex, uv).rgba)); return val2c(val); } -vec4 uvw2c_i16(vec3 uv) { +vec4 uv2c_i16(vec2 uv) { float val = float(decode_i16(texture(tex, uv).rg)); return val2c(val); } -vec4 uvw2c_u8(vec3 uv) { +vec4 uv2c_u8(vec2 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; + vec2 uv = frag_uv; + uv.y = 1.0 - uv.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 = uv2c_f32(frag_uv); 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; - -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( - r"passes_post_fragment_100es.frag", - r#"#version 300 es -precision mediump float; - -in vec2 v_tc; -out vec4 color; - -uniform sampler2D fbo_tex; - -vec3 srgb_from_linear(vec3 rgb) { - bvec3 cutoff = lessThan(rgb, vec3(0.0031308)); - vec3 lower = rgb * vec3(3294.6); - vec3 higher = vec3(269.025) * pow(rgb, vec3(1.0 / 2.4)) - vec3(14.025); - return mix(higher, lower, vec3(cutoff)); -} - -vec4 srgba_from_linear(vec4 rgba) { - return vec4(srgb_from_linear(rgba.rgb), 255.0 * rgba.a); -} - -void main() { - color = texture(fbo_tex, v_tc); - -}"#, - ); - out.insert( - 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( @@ -1126,1022 +996,6 @@ 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( @@ -2411,1266 +1265,18 @@ void main() { }"#, ); out.insert( - r"line_base.vert", - r#"#version 300 es -precision highp float; -layout (location = 0) in vec2 ndc_pos; - -out float l; - -void main() { - gl_Position = vec4( - ndc_pos, - 0.0, - 1.0 - ); -}"#, - ); - out.insert( - r"hips_raytracer_u8.frag", + r"hips3d_raster.vert", r#"#version 300 es precision lowp float; -precision lowp sampler2DArray; -precision lowp usampler2DArray; -precision lowp isampler2DArray; -precision mediump int; -uniform sampler2DArray tex; +layout (location = 0) in vec2 lonlat; +layout (location = 1) in vec3 uv; -in vec3 frag_pos; -in vec2 out_clip_pos; -out vec4 out_frag_color; +out vec3 frag_uv; -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_u8(uv); - - - out_frag_color = c; - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"hips_raytracer_i32.frag", - r#"#version 300 es -precision lowp float; -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; - -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; - -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 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 = xyz2uv(normalize(frag_pos)); - - uv.y = 1.0 - uv.y; - vec4 c = uvw2c_i32(uv); - - out_frag_color = c; - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - 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"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"fits_u8.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_u8(frag_uv); - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"catalogs_ortho.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; @@ -3773,343 +1379,41 @@ vec2 proj(vec3 p) { } } - void main() { - vec3 p = inv_model * center; + vec3 p_xyz = lonlat2xyz(lonlat); + vec3 p_w = inv_model * p_xyz; + vec2 p_clip = proj(p_w.xyz); - vec2 center_pos_clip_space = world2clip_orthographic(p); + vec2 p_ndc = p_clip / (ndc_to_clip * czf); + gl_Position = vec4(p_ndc, 0.0, 1.0); - 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; + 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( - r"image_sampler.frag", - r#"#version 300 es -precision highp float; -precision highp sampler2D; - -out vec4 out_frag_color; -in vec2 frag_uv; - -uniform sampler2D tex; -uniform float opacity; - -void main() { - out_frag_color = texture(tex, frag_uv); - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"hips3d_i16.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_i16(uv); - - out_frag_color = color; - out_frag_color.a = out_frag_color.a * opacity; -}"#, - ); - out.insert( - r"hips_rasterizer_i32.frag", + r"hips_raytracer_i16.frag", r#"#version 300 es precision lowp float; precision lowp sampler2DArray; +precision mediump int; uniform sampler2DArray tex; -in vec3 frag_uv_start; -in vec3 frag_uv_end; -in float frag_blending_factor; - +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; @@ -4351,19 +1655,133 @@ 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; -uniform float opacity; +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 uv0 = frag_uv_start; - vec3 uv1 = frag_uv_end; - uv0.y = 1.0 - uv0.y; - uv1.y = 1.0 - uv1.y; + vec3 uv = xyz2uv(normalize(frag_pos)); - vec4 color_start = uvw2c_i32(uv0); - vec4 color_end = uvw2c_i32(uv1); + uv.y = 1.0 - uv.y; + vec4 c = uvw2c_i16(uv); - out_frag_color = mix(color_start, color_end, frag_blending_factor); + + out_frag_color = c; out_frag_color.a = out_frag_color.a * opacity; }"#, ); @@ -4761,7 +2179,7 @@ void main() { }"#, ); out.insert( - r"catalogs_mercator.vert", + r"catalogs_ortho.vert", r#"#version 300 es precision lowp float; layout (location = 0) in vec2 offset; @@ -4883,7 +2301,7 @@ vec2 proj(vec3 p) { void main() { vec3 p = inv_model * center; - vec2 center_pos_clip_space = world2clip_mercator(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); @@ -4893,16 +2311,27 @@ void main() { }"#, ); out.insert( - r"colormaps_colormap.frag", + r"hips3d_red.frag", r#"#version 300 es precision lowp float; -precision lowp sampler2D; +precision lowp sampler3D; +precision lowp isampler3D; +precision lowp usampler3D; -in vec2 out_uv; -out vec4 color; +uniform sampler3D tex; -uniform sampler2D texture_fbo; -uniform float alpha; +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; @@ -4912,150 +2341,259 @@ 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() { - float opacity = texture(texture_fbo, out_uv).r; + vec3 uv = vec3(frag_uv.xyz); + vec4 color = uvw2c_ra(uv); - float o = smoothstep(0.0, 0.1, opacity); - - color = colormap_f(opacity); - color.a = o * alpha; + out_frag_color = color; + out_frag_color.a = opacity * out_frag_color.a; }"#, ); out.insert( - r"catalogs_healpix.vert", + r"image_sampler.frag", 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; +precision highp float; +precision highp sampler2D; -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); - } -} +out vec4 out_frag_color; +in vec2 frag_uv; +uniform sampler2D tex; +uniform float opacity; 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_frag_color = texture(tex, frag_uv); + out_frag_color.a = out_frag_color.a * opacity; }"#, ); out.insert( - r"hips3d_i32.frag", + r"hips3d_i16.frag", r#"#version 300 es precision lowp float; precision lowp sampler3D; @@ -5316,24 +2854,48 @@ void main() { vec3 uv = vec3(frag_uv.xyz); uv.y = 1.0 - uv.y; - vec4 color = uvw2c_i32(uv); + vec4 color = uvw2c_i16(uv); out_frag_color = color; out_frag_color.a = out_frag_color.a * opacity; }"#, ); out.insert( - r"fits_f32.frag", + r"catalogs_ortho.frag", r#"#version 300 es -precision highp float; -precision highp sampler2D; -precision highp int; +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; -in vec2 frag_uv; - -uniform sampler2D tex; -uniform float opacity; uniform float scale; uniform float offset; @@ -5435,6 +2997,21 @@ vec4 apply_tonal(vec4 color) { 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; @@ -5478,6 +3055,49 @@ uint decode_u8(float r) { +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; @@ -5499,36 +3119,43 @@ vec4 val2c(float x) { return apply_tonal(new_color); } -vec4 uv2c_f32(vec2 uv) { +vec4 uvw2c_f32(vec3 uv) { float val = decode_f32(texture(tex, uv).rgba*255.0); return val2c_f32(val); } -vec4 uv2c_i32(vec2 uv) { +vec4 uvw2c_i32(vec3 uv) { float val = float(decode_i32(texture(tex, uv).rgba)); return val2c(val); } -vec4 uv2c_i16(vec2 uv) { +vec4 uvw2c_i16(vec3 uv) { float val = float(decode_i16(texture(tex, uv).rg)); return val2c(val); } -vec4 uv2c_u8(vec2 uv) { +vec4 uvw2c_u8(vec3 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; +uniform float opacity; - out_frag_color = uv2c_f32(frag_uv); +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"fits_i16.frag", + r"fits_u8.frag", r#"#version 300 es precision lowp float; precision lowp sampler2D; @@ -5728,7 +3355,7 @@ void main() { vec2 uv = frag_uv; uv.y = 1.0 - uv.y; - out_frag_color = uv2c_i16(frag_uv); + out_frag_color = uv2c_u8(frag_uv); out_frag_color.a = out_frag_color.a * opacity; }"#, ); @@ -6004,146 +3631,21 @@ void main() { }"#, ); 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"line_inst_lonlat.vert", r#"#version 300 es precision highp float; -layout (location = 0) in vec2 lonlat; +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; @@ -6247,78 +3749,244 @@ vec2 proj(vec3 p) { } void main() { - vec3 p_xyz = lonlat2xyz(lonlat); - vec3 p_w = u_2world * p_xyz; - vec2 p_clip = proj(p_w); + 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 p_ndc = p_clip / (ndc_to_clip * czf); + 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"catalogs_catalog.frag", + r"fits_i32.frag", r#"#version 300 es precision lowp float; +precision lowp sampler2D; +precision mediump int; -in vec2 out_uv; -in vec3 out_p; +out vec4 out_frag_color; +in vec2 frag_uv; -out vec4 color; +uniform sampler2D tex; +uniform float opacity; -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 +uniform float scale; +uniform float offset; +uniform float blank; +uniform float min_value; +uniform float max_value; +uniform int H; +uniform float reversed; -precision highp float; +uniform sampler2D colormaps; +uniform float num_colormaps; +uniform float colormap_id; -out vec4 color; -in vec2 l; +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); +} -uniform vec4 u_color; -uniform float u_thickness; -uniform float u_width; -uniform float u_height; +float sqrt_f(float x, float min_value, float max_value) { + float a = linear_f(x, min_value, max_value); + return sqrt(a); +} -void main() { - if (l.x > 0.05) { - discard; +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 { - 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)); + return pow2_f(x, min_value, max_value); } -}"#, - ); - 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; +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() { - gl_Position = vec4(a_pos * 2. - 1., 0.0, 1.0); - v_tc = a_pos; + 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_u8.frag", + r"hips3d_i32.frag", r#"#version 300 es precision lowp float; precision lowp sampler3D; +precision lowp isampler3D; +precision lowp usampler3D; uniform sampler3D tex; @@ -6574,10 +4242,37 @@ void main() { vec3 uv = vec3(frag_uv.xyz); uv.y = 1.0 - uv.y; - vec4 color = uvw2c_u8(uv); + vec4 color = uvw2c_i32(uv); out_frag_color = color; out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + 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( @@ -6969,401 +4664,6 @@ 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; -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; }"#, @@ -7766,6 +5066,2076 @@ void main() { out_frag_color = c; 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_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"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( + 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( + 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_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_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"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"hips_raytracer_u8.frag", + r#"#version 300 es +precision lowp float; +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; + +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_u8(uv); + + + out_frag_color = c; + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + 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_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"line_base.vert", + r#"#version 300 es +precision highp float; +layout (location = 0) in vec2 ndc_pos; + +out float l; + +void main() { + gl_Position = vec4( + ndc_pos, + 0.0, + 1.0 + ); }"#, ); out.insert( @@ -7897,6 +7267,636 @@ void main() { out_uv = uv; out_p = p; +}"#, + ); + out.insert( + 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"passes_post_fragment_100es.frag", + r#"#version 300 es +precision mediump float; + +in vec2 v_tc; +out vec4 color; + +uniform sampler2D fbo_tex; + +vec3 srgb_from_linear(vec3 rgb) { + bvec3 cutoff = lessThan(rgb, vec3(0.0031308)); + vec3 lower = rgb * vec3(3294.6); + vec3 higher = vec3(269.025) * pow(rgb, vec3(1.0 / 2.4)) - vec3(14.025); + return mix(higher, lower, vec3(cutoff)); +} + +vec4 srgba_from_linear(vec4 rgba) { + return vec4(srgb_from_linear(rgba.rgb), 255.0 * rgba.a); +} + +void main() { + color = texture(fbo_tex, v_tc); + +}"#, + ); + 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"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"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"hips_raytracer_i32.frag", + r#"#version 300 es +precision lowp float; +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; + +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; + +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 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 = xyz2uv(normalize(frag_pos)); + + uv.y = 1.0 - uv.y; + vec4 c = uvw2c_i32(uv); + + out_frag_color = c; + out_frag_color.a = out_frag_color.a * opacity; +}"#, + ); + 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 diff --git a/src/js/A.js b/src/js/A.js index 8a4402c3..7e997688 100644 --- a/src/js/A.js +++ b/src/js/A.js @@ -362,7 +362,7 @@ A.graphicOverlay = function (options) { * @returns {ProgressiveCat} Returns a new Overlay object representing the graphic overlay. * * @example - * let gaia = A.catalogHiPS('http://axel.u-strasbg.fr/HiPSCatService/I/345/gaia2', {onClick: 'showTable', color: 'orange', name: 'Gaia', filter: myFilterFunction}); + * let gaia = A.catalogHiPS('http://axel.cds.unistra.fr/HiPSCatService/I/345/gaia2', {onClick: 'showTable', color: 'orange', name: 'Gaia', filter: myFilterFunction}); * aladin.addCatalog(gaia) */ A.catalogHiPS = function (url, options) { diff --git a/src/js/Aladin.js b/src/js/Aladin.js index acca5f52..67242ab7 100644 --- a/src/js/Aladin.js +++ b/src/js/Aladin.js @@ -941,7 +941,7 @@ export let Aladin = (function () { objectName + "'"; var url = - "//simbad.u-strasbg.fr/simbad/sim-tap/sync?query=" + + "//simbad.cds.unistra.fr/simbad/sim-tap/sync?query=" + encodeURIComponent(query) + "&request=doQuery&lang=adql&format=json&phase=run"; diff --git a/src/js/SimbadPointer.js b/src/js/SimbadPointer.js index de06c8e2..c50f26e7 100644 --- a/src/js/SimbadPointer.js +++ b/src/js/SimbadPointer.js @@ -60,7 +60,7 @@ export let SimbadPointer = (function() { if (Utils.isNumber(magnitude)) { content += 'Mag: ' + magnitude + '
'; } - content += '
Query in CDS portal'; + content += '
Query in CDS portal'; content += ''; aladinInstance.showPopup(objCoo.lon, objCoo.lat, title, content); diff --git a/src/js/gui/Box/StackBox.js b/src/js/gui/Box/StackBox.js index 2ff537eb..c9c92a5a 100644 --- a/src/js/gui/Box/StackBox.js +++ b/src/js/gui/Box/StackBox.js @@ -75,7 +75,7 @@ export class OverlayStackBox extends Box { };*/ static predefinedCats = { simbad: { - url: "https://axel.u-strasbg.fr/HiPSCatService/SIMBAD", + url: "https://axel.cds.unistra.fr/HiPSCatService/SIMBAD", options: { id: "simbad", name: "SIMBAD", @@ -98,7 +98,7 @@ export class OverlayStackBox extends Box { }, }, gaia: { - url: "https://axel.u-strasbg.fr/HiPSCatService/I/355/gaiadr3", + url: "https://axel.cds.unistra.fr/HiPSCatService/I/355/gaiadr3", options: { id: "gaia-dr3", name: "Gaia DR3", @@ -109,7 +109,7 @@ export class OverlayStackBox extends Box { }, }, twomass: { - url: "https://axel.u-strasbg.fr/HiPSCatService/II/246/out", + url: "https://axel.cds.unistra.fr/HiPSCatService/II/246/out", options: { id: "2mass", name: "2MASS", @@ -790,7 +790,7 @@ export class OverlayStackBox extends Box { moreHiPSLink.addEventListener("click", (e) => { e.preventDefault(); if (!self.hipsBrowser) - self.hipsBrowser = new HiPSBrowserBox(aladin); + self.hipsBrowser = new HiPSBrowserBox(self.aladin); self.hipsBrowser._show({ position: { anchor: "center center" } }); });