mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2025-12-12 15:49:18 -08:00
wip: hips3d struct and hips enum
This commit is contained in:
committed by
Matthieu Baumann
parent
8ca394459d
commit
1e51a6e17e
52
examples/al-hips-cube.html
Normal file
52
examples/al-hips-cube.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div id="aladin-lite-div" style="width: 768px; height: 512px"></div>
|
||||
<script>let aladin; let hips;</script>
|
||||
<script type="module">
|
||||
import A from '../src/js/A.js';
|
||||
A.init.then(() => {
|
||||
aladin = A.aladin(
|
||||
'#aladin-lite-div',
|
||||
{
|
||||
showSimbadPointerControl: true,
|
||||
projection: 'AIT', // set a projection
|
||||
fov: 360, // initial field of view in degrees
|
||||
target: '169.58868 +45.74914', // initial target
|
||||
cooFrame: 'icrs', // set galactic frame
|
||||
reticleColor: '#ff89ff', // change reticle color
|
||||
reticleSize: 64, // change reticle size
|
||||
showContextMenu: true,
|
||||
showFrame: true,
|
||||
showZoomControl:true,
|
||||
showSettingsControl:true,
|
||||
showCooGrid: true,
|
||||
fullScreen: true,
|
||||
samp: true,
|
||||
}
|
||||
);
|
||||
|
||||
hips = aladin.newImageSurvey("https://alasky.cds.unistra.fr/CALIFA/V500DR2/");
|
||||
aladin.setImageLayer(hips)
|
||||
|
||||
/*let id;
|
||||
aladin.on("zoomChanged", () => {
|
||||
if (id)
|
||||
clearTimeout(id);
|
||||
id = setTimeout(() => {
|
||||
console.log("wheel stopped, new cone search here")
|
||||
}, 500);
|
||||
})*/
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.aladin-cat-browser-box {
|
||||
width: 600px;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
||||
@@ -50,13 +50,11 @@ optional = true
|
||||
|
||||
[dependencies.healpix]
|
||||
package = "cdshealpix"
|
||||
git = "https://github.com/cds-astro/cds-healpix-rust"
|
||||
branch = "master"
|
||||
version = "0.7.0"
|
||||
|
||||
[dependencies.moclib]
|
||||
package = "moc"
|
||||
git = "https://github.com/cds-astro/cds-moc-rust"
|
||||
branch = "main"
|
||||
version = "0.17.0"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "^1.0.183"
|
||||
|
||||
@@ -19,7 +19,7 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::texture::{Tex3D, Texture2DArray};
|
||||
use crate::texture::Tex3D;
|
||||
use wasm_bindgen::JsValue;
|
||||
impl<F> Image for Bitmap<F>
|
||||
where
|
||||
|
||||
@@ -19,7 +19,7 @@ where
|
||||
|
||||
use crate::image::format::ImageFormat;
|
||||
use crate::image::Image;
|
||||
use crate::texture::{Tex3D, Texture2DArray};
|
||||
use crate::texture::Tex3D;
|
||||
use cgmath::Vector3;
|
||||
use wasm_bindgen::JsValue;
|
||||
impl<F> Image for Canvas<F>
|
||||
|
||||
@@ -116,7 +116,6 @@ impl<'a> Fits<'a> {
|
||||
}
|
||||
}*/
|
||||
|
||||
use crate::Texture2DArray;
|
||||
use crate::{image::Image, texture::Tex3D};
|
||||
impl Image for Fits<'_> {
|
||||
fn insert_into_3d_texture<T: Tex3D>(
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::image::format::ImageFormat;
|
||||
use web_sys::HtmlCanvasElement;
|
||||
use web_sys::WebGlTexture;
|
||||
|
||||
use crate::texture::pixel::Pixel;
|
||||
use crate::texture::Texture2DMeta;
|
||||
use crate::webgl_ctx::WebGlContext;
|
||||
use crate::webgl_ctx::WebGlRenderingCtx;
|
||||
@@ -80,6 +81,89 @@ impl Texture2DArray {
|
||||
.active_texture(WebGlRenderingCtx::TEXTURE0 + idx_tex_unit as u32);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn read_pixel(&self, x: i32, y: i32, slice_idx: i32) -> Result<JsValue, JsValue> {
|
||||
// Create and bind the framebuffer
|
||||
let reader = self.gl.create_framebuffer();
|
||||
self.gl
|
||||
.bind_framebuffer(WebGlRenderingCtx::FRAMEBUFFER, reader.as_ref());
|
||||
|
||||
// Attach the texture as the first color attachment
|
||||
self.gl.framebuffer_texture_layer(
|
||||
WebGlRenderingCtx::READ_FRAMEBUFFER,
|
||||
WebGlRenderingCtx::COLOR_ATTACHMENT0,
|
||||
self.texture.as_ref(),
|
||||
0,
|
||||
slice_idx,
|
||||
);
|
||||
|
||||
let status = self
|
||||
.gl
|
||||
.check_framebuffer_status(WebGlRenderingCtx::FRAMEBUFFER);
|
||||
if status != WebGlRenderingCtx::FRAMEBUFFER_COMPLETE {
|
||||
// Unbind the framebuffer
|
||||
self.gl
|
||||
.bind_framebuffer(WebGlRenderingCtx::FRAMEBUFFER, None);
|
||||
// Delete the framebuffer
|
||||
self.gl.delete_framebuffer(reader.as_ref());
|
||||
|
||||
Err(JsValue::from_str("incomplete framebuffer"))
|
||||
} else {
|
||||
// set the viewport as the FBO won't be the same dimension as the screen
|
||||
let metadata = self.metadata.as_ref().unwrap_abort().borrow();
|
||||
self.gl
|
||||
.viewport(0, 0, metadata.width as i32, metadata.height as i32);
|
||||
|
||||
#[cfg(feature = "webgl2")]
|
||||
let value = match (metadata.format, metadata.type_) {
|
||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
||||
let p = <[u8; 1]>::read_pixel(&self.gl, x, y)?;
|
||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||
}
|
||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::SHORT) => {
|
||||
let p = <[i16; 1]>::read_pixel(&self.gl, x, y)?;
|
||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||
}
|
||||
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::INT) => {
|
||||
let p = <[i32; 1]>::read_pixel(&self.gl, x, y)?;
|
||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||
}
|
||||
(WebGlRenderingCtx::RED, WebGlRenderingCtx::FLOAT) => {
|
||||
let p = <[f32; 1]>::read_pixel(&self.gl, x, y)?;
|
||||
Ok(serde_wasm_bindgen::to_value(&p[0])?)
|
||||
}
|
||||
(WebGlRenderingCtx::RGB, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
||||
let p = <[u8; 3]>::read_pixel(&self.gl, x, y)?;
|
||||
Ok(serde_wasm_bindgen::to_value(&p)?)
|
||||
}
|
||||
(WebGlRenderingCtx::RGBA, WebGlRenderingCtx::UNSIGNED_BYTE) => {
|
||||
let p = <[u8; 4]>::read_pixel(&self.gl, x, y)?;
|
||||
Ok(serde_wasm_bindgen::to_value(&p)?)
|
||||
}
|
||||
_ => Err(JsValue::from_str(
|
||||
"Pixel retrieval not implemented for that texture format.",
|
||||
)),
|
||||
};
|
||||
|
||||
// Unbind the framebuffer
|
||||
self.gl
|
||||
.bind_framebuffer(WebGlRenderingCtx::FRAMEBUFFER, None);
|
||||
// Delete the framebuffer
|
||||
self.gl.delete_framebuffer(reader.as_ref());
|
||||
|
||||
// set the viewport as the FBO won't be the same dimension as the screen
|
||||
let canvas = self
|
||||
.gl
|
||||
.canvas()
|
||||
.unwrap_abort()
|
||||
.dyn_into::<web_sys::HtmlCanvasElement>()
|
||||
.unwrap_abort();
|
||||
self.gl
|
||||
.viewport(0, 0, canvas.width() as i32, canvas.height() as i32);
|
||||
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Texture2DArray {
|
||||
|
||||
@@ -328,7 +328,7 @@ impl Texture2D {
|
||||
// set the viewport as the FBO won't be the same dimension as the screen
|
||||
let metadata = self.metadata.as_ref().unwrap_abort().borrow();
|
||||
self.gl
|
||||
.viewport(x, y, metadata.width as i32, metadata.height as i32);
|
||||
.viewport(0, 0, metadata.width as i32, metadata.height as i32);
|
||||
|
||||
#[cfg(feature = "webgl2")]
|
||||
let value = match (metadata.format, metadata.type_) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::renderable::ImageLayer;
|
||||
use crate::tile_fetcher::HiPSLocalFiles;
|
||||
|
||||
use crate::renderable::hips::HiPS;
|
||||
use crate::{
|
||||
//async_task::{BuildCatalogIndex, ParseTableTask, TaskExecutor, TaskResult, TaskType},
|
||||
camera::CameraViewPort,
|
||||
@@ -19,7 +20,6 @@ use crate::{
|
||||
tile_fetcher::TileFetcherQueue,
|
||||
time::DeltaTime,
|
||||
};
|
||||
use al_core::log::console_log;
|
||||
use wcs::WCS;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
@@ -28,7 +28,6 @@ use al_core::colormap::{Colormap, Colormaps};
|
||||
use al_core::WebGlContext;
|
||||
|
||||
use super::coosys;
|
||||
use crate::Abort;
|
||||
use al_api::{
|
||||
coo_system::CooSystem,
|
||||
grid::GridCfg,
|
||||
@@ -140,7 +139,7 @@ impl App {
|
||||
//gl.enable(WebGl2RenderingContext::SCISSOR_TEST);
|
||||
|
||||
//gl.enable(WebGl2RenderingContext::CULL_FACE);
|
||||
//gl.cull_face(WebGl2RenderingContext::BACK);
|
||||
gl.cull_face(WebGl2RenderingContext::BACK);
|
||||
//gl.enable(WebGl2RenderingContext::CULL_FACE);
|
||||
|
||||
// The tile buffer responsible for the tile requests
|
||||
@@ -153,7 +152,7 @@ impl App {
|
||||
FrameBufferObject::new(&gl, screen_size.x as usize, screen_size.y as usize)?;
|
||||
let _fbo_ui = FrameBufferObject::new(&gl, screen_size.x as usize, screen_size.y as usize)?;
|
||||
|
||||
// The surveys storing the textures of the resolved tiles
|
||||
// The hipss storing the textures of the resolved tiles
|
||||
let layers = Layers::new(&gl, &projection)?;
|
||||
|
||||
let time_start_blending = Time::now();
|
||||
@@ -255,22 +254,23 @@ impl App {
|
||||
}
|
||||
|
||||
fn look_for_new_tiles(&mut self) -> Result<(), JsValue> {
|
||||
// Move the views of the different active surveys
|
||||
// Move the views of the different active hipss
|
||||
self.tile_fetcher.clear();
|
||||
// Loop over the surveys
|
||||
for survey in self.layers.values_mut_hips() {
|
||||
let cfg = survey.get_config();
|
||||
|
||||
if self.camera.get_texture_depth() == 0
|
||||
&& self
|
||||
.downloader
|
||||
.borrow()
|
||||
.is_queried(&query::Allsky::new(cfg).id)
|
||||
{
|
||||
// do not ask for tiles if we download the allsky
|
||||
continue;
|
||||
// Loop over the hipss
|
||||
for hips in self.layers.get_mut_hipses() {
|
||||
if self.camera.get_texture_depth() == 0 {
|
||||
let allsky_query = match hips {
|
||||
HiPS::D2(h) => query::Allsky::new(h.get_config(), None),
|
||||
HiPS::D3(h) => query::Allsky::new(h.get_config(), Some(h.get_slice() as u32)),
|
||||
};
|
||||
if self.downloader.borrow().is_queried(&allsky_query.id) {
|
||||
// do not ask for tiles if we download the allsky
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let cfg = hips.get_config();
|
||||
|
||||
let min_tile_depth = cfg.delta_depth().max(cfg.get_min_depth_tile());
|
||||
let mut ancestors = HashSet::new();
|
||||
|
||||
@@ -278,16 +278,9 @@ impl App {
|
||||
let root_url = cfg.get_root_url().to_string();
|
||||
let format = cfg.get_format();
|
||||
|
||||
if let Some(tiles_iter) = survey.look_for_new_tiles(&mut self.camera, &self.projection)
|
||||
{
|
||||
for tile_cell in tiles_iter.into_iter() {
|
||||
self.tile_fetcher.append(query::Tile::new(
|
||||
&tile_cell,
|
||||
creator_did.clone(),
|
||||
root_url.clone(),
|
||||
format,
|
||||
None,
|
||||
));
|
||||
if let Some(tiles) = hips.look_for_new_tiles(&mut self.camera, &self.projection) {
|
||||
for tile_cell in tiles {
|
||||
self.tile_fetcher.append(hips.get_tile_query(&tile_cell));
|
||||
|
||||
// check if we are starting aladin lite or not.
|
||||
// If so we want to retrieve only the tiles in the view and access them
|
||||
@@ -301,15 +294,21 @@ impl App {
|
||||
}
|
||||
}
|
||||
// Request for ancestor
|
||||
for ancestor in ancestors {
|
||||
if !survey.update_priority_tile(&ancestor) {
|
||||
self.tile_fetcher.append(query::Tile::new(
|
||||
&ancestor,
|
||||
creator_did.clone(),
|
||||
root_url.clone(),
|
||||
format,
|
||||
None,
|
||||
));
|
||||
match hips {
|
||||
HiPS::D2(hips) => {
|
||||
for ancestor in ancestors {
|
||||
if !hips.update_priority_tile(&ancestor) {
|
||||
self.tile_fetcher.append(hips.get_tile_query(&ancestor));
|
||||
}
|
||||
}
|
||||
}
|
||||
HiPS::D3(hips) => {
|
||||
let slice = hips.get_slice();
|
||||
for ancestor in ancestors {
|
||||
if !hips.contains_tile(&ancestor, slice) {
|
||||
self.tile_fetcher.append(hips.get_tile_query(&ancestor));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -345,7 +344,7 @@ impl App {
|
||||
colormap,
|
||||
&mut self.shaders,
|
||||
&self.camera,
|
||||
self.surveys.get_view().unwrap_abort(),
|
||||
self.hipss.get_view().unwrap_abort(),
|
||||
);
|
||||
self.catalog_loaded = true;
|
||||
self.request_redraw = true;
|
||||
@@ -380,7 +379,7 @@ impl App {
|
||||
colormap,
|
||||
&mut self.shaders,
|
||||
&self.camera,
|
||||
self.surveys.get_view().unwrap_abort(),
|
||||
self.hipss.get_view().unwrap_abort(),
|
||||
);
|
||||
self.catalog_loaded = true;
|
||||
self.request_redraw = true;
|
||||
@@ -395,7 +394,6 @@ impl App {
|
||||
use crate::downloader::request::Resource;
|
||||
use al_api::cell::HEALPixCellProjeted;
|
||||
|
||||
use crate::downloader::request::tile::Tile;
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
|
||||
use al_api::color::ColorRGB;
|
||||
@@ -566,11 +564,11 @@ impl App {
|
||||
{
|
||||
// Newly available tiles must lead to
|
||||
// 1. Surveys must be aware of the new available tiles
|
||||
//self.surveys.set_available_tiles(&available_tiles);
|
||||
// 2. Get the resolved tiles and push them to the image surveys
|
||||
//self.hipss.set_available_tiles(&available_tiles);
|
||||
// 2. Get the resolved tiles and push them to the image hipss
|
||||
/*let is_there_new_available_tiles = self
|
||||
.downloader
|
||||
.get_resolved_tiles(/*&available_tiles, */&mut self.surveys);*/
|
||||
.get_resolved_tiles(/*&available_tiles, */&mut self.hipss);*/
|
||||
|
||||
if self.request_for_new_tiles
|
||||
//&& Time::now() - self.last_time_request_for_new_tiles > DeltaTime::from(200.0)
|
||||
@@ -606,9 +604,8 @@ impl App {
|
||||
match rsc {
|
||||
Resource::Tile(tile) => {
|
||||
//if !_has_camera_zoomed {
|
||||
if let Some(survey) = self.layers.get_mut_hips_from_cdid(&tile.get_hips_cdid())
|
||||
{
|
||||
let cfg = survey.get_config_mut();
|
||||
if let Some(hips) = self.layers.get_mut_hips_from_cdid(&tile.get_hips_cdid()) {
|
||||
let cfg = hips.get_config_mut();
|
||||
|
||||
if cfg.get_format() == tile.format {
|
||||
let delta_depth = cfg.delta_depth();
|
||||
@@ -707,7 +704,17 @@ impl App {
|
||||
|
||||
self.request_redraw = true;
|
||||
tile_copied = true;
|
||||
survey.add_tile(&tile.cell, img, tile.time_req)?;
|
||||
match hips {
|
||||
HiPS::D2(hips) => {
|
||||
hips.add_tile(&tile.cell, img, tile.time_req)?
|
||||
}
|
||||
HiPS::D3(hips) => hips.add_tile(
|
||||
&tile.cell,
|
||||
img,
|
||||
tile.time_req,
|
||||
tile.channel.unwrap() as u16,
|
||||
)?,
|
||||
}
|
||||
|
||||
self.time_start_blending = Time::now();
|
||||
}
|
||||
@@ -720,28 +727,22 @@ impl App {
|
||||
Resource::Allsky(allsky) => {
|
||||
let hips_cdid = allsky.get_hips_cdid();
|
||||
|
||||
if let Some(survey) = self.layers.get_mut_hips_from_cdid(hips_cdid) {
|
||||
if let Some(hips) = self.layers.get_mut_hips_from_cdid(hips_cdid) {
|
||||
let is_missing = allsky.missing();
|
||||
if is_missing {
|
||||
// The allsky image is missing so we donwload all the tiles contained into
|
||||
// the 0's cell
|
||||
let cfg = survey.get_config();
|
||||
let cfg = hips.get_config();
|
||||
for texture_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||
for cell in texture_cell.get_tile_cells(cfg.delta_depth()) {
|
||||
let query = query::Tile::new(
|
||||
&cell,
|
||||
cfg.get_creator_did().to_string(),
|
||||
cfg.get_root_url().to_string(),
|
||||
cfg.get_format(),
|
||||
None,
|
||||
);
|
||||
let query = hips.get_tile_query(&cell);
|
||||
self.tile_fetcher.append_base_tile(query);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// tell the survey to not download tiles which order is <= 3 because the allsky
|
||||
// tell the hips to not download tiles which order is <= 3 because the allsky
|
||||
// give them already
|
||||
survey.add_allsky(allsky)?;
|
||||
hips.add_allsky(allsky)?;
|
||||
// Once received ask for redraw
|
||||
self.request_redraw = true;
|
||||
}
|
||||
@@ -793,8 +794,8 @@ impl App {
|
||||
|
||||
pub(crate) fn read_pixel(&self, pos: &Vector2<f64>, layer: &str) -> Result<JsValue, JsValue> {
|
||||
if let Some(lonlat) = self.screen_to_world(pos) {
|
||||
if let Some(survey) = self.layers.get_hips_from_layer(layer) {
|
||||
survey.read_pixel(&lonlat, &self.camera)
|
||||
if let Some(hips) = self.layers.get_hips_from_layer(layer) {
|
||||
hips.read_pixel(&lonlat, &self.camera)
|
||||
} else if let Some(_image) = self.layers.get_image_from_layer(layer) {
|
||||
Err(JsValue::from_str("TODO: read pixel value"))
|
||||
} else {
|
||||
@@ -960,14 +961,14 @@ impl App {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn add_image_hips(
|
||||
pub(crate) fn add_hips(
|
||||
&mut self,
|
||||
hips_cfg: HiPSCfg,
|
||||
local_files: Option<HiPSLocalFiles>,
|
||||
) -> Result<(), JsValue> {
|
||||
let cdid = hips_cfg.properties.get_creator_did().to_string();
|
||||
|
||||
let hips = self.layers.add_image_hips(
|
||||
let hips = self.layers.add_hips(
|
||||
&self.gl,
|
||||
hips_cfg,
|
||||
&mut self.camera,
|
||||
@@ -1252,18 +1253,25 @@ impl App {
|
||||
self.layers.get_layer_cfg(layer)
|
||||
}
|
||||
|
||||
pub(crate) fn set_hips_url(&mut self, cdid: &String, new_url: String) -> Result<(), JsValue> {
|
||||
self.layers.set_survey_url(cdid, new_url.clone())?;
|
||||
pub(crate) fn set_hips_slice_number(&mut self, layer: &str, slice: u32) -> Result<(), JsValue> {
|
||||
let hips = self
|
||||
.layers
|
||||
.get_mut_hips_from_layer(&layer)
|
||||
.ok_or_else(|| JsValue::from_str("Layer not found"))?;
|
||||
|
||||
//let hips = self.layers.get_hips_from_url(&new_url).unwrap_abort();
|
||||
// Relaunch the base tiles for the survey to be ready with the new url
|
||||
//self.tile_fetcher
|
||||
// .launch_starting_hips_requests(hips, &mut self.downloader);
|
||||
self.request_for_new_tiles = true;
|
||||
|
||||
Ok(())
|
||||
match hips {
|
||||
HiPS::D2(_) => Err(JsValue::from_str("layer do not refers to a cube")),
|
||||
HiPS::D3(hips) => {
|
||||
hips.set_slice(slice as u16);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_image_survey_color_cfg(
|
||||
pub(crate) fn set_image_hips_color_cfg(
|
||||
&mut self,
|
||||
layer: String,
|
||||
meta: ImageMetadata,
|
||||
@@ -1271,19 +1279,19 @@ impl App {
|
||||
let old_meta = self.layers.get_layer_cfg(&layer)?;
|
||||
// Set the new meta
|
||||
// keep the old meta data
|
||||
let new_img_fmt = meta.img_format;
|
||||
let new_img_ext = meta.img_format;
|
||||
self.layers
|
||||
.set_layer_cfg(layer.clone(), meta, &mut self.camera, &self.projection)?;
|
||||
|
||||
if old_meta.img_format != new_img_fmt {
|
||||
if old_meta.img_format != new_img_ext {
|
||||
// The image format has been changed
|
||||
let hips = self
|
||||
.layers
|
||||
.get_mut_hips_from_layer(&layer)
|
||||
.ok_or_else(|| JsValue::from_str("Layer not found"))?;
|
||||
hips.set_img_format(new_img_fmt)?;
|
||||
hips.set_image_ext(new_img_ext)?;
|
||||
|
||||
// Relaunch the base tiles for the survey to be ready with the new url
|
||||
// Relaunch the base tiles for the hips to be ready with the new url
|
||||
self.tile_fetcher
|
||||
.launch_starting_hips_requests(hips, self.downloader.clone());
|
||||
|
||||
@@ -1364,8 +1372,8 @@ impl App {
|
||||
self.request_redraw = true;
|
||||
}
|
||||
|
||||
pub(crate) fn set_survey_url(&mut self, cdid: &String, new_url: String) -> Result<(), JsValue> {
|
||||
self.layers.set_survey_url(cdid, new_url)
|
||||
pub(crate) fn set_hips_url(&mut self, cdid: &String, new_url: String) -> Result<(), JsValue> {
|
||||
self.layers.set_hips_url(cdid, new_url)
|
||||
}
|
||||
|
||||
pub(crate) fn set_catalog_opacity(
|
||||
|
||||
@@ -20,19 +20,18 @@ pub struct Tile {
|
||||
// The total url of the query
|
||||
pub url: Url,
|
||||
pub id: QueryId,
|
||||
pub channel: Option<u32>,
|
||||
}
|
||||
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
use crate::renderable::hips::config::HiPSConfig;
|
||||
use crate::renderable::CreatorDid;
|
||||
impl Tile {
|
||||
pub fn new(
|
||||
cell: &HEALPixCell,
|
||||
hips_cdid: String,
|
||||
hips_url: String,
|
||||
format: ImageFormatType,
|
||||
channel: Option<u32>,
|
||||
) -> Self {
|
||||
pub fn new(cell: &HEALPixCell, channel: Option<u32>, cfg: &HiPSConfig) -> Self {
|
||||
let hips_cdid = cfg.get_creator_did();
|
||||
let hips_url = cfg.get_root_url();
|
||||
let format = cfg.get_format();
|
||||
|
||||
let ext = format.get_ext_file();
|
||||
|
||||
let HEALPixCell(depth, idx) = *cell;
|
||||
@@ -43,22 +42,30 @@ impl Tile {
|
||||
|
||||
// handle cube case
|
||||
if let Some(channel) = channel {
|
||||
url.push_str(&format!("_{:?}", channel));
|
||||
if channel > 0 {
|
||||
url.push_str(&format!("_{:?}", channel));
|
||||
}
|
||||
}
|
||||
|
||||
// add the tile format
|
||||
url.push_str(&format!(".{}", ext));
|
||||
|
||||
let channel = channel.unwrap_or(0);
|
||||
|
||||
let id = format!("{}{}{}{}{}", hips_cdid, depth, idx, channel, ext);
|
||||
let id = format!(
|
||||
"{}{}{}{}{}",
|
||||
hips_cdid,
|
||||
depth,
|
||||
idx,
|
||||
channel.unwrap_or(0),
|
||||
ext
|
||||
);
|
||||
|
||||
Tile {
|
||||
hips_cdid,
|
||||
hips_cdid: hips_cdid.to_string(),
|
||||
url,
|
||||
cell: *cell,
|
||||
format,
|
||||
id,
|
||||
channel,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,6 +84,7 @@ pub struct Allsky {
|
||||
pub format: ImageFormatType,
|
||||
pub tile_size: i32,
|
||||
pub texture_size: i32,
|
||||
pub channel: Option<u32>,
|
||||
// The root url of the HiPS
|
||||
pub hips_cdid: CreatorDid,
|
||||
// The total url of the query
|
||||
@@ -85,16 +93,31 @@ pub struct Allsky {
|
||||
}
|
||||
|
||||
impl Allsky {
|
||||
pub fn new(cfg: &HiPSConfig) -> Self {
|
||||
pub fn new(cfg: &HiPSConfig, channel: Option<u32>) -> Self {
|
||||
let hips_cdid = cfg.get_creator_did().to_string();
|
||||
let tile_size = cfg.get_tile_size();
|
||||
let texture_size = cfg.get_texture_size();
|
||||
let format = cfg.get_format();
|
||||
let ext = format.get_ext_file();
|
||||
|
||||
let url = format!("{}/Norder3/Allsky.{}", cfg.get_root_url(), ext);
|
||||
let mut url = format!("{}/Norder3/Allsky", cfg.get_root_url());
|
||||
|
||||
let id = format!("{}Allsky{}", cfg.get_creator_did(), ext);
|
||||
// handle cube case
|
||||
if let Some(channel) = channel {
|
||||
if channel > 0 {
|
||||
url.push_str(&format!("_{:?}", channel));
|
||||
}
|
||||
}
|
||||
|
||||
// add the tile format
|
||||
url.push_str(&format!(".{}", ext));
|
||||
|
||||
let id = format!(
|
||||
"{}Allsky{}{}",
|
||||
cfg.get_creator_did(),
|
||||
ext,
|
||||
channel.unwrap_or(0)
|
||||
);
|
||||
|
||||
Allsky {
|
||||
tile_size,
|
||||
@@ -103,6 +126,7 @@ impl Allsky {
|
||||
url,
|
||||
format,
|
||||
id,
|
||||
channel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ pub struct AllskyRequest {
|
||||
pub url: Url,
|
||||
pub depth_tile: u8,
|
||||
pub id: QueryId,
|
||||
pub channel: Option<u32>,
|
||||
|
||||
request: Request<Vec<ImageType>>,
|
||||
}
|
||||
@@ -80,6 +81,7 @@ impl From<query::Allsky> for AllskyRequest {
|
||||
hips_cdid,
|
||||
texture_size,
|
||||
id,
|
||||
channel: slice,
|
||||
} = query;
|
||||
|
||||
let depth_tile = crate::math::utils::log_2_unchecked(texture_size / tile_size) as u8;
|
||||
@@ -212,6 +214,7 @@ impl From<query::Allsky> for AllskyRequest {
|
||||
depth_tile,
|
||||
url,
|
||||
request,
|
||||
channel: slice,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -306,7 +309,6 @@ use al_core::image::format::RGBA8U;
|
||||
use crate::time::Time;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
pub struct Allsky {
|
||||
pub image: Rc<RefCell<Option<Vec<ImageType>>>>,
|
||||
pub time_req: Time,
|
||||
@@ -314,6 +316,7 @@ pub struct Allsky {
|
||||
|
||||
pub hips_cdid: CreatorDid,
|
||||
url: Url,
|
||||
pub channel: Option<u32>,
|
||||
}
|
||||
|
||||
use crate::Abort;
|
||||
@@ -339,6 +342,7 @@ impl<'a> From<&'a AllskyRequest> for Option<Allsky> {
|
||||
hips_cdid,
|
||||
depth_tile,
|
||||
url,
|
||||
channel,
|
||||
..
|
||||
} = request;
|
||||
if request.is_resolved() {
|
||||
@@ -352,6 +356,7 @@ impl<'a> From<&'a AllskyRequest> for Option<Allsky> {
|
||||
hips_cdid: hips_cdid.clone(),
|
||||
url: url.clone(),
|
||||
depth_tile: *depth_tile,
|
||||
channel: *channel,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -134,7 +134,6 @@ impl From<query::PixelMetadata> for PixelMetadataRequest {
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
#[derive(Debug)]
|
||||
pub struct PixelMetadata {
|
||||
pub value: Rc<RefCell<Option<Metadata>>>,
|
||||
|
||||
@@ -104,7 +104,6 @@ impl From<query::Moc> for MOCRequest {
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
pub struct Moc {
|
||||
pub moc: Rc<RefCell<Option<HEALPixCoverage>>>,
|
||||
pub params: al_api::moc::MOC,
|
||||
|
||||
@@ -10,7 +10,6 @@ pub mod tile;
|
||||
use crate::time::Time;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
pub type Url = String;
|
||||
pub struct Request<R> {
|
||||
data: Rc<RefCell<Option<R>>>,
|
||||
@@ -27,7 +26,6 @@ pub enum ResolvedStatus {
|
||||
Failed,
|
||||
Found,
|
||||
}
|
||||
use crate::Abort;
|
||||
use std::future::Future;
|
||||
use wasm_bindgen::JsValue;
|
||||
impl<R> Request<R>
|
||||
|
||||
@@ -10,14 +10,14 @@ use super::{Request, RequestType};
|
||||
use crate::downloader::QueryId;
|
||||
|
||||
pub struct TileRequest {
|
||||
request: Request<ImageType>,
|
||||
pub id: QueryId,
|
||||
|
||||
cell: HEALPixCell,
|
||||
hips_cdid: CreatorDid,
|
||||
url: Url,
|
||||
format: ImageFormatType,
|
||||
|
||||
request: Request<ImageType>,
|
||||
channel: Option<u32>,
|
||||
}
|
||||
|
||||
impl From<TileRequest> for RequestType {
|
||||
@@ -59,6 +59,7 @@ impl From<query::Tile> for TileRequest {
|
||||
url,
|
||||
hips_cdid,
|
||||
id,
|
||||
channel: slice,
|
||||
} = query;
|
||||
|
||||
let url_clone = url.clone();
|
||||
@@ -180,6 +181,7 @@ impl From<query::Tile> for TileRequest {
|
||||
hips_cdid,
|
||||
url,
|
||||
request,
|
||||
channel: slice,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,12 +189,12 @@ impl From<query::Tile> for TileRequest {
|
||||
use crate::time::Time;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
pub struct Tile {
|
||||
pub image: Rc<RefCell<Option<ImageType>>>,
|
||||
pub time_req: Time,
|
||||
pub cell: HEALPixCell,
|
||||
pub format: ImageFormatType,
|
||||
pub channel: Option<u32>,
|
||||
hips_cdid: CreatorDid,
|
||||
url: Url,
|
||||
}
|
||||
@@ -228,6 +230,7 @@ impl<'a> From<&'a TileRequest> for Option<Tile> {
|
||||
hips_cdid,
|
||||
url,
|
||||
format,
|
||||
channel,
|
||||
..
|
||||
} = request;
|
||||
if request.is_resolved() {
|
||||
@@ -242,6 +245,7 @@ impl<'a> From<&'a TileRequest> for Option<Tile> {
|
||||
hips_cdid: hips_cdid.clone(),
|
||||
url: url.clone(),
|
||||
format: *format,
|
||||
channel: *channel,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -320,13 +320,13 @@ impl WebClient {
|
||||
Ok(self.app.get_norder())
|
||||
}
|
||||
|
||||
/// Set new image surveys
|
||||
/// Set new image hips
|
||||
///
|
||||
/// Send the image surveys to render inside the Aladin Lite view
|
||||
/// Send the image hips to render inside the Aladin Lite view
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `surveys` - A list/array of survey. A survey is a javascript object
|
||||
/// * `hips` - A list/array of hips. A hips is a javascript object
|
||||
/// having the specific form. Please check the file in core/src/hips.rs to see
|
||||
/// the different semantics accepted.
|
||||
///
|
||||
@@ -362,19 +362,19 @@ impl WebClient {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * If the surveys do not match SimpleHiPS type
|
||||
/// * If the number of surveys is greater than 4. For the moment, due to the limitations
|
||||
/// of WebGL2 texture units on some architectures, the total number of surveys rendered is
|
||||
/// * If the hips do not match SimpleHiPS type
|
||||
/// * If the number of hips is greater than 4. For the moment, due to the limitations
|
||||
/// of WebGL2 texture units on some architectures, the total number of hips rendered is
|
||||
/// limited to 4.
|
||||
#[wasm_bindgen(js_name = addHiPS)]
|
||||
pub fn add_image_hips(
|
||||
pub fn add_hips(
|
||||
&mut self,
|
||||
hips: JsValue,
|
||||
files: Option<HiPSLocalFiles>,
|
||||
) -> Result<(), JsValue> {
|
||||
// Deserialize the survey objects that compose the survey
|
||||
// Deserialize the hips objects that compose the hips
|
||||
let hips = serde_wasm_bindgen::from_value(hips)?;
|
||||
self.app.add_image_hips(hips, files)?;
|
||||
self.app.add_hips(hips, files)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -410,7 +410,7 @@ impl WebClient {
|
||||
|
||||
#[wasm_bindgen(js_name = removeLayer)]
|
||||
pub fn remove_layer(&mut self, layer: String) -> Result<(), JsValue> {
|
||||
// Deserialize the survey objects that compose the survey
|
||||
// Deserialize the hips objects that compose the hips
|
||||
self.app.remove_layer(&layer)?;
|
||||
|
||||
Ok(())
|
||||
@@ -418,7 +418,7 @@ impl WebClient {
|
||||
|
||||
#[wasm_bindgen(js_name = renameLayer)]
|
||||
pub fn rename_layer(&mut self, layer: String, new_layer: String) -> Result<(), JsValue> {
|
||||
// Deserialize the survey objects that compose the survey
|
||||
// Deserialize the hips objects that compose the hips
|
||||
self.app.rename_layer(&layer, &new_layer)
|
||||
}
|
||||
|
||||
@@ -428,7 +428,7 @@ impl WebClient {
|
||||
first_layer: String,
|
||||
second_layer: String,
|
||||
) -> Result<(), JsValue> {
|
||||
// Deserialize the survey objects that compose the survey
|
||||
// Deserialize the hips objects that compose the hips
|
||||
self.app.swap_layers(&first_layer, &second_layer)
|
||||
}
|
||||
|
||||
@@ -444,15 +444,15 @@ impl WebClient {
|
||||
|
||||
// Set a new color associated with a layer
|
||||
#[wasm_bindgen(js_name = setImageMetadata)]
|
||||
pub fn set_survey_color_cfg(&mut self, layer: String, meta: JsValue) -> Result<(), JsValue> {
|
||||
pub fn set_hips_color_cfg(&mut self, layer: String, meta: JsValue) -> Result<(), JsValue> {
|
||||
let meta = serde_wasm_bindgen::from_value(meta)?;
|
||||
|
||||
self.app.set_image_survey_color_cfg(layer, meta)
|
||||
self.app.set_image_hips_color_cfg(layer, meta)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = setImageSurveyUrl)]
|
||||
pub fn set_survey_url(&mut self, cdid: String, new_url: String) -> Result<(), JsValue> {
|
||||
self.app.set_survey_url(&cdid, new_url)
|
||||
#[wasm_bindgen(js_name = setSliceNumber)]
|
||||
pub fn set_hips_slice_number(&mut self, layer: String, slice: u32) -> Result<(), JsValue> {
|
||||
self.app.set_hips_slice_number(&layer, slice)
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = setBackgroundColor)]
|
||||
@@ -963,7 +963,7 @@ impl WebClient {
|
||||
/// Read the pixel value
|
||||
///
|
||||
/// The current implementation only returns the pixel value
|
||||
/// of the first survey of the `layer` specified.
|
||||
/// of the first hips of the `layer` specified.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
@@ -975,7 +975,7 @@ impl WebClient {
|
||||
///
|
||||
/// * `x` - The x screen coordinate in pixels
|
||||
/// * `y` - The y screen coordinate in pixels
|
||||
/// * `base_url` - The base url of the survey identifying it
|
||||
/// * `base_url` - The base url of the hips identifying it
|
||||
#[wasm_bindgen(js_name = readPixel)]
|
||||
pub fn read_pixel(&self, x: f64, y: f64, layer: String) -> Result<JsValue, JsValue> {
|
||||
let pixel = self.app.read_pixel(&Vector2::new(x, y), layer.as_str())?;
|
||||
|
||||
@@ -73,7 +73,7 @@ impl PrimInt for i32 {
|
||||
|
||||
pub fn log_2_unchecked<T>(x: T) -> u32
|
||||
where
|
||||
T: Zero + PrimInt + std::cmp::PartialOrd
|
||||
T: Zero + PrimInt + std::cmp::PartialOrd,
|
||||
{
|
||||
debug_assert!(x > T::zero());
|
||||
num_bits::<T>() as u32 - x.leading_zeros() - 1
|
||||
@@ -105,7 +105,6 @@ pub fn lambert_wm1(x: f32) -> f32 {
|
||||
* (1.0 - 1.0 / (1.0 + ((m1 * s_div_2_root) / (1.0 + m2 * s * (m3 * s_root).exp()))))
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
pub fn ccw_tri<S: BaseFloat>(a: &[S; 2], b: &[S; 2], c: &[S; 2]) -> bool {
|
||||
// From: https://math.stackexchange.com/questions/1324179/how-to-tell-if-3-connected-points-are-connected-clockwise-or-counter-clockwise
|
||||
@@ -113,5 +112,5 @@ pub fn ccw_tri<S: BaseFloat>(a: &[S; 2], b: &[S; 2], c: &[S; 2]) -> bool {
|
||||
// | x2, y2, 1 | > 0 => the triangle is given in anticlockwise order
|
||||
// | x3, y3, 1 |
|
||||
|
||||
a[0]*b[1] + a[1]*c[0] + b[0]*c[1] - c[0]*b[1] - c[1]*a[0] - b[0]*a[1] >= S::zero()
|
||||
a[0] * b[1] + a[1] * c[0] + b[0] * c[1] - c[0] * b[1] - c[1] * a[0] - b[0] * a[1] >= S::zero()
|
||||
}
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
use al_api::hips::ImageExt;
|
||||
|
||||
use al_core::{image::format::ImageFormat, image::raw::ImageBuffer};
|
||||
|
||||
use al_core::{image::ImageType, pixel::Pixel};
|
||||
|
||||
use al_core::{
|
||||
image::{
|
||||
format::{R16I, R32F, R32I, R8UI},
|
||||
Image,
|
||||
},
|
||||
Texture2DArray,
|
||||
};
|
||||
use cgmath::Vector3;
|
||||
|
||||
use al_core::image::format::{ChannelType, ImageFormatType, RGB8U, RGBA8U};
|
||||
use al_core::image::format::{ChannelType, ImageFormatType};
|
||||
#[derive(Debug)]
|
||||
pub struct HiPSConfig {
|
||||
pub root_url: String,
|
||||
@@ -228,7 +215,7 @@ impl HiPSConfig {
|
||||
Ok(hips_config)
|
||||
}
|
||||
|
||||
pub fn set_image_fmt(&mut self, ext: ImageExt) -> Result<(), JsValue> {
|
||||
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
|
||||
let format = match ext {
|
||||
ImageExt::Fits => {
|
||||
// Check the bitpix to determine the internal format of the tiles
|
||||
@@ -297,17 +284,6 @@ impl HiPSConfig {
|
||||
|
||||
self.format = format;
|
||||
|
||||
// Recompute if the survey will be colored or not
|
||||
/*self.colored = if self.tex_storing_fits {
|
||||
false
|
||||
} else {
|
||||
if let Some(subtypes) = &self.dataproduct_subtype {
|
||||
subtypes.iter().any(|subtype| subtype == "color")
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -321,6 +297,10 @@ impl HiPSConfig {
|
||||
self.root_url = root_url;
|
||||
}
|
||||
|
||||
pub fn get_cube_depth(&self) -> Option<u32> {
|
||||
self.cube_depth
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_fits_metadata(&mut self, bscale: f32, bzero: f32, blank: f32) {
|
||||
self.scale = bscale;
|
||||
|
||||
@@ -4,11 +4,15 @@ use std::collections::HashMap;
|
||||
|
||||
use al_core::image::format::ChannelType;
|
||||
|
||||
use crate::renderable::hips::HpxTile;
|
||||
use cgmath::Vector3;
|
||||
|
||||
use al_api::hips::ImageExt;
|
||||
use al_core::webgl_ctx::WebGlRenderingCtx;
|
||||
|
||||
use crate::math::lonlat::LonLat;
|
||||
use crate::CameraViewPort;
|
||||
use crate::LonLatT;
|
||||
use al_core::image::format::ImageFormat;
|
||||
use al_core::image::format::{R16I, R32F, R32I, R64F, R8UI, RGB8U, RGBA8U};
|
||||
use al_core::image::Image;
|
||||
@@ -16,12 +20,11 @@ use al_core::shader::{SendUniforms, ShaderBound};
|
||||
use al_core::Texture2DArray;
|
||||
use al_core::WebGlContext;
|
||||
|
||||
use super::texture::{Texture, TextureUniforms};
|
||||
use super::texture::{HpxTexture2D, HpxTexture2DUniforms};
|
||||
|
||||
use crate::downloader::request::allsky::Allsky;
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
use crate::healpix::cell::NUM_HPX_TILES_DEPTH_ZERO;
|
||||
use crate::math::lonlat::LonLatT;
|
||||
use crate::renderable::hips::config::HiPSConfig;
|
||||
use crate::time::Time;
|
||||
use crate::Abort;
|
||||
@@ -58,24 +61,24 @@ impl Ord for TextureCellItem {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Texture> for TextureCellItem {
|
||||
fn from(texture: Texture) -> Self {
|
||||
impl From<HpxTexture2D> for TextureCellItem {
|
||||
fn from(texture: HpxTexture2D) -> Self {
|
||||
let time_request = texture.time_request();
|
||||
let cell = *texture.cell();
|
||||
|
||||
Self { cell, time_request }
|
||||
}
|
||||
}
|
||||
impl From<&Texture> for TextureCellItem {
|
||||
fn from(texture: &Texture) -> Self {
|
||||
impl From<&HpxTexture2D> for TextureCellItem {
|
||||
fn from(texture: &HpxTexture2D) -> Self {
|
||||
let time_request = texture.time_request();
|
||||
let cell = *texture.cell();
|
||||
|
||||
Self { cell, time_request }
|
||||
}
|
||||
}
|
||||
impl From<&mut Texture> for TextureCellItem {
|
||||
fn from(texture: &mut Texture) -> Self {
|
||||
impl From<&mut HpxTexture2D> for TextureCellItem {
|
||||
fn from(texture: &mut HpxTexture2D) -> Self {
|
||||
let time_request = texture.time_request();
|
||||
let cell = *texture.cell();
|
||||
|
||||
@@ -121,6 +124,7 @@ impl HEALPixCellHeap {
|
||||
}
|
||||
}
|
||||
|
||||
use crate::renderable::hips::HpxTileBuffer;
|
||||
// Fixed sized binary heap
|
||||
pub struct HiPS2DBuffer {
|
||||
// Some information about the HiPS
|
||||
@@ -130,8 +134,8 @@ pub struct HiPS2DBuffer {
|
||||
num_root_textures_available: u8,
|
||||
size: usize,
|
||||
|
||||
textures: HashMap<HEALPixCell, Texture>,
|
||||
base_textures: [Texture; NUM_HPX_TILES_DEPTH_ZERO],
|
||||
textures: HashMap<HEALPixCell, HpxTexture2D>,
|
||||
base_textures: [HpxTexture2D; NUM_HPX_TILES_DEPTH_ZERO],
|
||||
|
||||
// Array of 2D textures
|
||||
texture_2d_array: Texture2DArray,
|
||||
@@ -180,110 +184,6 @@ fn create_texture_array<F: ImageFormat>(
|
||||
}
|
||||
|
||||
impl HiPS2DBuffer {
|
||||
pub fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<HiPS2DBuffer, JsValue> {
|
||||
let size = 128 - NUM_HPX_TILES_DEPTH_ZERO;
|
||||
// Ensures there is at least space for the 12
|
||||
// root textures
|
||||
//debug_assert!(size >= NUM_HPX_TILES_DEPTH_ZERO);
|
||||
let heap = HEALPixCellHeap::with_capacity(size);
|
||||
let textures = HashMap::with_capacity(size);
|
||||
|
||||
let now = Time::now();
|
||||
let base_textures = [
|
||||
Texture::new(&HEALPixCell(0, 0), 0, now),
|
||||
Texture::new(&HEALPixCell(0, 1), 1, now),
|
||||
Texture::new(&HEALPixCell(0, 2), 2, now),
|
||||
Texture::new(&HEALPixCell(0, 3), 3, now),
|
||||
Texture::new(&HEALPixCell(0, 4), 4, now),
|
||||
Texture::new(&HEALPixCell(0, 5), 5, now),
|
||||
Texture::new(&HEALPixCell(0, 6), 6, now),
|
||||
Texture::new(&HEALPixCell(0, 7), 7, now),
|
||||
Texture::new(&HEALPixCell(0, 8), 8, now),
|
||||
Texture::new(&HEALPixCell(0, 9), 9, now),
|
||||
Texture::new(&HEALPixCell(0, 10), 10, now),
|
||||
Texture::new(&HEALPixCell(0, 11), 11, now),
|
||||
];
|
||||
let channel = config.get_format().get_channel();
|
||||
|
||||
let texture_2d_array = match channel {
|
||||
ChannelType::RGBA32F => unimplemented!(),
|
||||
ChannelType::RGB32F => unimplemented!(),
|
||||
ChannelType::RGBA8U => create_texture_array::<RGBA8U>(gl, &config)?,
|
||||
ChannelType::RGB8U => create_texture_array::<RGB8U>(gl, &config)?,
|
||||
ChannelType::R32F => create_texture_array::<R32F>(gl, &config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R8UI => create_texture_array::<R8UI>(gl, &config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R16I => create_texture_array::<R16I>(gl, &config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R32I => create_texture_array::<R32I>(gl, &config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R64F => create_texture_array::<R64F>(gl, &config)?,
|
||||
};
|
||||
// The root textures have not been loaded
|
||||
|
||||
let num_root_textures_available = 0;
|
||||
let available_tiles_during_frame = false;
|
||||
|
||||
Ok(HiPS2DBuffer {
|
||||
config,
|
||||
heap,
|
||||
|
||||
size,
|
||||
num_root_textures_available,
|
||||
textures,
|
||||
base_textures,
|
||||
texture_2d_array,
|
||||
available_tiles_during_frame,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_format(&mut self, gl: &WebGlContext, ext: ImageExt) -> Result<(), JsValue> {
|
||||
self.config.set_image_fmt(ext)?;
|
||||
|
||||
let channel = self.config.get_format().get_channel();
|
||||
|
||||
self.texture_2d_array = match channel {
|
||||
ChannelType::RGBA32F => unimplemented!(),
|
||||
ChannelType::RGB32F => unimplemented!(),
|
||||
ChannelType::RGBA8U => create_texture_array::<RGBA8U>(gl, &self.config)?,
|
||||
ChannelType::RGB8U => create_texture_array::<RGB8U>(gl, &self.config)?,
|
||||
ChannelType::R32F => create_texture_array::<R32F>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R8UI => create_texture_array::<R8UI>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R16I => create_texture_array::<R16I>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R32I => create_texture_array::<R32I>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R64F => create_texture_array::<R64F>(gl, &self.config)?,
|
||||
};
|
||||
|
||||
let now = Time::now();
|
||||
self.base_textures = [
|
||||
Texture::new(&HEALPixCell(0, 0), 0, now),
|
||||
Texture::new(&HEALPixCell(0, 1), 1, now),
|
||||
Texture::new(&HEALPixCell(0, 2), 2, now),
|
||||
Texture::new(&HEALPixCell(0, 3), 3, now),
|
||||
Texture::new(&HEALPixCell(0, 4), 4, now),
|
||||
Texture::new(&HEALPixCell(0, 5), 5, now),
|
||||
Texture::new(&HEALPixCell(0, 6), 6, now),
|
||||
Texture::new(&HEALPixCell(0, 7), 7, now),
|
||||
Texture::new(&HEALPixCell(0, 8), 8, now),
|
||||
Texture::new(&HEALPixCell(0, 9), 9, now),
|
||||
Texture::new(&HEALPixCell(0, 10), 10, now),
|
||||
Texture::new(&HEALPixCell(0, 11), 11, now),
|
||||
];
|
||||
|
||||
self.heap.clear();
|
||||
self.textures.clear();
|
||||
//self.ready = false;
|
||||
self.num_root_textures_available = 0;
|
||||
self.available_tiles_during_frame = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_allsky(&mut self, allsky: Allsky) -> Result<(), JsValue> {
|
||||
let Allsky {
|
||||
image,
|
||||
@@ -303,8 +203,72 @@ impl HiPS2DBuffer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This method pushes a new downloaded tile into the buffer
|
||||
// It must be ensured that the tile is not already contained into the buffer
|
||||
// Check whether the buffer has a tile
|
||||
// For that purpose, we first need to verify that its
|
||||
// texture ancestor exists and then, it it contains the tile
|
||||
pub fn contains_tile(&self, cell: &HEALPixCell) -> bool {
|
||||
let dd = self.config.delta_depth();
|
||||
|
||||
let texture_cell = cell.get_texture_cell(dd);
|
||||
|
||||
let tex_cell_is_root = texture_cell.is_root();
|
||||
if tex_cell_is_root {
|
||||
let HEALPixCell(_, idx) = texture_cell;
|
||||
self.base_textures[idx as usize].contains_tile(cell)
|
||||
} else {
|
||||
if let Some(texture) = self.get(&texture_cell) {
|
||||
// The texture is present in the buffer
|
||||
// We must check whether it contains the tile
|
||||
texture.contains_tile(cell)
|
||||
} else {
|
||||
// The texture in which cell should be is not present
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_heap_full(&self) -> bool {
|
||||
// Check that there are no more than num_textures
|
||||
// textures in the buffer
|
||||
let num_textures_heap = self.heap.len();
|
||||
|
||||
num_textures_heap == self.size
|
||||
}
|
||||
|
||||
// Update the priority of the texture containing the tile
|
||||
// It must be ensured that the tile is already contained in the buffer
|
||||
pub fn update_priority(&mut self, cell: &HEALPixCell /*, new_fov_cell: bool*/) {
|
||||
debug_assert!(self.contains_tile(cell));
|
||||
|
||||
let dd = self.config.delta_depth();
|
||||
|
||||
// Get the texture cell in which the tile has to be
|
||||
let texture_cell = cell.get_texture_cell(dd);
|
||||
if texture_cell.is_root() {
|
||||
return;
|
||||
}
|
||||
|
||||
let texture = self
|
||||
.textures
|
||||
.get_mut(&texture_cell)
|
||||
.expect("Texture cell has not been found while the buffer contains one of its tile!");
|
||||
// Reset the time the tile has been received if it is a new cell present in the fov
|
||||
//if new_fov_cell {
|
||||
// texture.update_start_time(Time::now());
|
||||
//}
|
||||
|
||||
// MAYBE WE DO NOT NEED TO UPDATE THE TIME REQUEST IN THE BHEAP
|
||||
// BECAUSE IT INTRODUCES UNECESSARY CODE COMPLEXITY
|
||||
// Root textures are always in the buffer
|
||||
// But other textures can be removed thanks to the heap
|
||||
// data-structure. We have to update the time_request of the texture
|
||||
// and push it again in the heap to update its position.
|
||||
let mut tex_cell_item: TextureCellItem = texture.into();
|
||||
tex_cell_item.time_request = Time::now();
|
||||
|
||||
self.heap.update_entry(tex_cell_item);
|
||||
}
|
||||
|
||||
pub fn push<I: Image>(
|
||||
&mut self,
|
||||
cell: &HEALPixCell,
|
||||
@@ -336,7 +300,7 @@ impl HiPS2DBuffer {
|
||||
} else {
|
||||
let idx = NUM_HPX_TILES_DEPTH_ZERO + self.heap.len();
|
||||
|
||||
Texture::new(&tex_cell, idx as i32, time_request)
|
||||
HpxTexture2D::new(&tex_cell, idx as i32, time_request)
|
||||
};
|
||||
|
||||
// Push it to the buffer
|
||||
@@ -385,102 +349,171 @@ impl HiPS2DBuffer {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HpxTileBuffer for HiPS2DBuffer {
|
||||
type T = HpxTexture2D;
|
||||
|
||||
fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue> {
|
||||
let size = 128 - NUM_HPX_TILES_DEPTH_ZERO;
|
||||
// Ensures there is at least space for the 12
|
||||
// root textures
|
||||
//debug_assert!(size >= NUM_HPX_TILES_DEPTH_ZERO);
|
||||
let heap = HEALPixCellHeap::with_capacity(size);
|
||||
let textures = HashMap::with_capacity(size);
|
||||
|
||||
let now = Time::now();
|
||||
let base_textures = [
|
||||
HpxTexture2D::new(&HEALPixCell(0, 0), 0, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 1), 1, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 2), 2, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 3), 3, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 4), 4, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 5), 5, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 6), 6, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 7), 7, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 8), 8, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 9), 9, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 10), 10, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 11), 11, now),
|
||||
];
|
||||
let channel = config.get_format().get_channel();
|
||||
|
||||
let texture_2d_array = match channel {
|
||||
ChannelType::RGBA32F => unimplemented!(),
|
||||
ChannelType::RGB32F => unimplemented!(),
|
||||
ChannelType::RGBA8U => create_texture_array::<RGBA8U>(gl, &config)?,
|
||||
ChannelType::RGB8U => create_texture_array::<RGB8U>(gl, &config)?,
|
||||
ChannelType::R32F => create_texture_array::<R32F>(gl, &config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R8UI => create_texture_array::<R8UI>(gl, &config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R16I => create_texture_array::<R16I>(gl, &config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R32I => create_texture_array::<R32I>(gl, &config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R64F => create_texture_array::<R64F>(gl, &config)?,
|
||||
};
|
||||
// The root textures have not been loaded
|
||||
|
||||
let num_root_textures_available = 0;
|
||||
let available_tiles_during_frame = false;
|
||||
|
||||
Ok(HiPS2DBuffer {
|
||||
config,
|
||||
heap,
|
||||
|
||||
size,
|
||||
num_root_textures_available,
|
||||
textures,
|
||||
base_textures,
|
||||
texture_2d_array,
|
||||
available_tiles_during_frame,
|
||||
})
|
||||
}
|
||||
|
||||
fn set_image_ext(&mut self, gl: &WebGlContext, ext: ImageExt) -> Result<(), JsValue> {
|
||||
self.config.set_image_ext(ext)?;
|
||||
|
||||
let channel = self.config.get_format().get_channel();
|
||||
|
||||
self.texture_2d_array = match channel {
|
||||
ChannelType::RGBA32F => unimplemented!(),
|
||||
ChannelType::RGB32F => unimplemented!(),
|
||||
ChannelType::RGBA8U => create_texture_array::<RGBA8U>(gl, &self.config)?,
|
||||
ChannelType::RGB8U => create_texture_array::<RGB8U>(gl, &self.config)?,
|
||||
ChannelType::R32F => create_texture_array::<R32F>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R8UI => create_texture_array::<R8UI>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R16I => create_texture_array::<R16I>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R32I => create_texture_array::<R32I>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R64F => create_texture_array::<R64F>(gl, &self.config)?,
|
||||
};
|
||||
|
||||
let now = Time::now();
|
||||
self.base_textures = [
|
||||
HpxTexture2D::new(&HEALPixCell(0, 0), 0, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 1), 1, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 2), 2, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 3), 3, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 4), 4, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 5), 5, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 6), 6, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 7), 7, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 8), 8, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 9), 9, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 10), 10, now),
|
||||
HpxTexture2D::new(&HEALPixCell(0, 11), 11, now),
|
||||
];
|
||||
|
||||
self.heap.clear();
|
||||
self.textures.clear();
|
||||
//self.ready = false;
|
||||
self.num_root_textures_available = 0;
|
||||
self.available_tiles_during_frame = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This method pushes a new downloaded tile into the buffer
|
||||
// It must be ensured that the tile is not already contained into the buffer
|
||||
// Return if tiles did become available
|
||||
pub fn reset_available_tiles(&mut self) -> bool {
|
||||
fn reset_available_tiles(&mut self) -> bool {
|
||||
let available_tiles_during_frame = self.available_tiles_during_frame;
|
||||
self.available_tiles_during_frame = false;
|
||||
|
||||
available_tiles_during_frame
|
||||
}
|
||||
|
||||
fn is_heap_full(&self) -> bool {
|
||||
// Check that there are no more than num_textures
|
||||
// textures in the buffer
|
||||
let num_textures_heap = self.heap.len();
|
||||
|
||||
num_textures_heap == self.size
|
||||
}
|
||||
|
||||
// Tell if a texture is available meaning all its sub tiles
|
||||
// must have been written for the GPU
|
||||
pub fn contains(&self, texture_cell: &HEALPixCell) -> bool {
|
||||
if let Some(t) = self.get(texture_cell) {
|
||||
fn contains(&self, cell: &HEALPixCell) -> bool {
|
||||
if let Some(t) = self.get(cell) {
|
||||
t.is_full()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the buffer has a tile
|
||||
// For that purpose, we first need to verify that its
|
||||
// texture ancestor exists and then, it it contains the tile
|
||||
pub fn contains_tile(&self, cell: &HEALPixCell) -> bool {
|
||||
let dd = self.config.delta_depth();
|
||||
|
||||
let texture_cell = cell.get_texture_cell(dd);
|
||||
|
||||
let tex_cell_is_root = texture_cell.is_root();
|
||||
if tex_cell_is_root {
|
||||
let HEALPixCell(_, idx) = texture_cell;
|
||||
self.base_textures[idx as usize].contains(cell)
|
||||
/// Accessors
|
||||
fn get(&self, cell: &HEALPixCell) -> Option<&Self::T> {
|
||||
if cell.is_root() {
|
||||
let HEALPixCell(_, idx) = cell;
|
||||
Some(&self.base_textures[*idx as usize])
|
||||
} else {
|
||||
if let Some(texture) = self.get(&texture_cell) {
|
||||
// The texture is present in the buffer
|
||||
// We must check whether it contains the tile
|
||||
texture.contains(cell)
|
||||
} else {
|
||||
// The texture in which cell should be is not present
|
||||
false
|
||||
}
|
||||
self.textures.get(cell)
|
||||
}
|
||||
}
|
||||
|
||||
// Update the priority of the texture containing the tile
|
||||
// It must be ensured that the tile is already contained in the buffer
|
||||
pub fn update_priority(&mut self, cell: &HEALPixCell /*, new_fov_cell: bool*/) {
|
||||
debug_assert!(self.contains_tile(cell));
|
||||
|
||||
let dd = self.config.delta_depth();
|
||||
|
||||
// Get the texture cell in which the tile has to be
|
||||
let texture_cell = cell.get_texture_cell(dd);
|
||||
if texture_cell.is_root() {
|
||||
return;
|
||||
}
|
||||
|
||||
let texture = self
|
||||
.textures
|
||||
.get_mut(&texture_cell)
|
||||
.expect("Texture cell has not been found while the buffer contains one of its tile!");
|
||||
// Reset the time the tile has been received if it is a new cell present in the fov
|
||||
//if new_fov_cell {
|
||||
// texture.update_start_time(Time::now());
|
||||
//}
|
||||
|
||||
// MAYBE WE DO NOT NEED TO UPDATE THE TIME REQUEST IN THE BHEAP
|
||||
// BECAUSE IT INTRODUCES UNECESSARY CODE COMPLEXITY
|
||||
// Root textures are always in the buffer
|
||||
// But other textures can be removed thanks to the heap
|
||||
// data-structure. We have to update the time_request of the texture
|
||||
// and push it again in the heap to update its position.
|
||||
let mut tex_cell_item: TextureCellItem = texture.into();
|
||||
tex_cell_item.time_request = Time::now();
|
||||
|
||||
self.heap.update_entry(tex_cell_item);
|
||||
fn config(&self) -> &HiPSConfig {
|
||||
&self.config
|
||||
}
|
||||
|
||||
// lonlat is given in the
|
||||
pub fn get_pixel_position_in_texture(
|
||||
&self,
|
||||
lonlat: &LonLatT<f64>,
|
||||
depth: u8,
|
||||
) -> Result<Vector3<i32>, JsValue> {
|
||||
let (pix, dx, dy) = crate::healpix::utils::hash_with_dxdy(depth, lonlat);
|
||||
fn config_mut(&mut self) -> &mut HiPSConfig {
|
||||
&mut self.config
|
||||
}
|
||||
|
||||
fn read_pixel(&self, pos: &LonLatT<f64>, camera: &CameraViewPort) -> Result<JsValue, JsValue> {
|
||||
// 1. Convert it to the hips frame system
|
||||
let cfg = self.config();
|
||||
let camera_frame = camera.get_coo_system();
|
||||
let hips_frame = cfg.get_frame();
|
||||
|
||||
let pos: LonLatT<f64> =
|
||||
crate::coosys::apply_coo_system(camera_frame, hips_frame, &pos.vector()).lonlat();
|
||||
|
||||
// Get the array of textures from that survey
|
||||
let depth = camera.get_texture_depth().min(cfg.get_max_depth_texture());
|
||||
|
||||
// compute the tex
|
||||
let (pix, dx, dy) = crate::healpix::utils::hash_with_dxdy(depth, &pos);
|
||||
let texture_cell = HEALPixCell(depth, pix);
|
||||
|
||||
if let Some(texture) = self.get(&texture_cell) {
|
||||
let cfg = &self.config;
|
||||
let cfg = self.config();
|
||||
|
||||
// Index of the texture in the total set of textures
|
||||
let texture_idx = texture.idx();
|
||||
@@ -489,24 +522,38 @@ impl HiPS2DBuffer {
|
||||
let texture_size = cfg.get_texture_size();
|
||||
|
||||
// Offset in the slice in pixels
|
||||
let mut offset = Vector3::new(
|
||||
let mut pos_tex = Vector3::new(
|
||||
(dy * (texture_size as f64)) as i32,
|
||||
(dx * (texture_size as f64)) as i32,
|
||||
texture_idx,
|
||||
);
|
||||
|
||||
// Offset in the slice in pixels
|
||||
if self.config.tex_storing_fits {
|
||||
let texture_size = self.config.get_texture_size() as f32;
|
||||
let mut uvy = offset.y as f32 / texture_size;
|
||||
uvy = self.config.size_tile_uv
|
||||
+ 2.0 * self.config.size_tile_uv * (uvy / self.config.size_tile_uv).floor()
|
||||
if cfg.tex_storing_fits {
|
||||
let texture_size = cfg.get_texture_size() as f32;
|
||||
let mut uvy = pos_tex.y as f32 / texture_size;
|
||||
uvy = cfg.size_tile_uv + 2.0 * cfg.size_tile_uv * (uvy / cfg.size_tile_uv).floor()
|
||||
- uvy;
|
||||
|
||||
offset.y = (uvy * texture_size) as i32;
|
||||
pos_tex.y = (uvy * texture_size) as i32;
|
||||
}
|
||||
|
||||
Ok(offset)
|
||||
let mut value = self
|
||||
.texture_2d_array
|
||||
.read_pixel(pos_tex.x, pos_tex.y, pos_tex.z)?;
|
||||
|
||||
if cfg.tex_storing_fits {
|
||||
// scale the value
|
||||
let f64_v = value
|
||||
.as_f64()
|
||||
.ok_or_else(|| JsValue::from_str("Error unwraping the pixel read value."))?;
|
||||
let scale = cfg.scale as f64;
|
||||
let offset = cfg.offset as f64;
|
||||
|
||||
value = JsValue::from_f64(f64_v * scale + offset);
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(JsValue::from_str(&format!(
|
||||
"{:?} not loaded in the GPU, please wait before trying again.",
|
||||
@@ -514,53 +561,11 @@ impl HiPS2DBuffer {
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Accessors
|
||||
pub fn get(&self, texture_cell: &HEALPixCell) -> Option<&Texture> {
|
||||
if texture_cell.is_root() {
|
||||
let HEALPixCell(_, idx) = texture_cell;
|
||||
Some(&self.base_textures[*idx as usize])
|
||||
} else {
|
||||
self.textures.get(texture_cell)
|
||||
}
|
||||
}
|
||||
|
||||
// Get the nearest parent tile found in the CPU buffer
|
||||
pub fn get_nearest_parent(&self, cell: &HEALPixCell) -> Option<HEALPixCell> {
|
||||
if cell.is_root() {
|
||||
// Root cells are in the buffer by definition
|
||||
Some(*cell)
|
||||
} else {
|
||||
let mut parent_cell = cell.parent();
|
||||
|
||||
while !self.contains(&parent_cell) && !parent_cell.is_root() {
|
||||
parent_cell = parent_cell.parent();
|
||||
}
|
||||
|
||||
if self.contains(&parent_cell) {
|
||||
Some(parent_cell)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn config(&self) -> &HiPSConfig {
|
||||
&self.config
|
||||
}
|
||||
|
||||
pub fn config_mut(&mut self) -> &mut HiPSConfig {
|
||||
&mut self.config
|
||||
}
|
||||
|
||||
pub fn get_texture_array(&self) -> &Texture2DArray {
|
||||
&self.texture_2d_array
|
||||
}
|
||||
}
|
||||
|
||||
fn send_to_gpu<I: Image>(
|
||||
cell: &HEALPixCell,
|
||||
texture: &Texture,
|
||||
texture: &HpxTexture2D,
|
||||
image: I,
|
||||
texture_array: &Texture2DArray,
|
||||
cfg: &mut HiPSConfig,
|
||||
@@ -605,7 +610,7 @@ impl SendUniforms for HiPS2DBuffer {
|
||||
let cell = HEALPixCell(0, idx as u64);
|
||||
|
||||
let texture = self.get(&cell).unwrap();
|
||||
let texture_uniforms = TextureUniforms::new(texture, idx as i32);
|
||||
let texture_uniforms = HpxTexture2DUniforms::new(texture, idx as i32);
|
||||
shader.attach_uniforms_from(&texture_uniforms);
|
||||
}
|
||||
//}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
pub mod buffer;
|
||||
pub mod texture;
|
||||
|
||||
use crate::renderable::hips::HpxTile;
|
||||
use al_api::hips::ImageExt;
|
||||
use al_api::hips::ImageMetadata;
|
||||
use al_core::colormap::Colormap;
|
||||
use al_core::colormap::Colormaps;
|
||||
use al_core::image::format::ChannelType;
|
||||
|
||||
use crate::downloader::query;
|
||||
|
||||
use al_core::image::Image;
|
||||
|
||||
use al_core::shader::Shader;
|
||||
@@ -26,7 +29,6 @@ use crate::{math::lonlat::LonLatT, utils};
|
||||
|
||||
use crate::downloader::request::allsky::Allsky;
|
||||
use crate::healpix::{cell::HEALPixCell, coverage::HEALPixCoverage};
|
||||
use crate::math::lonlat::LonLat;
|
||||
use crate::renderable::utils::index_patch::DefaultPatchIndexIter;
|
||||
use crate::time::Time;
|
||||
|
||||
@@ -37,7 +39,7 @@ use std::collections::HashSet;
|
||||
// to not be too much skewed
|
||||
|
||||
use buffer::HiPS2DBuffer;
|
||||
use texture::Texture;
|
||||
use texture::HpxTexture2D;
|
||||
|
||||
use super::raytracing::RayTracer;
|
||||
use super::uv::{TileCorner, TileUVW};
|
||||
@@ -47,76 +49,16 @@ use cgmath::Matrix;
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::WebGl2RenderingContext;
|
||||
|
||||
const M: f64 = 280.0 * 280.0;
|
||||
const N: f64 = 150.0 * 150.0;
|
||||
const RAP: f64 = 0.7;
|
||||
|
||||
fn is_too_large(cell: &HEALPixCell, camera: &CameraViewPort, projection: &ProjectionType) -> bool {
|
||||
let vertices = cell
|
||||
.vertices()
|
||||
.iter()
|
||||
.filter_map(|(lon, lat)| {
|
||||
let vertex = crate::math::lonlat::radec_to_xyzw(Angle(*lon), Angle(*lat));
|
||||
projection.icrs_celestial_to_screen_space(&vertex, camera)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if vertices.len() < 4 {
|
||||
false
|
||||
} else {
|
||||
let d1 = dist2(vertices[0].as_ref(), &vertices[2].as_ref());
|
||||
let d2 = dist2(vertices[1].as_ref(), &vertices[3].as_ref());
|
||||
if d1 > M || d2 > M {
|
||||
true
|
||||
} else if d1 < N && d2 < N {
|
||||
false
|
||||
} else {
|
||||
let rap = if d2 > d1 { d1 / d2 } else { d2 / d1 };
|
||||
|
||||
rap < RAP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn num_subdivision(cell: &HEALPixCell, camera: &CameraViewPort, projection: &ProjectionType) -> u8 {
|
||||
let d = cell.depth();
|
||||
// Subdivide all cells at least one time.
|
||||
// TODO: use a single subdivision number computed from the current cells inside the view
|
||||
// i.e. subdivide all cells in the view with the cell that has to be the most subdivided
|
||||
let mut num_sub = 1;
|
||||
if d < 2 {
|
||||
num_sub = 2 - d;
|
||||
}
|
||||
|
||||
// Largest deformation cell among the cells of a specific depth
|
||||
let largest_center_to_vertex_dist =
|
||||
healpix::largest_center_to_vertex_distance(d, 0.0, healpix::TRANSITION_LATITUDE);
|
||||
let smallest_center_to_vertex_dist =
|
||||
healpix::largest_center_to_vertex_distance(d, 0.0, healpix::LAT_OF_SQUARE_CELL);
|
||||
|
||||
let (lon, lat) = cell.center();
|
||||
let center_to_vertex_dist = healpix::largest_center_to_vertex_distance(d, lon, lat);
|
||||
|
||||
let skewed_factor = (center_to_vertex_dist - smallest_center_to_vertex_dist)
|
||||
/ (largest_center_to_vertex_dist - smallest_center_to_vertex_dist);
|
||||
|
||||
if skewed_factor > 0.25 || is_too_large(cell, camera, projection) || cell.is_on_pole() {
|
||||
num_sub += 1;
|
||||
}
|
||||
|
||||
num_sub
|
||||
}
|
||||
|
||||
pub struct TextureToDraw<'a, 'b> {
|
||||
pub starting_texture: &'a Texture,
|
||||
pub ending_texture: &'a Texture,
|
||||
pub starting_texture: &'a HpxTexture2D,
|
||||
pub ending_texture: &'a HpxTexture2D,
|
||||
pub cell: &'b HEALPixCell,
|
||||
}
|
||||
|
||||
impl<'a, 'b> TextureToDraw<'a, 'b> {
|
||||
fn new(
|
||||
starting_texture: &'a Texture,
|
||||
ending_texture: &'a Texture,
|
||||
starting_texture: &'a HpxTexture2D,
|
||||
ending_texture: &'a HpxTexture2D,
|
||||
cell: &'b HEALPixCell,
|
||||
) -> TextureToDraw<'a, 'b> {
|
||||
TextureToDraw {
|
||||
@@ -209,7 +151,7 @@ pub fn get_raytracer_shader<'a>(
|
||||
pub struct HiPS2D {
|
||||
//color: Color,
|
||||
// The image survey texture buffer
|
||||
textures: HiPS2DBuffer,
|
||||
buffer: HiPS2DBuffer,
|
||||
|
||||
// The projected vertices data
|
||||
// For WebGL2 wasm, the data are interleaved
|
||||
@@ -241,6 +183,8 @@ pub struct HiPS2D {
|
||||
hpx_cells_in_view: Vec<HEALPixCell>,
|
||||
}
|
||||
|
||||
use super::HpxTileBuffer;
|
||||
|
||||
impl HiPS2D {
|
||||
pub fn new(config: HiPSConfig, gl: &WebGlContext) -> Result<Self, JsValue> {
|
||||
let mut vao = VertexArrayObject::new(gl);
|
||||
@@ -294,7 +238,7 @@ impl HiPS2D {
|
||||
.unbind();
|
||||
|
||||
let num_idx = 0;
|
||||
let textures = HiPS2DBuffer::new(gl, config)?;
|
||||
let buffer = HiPS2DBuffer::new(gl, config)?;
|
||||
|
||||
let gl = gl.clone();
|
||||
let footprint_moc = None;
|
||||
@@ -302,7 +246,7 @@ impl HiPS2D {
|
||||
// request the allsky texture
|
||||
Ok(Self {
|
||||
// The image survey texture buffer
|
||||
textures,
|
||||
buffer,
|
||||
num_idx,
|
||||
|
||||
vao,
|
||||
@@ -382,7 +326,12 @@ impl HiPS2D {
|
||||
}
|
||||
|
||||
pub fn contains_tile(&self, cell: &HEALPixCell) -> bool {
|
||||
self.textures.contains_tile(cell)
|
||||
self.buffer.contains_tile(cell)
|
||||
}
|
||||
|
||||
pub fn get_tile_query(&self, cell: &HEALPixCell) -> query::Tile {
|
||||
let cfg = self.get_config();
|
||||
query::Tile::new(cell, None, cfg)
|
||||
}
|
||||
|
||||
pub fn update(&mut self, camera: &mut CameraViewPort, projection: &ProjectionType) {
|
||||
@@ -393,7 +342,7 @@ impl HiPS2D {
|
||||
}
|
||||
|
||||
// rasterizer mode
|
||||
let available_tiles = self.textures.reset_available_tiles();
|
||||
let available_tiles = self.buffer.reset_available_tiles();
|
||||
let new_cells_in_view = self.retrieve_cells_in_camera(camera);
|
||||
|
||||
if new_cells_in_view || available_tiles {
|
||||
@@ -434,51 +383,21 @@ impl HiPS2D {
|
||||
self.footprint_moc.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_img_format(&mut self, ext: ImageExt) -> Result<(), JsValue> {
|
||||
self.textures.set_format(&self.gl, ext)
|
||||
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
|
||||
self.buffer.set_image_ext(&self.gl, ext)
|
||||
}
|
||||
|
||||
pub fn is_allsky(&self) -> bool {
|
||||
self.textures.config().is_allsky
|
||||
self.buffer.config().is_allsky
|
||||
}
|
||||
|
||||
// Position given is in the camera space
|
||||
pub fn read_pixel(
|
||||
&self,
|
||||
pos: &LonLatT<f64>,
|
||||
p: &LonLatT<f64>,
|
||||
camera: &CameraViewPort,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
// 1. Convert it to the hips frame system
|
||||
let cfg = self.textures.config();
|
||||
let camera_frame = camera.get_coo_system();
|
||||
let hips_frame = cfg.get_frame();
|
||||
|
||||
let pos = crate::coosys::apply_coo_system(camera_frame, hips_frame, &pos.vector());
|
||||
|
||||
// Get the array of textures from that survey
|
||||
let tile_depth = camera.get_texture_depth().min(cfg.get_max_depth_texture());
|
||||
|
||||
let pos_tex = self
|
||||
.textures
|
||||
.get_pixel_position_in_texture(&pos.lonlat(), tile_depth)?;
|
||||
|
||||
let slice_idx = pos_tex.z as usize;
|
||||
let texture_array = self.textures.get_texture_array();
|
||||
|
||||
unimplemented!();
|
||||
/*let value = texture_array[slice_idx].read_pixel(pos_tex.x, pos_tex.y)?;
|
||||
|
||||
if cfg.tex_storing_fits {
|
||||
let value = value
|
||||
.as_f64()
|
||||
.ok_or_else(|| JsValue::from_str("Error unwraping the pixel read value."))?;
|
||||
let scale = cfg.scale as f64;
|
||||
let offset = cfg.offset as f64;
|
||||
|
||||
Ok(JsValue::from_f64(value * scale + offset))
|
||||
} else {
|
||||
Ok(value)
|
||||
}*/
|
||||
self.buffer.read_pixel(p, camera)
|
||||
}
|
||||
|
||||
fn recompute_vertices(&mut self, camera: &mut CameraViewPort, projection: &ProjectionType) {
|
||||
@@ -488,7 +407,7 @@ impl HiPS2D {
|
||||
self.time_tile_received.clear();
|
||||
self.idx_vertices.clear();
|
||||
|
||||
let cfg = self.textures.config();
|
||||
let cfg = self.buffer.config();
|
||||
// Get the coo system transformation matrix
|
||||
let channel = cfg.get_format().get_channel();
|
||||
|
||||
@@ -516,10 +435,10 @@ impl HiPS2D {
|
||||
};
|
||||
|
||||
if let Some(cell) = cell {
|
||||
let texture_to_draw = if self.textures.contains(cell) {
|
||||
if let Some(ending_cell_in_tex) = self.textures.get(cell) {
|
||||
if let Some(parent_cell) = self.textures.get_nearest_parent(cell) {
|
||||
if let Some(starting_cell_in_tex) = self.textures.get(&parent_cell) {
|
||||
let texture_to_draw = if self.buffer.contains(cell) {
|
||||
if let Some(ending_cell_in_tex) = self.buffer.get(cell) {
|
||||
if let Some(parent_cell) = self.buffer.get_nearest_parent(cell) {
|
||||
if let Some(starting_cell_in_tex) = self.buffer.get(&parent_cell) {
|
||||
Some(TextureToDraw::new(
|
||||
starting_cell_in_tex,
|
||||
ending_cell_in_tex,
|
||||
@@ -544,13 +463,13 @@ impl HiPS2D {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
if let Some(parent_cell) = self.textures.get_nearest_parent(cell) {
|
||||
if let Some(ending_cell_in_tex) = self.textures.get(&parent_cell) {
|
||||
if let Some(parent_cell) = self.buffer.get_nearest_parent(cell) {
|
||||
if let Some(ending_cell_in_tex) = self.buffer.get(&parent_cell) {
|
||||
if let Some(grand_parent_cell) =
|
||||
self.textures.get_nearest_parent(&parent_cell)
|
||||
self.buffer.get_nearest_parent(&parent_cell)
|
||||
{
|
||||
if let Some(starting_cell_in_tex) =
|
||||
self.textures.get(&grand_parent_cell)
|
||||
self.buffer.get(&grand_parent_cell)
|
||||
{
|
||||
Some(TextureToDraw::new(
|
||||
starting_cell_in_tex,
|
||||
@@ -595,7 +514,8 @@ impl HiPS2D {
|
||||
|
||||
let start_time = ending_texture.start_time().as_millis();
|
||||
|
||||
let num_subdivision = num_subdivision(cell, camera, projection);
|
||||
let num_subdivision =
|
||||
super::subdivide::num_hpxcell_subdivision(cell, camera, projection);
|
||||
|
||||
let n_segments_by_side: usize = 1 << (num_subdivision as usize);
|
||||
let n_segments_by_side_f32 = n_segments_by_side as f32;
|
||||
@@ -693,9 +613,9 @@ impl HiPS2D {
|
||||
|
||||
// Return a boolean to signal if the tile is present or not in the survey
|
||||
pub fn update_priority_tile(&mut self, cell: &HEALPixCell) -> bool {
|
||||
if self.textures.contains_tile(cell) {
|
||||
if self.buffer.contains_tile(cell) {
|
||||
// The cell is present in the survey, we update its priority
|
||||
self.textures.update_priority(cell);
|
||||
self.buffer.update_priority(cell);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -708,22 +628,22 @@ impl HiPS2D {
|
||||
image: I,
|
||||
time_request: Time,
|
||||
) -> Result<(), JsValue> {
|
||||
self.textures.push(&cell, image, time_request)
|
||||
self.buffer.push(&cell, image, time_request)
|
||||
}
|
||||
|
||||
pub fn add_allsky(&mut self, allsky: Allsky) -> Result<(), JsValue> {
|
||||
self.textures.push_allsky(allsky)
|
||||
self.buffer.push_allsky(allsky)
|
||||
}
|
||||
|
||||
/* Accessors */
|
||||
#[inline]
|
||||
pub fn get_config(&self) -> &HiPSConfig {
|
||||
self.textures.config()
|
||||
self.buffer.config()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_config_mut(&mut self) -> &mut HiPSConfig {
|
||||
self.textures.config_mut()
|
||||
self.buffer.config_mut()
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
@@ -737,7 +657,7 @@ impl HiPS2D {
|
||||
) -> Result<(), JsValue> {
|
||||
// Get the coo system transformation matrix
|
||||
let selected_frame = camera.get_coo_system();
|
||||
let hips_cfg = self.textures.config();
|
||||
let hips_cfg = self.buffer.config();
|
||||
let hips_frame = hips_cfg.get_frame();
|
||||
let c = selected_frame.to(hips_frame);
|
||||
|
||||
@@ -768,7 +688,7 @@ impl HiPS2D {
|
||||
let shader = shader.bind(&self.gl);
|
||||
shader
|
||||
.attach_uniforms_from(camera)
|
||||
.attach_uniforms_from(&self.textures)
|
||||
.attach_uniforms_from(&self.buffer)
|
||||
// send the cmap appart from the color config
|
||||
.attach_uniforms_with_params_from(cmap, colormaps)
|
||||
.attach_uniforms_from(color)
|
||||
@@ -796,7 +716,7 @@ impl HiPS2D {
|
||||
let shader = get_raster_shader(cmap, &self.gl, shaders, &config)?.bind(&self.gl);
|
||||
|
||||
shader
|
||||
.attach_uniforms_from(&self.textures)
|
||||
.attach_uniforms_from(&self.buffer)
|
||||
// send the cmap appart from the color config
|
||||
.attach_uniforms_with_params_from(cmap, colormaps)
|
||||
.attach_uniforms_from(color)
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{healpix::cell::HEALPixCell, time::Time};
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub struct Texture {
|
||||
pub struct HpxTexture2D {
|
||||
texture_cell: HEALPixCell,
|
||||
// Precomputed uniq number
|
||||
uniq: i32,
|
||||
@@ -36,17 +36,20 @@ pub struct Texture {
|
||||
|
||||
use crate::renderable::hips::config::HiPSConfig;
|
||||
|
||||
impl Texture {
|
||||
pub fn new(texture_cell: &HEALPixCell, idx: i32, time_request: Time) -> Texture {
|
||||
use crate::renderable::hips::HpxTile;
|
||||
|
||||
impl HpxTexture2D {
|
||||
pub fn new(cell: &HEALPixCell, idx: i32, time_request: Time) -> Self {
|
||||
let tiles = HashSet::new();
|
||||
|
||||
let start_time = None;
|
||||
let full = false;
|
||||
let texture_cell = *texture_cell;
|
||||
let texture_cell = *cell;
|
||||
let uniq = texture_cell.uniq();
|
||||
//let missing = true;
|
||||
let num_tiles_written = 0;
|
||||
Texture {
|
||||
|
||||
Self {
|
||||
texture_cell,
|
||||
uniq,
|
||||
time_request,
|
||||
@@ -55,14 +58,42 @@ impl Texture {
|
||||
start_time,
|
||||
full,
|
||||
num_tiles_written,
|
||||
//missing,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.full
|
||||
}
|
||||
|
||||
pub fn idx(&self) -> i32 {
|
||||
self.idx
|
||||
}
|
||||
|
||||
// Setter
|
||||
pub fn replace(&mut self, texture_cell: &HEALPixCell, time_request: Time) {
|
||||
// Cancel the tasks copying the tiles contained in the texture
|
||||
// which have not yet been completed.
|
||||
//self.clear_tasks_in_progress(config, exec);
|
||||
|
||||
self.texture_cell = *texture_cell;
|
||||
self.uniq = texture_cell.uniq();
|
||||
self.full = false;
|
||||
self.start_time = None;
|
||||
self.time_request = time_request;
|
||||
self.tiles.clear();
|
||||
//self.missing = true;
|
||||
self.num_tiles_written = 0;
|
||||
}
|
||||
|
||||
// Cell must be contained in the texture
|
||||
pub fn contains_tile(&self, tile_cell: &HEALPixCell) -> bool {
|
||||
self.is_full() || self.tiles.contains(tile_cell)
|
||||
}
|
||||
|
||||
// Panic if cell is not contained in the texture
|
||||
// Do nothing if the texture is full
|
||||
// Return true if the tile is newly added
|
||||
pub fn append(&mut self, cell: &HEALPixCell, cfg: &HiPSConfig /*, missing: bool */) {
|
||||
pub fn append(&mut self, cell: &HEALPixCell, cfg: &HiPSConfig) {
|
||||
let texture_cell = cell.get_texture_cell(cfg.delta_depth());
|
||||
debug_assert!(texture_cell == self.texture_cell);
|
||||
debug_assert!(!self.full);
|
||||
@@ -95,19 +126,12 @@ impl Texture {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cell must be contained in the texture
|
||||
pub fn contains(&self, cell: &HEALPixCell) -> bool {
|
||||
self.is_full() || self.tiles.contains(cell)
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.full
|
||||
}
|
||||
|
||||
impl HpxTile for HpxTexture2D {
|
||||
// Getter
|
||||
// Returns the current time if the texture is not full
|
||||
pub fn start_time(&self) -> Time {
|
||||
fn start_time(&self) -> Time {
|
||||
if self.is_full() {
|
||||
self.start_time.unwrap_abort()
|
||||
} else {
|
||||
@@ -115,80 +139,49 @@ impl Texture {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn time_request(&self) -> Time {
|
||||
fn time_request(&self) -> Time {
|
||||
self.time_request
|
||||
}
|
||||
|
||||
pub fn cell(&self) -> &HEALPixCell {
|
||||
fn cell(&self) -> &HEALPixCell {
|
||||
&self.texture_cell
|
||||
}
|
||||
|
||||
pub fn idx(&self) -> i32 {
|
||||
self.idx
|
||||
}
|
||||
|
||||
/*pub fn is_missing(&self) -> bool {
|
||||
self.missing
|
||||
}*/
|
||||
|
||||
// Setter
|
||||
pub fn replace(&mut self, texture_cell: &HEALPixCell, time_request: Time) {
|
||||
// Cancel the tasks copying the tiles contained in the texture
|
||||
// which have not yet been completed.
|
||||
//self.clear_tasks_in_progress(config, exec);
|
||||
|
||||
self.texture_cell = *texture_cell;
|
||||
self.uniq = texture_cell.uniq();
|
||||
self.full = false;
|
||||
self.start_time = None;
|
||||
self.time_request = time_request;
|
||||
self.tiles.clear();
|
||||
//self.missing = true;
|
||||
self.num_tiles_written = 0;
|
||||
}
|
||||
|
||||
/*pub fn clear_tasks_in_progress(&self, config: &HiPSConfig, exec: &mut TaskExecutor) {
|
||||
for tile_cell in self.texture_cell.get_tile_cells(config) {
|
||||
let tile = Tile::new(&tile_cell, config);
|
||||
exec.remove(&TaskType::ImageTile2GpuTask(tile));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
use std::cmp::Ordering;
|
||||
impl PartialOrd for Texture {
|
||||
impl PartialOrd for HpxTexture2D {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.uniq.partial_cmp(&other.uniq)
|
||||
}
|
||||
}
|
||||
use crate::Abort;
|
||||
impl Ord for Texture {
|
||||
impl Ord for HpxTexture2D {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap_abort()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Texture {
|
||||
impl PartialEq for HpxTexture2D {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.uniq == other.uniq
|
||||
}
|
||||
}
|
||||
impl Eq for Texture {}
|
||||
impl Eq for HpxTexture2D {}
|
||||
|
||||
pub struct TextureUniforms<'a> {
|
||||
texture: &'a Texture,
|
||||
pub struct HpxTexture2DUniforms<'a> {
|
||||
texture: &'a HpxTexture2D,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl<'a> TextureUniforms<'a> {
|
||||
pub fn new(texture: &Texture, idx_texture: i32) -> TextureUniforms {
|
||||
impl<'a> HpxTexture2DUniforms<'a> {
|
||||
pub fn new(texture: &'a HpxTexture2D, idx_texture: i32) -> Self {
|
||||
let name = format!("textures_tiles[{}].", idx_texture);
|
||||
TextureUniforms { texture, name }
|
||||
HpxTexture2DUniforms { texture, name }
|
||||
}
|
||||
}
|
||||
|
||||
use al_core::shader::{SendUniforms, ShaderBound};
|
||||
impl<'a> SendUniforms for TextureUniforms<'a> {
|
||||
impl<'a> SendUniforms for HpxTexture2DUniforms<'a> {
|
||||
fn attach_uniforms<'b>(&self, shader: &'b ShaderBound<'b>) -> &'b ShaderBound<'b> {
|
||||
shader
|
||||
.attach_uniform(&format!("{}{}", self.name, "uniq"), &self.texture.uniq)
|
||||
|
||||
@@ -1,34 +1,23 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use al_core::image::format::ChannelType;
|
||||
|
||||
use cgmath::Vector3;
|
||||
|
||||
use al_api::hips::ImageExt;
|
||||
use al_core::webgl_ctx::WebGlRenderingCtx;
|
||||
|
||||
use al_core::image::format::ImageFormat;
|
||||
use al_core::image::format::{R16I, R32F, R32I, R64F, R8UI, RGB8U, RGBA8U};
|
||||
use crate::CameraViewPort;
|
||||
use crate::LonLatT;
|
||||
use al_core::image::Image;
|
||||
use al_core::shader::{SendUniforms, ShaderBound};
|
||||
use al_core::Texture2DArray;
|
||||
use al_core::WebGlContext;
|
||||
|
||||
use super::texture::HEALPixTexturedCube;
|
||||
use super::texture::HpxTexture3D;
|
||||
use crate::downloader::request::allsky::Allsky;
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
use crate::healpix::cell::NUM_HPX_TILES_DEPTH_ZERO;
|
||||
use crate::math::lonlat::LonLatT;
|
||||
use crate::renderable::hips::config::HiPSConfig;
|
||||
use crate::renderable::hips::HpxTileBuffer;
|
||||
use crate::time::Time;
|
||||
use crate::Abort;
|
||||
use crate::JsValue;
|
||||
use al_api::hips::ImageExt;
|
||||
// Fixed sized binary heap
|
||||
pub struct HiPS3DBuffer {
|
||||
// Some information about the HiPS
|
||||
textures: HashMap<HEALPixCell, HEALPixTexturedCube>,
|
||||
textures: HashMap<HEALPixCell, HpxTexture3D>,
|
||||
|
||||
config: HiPSConfig,
|
||||
num_root_textures_available: u8,
|
||||
@@ -56,58 +45,12 @@ impl HiPS3DBuffer {
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn set_format(&mut self, gl: &WebGlContext, ext: ImageExt) -> Result<(), JsValue> {
|
||||
self.config.set_image_fmt(ext)?;
|
||||
|
||||
let channel = self.config.get_format().get_channel();
|
||||
|
||||
self.texture_2d_array = match channel {
|
||||
ChannelType::RGBA32F => unimplemented!(),
|
||||
ChannelType::RGB32F => unimplemented!(),
|
||||
ChannelType::RGBA8U => create_texture_array::<RGBA8U>(gl, &self.config)?,
|
||||
ChannelType::RGB8U => create_texture_array::<RGB8U>(gl, &self.config)?,
|
||||
ChannelType::R32F => create_texture_array::<R32F>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R8UI => create_texture_array::<R8UI>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R16I => create_texture_array::<R16I>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R32I => create_texture_array::<R32I>(gl, &self.config)?,
|
||||
#[cfg(feature = "webgl2")]
|
||||
ChannelType::R64F => create_texture_array::<R64F>(gl, &self.config)?,
|
||||
};
|
||||
|
||||
let now = Time::now();
|
||||
self.base_textures = [
|
||||
Texture::new(&HEALPixCell(0, 0), 0, now),
|
||||
Texture::new(&HEALPixCell(0, 1), 1, now),
|
||||
Texture::new(&HEALPixCell(0, 2), 2, now),
|
||||
Texture::new(&HEALPixCell(0, 3), 3, now),
|
||||
Texture::new(&HEALPixCell(0, 4), 4, now),
|
||||
Texture::new(&HEALPixCell(0, 5), 5, now),
|
||||
Texture::new(&HEALPixCell(0, 6), 6, now),
|
||||
Texture::new(&HEALPixCell(0, 7), 7, now),
|
||||
Texture::new(&HEALPixCell(0, 8), 8, now),
|
||||
Texture::new(&HEALPixCell(0, 9), 9, now),
|
||||
Texture::new(&HEALPixCell(0, 10), 10, now),
|
||||
Texture::new(&HEALPixCell(0, 11), 11, now),
|
||||
];
|
||||
|
||||
self.heap.clear();
|
||||
self.textures.clear();
|
||||
//self.ready = false;
|
||||
self.num_root_textures_available = 0;
|
||||
self.available_tiles_during_frame = false;
|
||||
|
||||
Ok(())
|
||||
}*/
|
||||
|
||||
pub fn push_allsky(&mut self, allsky: Allsky, slice_idx: u16) -> Result<(), JsValue> {
|
||||
pub fn push_allsky(&mut self, allsky: Allsky) -> Result<(), JsValue> {
|
||||
let Allsky {
|
||||
image,
|
||||
time_req,
|
||||
depth_tile,
|
||||
channel,
|
||||
..
|
||||
} = allsky;
|
||||
|
||||
@@ -119,7 +62,7 @@ impl HiPS3DBuffer {
|
||||
&HEALPixCell(depth_tile, idx as u64),
|
||||
image,
|
||||
time_req,
|
||||
slice_idx,
|
||||
channel.map(|c| c as u16).unwrap_or(0),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
@@ -127,6 +70,10 @@ impl HiPS3DBuffer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_nearest_slice(&self, cell: &HEALPixCell, slice: u16) -> Option<u16> {
|
||||
self.get(cell).and_then(|t| t.find_nearest_slice(slice))
|
||||
}
|
||||
|
||||
// This method pushes a new downloaded tile into the buffer
|
||||
// It must be ensured that the tile is not already contained into the buffer
|
||||
pub fn push<I: Image>(
|
||||
@@ -140,13 +87,13 @@ impl HiPS3DBuffer {
|
||||
tex
|
||||
} else {
|
||||
self.textures
|
||||
.insert(*cell, HEALPixTexturedCube::new(*cell, time_request));
|
||||
.insert(*cell, HpxTexture3D::new(*cell, time_request));
|
||||
|
||||
self.textures.get_mut(cell).unwrap()
|
||||
};
|
||||
|
||||
// copy to the 3D textured block
|
||||
tex.append_slice(image, slice_idx, &self.config, &self.gl)?;
|
||||
tex.append(image, slice_idx, &self.config, &self.gl)?;
|
||||
|
||||
self.available_tiles_during_frame = true;
|
||||
|
||||
@@ -163,80 +110,16 @@ impl HiPS3DBuffer {
|
||||
|
||||
// Tell if a texture is available meaning all its sub tiles
|
||||
// must have been written for the GPU
|
||||
pub fn contains(&self, texture_cell: &HEALPixCell) -> bool {
|
||||
self.get(texture_cell).is_some()
|
||||
pub fn contains_tile(&self, texture_cell: &HEALPixCell, slice: u16) -> bool {
|
||||
self.get(texture_cell)
|
||||
.map_or(false, |t| t.contains_slice(slice))
|
||||
}
|
||||
|
||||
// lonlat is given in the
|
||||
/*pub fn get_pixel_position_in_texture(
|
||||
&self,
|
||||
lonlat: &LonLatT<f64>,
|
||||
depth: u8,
|
||||
) -> Result<Vector3<i32>, JsValue> {
|
||||
let (pix, dx, dy) = crate::healpix::utils::hash_with_dxdy(depth, lonlat);
|
||||
let texture_cell = HEALPixCell(depth, pix);
|
||||
|
||||
if let Some(texture) = self.get(&texture_cell) {
|
||||
let cfg = &self.config;
|
||||
|
||||
// Index of the texture in the total set of textures
|
||||
let texture_idx = texture.idx();
|
||||
|
||||
// The size of the global texture containing the tiles
|
||||
let texture_size = cfg.get_texture_size();
|
||||
|
||||
// Offset in the slice in pixels
|
||||
let mut offset = Vector3::new(
|
||||
(dy * (texture_size as f64)) as i32,
|
||||
(dx * (texture_size as f64)) as i32,
|
||||
texture_idx,
|
||||
);
|
||||
|
||||
// Offset in the slice in pixels
|
||||
if self.config.tex_storing_fits {
|
||||
let texture_size = self.config.get_texture_size() as f32;
|
||||
let mut uvy = offset.y as f32 / texture_size;
|
||||
uvy = self.config.size_tile_uv
|
||||
+ 2.0 * self.config.size_tile_uv * (uvy / self.config.size_tile_uv).floor()
|
||||
- uvy;
|
||||
|
||||
offset.y = (uvy * texture_size) as i32;
|
||||
}
|
||||
|
||||
Ok(offset)
|
||||
} else {
|
||||
Err(JsValue::from_str(&format!(
|
||||
"{:?} not loaded in the GPU, please wait before trying again.",
|
||||
texture_cell
|
||||
)))
|
||||
}
|
||||
}*/
|
||||
|
||||
/// Accessors
|
||||
pub fn get(&self, cell: &HEALPixCell) -> Option<&HEALPixTexturedCube> {
|
||||
pub fn get(&self, cell: &HEALPixCell) -> Option<&HpxTexture3D> {
|
||||
self.textures.get(cell)
|
||||
}
|
||||
|
||||
// Get the nearest parent tile found in the CPU buffer
|
||||
pub fn get_nearest_parent(&self, cell: &HEALPixCell) -> Option<HEALPixCell> {
|
||||
if cell.is_root() {
|
||||
// Root cells are in the buffer by definition
|
||||
Some(*cell)
|
||||
} else {
|
||||
let mut parent_cell = cell.parent();
|
||||
|
||||
while !self.contains(&parent_cell) && !parent_cell.is_root() {
|
||||
parent_cell = parent_cell.parent();
|
||||
}
|
||||
|
||||
if self.contains(&parent_cell) {
|
||||
Some(parent_cell)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn config(&self) -> &HiPSConfig {
|
||||
&self.config
|
||||
}
|
||||
@@ -244,10 +127,62 @@ impl HiPS3DBuffer {
|
||||
pub fn config_mut(&mut self) -> &mut HiPSConfig {
|
||||
&mut self.config
|
||||
}
|
||||
}
|
||||
|
||||
/*pub fn get_texture_array(&self) -> &Texture2DArray {
|
||||
&self.texture_2d_array
|
||||
}*/
|
||||
impl HpxTileBuffer for HiPS3DBuffer {
|
||||
type T = HpxTexture3D;
|
||||
|
||||
fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue> {
|
||||
let textures = HashMap::new();
|
||||
|
||||
let num_root_textures_available = 0;
|
||||
let available_tiles_during_frame = false;
|
||||
|
||||
let gl = gl.clone();
|
||||
Ok(Self {
|
||||
config,
|
||||
|
||||
num_root_textures_available,
|
||||
textures,
|
||||
available_tiles_during_frame,
|
||||
gl,
|
||||
})
|
||||
}
|
||||
|
||||
// Return if tiles did become available
|
||||
fn reset_available_tiles(&mut self) -> bool {
|
||||
let available_tiles_during_frame = self.available_tiles_during_frame;
|
||||
self.available_tiles_during_frame = false;
|
||||
|
||||
available_tiles_during_frame
|
||||
}
|
||||
|
||||
fn set_image_ext(&mut self, gl: &WebGlContext, ext: ImageExt) -> Result<(), JsValue> {
|
||||
todo!();
|
||||
}
|
||||
|
||||
fn read_pixel(&self, pos: &LonLatT<f64>, camera: &CameraViewPort) -> Result<JsValue, JsValue> {
|
||||
todo!();
|
||||
}
|
||||
|
||||
// Tell if a texture is available meaning all its sub tiles
|
||||
// must have been written for the GPU
|
||||
fn contains(&self, cell: &HEALPixCell) -> bool {
|
||||
self.get(cell).is_some()
|
||||
}
|
||||
|
||||
/// Accessors
|
||||
fn get(&self, cell: &HEALPixCell) -> Option<&HpxTexture3D> {
|
||||
self.textures.get(cell)
|
||||
}
|
||||
|
||||
fn config(&self) -> &HiPSConfig {
|
||||
&self.config
|
||||
}
|
||||
|
||||
fn config_mut(&mut self) -> &mut HiPSConfig {
|
||||
&mut self.config
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,2 +1,657 @@
|
||||
pub mod buffer;
|
||||
pub mod texture;
|
||||
|
||||
use crate::renderable::hips::HpxTile;
|
||||
use al_api::hips::ImageExt;
|
||||
use al_api::hips::ImageMetadata;
|
||||
use al_core::colormap::Colormap;
|
||||
use al_core::colormap::Colormaps;
|
||||
use al_core::image::format::ChannelType;
|
||||
|
||||
use al_core::image::Image;
|
||||
|
||||
use al_core::shader::Shader;
|
||||
use al_core::webgl_ctx::GlWrapper;
|
||||
|
||||
use al_core::VecData;
|
||||
use al_core::VertexArrayObject;
|
||||
use al_core::WebGlContext;
|
||||
|
||||
use crate::math::{angle::Angle, vector::dist2};
|
||||
use crate::ProjectionType;
|
||||
|
||||
use crate::camera::CameraViewPort;
|
||||
|
||||
use crate::downloader::query;
|
||||
|
||||
use crate::shader::ShaderManager;
|
||||
use crate::{math::lonlat::LonLatT, utils};
|
||||
|
||||
use crate::downloader::request::allsky::Allsky;
|
||||
use crate::healpix::{cell::HEALPixCell, coverage::HEALPixCoverage};
|
||||
use crate::renderable::utils::index_patch::DefaultPatchIndexIter;
|
||||
use crate::time::Time;
|
||||
|
||||
use super::config::HiPSConfig;
|
||||
use std::collections::HashSet;
|
||||
|
||||
// Recursively compute the number of subdivision needed for a cell
|
||||
// to not be too much skewed
|
||||
|
||||
use super::d2::texture::HpxTexture2D;
|
||||
use buffer::HiPS3DBuffer;
|
||||
|
||||
use super::raytracing::RayTracer;
|
||||
use super::uv::{TileCorner, TileUVW};
|
||||
|
||||
use cgmath::Matrix;
|
||||
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::WebGl2RenderingContext;
|
||||
|
||||
pub fn get_raster_shader<'a>(
|
||||
cmap: &Colormap,
|
||||
gl: &WebGlContext,
|
||||
shaders: &'a mut ShaderManager,
|
||||
config: &HiPSConfig,
|
||||
) -> Result<&'a Shader, JsValue> {
|
||||
if config.get_format().is_colored() && cmap.label() == "native" {
|
||||
crate::shader::get_shader(
|
||||
gl,
|
||||
shaders,
|
||||
"hips3d_rasterizer_raster.vert",
|
||||
"hips3d_rasterizer_color.frag",
|
||||
)
|
||||
} else {
|
||||
if config.tex_storing_unsigned_int {
|
||||
crate::shader::get_shader(
|
||||
gl,
|
||||
shaders,
|
||||
"hips3d_rasterizer_raster.vert",
|
||||
"hips3d_rasterizer_grayscale_to_colormap_u.frag",
|
||||
)
|
||||
} else if config.tex_storing_integers {
|
||||
crate::shader::get_shader(
|
||||
gl,
|
||||
shaders,
|
||||
"hips3d_rasterizer_raster.vert",
|
||||
"hips3d_rasterizer_grayscale_to_colormap_i.frag",
|
||||
)
|
||||
} else {
|
||||
crate::shader::get_shader(
|
||||
gl,
|
||||
shaders,
|
||||
"hips3d_rasterizer_raster.vert",
|
||||
"hips3d_rasterizer_grayscale_to_colormap.frag",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn get_raytracer_shader<'a>(
|
||||
cmap: &Colormap,
|
||||
gl: &WebGlContext,
|
||||
shaders: &'a mut ShaderManager,
|
||||
config: &HiPSConfig,
|
||||
) -> Result<&'a Shader, JsValue> {
|
||||
//let colored_hips = config.is_colored();
|
||||
if config.get_format().is_colored() && cmap.label() == "native" {
|
||||
crate::shader::get_shader(
|
||||
gl,
|
||||
shaders,
|
||||
"hips_raytracer_raytracer.vert",
|
||||
"hips_raytracer_color.frag",
|
||||
)
|
||||
} else {
|
||||
if config.tex_storing_unsigned_int {
|
||||
crate::shader::get_shader(
|
||||
gl,
|
||||
shaders,
|
||||
"hips_raytracer_raytracer.vert",
|
||||
"hips_raytracer_grayscale_to_colormap_u.frag",
|
||||
)
|
||||
} else if config.tex_storing_integers {
|
||||
crate::shader::get_shader(
|
||||
gl,
|
||||
shaders,
|
||||
"hips_raytracer_raytracer.vert",
|
||||
"hips_raytracer_grayscale_to_colormap_i.frag",
|
||||
)
|
||||
} else {
|
||||
crate::shader::get_shader(
|
||||
gl,
|
||||
shaders,
|
||||
"hips_raytracer_raytracer.vert",
|
||||
"hips_raytracer_grayscale_to_colormap.frag",
|
||||
)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
pub struct HiPS3D {
|
||||
//color: Color,
|
||||
// The image survey texture buffer
|
||||
buffer: HiPS3DBuffer,
|
||||
|
||||
// The projected vertices data
|
||||
// For WebGL2 wasm, the data are interleaved
|
||||
//#[cfg(feature = "webgl2")]
|
||||
//vertices: Vec<f32>,
|
||||
//#[cfg(feature = "webgl1")]
|
||||
// layout (location = 0) in vec3 position;
|
||||
position: Vec<f32>,
|
||||
//#[cfg(feature = "webgl1")]
|
||||
// layout (location = 1) in vec3 uv_start;
|
||||
uv: Vec<f32>,
|
||||
idx_vertices: Vec<u16>,
|
||||
|
||||
vao: VertexArrayObject,
|
||||
gl: WebGlContext,
|
||||
|
||||
footprint_moc: Option<HEALPixCoverage>,
|
||||
|
||||
// A buffer storing the cells in the view
|
||||
hpx_cells_in_view: Vec<HEALPixCell>,
|
||||
|
||||
// The current slice index
|
||||
slice: u16,
|
||||
|
||||
num_indices: Vec<usize>,
|
||||
slice_indices: Vec<usize>,
|
||||
cells: Vec<HEALPixCell>,
|
||||
}
|
||||
|
||||
use super::HpxTileBuffer;
|
||||
|
||||
impl HiPS3D {
|
||||
pub fn new(config: HiPSConfig, gl: &WebGlContext) -> Result<Self, JsValue> {
|
||||
let mut vao = VertexArrayObject::new(gl);
|
||||
|
||||
let slice = 0;
|
||||
|
||||
let num_indices = vec![];
|
||||
let slice_indices = vec![];
|
||||
// layout (location = 0) in vec2 lonlat;
|
||||
// layout (location = 1) in vec3 position;
|
||||
// layout (location = 2) in vec3 uv_start;
|
||||
// layout (location = 3) in vec3 uv_end;
|
||||
// layout (location = 4) in float time_tile_received;
|
||||
//let vertices = vec![0.0; MAX_NUM_FLOATS_TO_DRAW];
|
||||
//let indices = vec![0_u16; MAX_NUM_INDICES_TO_DRAW];
|
||||
|
||||
//let vertices = vec![];
|
||||
let position = vec![];
|
||||
let uv = vec![];
|
||||
let idx_vertices = vec![];
|
||||
|
||||
#[cfg(feature = "webgl2")]
|
||||
vao.bind_for_update()
|
||||
.add_array_buffer_single(
|
||||
2,
|
||||
"position",
|
||||
WebGl2RenderingContext::DYNAMIC_DRAW,
|
||||
VecData::<f32>(&position),
|
||||
)
|
||||
.add_array_buffer_single(
|
||||
3,
|
||||
"uv",
|
||||
WebGl2RenderingContext::DYNAMIC_DRAW,
|
||||
VecData::<f32>(&uv),
|
||||
)
|
||||
// Set the element buffer
|
||||
.add_element_buffer(
|
||||
WebGl2RenderingContext::DYNAMIC_DRAW,
|
||||
VecData::<u16>(&idx_vertices),
|
||||
)
|
||||
.unbind();
|
||||
|
||||
let buffer = HiPS3DBuffer::new(gl, config)?;
|
||||
|
||||
let cells = vec![];
|
||||
|
||||
let gl = gl.clone();
|
||||
let footprint_moc = None;
|
||||
let hpx_cells_in_view = vec![];
|
||||
// request the allsky texture
|
||||
Ok(Self {
|
||||
// The image survey texture buffer
|
||||
buffer,
|
||||
|
||||
vao,
|
||||
|
||||
gl,
|
||||
|
||||
position,
|
||||
uv,
|
||||
idx_vertices,
|
||||
|
||||
footprint_moc,
|
||||
hpx_cells_in_view,
|
||||
|
||||
slice,
|
||||
cells,
|
||||
num_indices,
|
||||
slice_indices,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn look_for_new_tiles<'a>(
|
||||
&'a mut self,
|
||||
camera: &'a CameraViewPort,
|
||||
proj: &ProjectionType,
|
||||
) -> Option<impl Iterator<Item = HEALPixCell> + 'a> {
|
||||
// do not add tiles if the view is already at depth 0
|
||||
let cfg = self.get_config();
|
||||
let mut depth_tile = (camera.get_texture_depth() + cfg.delta_depth())
|
||||
.min(cfg.get_max_depth_tile())
|
||||
.max(cfg.get_min_depth_tile());
|
||||
let dd = cfg.delta_depth();
|
||||
|
||||
//let min_depth_tile = self.get_min_depth_tile();
|
||||
//let delta_depth = self.get_config().delta_depth();
|
||||
|
||||
//let min_bound_depth = min_depth_tile.max(delta_depth);
|
||||
// do not ask to query tiles that:
|
||||
// * either do not exist because < to min_depth_tile
|
||||
// * either are part of a base tile already handled i.e. tiles < delta_depth
|
||||
//console_log(depth_tile);
|
||||
//console_log(min_bound_depth);
|
||||
|
||||
//if depth_tile >= min_bound_depth {
|
||||
//let depth_tile = depth_tile.max(min_bound_depth);
|
||||
let survey_frame = cfg.get_frame();
|
||||
let mut already_considered_tiles = HashSet::new();
|
||||
|
||||
// raytracer is rendering and the shader only renders HPX texture cells of depth 0
|
||||
if camera.is_raytracing(proj) {
|
||||
depth_tile = 0;
|
||||
}
|
||||
|
||||
let tile_cells_iter = camera
|
||||
.get_hpx_cells(depth_tile, survey_frame)
|
||||
//.flat_map(move |cell| {
|
||||
// let texture_cell = cell.get_texture_cell(delta_depth);
|
||||
// texture_cell.get_tile_cells(delta_depth)
|
||||
//})
|
||||
.into_iter()
|
||||
.flat_map(move |tile_cell| {
|
||||
let tex_cell = tile_cell.get_texture_cell(dd);
|
||||
tex_cell.get_tile_cells(dd)
|
||||
})
|
||||
.filter(move |tile_cell| {
|
||||
if already_considered_tiles.contains(tile_cell) {
|
||||
return false;
|
||||
}
|
||||
|
||||
already_considered_tiles.insert(*tile_cell);
|
||||
|
||||
if let Some(moc) = self.footprint_moc.as_ref() {
|
||||
moc.intersects_cell(tile_cell)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
Some(tile_cells_iter)
|
||||
}
|
||||
|
||||
pub fn set_slice(&mut self, slice: u16) {
|
||||
self.slice = slice;
|
||||
}
|
||||
|
||||
pub fn get_tile_query(&self, cell: &HEALPixCell) -> query::Tile {
|
||||
let cfg = self.get_config();
|
||||
query::Tile::new(cell, Some(self.get_slice() as u32), cfg)
|
||||
}
|
||||
|
||||
pub fn contains_tile(&self, cell: &HEALPixCell, slice: u16) -> bool {
|
||||
self.buffer.contains_tile(cell, slice)
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
&mut self,
|
||||
shaders: &mut ShaderManager,
|
||||
colormaps: &Colormaps,
|
||||
camera: &mut CameraViewPort,
|
||||
raytracer: &RayTracer,
|
||||
cfg: &ImageMetadata,
|
||||
proj: &ProjectionType,
|
||||
) -> Result<(), JsValue> {
|
||||
//let raytracing = camera.is_raytracing(proj);
|
||||
|
||||
//if raytracing {
|
||||
// self.draw_internal(shaders, colormaps, camera, raytracer, cfg, proj)
|
||||
//} else {
|
||||
// rasterizer mode
|
||||
let available_tiles = self.reset_available_tiles();
|
||||
let new_cells_in_view = self.retrieve_cells_in_camera(camera);
|
||||
|
||||
if new_cells_in_view || available_tiles {
|
||||
// TODO: append the vertices independently to the draw method
|
||||
self.recompute_vertices(camera, proj);
|
||||
}
|
||||
|
||||
self.draw_internal(shaders, colormaps, camera, raytracer, cfg, proj)
|
||||
//}
|
||||
}
|
||||
|
||||
fn recompute_vertices(&mut self, camera: &CameraViewPort, proj: &ProjectionType) {
|
||||
self.cells.clear();
|
||||
self.slice_indices.clear();
|
||||
|
||||
self.position.clear();
|
||||
self.uv.clear();
|
||||
self.idx_vertices.clear();
|
||||
|
||||
self.num_indices.clear();
|
||||
|
||||
let mut off_indices = 0;
|
||||
|
||||
let channel = self.get_config().get_format().get_channel();
|
||||
|
||||
for cell in &self.hpx_cells_in_view {
|
||||
// filter textures that are not in the moc
|
||||
let cell = if let Some(moc) = self.footprint_moc.as_ref() {
|
||||
if moc.intersects_cell(&cell) {
|
||||
Some(&cell)
|
||||
} else {
|
||||
if channel == ChannelType::RGB8U {
|
||||
// Rasterizer does not render tiles that are not in the MOC
|
||||
// This is not a problem for transparency rendered HiPses (FITS or PNG)
|
||||
// but JPEG tiles do have black when no pixels data is found
|
||||
// We therefore must draw in black for the tiles outside the HiPS MOC
|
||||
Some(&cell)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Some(&cell)
|
||||
};
|
||||
|
||||
let mut slice_contained = 0;
|
||||
|
||||
if let Some(cell) = cell {
|
||||
let hpx_cell_texture = if self.buffer.contains_tile(cell, self.slice) {
|
||||
slice_contained = self.slice;
|
||||
self.buffer.get(cell)
|
||||
} else if let Some(next_slice) = self.buffer.find_nearest_slice(&cell, self.slice) {
|
||||
slice_contained = next_slice;
|
||||
self.buffer.get(cell)
|
||||
} else if let Some(parent_cell) = self.buffer.get_nearest_parent(cell) {
|
||||
// find the slice of the parent available, if possible near slice
|
||||
slice_contained = self
|
||||
.buffer
|
||||
.find_nearest_slice(&parent_cell, self.slice)
|
||||
.unwrap();
|
||||
self.buffer.get(&parent_cell)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(texture) = hpx_cell_texture {
|
||||
self.slice_indices.push(slice_contained as usize);
|
||||
self.cells.push(texture.cell().clone());
|
||||
// The slice is sure to be contained so we can unwrap
|
||||
let hpx_slice_tex = texture.extract_2d_slice_texture(slice_contained).unwrap();
|
||||
|
||||
let uv_1 = TileUVW::new(cell, &hpx_slice_tex, self.get_config());
|
||||
let d01e = uv_1[TileCorner::BottomRight].x - uv_1[TileCorner::BottomLeft].x;
|
||||
let d02e = uv_1[TileCorner::TopLeft].y - uv_1[TileCorner::BottomLeft].y;
|
||||
|
||||
let num_subdivision =
|
||||
super::subdivide::num_hpxcell_subdivision(cell, camera, proj);
|
||||
|
||||
let n_segments_by_side: usize = 1 << (num_subdivision as usize);
|
||||
let n_segments_by_side_f32 = n_segments_by_side as f32;
|
||||
|
||||
let n_vertices_per_segment = n_segments_by_side + 1;
|
||||
|
||||
let mut pos = Vec::with_capacity((n_segments_by_side + 1) * 4);
|
||||
|
||||
let grid_lonlat =
|
||||
healpix::nested::grid(cell.depth(), cell.idx(), n_segments_by_side as u16);
|
||||
let grid_lonlat_iter = grid_lonlat.iter();
|
||||
|
||||
for (idx, &(lon, lat)) in grid_lonlat_iter.enumerate() {
|
||||
let i: usize = idx / n_vertices_per_segment;
|
||||
let j: usize = idx % n_vertices_per_segment;
|
||||
|
||||
let hj0 = (j as f32) / n_segments_by_side_f32;
|
||||
let hi0 = (i as f32) / n_segments_by_side_f32;
|
||||
|
||||
let uv_end = [
|
||||
uv_1[TileCorner::BottomLeft].x + hj0 * d01e,
|
||||
uv_1[TileCorner::BottomLeft].y + hi0 * d02e,
|
||||
uv_1[TileCorner::BottomLeft].z,
|
||||
];
|
||||
|
||||
self.uv.extend(uv_end);
|
||||
|
||||
pos.push([lon as f32, lat as f32]);
|
||||
}
|
||||
|
||||
let patch_indices_iter = DefaultPatchIndexIter::new(
|
||||
&(0..=n_segments_by_side),
|
||||
&(0..=n_segments_by_side),
|
||||
n_vertices_per_segment,
|
||||
)
|
||||
.flatten()
|
||||
.map(|indices| {
|
||||
[
|
||||
indices.0 + off_indices,
|
||||
indices.1 + off_indices,
|
||||
indices.2 + off_indices,
|
||||
]
|
||||
})
|
||||
.flatten();
|
||||
let tmp = self.idx_vertices.len();
|
||||
self.idx_vertices.extend(patch_indices_iter);
|
||||
|
||||
self.num_indices.push(self.idx_vertices.len() - tmp);
|
||||
off_indices += pos.len() as u16;
|
||||
|
||||
// Replace options with an arbitrary vertex
|
||||
let position_iter = pos
|
||||
.into_iter()
|
||||
//.map(|ndc| ndc.unwrap_or([0.0, 0.0]))
|
||||
.flatten();
|
||||
self.position.extend(position_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut vao = self.vao.bind_for_update();
|
||||
vao.update_array(
|
||||
"position",
|
||||
WebGl2RenderingContext::DYNAMIC_DRAW,
|
||||
VecData(&self.position),
|
||||
)
|
||||
.update_array(
|
||||
"uv",
|
||||
WebGl2RenderingContext::DYNAMIC_DRAW,
|
||||
VecData(&self.uv),
|
||||
)
|
||||
.update_element_array(
|
||||
WebGl2RenderingContext::DYNAMIC_DRAW,
|
||||
VecData(&self.idx_vertices),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_available_tiles(&mut self) -> bool {
|
||||
self.buffer.reset_available_tiles()
|
||||
}
|
||||
|
||||
// returns a boolean if the view cells has changed with respect to the last frame
|
||||
fn retrieve_cells_in_camera(&mut self, camera: &CameraViewPort) -> bool {
|
||||
let cfg = self.get_config();
|
||||
// Get the coo system transformation matrix
|
||||
let hips_frame = cfg.get_frame();
|
||||
let depth = camera.get_texture_depth().min(cfg.get_max_depth_texture());
|
||||
|
||||
let hpx_cells_in_view = camera.get_hpx_cells(depth, hips_frame);
|
||||
let new_cells = if hpx_cells_in_view.len() != self.hpx_cells_in_view.len() {
|
||||
true
|
||||
} else {
|
||||
!self
|
||||
.hpx_cells_in_view
|
||||
.iter()
|
||||
.zip(hpx_cells_in_view.iter())
|
||||
.all(|(&a, &b)| a == b)
|
||||
};
|
||||
|
||||
self.hpx_cells_in_view = hpx_cells_in_view;
|
||||
|
||||
new_cells
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_moc(&mut self, moc: HEALPixCoverage) {
|
||||
self.footprint_moc = Some(moc);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_moc(&self) -> Option<&HEALPixCoverage> {
|
||||
self.footprint_moc.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
|
||||
self.buffer.set_image_ext(&self.gl, ext)
|
||||
}
|
||||
|
||||
pub fn is_allsky(&self) -> bool {
|
||||
self.buffer.config().is_allsky
|
||||
}
|
||||
|
||||
// Position given is in the camera space
|
||||
pub fn read_pixel(
|
||||
&self,
|
||||
p: &LonLatT<f64>,
|
||||
camera: &CameraViewPort,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
self.buffer.read_pixel(p, camera)
|
||||
}
|
||||
|
||||
fn draw_internal(
|
||||
&self,
|
||||
shaders: &mut ShaderManager,
|
||||
colormaps: &Colormaps,
|
||||
camera: &mut CameraViewPort,
|
||||
raytracer: &RayTracer,
|
||||
cfg: &ImageMetadata,
|
||||
proj: &ProjectionType,
|
||||
) -> Result<(), JsValue> {
|
||||
let hips_cfg = self.buffer.config();
|
||||
// Get the coo system transformation matrix
|
||||
let selected_frame = camera.get_coo_system();
|
||||
let hips_frame = hips_cfg.get_frame();
|
||||
let c = selected_frame.to(hips_frame);
|
||||
|
||||
let big_fov = camera.is_raytracing(proj);
|
||||
if big_fov {
|
||||
self.gl.enable(WebGl2RenderingContext::CULL_FACE);
|
||||
}
|
||||
|
||||
let ImageMetadata {
|
||||
color,
|
||||
opacity,
|
||||
blend_cfg,
|
||||
..
|
||||
} = cfg;
|
||||
|
||||
let cmap = colormaps.get(color.cmap_name.as_ref());
|
||||
|
||||
let v2w = (*camera.get_m2w()) * c.transpose();
|
||||
|
||||
// The rasterizer has a buffer containing:
|
||||
// - The vertices of the HEALPix cells for the most refined survey
|
||||
// - The starting and ending uv for the blending animation
|
||||
// - The time for each HEALPix cell at which the animation begins
|
||||
//
|
||||
// Each of these data can be changed at different circumstances:
|
||||
// - The vertices are changed if:
|
||||
// * new cells are added/removed (because new cells are added)
|
||||
// to the previous frame.
|
||||
// - The UVs are changed if:
|
||||
// * new cells are added/removed (because new cells are added)
|
||||
// * there are new available tiles for the GPU
|
||||
let mut off_idx = 0;
|
||||
|
||||
for (slice_idx, (cell, num_indices)) in self
|
||||
.slice_indices
|
||||
.iter()
|
||||
.zip(self.cells.iter().zip(self.num_indices.iter()))
|
||||
{
|
||||
blend_cfg.enable(&self.gl, || {
|
||||
let shader = get_raster_shader(cmap, &self.gl, shaders, &hips_cfg)?.bind(&self.gl);
|
||||
|
||||
shader
|
||||
.attach_uniform(
|
||||
"tex",
|
||||
self.buffer
|
||||
.get(cell)
|
||||
.unwrap()
|
||||
.get_3d_block_from_slice(*slice_idx as u16)
|
||||
.unwrap(),
|
||||
)
|
||||
.attach_uniforms_with_params_from(cmap, colormaps)
|
||||
.attach_uniforms_from(color)
|
||||
.attach_uniforms_from(camera)
|
||||
.attach_uniform("inv_model", &v2w)
|
||||
.attach_uniform("opacity", opacity)
|
||||
.attach_uniform("u_proj", proj)
|
||||
.attach_uniforms_from(colormaps)
|
||||
.bind_vertex_array_object_ref(&self.vao)
|
||||
.draw_elements_with_i32(
|
||||
WebGl2RenderingContext::TRIANGLES,
|
||||
Some(*num_indices as i32),
|
||||
WebGl2RenderingContext::UNSIGNED_SHORT,
|
||||
(off_idx * std::mem::size_of::<u16>()) as i32,
|
||||
);
|
||||
|
||||
off_idx += (*num_indices) as usize;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
|
||||
if big_fov {
|
||||
self.gl.disable(WebGl2RenderingContext::CULL_FACE);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_tile<I: Image>(
|
||||
&mut self,
|
||||
cell: &HEALPixCell,
|
||||
image: I,
|
||||
time_request: Time,
|
||||
slice_idx: u16,
|
||||
) -> Result<(), JsValue> {
|
||||
self.buffer.push(&cell, image, time_request, slice_idx)
|
||||
}
|
||||
|
||||
pub fn add_allsky(&mut self, allsky: Allsky) -> Result<(), JsValue> {
|
||||
self.buffer.push_allsky(allsky)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_slice(&self) -> u16 {
|
||||
self.slice
|
||||
}
|
||||
|
||||
/* Accessors */
|
||||
#[inline]
|
||||
pub fn get_config(&self) -> &HiPSConfig {
|
||||
self.buffer.config()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_config_mut(&mut self) -> &mut HiPSConfig {
|
||||
self.buffer.config_mut()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
use crate::renderable::hips::d2::texture::HpxTexture2D;
|
||||
use crate::{healpix::cell::HEALPixCell, time::Time};
|
||||
|
||||
use al_core::image::format::{
|
||||
ChannelType, ImageFormatType, R16I, R32F, R32I, R64F, R8UI, RGB32F, RGB8U, RGBA32F, RGBA8U,
|
||||
ChannelType, R16I, R32F, R32I, R64F, R8UI, RGB32F, RGB8U, RGBA32F, RGBA8U,
|
||||
};
|
||||
use al_core::image::Image;
|
||||
use al_core::texture::Texture3D;
|
||||
use al_core::webgl_ctx::WebGlRenderingCtx;
|
||||
use cgmath::Vector3;
|
||||
use std::collections::HashSet;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
pub struct HEALPixTexturedCube {
|
||||
pub struct HpxTexture3D {
|
||||
tile_cell: HEALPixCell,
|
||||
// Precomputed uniq number
|
||||
uniq: i32,
|
||||
@@ -31,50 +31,205 @@ pub struct HEALPixTexturedCube {
|
||||
// We autorize 512 cubic tiles of size 32 each which allows to store max 16384 slices
|
||||
textures: Vec<Option<Texture3D>>,
|
||||
// A set of already inserted slices. Each cubic tiles can have 32 slices. The occupancy of the
|
||||
// slices inside a cubic tile is done with a u32 mask
|
||||
slices: [u32; 512],
|
||||
// slices inside a cubic tile is done with a u32 mask. Limited to 16384 slices
|
||||
blocks: [u32; 512],
|
||||
// sorted index list of 32-length blocks that are not empty
|
||||
block_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
use crate::renderable::hips::config::HiPSConfig;
|
||||
use crate::WebGlContext;
|
||||
|
||||
impl HEALPixTexturedCube {
|
||||
use crate::renderable::hips::HpxTile;
|
||||
|
||||
impl HpxTexture3D {
|
||||
pub fn new(tile_cell: HEALPixCell, time_request: Time) -> Self {
|
||||
let start_time = None;
|
||||
let uniq = tile_cell.uniq();
|
||||
let textures = std::iter::repeat(None).take(512).collect();
|
||||
let slices = [0; 512];
|
||||
|
||||
let blocks = [0; 512];
|
||||
let block_indices = Vec::new();
|
||||
Self {
|
||||
tile_cell,
|
||||
uniq,
|
||||
time_request,
|
||||
start_time,
|
||||
textures,
|
||||
slices,
|
||||
blocks,
|
||||
block_indices,
|
||||
}
|
||||
}
|
||||
|
||||
// Get the good cubic texture and the slice idx inside it
|
||||
pub fn get_cubic_texture_from_slice(&self, slice: u16) -> (Option<&Texture3D>, u8) {
|
||||
let cube_idx = slice >> 5;
|
||||
pub fn find_nearest_slice(&self, slice: u16) -> Option<u16> {
|
||||
let block_idx = (slice >> 5) as usize;
|
||||
|
||||
match self.block_indices.binary_search(&block_idx) {
|
||||
Ok(_) => {
|
||||
if self.contains_slice(slice) {
|
||||
Some(slice)
|
||||
} else {
|
||||
// the slice is not present but we know there is one in the block
|
||||
let block = self.blocks[block_idx];
|
||||
|
||||
let slice_idx = (slice & 0x1f) as u32;
|
||||
|
||||
let m2 = if slice_idx == 31 {
|
||||
0
|
||||
} else {
|
||||
0xffffffff >> (slice_idx + 1)
|
||||
};
|
||||
let m1 = (!m2) & !(1 << (31 - slice_idx));
|
||||
|
||||
al_core::log(&format!("m1 {:#x} m2 {:#x} {:?}", m1, m2, slice_idx));
|
||||
|
||||
let lb = ((block & m1) >> (32 - slice_idx)) as u32;
|
||||
let rb = (block & m2) as u32;
|
||||
|
||||
let lb_trailing_zeros = (lb.trailing_zeros() as u16).min(slice_idx as u16);
|
||||
let rb_leading_zeros = (rb.leading_zeros() - slice_idx - 1) as u16;
|
||||
|
||||
let no_more_left_bits = slice_idx - (lb_trailing_zeros as u32) == 0;
|
||||
let no_more_right_bits = slice_idx + (rb_leading_zeros as u32) == 31;
|
||||
|
||||
al_core::log(&format!(
|
||||
"{:?} {:?} slice idx {:?}, {:x?} rb {:?}",
|
||||
no_more_left_bits,
|
||||
no_more_right_bits,
|
||||
slice_idx,
|
||||
lb,
|
||||
lb_trailing_zeros as u32
|
||||
));
|
||||
|
||||
match (no_more_left_bits, no_more_right_bits) {
|
||||
(false, false) => {
|
||||
if lb_trailing_zeros <= rb_leading_zeros {
|
||||
Some(slice - lb_trailing_zeros - 1)
|
||||
} else {
|
||||
Some(slice + rb_leading_zeros + 1)
|
||||
}
|
||||
}
|
||||
(false, true) => {
|
||||
if lb_trailing_zeros <= rb_leading_zeros {
|
||||
Some(slice - lb_trailing_zeros - 1)
|
||||
} else {
|
||||
// explore next block
|
||||
if block_idx == self.blocks.len() - 1 {
|
||||
// no after block
|
||||
Some(slice - lb_trailing_zeros - 1)
|
||||
} else {
|
||||
// get the next block
|
||||
let next_block = self.blocks[block_idx + 1];
|
||||
|
||||
let num_bits_to_next_block =
|
||||
next_block.leading_zeros() as u16 + rb_leading_zeros;
|
||||
|
||||
if num_bits_to_next_block < lb_trailing_zeros {
|
||||
Some(slice + num_bits_to_next_block + 1)
|
||||
} else {
|
||||
Some(slice - lb_trailing_zeros - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(true, false) => {
|
||||
if rb_leading_zeros <= lb_trailing_zeros {
|
||||
Some(slice + rb_leading_zeros + 1)
|
||||
} else {
|
||||
// explore previous block
|
||||
if block_idx == 0 {
|
||||
// no after block
|
||||
Some(slice + rb_leading_zeros + 1)
|
||||
} else {
|
||||
// get the next block
|
||||
let prev_block = self.blocks[block_idx - 1];
|
||||
|
||||
let num_bits_from_prev_block =
|
||||
prev_block.trailing_zeros() as u16 + lb_trailing_zeros;
|
||||
if num_bits_from_prev_block < rb_leading_zeros {
|
||||
Some(slice - num_bits_from_prev_block - 1)
|
||||
} else {
|
||||
Some(slice + rb_leading_zeros + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(true, true) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(i) => {
|
||||
match (self.block_indices.get(i - 1), self.block_indices.get(i)) {
|
||||
(Some(b_idx_1), Some(b_idx_2)) => {
|
||||
let b1 = self.blocks[*b_idx_1];
|
||||
let b2 = self.blocks[*b_idx_2];
|
||||
|
||||
let b1_tz = b1.trailing_zeros() as usize;
|
||||
let b2_lz = b2.leading_zeros() as usize;
|
||||
|
||||
let slice_b1 = ((*b_idx_1 << 5) + 32 - b1_tz - 1) as u16;
|
||||
let slice_b2 = ((*b_idx_2 << 5) + b2_lz) as u16;
|
||||
if slice - slice_b1 <= slice_b2 - slice {
|
||||
// the nearest slice is in b1
|
||||
Some(slice_b1 as u16)
|
||||
} else {
|
||||
// the nearest slice is in b2
|
||||
Some(slice_b2 as u16)
|
||||
}
|
||||
}
|
||||
(None, Some(b_idx_2)) => {
|
||||
let b2 = self.blocks[*b_idx_2];
|
||||
let b2_lz = b2.leading_zeros() as usize;
|
||||
|
||||
Some(((*b_idx_2 << 5) + b2_lz) as u16)
|
||||
}
|
||||
(Some(b_idx_1), None) => {
|
||||
let b1 = self.blocks[*b_idx_1];
|
||||
let b1_tz = b1.trailing_zeros() as usize;
|
||||
|
||||
Some(((*b_idx_1 << 5) + 32 - b1_tz - 1) as u16)
|
||||
}
|
||||
(None, None) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_3d_block_from_slice(&self, slice: u16) -> Option<&Texture3D> {
|
||||
let block_idx = slice >> 5;
|
||||
|
||||
self.textures[block_idx as usize].as_ref()
|
||||
}
|
||||
|
||||
pub fn extract_2d_slice_texture(&self, slice: u16) -> Option<HpxTexture2D> {
|
||||
// Find the good sub cube containing the slice
|
||||
let block_idx = (slice >> 5) as usize;
|
||||
let slice_idx = (slice & 0x1f) as u8;
|
||||
(self.textures[cube_idx as usize].as_ref(), slice_idx)
|
||||
|
||||
// check the texture is there
|
||||
if self.blocks[block_idx] & (1 << (31 - slice_idx)) != 0 {
|
||||
Some(HpxTexture2D::new(
|
||||
&self.tile_cell,
|
||||
slice_idx as i32,
|
||||
self.time_request,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Panic if cell is not contained in the texture
|
||||
// Do nothing if the texture is full
|
||||
// Return true if the tile is newly added
|
||||
pub fn append_slice<I: Image>(
|
||||
pub fn append<I: Image>(
|
||||
&mut self,
|
||||
image: I,
|
||||
slice: u16,
|
||||
cfg: &HiPSConfig,
|
||||
gl: &WebGlContext,
|
||||
) -> Result<(), JsValue> {
|
||||
let cube_idx = (slice >> 5) as usize;
|
||||
let block_idx = (slice >> 5) as usize;
|
||||
|
||||
let texture = if let Some(texture) = self.textures[cube_idx as usize].as_ref() {
|
||||
let texture = if let Some(texture) = self.textures[block_idx as usize].as_ref() {
|
||||
texture
|
||||
} else {
|
||||
let tile_size = cfg.get_tile_size();
|
||||
@@ -133,16 +288,23 @@ impl HEALPixTexturedCube {
|
||||
Texture3D::create_empty::<R32I>(gl, tile_size, tile_size, 32, params)
|
||||
}
|
||||
};
|
||||
self.textures[cube_idx] = Some(texture?);
|
||||
self.textures[block_idx] = Some(texture?);
|
||||
|
||||
self.textures[cube_idx].as_ref().unwrap()
|
||||
self.textures[block_idx].as_ref().unwrap()
|
||||
};
|
||||
|
||||
let slice_idx = slice & 0x1f;
|
||||
|
||||
// if there is already something, do not tex sub
|
||||
if self.slices[cube_idx] & (1 << slice_idx) == 0 {
|
||||
image.insert_into_3d_texture(texture, &Vector3::<i32>::new(0, 0, slice_idx as i32))?
|
||||
if self.blocks[block_idx] & (1 << (31 - slice_idx)) == 0 {
|
||||
image.insert_into_3d_texture(texture, &Vector3::<i32>::new(0, 0, slice_idx as i32))?;
|
||||
|
||||
match self.block_indices.binary_search(&block_idx) {
|
||||
Ok(i) => {} // element already in vector @ `pos`
|
||||
Err(i) => self.block_indices.insert(i, block_idx),
|
||||
}
|
||||
|
||||
self.blocks[block_idx] |= 1 << (31 - slice_idx);
|
||||
}
|
||||
|
||||
self.start_time = Some(Time::now());
|
||||
@@ -152,15 +314,17 @@ impl HEALPixTexturedCube {
|
||||
|
||||
// Cell must be contained in the texture
|
||||
pub fn contains_slice(&self, slice: u16) -> bool {
|
||||
let cube_idx = (slice >> 5) as usize;
|
||||
let slice_idx = slice & 0x1f;
|
||||
let block_idx = (slice >> 5) as usize;
|
||||
let idx_in_block = slice & 0x1f;
|
||||
|
||||
self.slices[cube_idx] & (1 << slice_idx) == 1
|
||||
(self.blocks[block_idx] >> (31 - idx_in_block)) & 0x1 == 1
|
||||
}
|
||||
}
|
||||
|
||||
impl HpxTile for HpxTexture3D {
|
||||
// Getter
|
||||
// Returns the current time if the texture is not full
|
||||
pub fn start_time(&self) -> Time {
|
||||
fn start_time(&self) -> Time {
|
||||
if let Some(t) = self.start_time {
|
||||
t
|
||||
} else {
|
||||
@@ -168,54 +332,38 @@ impl HEALPixTexturedCube {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn time_request(&self) -> Time {
|
||||
fn time_request(&self) -> Time {
|
||||
self.time_request
|
||||
}
|
||||
|
||||
pub fn cell(&self) -> &HEALPixCell {
|
||||
fn cell(&self) -> &HEALPixCell {
|
||||
&self.tile_cell
|
||||
}
|
||||
|
||||
// Setter
|
||||
/*pub fn replace(&mut self, texture_cell: &HEALPixCell, time_request: Time) {
|
||||
// Cancel the tasks copying the tiles contained in the texture
|
||||
// which have not yet been completed.
|
||||
//self.clear_tasks_in_progress(config, exec);
|
||||
|
||||
self.texture_cell = *texture_cell;
|
||||
self.uniq = texture_cell.uniq();
|
||||
self.full = false;
|
||||
self.start_time = None;
|
||||
self.time_request = time_request;
|
||||
self.tiles.clear();
|
||||
//self.missing = true;
|
||||
self.num_tiles_written = 0;
|
||||
}*/
|
||||
}
|
||||
|
||||
use std::cmp::Ordering;
|
||||
impl PartialOrd for HEALPixTexturedCube {
|
||||
impl PartialOrd for HpxTexture3D {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.uniq.partial_cmp(&other.uniq)
|
||||
}
|
||||
}
|
||||
use crate::Abort;
|
||||
impl Ord for HEALPixTexturedCube {
|
||||
impl Ord for HpxTexture3D {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap_abort()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for HEALPixTexturedCube {
|
||||
impl PartialEq for HpxTexture3D {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.uniq == other.uniq
|
||||
}
|
||||
}
|
||||
impl Eq for HEALPixTexturedCube {}
|
||||
impl Eq for HpxTexture3D {}
|
||||
|
||||
/*
|
||||
pub struct TextureUniforms<'a> {
|
||||
texture: &'a HEALPixTexturedCube,
|
||||
texture: &'a HpxTexture3D,
|
||||
name: String,
|
||||
}
|
||||
|
||||
|
||||
@@ -7,3 +7,155 @@ mod triangulation;
|
||||
pub mod uv;
|
||||
|
||||
pub use d2::HiPS2D;
|
||||
|
||||
use crate::downloader::request::allsky::Allsky;
|
||||
use crate::renderable::HiPSConfig;
|
||||
use crate::time::Time;
|
||||
use crate::CameraViewPort;
|
||||
use crate::HEALPixCell;
|
||||
use crate::HEALPixCoverage;
|
||||
use crate::LonLatT;
|
||||
use crate::WebGlContext;
|
||||
use al_api::hips::ImageExt;
|
||||
use al_core::image::Image;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
mod subdivide;
|
||||
|
||||
trait HpxTile {
|
||||
// Getter
|
||||
// Returns the current time if the texture is not full
|
||||
fn start_time(&self) -> Time;
|
||||
|
||||
fn time_request(&self) -> Time;
|
||||
|
||||
fn cell(&self) -> &HEALPixCell;
|
||||
}
|
||||
|
||||
pub trait HpxTileBuffer {
|
||||
type T: HpxTile;
|
||||
|
||||
fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn set_image_ext(&mut self, gl: &WebGlContext, ext: ImageExt) -> Result<(), JsValue>;
|
||||
|
||||
// Return if tiles did become available
|
||||
fn reset_available_tiles(&mut self) -> bool;
|
||||
|
||||
/// Accessors
|
||||
fn get(&self, cell: &HEALPixCell) -> Option<&Self::T>;
|
||||
|
||||
fn contains(&self, cell: &HEALPixCell) -> bool;
|
||||
|
||||
// Get the nearest parent tile found in the CPU buffer
|
||||
fn get_nearest_parent(&self, cell: &HEALPixCell) -> Option<HEALPixCell> {
|
||||
/*if cell.is_root() {
|
||||
// Root cells are in the buffer by definition
|
||||
Some(*cell)
|
||||
} else {*/
|
||||
let mut parent_cell = cell.parent();
|
||||
|
||||
while !self.contains(&parent_cell) && !parent_cell.is_root() {
|
||||
parent_cell = parent_cell.parent();
|
||||
}
|
||||
|
||||
if self.contains(&parent_cell) {
|
||||
Some(parent_cell)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
fn config_mut(&mut self) -> &mut HiPSConfig;
|
||||
fn config(&self) -> &HiPSConfig;
|
||||
|
||||
fn read_pixel(&self, pos: &LonLatT<f64>, camera: &CameraViewPort) -> Result<JsValue, JsValue>;
|
||||
}
|
||||
|
||||
use crate::downloader::query;
|
||||
use crate::renderable::hips::HiPS::{D2, D3};
|
||||
use crate::renderable::HiPS3D;
|
||||
use crate::ProjectionType;
|
||||
pub enum HiPS {
|
||||
D2(HiPS2D),
|
||||
D3(HiPS3D),
|
||||
}
|
||||
|
||||
impl HiPS {
|
||||
pub fn look_for_new_tiles(
|
||||
&mut self,
|
||||
camera: &CameraViewPort,
|
||||
proj: &ProjectionType,
|
||||
) -> Option<Vec<HEALPixCell>> {
|
||||
match self {
|
||||
D2(hips) => hips.look_for_new_tiles(camera, proj).map(|it| it.collect()),
|
||||
D3(hips) => hips.look_for_new_tiles(camera, proj).map(|it| it.collect()),
|
||||
}
|
||||
}
|
||||
|
||||
// Position given is in the camera space
|
||||
pub fn read_pixel(
|
||||
&self,
|
||||
p: &LonLatT<f64>,
|
||||
camera: &CameraViewPort,
|
||||
) -> Result<JsValue, JsValue> {
|
||||
match self {
|
||||
D2(hips) => hips.read_pixel(p, camera),
|
||||
D3(hips) => hips.read_pixel(p, camera),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_config(&self) -> &HiPSConfig {
|
||||
match self {
|
||||
D2(hips) => hips.get_config(),
|
||||
D3(hips) => hips.get_config(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_config_mut(&mut self) -> &mut HiPSConfig {
|
||||
match self {
|
||||
D2(hips) => hips.get_config_mut(),
|
||||
D3(hips) => hips.get_config_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
|
||||
match self {
|
||||
D2(hips) => hips.set_image_ext(ext),
|
||||
D3(hips) => hips.set_image_ext(ext),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_moc(&mut self, moc: HEALPixCoverage) {
|
||||
match self {
|
||||
D2(hips) => hips.set_moc(moc),
|
||||
D3(hips) => hips.set_moc(moc),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_tile_query(&self, cell: &HEALPixCell) -> query::Tile {
|
||||
match self {
|
||||
HiPS::D2(hips) => hips.get_tile_query(cell),
|
||||
HiPS::D3(hips) => hips.get_tile_query(cell),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_allsky(&mut self, allsky: Allsky) -> Result<(), JsValue> {
|
||||
match self {
|
||||
HiPS::D2(hips) => hips.add_allsky(allsky),
|
||||
HiPS::D3(hips) => hips.add_allsky(allsky),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_allsky(&self) -> bool {
|
||||
self.get_config().is_allsky
|
||||
}
|
||||
}
|
||||
|
||||
69
src/core/src/renderable/hips/subdivide.rs
Normal file
69
src/core/src/renderable/hips/subdivide.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use crate::camera::CameraViewPort;
|
||||
use crate::math::angle::Angle;
|
||||
use crate::math::projection::ProjectionType;
|
||||
use crate::math::vector::dist2;
|
||||
use crate::HEALPixCell;
|
||||
|
||||
const M: f64 = 280.0 * 280.0;
|
||||
const N: f64 = 150.0 * 150.0;
|
||||
const RAP: f64 = 0.7;
|
||||
|
||||
fn is_too_large(cell: &HEALPixCell, camera: &CameraViewPort, projection: &ProjectionType) -> bool {
|
||||
let vertices = cell
|
||||
.vertices()
|
||||
.iter()
|
||||
.filter_map(|(lon, lat)| {
|
||||
let vertex = crate::math::lonlat::radec_to_xyzw(Angle(*lon), Angle(*lat));
|
||||
projection.icrs_celestial_to_screen_space(&vertex, camera)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if vertices.len() < 4 {
|
||||
false
|
||||
} else {
|
||||
let d1 = dist2(vertices[0].as_ref(), &vertices[2].as_ref());
|
||||
let d2 = dist2(vertices[1].as_ref(), &vertices[3].as_ref());
|
||||
if d1 > M || d2 > M {
|
||||
true
|
||||
} else if d1 < N && d2 < N {
|
||||
false
|
||||
} else {
|
||||
let rap = if d2 > d1 { d1 / d2 } else { d2 / d1 };
|
||||
|
||||
rap < RAP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_hpxcell_subdivision(
|
||||
cell: &HEALPixCell,
|
||||
camera: &CameraViewPort,
|
||||
projection: &ProjectionType,
|
||||
) -> u8 {
|
||||
let d = cell.depth();
|
||||
// Subdivide all cells at least one time.
|
||||
// TODO: use a single subdivision number computed from the current cells inside the view
|
||||
// i.e. subdivide all cells in the view with the cell that has to be the most subdivided
|
||||
let mut num_sub = 1;
|
||||
if d < 2 {
|
||||
num_sub = 2 - d;
|
||||
}
|
||||
|
||||
// Largest deformation cell among the cells of a specific depth
|
||||
let largest_center_to_vertex_dist =
|
||||
healpix::largest_center_to_vertex_distance(d, 0.0, healpix::TRANSITION_LATITUDE);
|
||||
let smallest_center_to_vertex_dist =
|
||||
healpix::largest_center_to_vertex_distance(d, 0.0, healpix::LAT_OF_SQUARE_CELL);
|
||||
|
||||
let (lon, lat) = cell.center();
|
||||
let center_to_vertex_dist = healpix::largest_center_to_vertex_distance(d, lon, lat);
|
||||
|
||||
let skewed_factor = (center_to_vertex_dist - smallest_center_to_vertex_dist)
|
||||
/ (largest_center_to_vertex_dist - smallest_center_to_vertex_dist);
|
||||
|
||||
if skewed_factor > 0.25 || is_too_large(cell, camera, projection) || cell.is_on_pole() {
|
||||
num_sub += 1;
|
||||
}
|
||||
|
||||
num_sub
|
||||
}
|
||||
@@ -13,12 +13,13 @@ impl<T> Deref for UV<T> {
|
||||
}
|
||||
|
||||
use super::config::HiPSConfig;
|
||||
use super::d2::texture::Texture;
|
||||
use super::d2::texture::HpxTexture2D;
|
||||
use crate::healpix::cell::HEALPixCell;
|
||||
use crate::renderable::hips::HpxTile;
|
||||
pub struct TileUVW([Vector3<f32>; 4]);
|
||||
impl TileUVW {
|
||||
// The texture cell passed must be a child of texture
|
||||
pub fn new(cell: &HEALPixCell, texture: &Texture, cfg: &HiPSConfig) -> TileUVW {
|
||||
pub fn new(cell: &HEALPixCell, texture: &HpxTexture2D, cfg: &HiPSConfig) -> TileUVW {
|
||||
// Index of the texture in the total set of textures
|
||||
let texture_idx = texture.idx();
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ use crate::tile_fetcher::TileFetcherQueue;
|
||||
|
||||
use al_core::image::format::ChannelType;
|
||||
|
||||
pub use hips::HiPS2D;
|
||||
|
||||
pub use catalog::Manager;
|
||||
|
||||
use al_api::color::ColorRGB;
|
||||
@@ -43,6 +41,9 @@ use hips::raytracing::RayTracer;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use hips::d2::HiPS2D;
|
||||
use hips::d3::HiPS3D;
|
||||
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::WebGl2RenderingContext;
|
||||
|
||||
@@ -54,10 +55,12 @@ pub trait Renderer {
|
||||
pub(crate) type Id = String; // ID of an image, can be an url or a uuidv4
|
||||
pub(crate) type CreatorDid = String;
|
||||
|
||||
use hips::HiPS;
|
||||
type LayerId = String;
|
||||
pub struct Layers {
|
||||
// Surveys to query
|
||||
surveys: HashMap<CreatorDid, HiPS2D>,
|
||||
hipses: HashMap<CreatorDid, HiPS>,
|
||||
|
||||
images: HashMap<Id, Vec<Image>>, // an url can contain multiple images i.e. a fits file can contain
|
||||
// multiple image extensions
|
||||
// The meta data associated with a layer
|
||||
@@ -121,7 +124,8 @@ impl ImageLayer {
|
||||
|
||||
impl Layers {
|
||||
pub fn new(gl: &WebGlContext, projection: &ProjectionType) -> Result<Self, JsValue> {
|
||||
let surveys = HashMap::new();
|
||||
let hipses = HashMap::new();
|
||||
|
||||
let images = HashMap::new();
|
||||
let meta = HashMap::new();
|
||||
let ids = HashMap::new();
|
||||
@@ -155,7 +159,7 @@ impl Layers {
|
||||
|
||||
let background_color = DEFAULT_BACKGROUND_COLOR;
|
||||
Ok(Layers {
|
||||
surveys,
|
||||
hipses,
|
||||
images,
|
||||
|
||||
meta,
|
||||
@@ -171,19 +175,10 @@ impl Layers {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_survey_url(&mut self, cdid: &CreatorDid, new_url: String) -> Result<(), JsValue> {
|
||||
if let Some(survey) = self.surveys.get_mut(cdid) {
|
||||
pub fn set_hips_url(&mut self, cdid: &CreatorDid, new_url: String) -> Result<(), JsValue> {
|
||||
if let Some(hips) = self.hipses.get_mut(cdid) {
|
||||
// update the root_url
|
||||
survey.get_config_mut().set_root_url(new_url.clone());
|
||||
|
||||
//self.surveys.insert(new_url.clone(), survey);
|
||||
|
||||
// update all the layer urls
|
||||
/*for id in self.ids.values_mut() {
|
||||
if *id == past_url {
|
||||
*id = new_url.clone();
|
||||
}
|
||||
}*/
|
||||
hips.get_config_mut().set_root_url(new_url.clone());
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -192,8 +187,8 @@ impl Layers {
|
||||
}
|
||||
|
||||
/*pub fn reset_frame(&mut self) {
|
||||
for survey in self.surveys.values_mut() {
|
||||
survey.reset_frame();
|
||||
for hips in self.hips.values_mut() {
|
||||
hips.reset_frame();
|
||||
}
|
||||
}*/
|
||||
|
||||
@@ -221,15 +216,15 @@ impl Layers {
|
||||
let raytracer = &self.raytracer;
|
||||
let raytracing = camera.is_raytracing(projection);
|
||||
|
||||
// Check whether a survey to plot is allsky
|
||||
// Check whether a hips to plot is allsky
|
||||
// if neither are, we draw a font
|
||||
// if there are, we do not draw nothing
|
||||
let render_background_color = !self.layers.iter().any(|layer| {
|
||||
let meta = self.meta.get(layer).unwrap_abort();
|
||||
let cdid = self.ids.get(layer).unwrap_abort();
|
||||
if let Some(survey) = self.surveys.get(cdid) {
|
||||
let hips_cfg = survey.get_config();
|
||||
(survey.is_allsky() || hips_cfg.get_format().get_channel() == ChannelType::RGB8U)
|
||||
if let Some(hips) = self.hipses.get(cdid) {
|
||||
let hips_cfg = hips.get_config();
|
||||
(hips.is_allsky() || hips_cfg.get_format().get_channel() == ChannelType::RGB8U)
|
||||
&& meta.opacity == 1.0
|
||||
} else {
|
||||
// image fits case
|
||||
@@ -268,13 +263,13 @@ impl Layers {
|
||||
let meta = self.meta.get(layer).expect("Meta should be found");
|
||||
|
||||
let id = self.ids.get(layer).expect("Url should be found");
|
||||
if let Some(survey) = self.surveys.get_mut(id) {
|
||||
let hips_cfg = survey.get_config();
|
||||
if let Some(hips) = self.hipses.get_mut(id) {
|
||||
let hips_cfg = hips.get_config();
|
||||
|
||||
let fully_covering_survey = (survey.is_allsky()
|
||||
let fully_covering_hips = (hips.is_allsky()
|
||||
|| hips_cfg.get_format().get_channel() == ChannelType::RGB8U)
|
||||
&& meta.opacity == 1.0;
|
||||
if fully_covering_survey {
|
||||
if fully_covering_hips {
|
||||
idx_start_layer = idx_layer;
|
||||
}
|
||||
}
|
||||
@@ -284,13 +279,19 @@ impl Layers {
|
||||
for layer in rendered_layers {
|
||||
let draw_opt = self.meta.get(layer).expect("Meta should be found");
|
||||
if draw_opt.visible() {
|
||||
// 1. Update the survey if necessary
|
||||
// 1. Update the hips if necessary
|
||||
let id = self.ids.get(layer).expect("Url should be found");
|
||||
if let Some(survey) = self.surveys.get_mut(id) {
|
||||
survey.update(camera, projection);
|
||||
|
||||
// 2. Draw it if its opacity is not null
|
||||
survey.draw(shaders, colormaps, camera, raytracer, draw_opt, projection)?;
|
||||
if let Some(hips) = self.hipses.get_mut(id) {
|
||||
match hips {
|
||||
HiPS::D2(hips) => {
|
||||
hips.update(camera, projection);
|
||||
// 2. Draw it if its opacity is not null
|
||||
hips.draw(shaders, colormaps, camera, raytracer, draw_opt, projection)?;
|
||||
}
|
||||
HiPS::D3(hips) => {
|
||||
hips.draw(shaders, colormaps, camera, raytracer, draw_opt, projection)?;
|
||||
}
|
||||
}
|
||||
} else if let Some(images) = self.images.get_mut(id) {
|
||||
// 2. Draw it if its opacity is not null
|
||||
for image in images {
|
||||
@@ -338,14 +339,14 @@ impl Layers {
|
||||
Ok(id_layer)
|
||||
} else {
|
||||
// Resource not needed anymore
|
||||
if let Some(s) = self.surveys.remove(&id) {
|
||||
if let Some(hips) = self.hipses.remove(&id) {
|
||||
// A HiPS has been found and removed
|
||||
let hips_frame = s.get_config().get_frame();
|
||||
let hips_frame = hips.get_config().get_frame();
|
||||
// remove the frame
|
||||
camera.unregister_view_frame(hips_frame, proj);
|
||||
|
||||
// remove the local files access from the tile fetcher
|
||||
tile_fetcher.delete_hips_local_files(s.get_config().get_creator_did());
|
||||
tile_fetcher.delete_hips_local_files(hips.get_config().get_creator_did());
|
||||
|
||||
Ok(id_layer)
|
||||
} else if let Some(_) = self.images.remove(&id) {
|
||||
@@ -353,7 +354,7 @@ impl Layers {
|
||||
Ok(id_layer)
|
||||
} else {
|
||||
Err(JsValue::from_str(&format!(
|
||||
"Url found {:?} is associated to no surveys.",
|
||||
"Url found {:?} is associated to no 2D HiPSes.",
|
||||
id
|
||||
)))
|
||||
}
|
||||
@@ -408,14 +409,14 @@ impl Layers {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_image_hips(
|
||||
pub fn add_hips(
|
||||
&mut self,
|
||||
gl: &WebGlContext,
|
||||
hips: HiPSCfg,
|
||||
camera: &mut CameraViewPort,
|
||||
proj: &ProjectionType,
|
||||
tile_fetcher: &mut TileFetcherQueue,
|
||||
) -> Result<&HiPS2D, JsValue> {
|
||||
) -> Result<&HiPS, JsValue> {
|
||||
let HiPSCfg {
|
||||
layer,
|
||||
properties,
|
||||
@@ -444,13 +445,13 @@ impl Layers {
|
||||
|
||||
camera.set_longitude_reversed(longitude_reversed, proj);
|
||||
|
||||
// 3. Add the image survey
|
||||
// 3. Add the image hips
|
||||
let creator_did = String::from(properties.get_creator_did());
|
||||
// The layer does not already exist
|
||||
// Let's check if no other hipses points to the
|
||||
// same url than `hips`
|
||||
let cdid_already_found = self
|
||||
.surveys
|
||||
.hipses
|
||||
.keys()
|
||||
.any(|hips_cdid| hips_cdid == &creator_did);
|
||||
|
||||
@@ -469,16 +470,21 @@ impl Layers {
|
||||
}*/
|
||||
camera.register_view_frame(cfg.get_frame(), proj);
|
||||
|
||||
let hips = HiPS2D::new(cfg, gl)?;
|
||||
// add the frame to the camera
|
||||
let hips = if cfg.get_cube_depth().is_some() {
|
||||
// HiPS cube
|
||||
HiPS::D3(HiPS3D::new(cfg, gl)?)
|
||||
} else {
|
||||
HiPS::D2(HiPS2D::new(cfg, gl)?)
|
||||
};
|
||||
|
||||
self.surveys.insert(creator_did.clone(), hips);
|
||||
// add the frame to the camera
|
||||
self.hipses.insert(creator_did.clone(), hips);
|
||||
}
|
||||
|
||||
self.ids.insert(layer.clone(), creator_did.clone());
|
||||
|
||||
let hips = self
|
||||
.surveys
|
||||
.hipses
|
||||
.get(&creator_did)
|
||||
.ok_or(JsValue::from_str("HiPS not found"))?;
|
||||
Ok(hips)
|
||||
@@ -559,15 +565,15 @@ impl Layers {
|
||||
&mut self,
|
||||
layer: String,
|
||||
meta: ImageMetadata,
|
||||
camera: &mut CameraViewPort,
|
||||
camera: &CameraViewPort,
|
||||
projection: &ProjectionType,
|
||||
) -> Result<(), JsValue> {
|
||||
let layer_ref = layer.as_str();
|
||||
|
||||
/*if let Some(meta_old) = self.meta.get(layer_ref) {
|
||||
if !meta_old.visible() && meta.visible() {
|
||||
if let Some(survey) = self.get_mut_hips_from_layer(layer_ref) {
|
||||
survey.recompute_vertices(camera, projection);
|
||||
if let Some(hips) = self.get_mut_hips_from_layer(layer_ref) {
|
||||
hips.recompute_vertices(camera, projection);
|
||||
}
|
||||
|
||||
if let Some(images) = self.get_mut_image_from_layer(layer_ref) {
|
||||
@@ -587,8 +593,8 @@ impl Layers {
|
||||
for idx in 0..layer_idx {
|
||||
let cur_layer = self.layers[idx].clone();
|
||||
|
||||
if let Some(survey) = self.get_mut_hips_from_layer(&cur_layer) {
|
||||
survey.recompute_vertices(camera, projection);
|
||||
if let Some(hips) = self.get_mut_hips_from_layer(&cur_layer) {
|
||||
hips.recompute_vertices(camera, projection);
|
||||
} else if let Some(images) = self.get_mut_image_from_layer(&cur_layer) {
|
||||
for image in images {
|
||||
image.recompute_vertices(camera, projection)?;
|
||||
@@ -598,7 +604,7 @@ impl Layers {
|
||||
}
|
||||
}*/
|
||||
|
||||
// Expect the image survey to be found in the hash map
|
||||
// Expect the image hips to be found in the hash map
|
||||
self.meta.insert(layer.clone(), meta).ok_or_else(|| {
|
||||
JsValue::from(js_sys::Error::new(&format!("{:?} layer not found", layer)))
|
||||
})?;
|
||||
@@ -608,35 +614,27 @@ impl Layers {
|
||||
|
||||
// Accessors
|
||||
// HiPSes getters
|
||||
pub fn get_hips_from_layer(&self, layer: &str) -> Option<&HiPS2D> {
|
||||
pub fn get_hips_from_layer(&self, layer: &str) -> Option<&HiPS> {
|
||||
self.ids
|
||||
.get(layer)
|
||||
.map(|cdid| self.surveys.get(cdid))
|
||||
.map(|cdid| self.hipses.get(cdid))
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub fn get_mut_hips_from_layer(&mut self, layer: &str) -> Option<&mut HiPS2D> {
|
||||
pub fn get_mut_hips_from_layer(&mut self, layer: &str) -> Option<&mut HiPS> {
|
||||
if let Some(cdid) = self.ids.get_mut(layer) {
|
||||
self.surveys.get_mut(cdid)
|
||||
self.hipses.get_mut(cdid)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut_hips_from_cdid(&mut self, cdid: &str) -> Option<&mut HiPS2D> {
|
||||
self.surveys.get_mut(cdid)
|
||||
pub fn get_mut_hips_from_cdid(&mut self, cdid: &str) -> Option<&mut HiPS> {
|
||||
self.hipses.get_mut(cdid)
|
||||
}
|
||||
|
||||
pub fn get_hips_from_cdid(&mut self, cdid: &str) -> Option<&HiPS2D> {
|
||||
self.surveys.get(cdid)
|
||||
}
|
||||
|
||||
pub fn values_hips(&self) -> impl Iterator<Item = &HiPS2D> {
|
||||
self.surveys.values()
|
||||
}
|
||||
|
||||
pub fn values_mut_hips(&mut self) -> impl Iterator<Item = &mut HiPS2D> {
|
||||
self.surveys.values_mut()
|
||||
pub fn get_mut_hipses(&mut self) -> impl Iterator<Item = &mut HiPS> {
|
||||
self.hipses.values_mut()
|
||||
}
|
||||
|
||||
// Fits images getters
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::downloader::{query, Downloader};
|
||||
use crate::renderable::HiPS2D;
|
||||
use crate::time::{DeltaTime, Time};
|
||||
use crate::Abort;
|
||||
|
||||
@@ -10,6 +9,8 @@ use std::rc::Rc;
|
||||
const MAX_NUM_TILE_FETCHING: usize = 8;
|
||||
const MAX_QUERY_QUEUE_LENGTH: usize = 100;
|
||||
|
||||
use crate::renderable::hips::HiPS;
|
||||
|
||||
pub struct TileFetcherQueue {
|
||||
// A stack of queries to fetch
|
||||
queries: VecDeque<query::Tile>,
|
||||
@@ -30,7 +31,6 @@ pub struct HiPSLocalFiles {
|
||||
use crate::tile_fetcher::query::Tile;
|
||||
use crate::HEALPixCell;
|
||||
use al_api::hips::ImageExt;
|
||||
use al_core::image::format::ImageFormatType;
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
use wasm_bindgen::JsValue;
|
||||
|
||||
@@ -52,13 +52,7 @@ impl HiPSLocalFiles {
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, depth: u8, ipix: u64, ext: ImageExt, file: web_sys::File) {
|
||||
let mut tiles_per_fmt = match ext {
|
||||
ImageExt::Fits => &mut self.tiles[0],
|
||||
ImageExt::Jpeg => &mut self.tiles[1],
|
||||
ImageExt::Png => &mut self.tiles[2],
|
||||
ImageExt::Webp => &mut self.tiles[3],
|
||||
};
|
||||
|
||||
let tiles_per_fmt = &mut self.tiles[ext as usize];
|
||||
tiles_per_fmt[depth as usize].insert(ipix, file);
|
||||
}
|
||||
|
||||
@@ -190,7 +184,7 @@ impl TileFetcherQueue {
|
||||
|
||||
pub fn launch_starting_hips_requests(
|
||||
&mut self,
|
||||
hips: &HiPS2D,
|
||||
hips: &HiPS,
|
||||
downloader: Rc<RefCell<Downloader>>,
|
||||
) {
|
||||
let cfg = hips.get_config();
|
||||
@@ -221,7 +215,13 @@ impl TileFetcherQueue {
|
||||
//Request the allsky for the small tile size or if base tiles are not available
|
||||
if tile_size <= 128 || cfg.get_min_depth_tile() > 0 {
|
||||
// Request the allsky
|
||||
downloader.borrow_mut().fetch(query::Allsky::new(cfg));
|
||||
downloader.borrow_mut().fetch(query::Allsky::new(
|
||||
cfg,
|
||||
match hips {
|
||||
HiPS::D2(_) => None,
|
||||
HiPS::D3(h) => Some(h.get_slice() as u32),
|
||||
},
|
||||
));
|
||||
} else if cfg.get_min_depth_tile() == 0 {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
@@ -231,13 +231,7 @@ impl TileFetcherQueue {
|
||||
let min_order = cfg.get_min_depth_texture();
|
||||
|
||||
for tile_cell in crate::healpix::cell::ALLSKY_HPX_CELLS_D0 {
|
||||
if let Ok(query) = self.check_in_file_list(query::Tile::new(
|
||||
tile_cell,
|
||||
hips_cdid.clone(),
|
||||
hips_url.clone(),
|
||||
hips_fmt,
|
||||
None,
|
||||
)) {
|
||||
if let Ok(query) = self.check_in_file_list(hips.get_tile_query(tile_cell)) {
|
||||
let dl = downloader.clone();
|
||||
|
||||
crate::utils::set_timeout(
|
||||
|
||||
21
src/glsl/webgl2/hips3d/rasterizer/color.frag
Normal file
21
src/glsl/webgl2/hips3d/rasterizer/color.frag
Normal file
@@ -0,0 +1,21 @@
|
||||
#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;
|
||||
|
||||
#include ../../hips/color.glsl;
|
||||
|
||||
void main() {
|
||||
vec4 color = get_color_from_texture(vec3(frag_uv.xy, mod(frag_uv.z, 32.0) / 32.0));
|
||||
|
||||
out_frag_color = color;
|
||||
out_frag_color.a = opacity * out_frag_color.a;
|
||||
}
|
||||
22
src/glsl/webgl2/hips3d/rasterizer/grayscale_to_colormap.frag
Normal file
22
src/glsl/webgl2/hips3d/rasterizer/grayscale_to_colormap.frag
Normal file
@@ -0,0 +1,22 @@
|
||||
#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;
|
||||
|
||||
#include ../../hips/color.glsl;
|
||||
|
||||
uniform float opacity;
|
||||
|
||||
void main() {
|
||||
vec4 color = get_colormap_from_grayscale_texture(frag_uv);
|
||||
|
||||
out_frag_color = color;
|
||||
out_frag_color.a = out_frag_color.a * opacity;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#version 300 es
|
||||
precision lowp float;
|
||||
precision lowp sampler3D;
|
||||
precision lowp isampler3D;
|
||||
precision lowp usampler3D;
|
||||
|
||||
uniform isampler3D tex;
|
||||
|
||||
in vec3 frag_uv;
|
||||
|
||||
out vec4 out_frag_color;
|
||||
|
||||
#include ../../hips/color_i.glsl;
|
||||
|
||||
uniform float opacity;
|
||||
|
||||
void main() {
|
||||
vec4 color = get_colormap_from_grayscale_texture(frag_uv);
|
||||
|
||||
out_frag_color = color;
|
||||
out_frag_color.a = out_frag_color.a * opacity;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#version 300 es
|
||||
precision lowp float;
|
||||
precision lowp sampler3D;
|
||||
precision lowp isampler3D;
|
||||
precision lowp usampler3D;
|
||||
|
||||
uniform usampler3D tex;
|
||||
|
||||
in vec3 frag_uv;
|
||||
|
||||
out vec4 out_frag_color;
|
||||
|
||||
#include ../../hips/color_u.glsl;
|
||||
|
||||
uniform float opacity;
|
||||
|
||||
void main() {
|
||||
vec4 color = get_colormap_from_grayscale_texture(frag_uv);
|
||||
|
||||
out_frag_color = color;
|
||||
out_frag_color.a = out_frag_color.a * opacity;
|
||||
}
|
||||
26
src/glsl/webgl2/hips3d/rasterizer/raster.vert
Normal file
26
src/glsl/webgl2/hips3d/rasterizer/raster.vert
Normal file
@@ -0,0 +1,26 @@
|
||||
#version 300 es
|
||||
precision lowp float;
|
||||
|
||||
layout (location = 0) in vec2 lonlat;
|
||||
layout (location = 1) in vec3 uv;
|
||||
|
||||
out vec3 frag_uv;
|
||||
|
||||
// current time in ms
|
||||
uniform mat4 inv_model;
|
||||
uniform vec2 ndc_to_clip;
|
||||
uniform float czf;
|
||||
|
||||
#include ../../projection/projection.glsl;
|
||||
|
||||
void main() {
|
||||
vec3 p_xyz = lonlat2xyz(lonlat);
|
||||
vec4 p_w = inv_model * vec4(p_xyz, 1.0);
|
||||
// 3. Process the projection
|
||||
vec2 p_clip = proj(p_w.xyz);
|
||||
|
||||
vec2 p_ndc = p_clip / (ndc_to_clip * czf);
|
||||
gl_Position = vec4(p_ndc, 0.0, 1.0);
|
||||
|
||||
frag_uv = uv;
|
||||
}
|
||||
@@ -287,7 +287,9 @@ export let HiPS = (function () {
|
||||
HiPS.prototype._parseProperties = function(properties) {
|
||||
let self = this;
|
||||
self.creatorDid = properties.creator_did || self.creatorDid;
|
||||
// url
|
||||
|
||||
// Cube depth
|
||||
self.cubeDepth = properties && properties.hips_cube_depth && +properties.hips_cube_depth;
|
||||
|
||||
// Max order
|
||||
self.maxOrder =
|
||||
@@ -704,6 +706,12 @@ export let HiPS = (function () {
|
||||
this.setOptions({contrast})
|
||||
};
|
||||
|
||||
HiPS.prototype.setSliceNumber = function(slice) {
|
||||
if (this.added) {
|
||||
this.view.wasm.setSliceNumber(this.layer, slice);
|
||||
}
|
||||
}
|
||||
|
||||
// Private method for updating the backend with the new meta
|
||||
HiPS.prototype._updateMetadata = function () {
|
||||
try {
|
||||
@@ -960,6 +968,7 @@ export let HiPS = (function () {
|
||||
hipsInitialFov: self.initialFov,
|
||||
hipsInitialRa: self.initialRa,
|
||||
hipsInitialDec: self.initialDec,
|
||||
hipsCubeDepth: self.cubeDepth,
|
||||
isPlanetaryBody: self.isPlanetaryBody(),
|
||||
hipsBody: self.hipsBody,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user