Compare commits

..

11 Commits

Author SHA1 Message Date
Matthieu Baumann
0c9c4cf9a9 wip 2024-09-25 19:05:37 +02:00
Philip Matsson
ea8af8acb3 Cleaning up 2024-09-25 11:23:40 +02:00
Philip Matsson
fac6c045f4 Add option for manual selection logic 2024-09-25 10:47:56 +02:00
Philip Matsson
b778ce380a Push overlayItems in selector getObjects as an array for consistency 2024-09-24 17:33:32 +02:00
Philip Matsson
d3e0bb4fbc Update select logic 2024-09-24 16:59:41 +02:00
Philip Matsson
81e1eaddee Allow color as function for select types 2024-09-24 16:58:19 +02:00
Philip Matsson
51af4fa2f4 Customize select logic 2024-09-24 16:58:17 +02:00
Philip Matsson
ef86dbd06d Merge branch 'cds-astro:master' into select-impl 2024-09-24 16:34:10 +02:00
Philip Matsson
45f77feeb1 Update polyline select implementation 2024-07-11 12:09:45 +02:00
Philip Matsson
b8820d6f19 Fix typo in polyline BB intersect function 2024-06-19 11:59:05 +02:00
Philip Matsson
98d877b937 Modify objects returned from selector and finish poly select impl 2024-06-19 10:26:49 +02:00
136 changed files with 4096 additions and 5882 deletions

View File

@@ -37,7 +37,7 @@ jobs:
uses: actions/configure-pages@v4
- name: Build docs
run: |
npm install
npm install -g jsdoc
npm run doc
- name: Upload artifact
uses: actions/upload-pages-artifact@v3

View File

@@ -22,6 +22,8 @@ jobs:
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source "$HOME/.cargo/env"
rustup default nightly
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
- name: "Install wasm-pack"
run: |
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -y
@@ -30,7 +32,7 @@ jobs:
npm install
- name: "Build Aladin Lite"
run: |
npm run build:dbg
npm run build
- name: "Run the rust tests"
run: |
npm run test:build

View File

@@ -13,7 +13,6 @@ A new [API technical documentation](https://cds-astro.github.io/aladin-lite/) is
[![Run tests](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml/badge.svg)](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml)
[![API Documentation](https://img.shields.io/badge/API-documentation-blue.svg)](https://cds-astro.github.io/aladin-lite)
[![Releases page](https://img.shields.io/badge/Releases-forge-yellow.svg)](https://aladin.cds.unistra.fr/AladinLite/doc/release/)
Aladin Lite is available [at this link](https://aladin.u-strasbg.fr/AladinLite).
@@ -88,7 +87,6 @@ Aladin Lite can be imported with:
```html
<script type="module">
import A from 'aladin-lite';
// your code...
</script>
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 962 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

@@ -16,9 +16,9 @@
simbad.addSources([A.marker(204.97010833333336, 0.8400166666666667, {popupTitle: 'NGC 5257', popupDesc: '<em>Object type:</em> HII galaxy<br/><em>Morphological type:</em> Sbc<br/><br/>More info <a href="https://simbad.u-strasbg.fr/simbad/sim-id?Ident=NGC+5257">in Simbad</a>'}), A.marker(204.9903125, 0.8309694444444445, {popupTitle: 'NGC 5258', popupDesc: '<em>Object type:</em> Galaxy in Pair of Galaxies <br/><em>Morphological type:</em> Sb<br/><br/>More info <a href="https://simbad.u-strasbg.fr/simbad/sim-id?Ident=NGC+5258">in Simbad</a>'})]);
var overlay = A.graphicOverlay({color: '#aa2222', lineWidth: 4});
overlay.addFootprints(A.polygon([[204.970214, 0.81206], [204.97110047, 0.80993368], [204.978723, 0.79165], [204.999152, 0.800162], [204.99482125, 0.81055582], [205.002941, 0.813851], [204.99986816, 0.82141125], [205.010312, 0.825578], [205.002112, 0.846123], [204.981546, 0.837916], [204.98157771, 0.83783654], [204.962977, 0.830202], [204.9703941, 0.81213504]]));
aladin.addOverlay(overlay);
overlay.addFootprints(A.polygon([[204.970214, 0.81206], [204.97110047, 0.80993368], [204.978723, 0.79165], [204.999152, 0.800162], [204.99482125, 0.81055582], [205.002941, 0.813851], [204.99986816, 0.82141125], [205.010312, 0.825578], [205.002112, 0.846123], [204.981546, 0.837916], [204.98157771, 0.83783654], [204.962977, 0.830202], [204.9703941, 0.81213504]]));
aladin.displayJPG('http://images.ipac.caltech.edu/esahubble/heic0810at/esahubble_heic0810at_1600.jpg');
});

View File

@@ -10,9 +10,8 @@
import A from '../src/js/A.js';
let aladin;
A.init.then(() => {
let startFov = 1000;
aladin = A.aladin('#aladin-lite-div', {showSettingsControl: true, survey: "P/PanSTARRS/DR1/color-z-zg-g", showReticle: false, projection: "AIT", cooFrame: 'icrs', target: "stephan's quintet", fov: startFov, showGotoControl: false, showFrame: false, fullScreen: true, showLayersControl: true, showCooGridControl: false});
aladin = A.aladin('#aladin-lite-div', {showSettingsControl: true, survey: "P/PanSTARRS/DR1/color-z-zg-g", showReticle: false, projection: "AIT", cooFrame: 'icrs', target: "stephan's quintet", fov: 1000, showGotoControl: false, showFrame: false, fullScreen: true, showLayersControl: true, showCooGridControl: false});
aladin.showHealpixGrid(true);
const chft = aladin.createImageSurvey('CFHT', "CFHT deep view of NGC7331 and Stephan's quintet u+g+r", "https://cds.unistra.fr/~derriere/PR_HiPS/2022_Duc/", null, null, {imgFormat: 'png'});
const nircamJWST = aladin.createImageSurvey('Nircam', "Stephans Quintet NIRCam+MIRI", "http://alasky.cds.unistra.fr/JWST/CDS_P_JWST_Stephans-Quintet_NIRCam+MIRI/", null, null, {imgFormat: 'png', colormap: "viridis"});
@@ -22,7 +21,7 @@
aladin.getOverlayImageLayer("CFHT").toggle();
aladin.getOverlayImageLayer("Nircam").toggle();
let fov = startFov;
let fov = 360;
let rotation = 0;
setInterval(function zoom() {

View File

@@ -13,7 +13,7 @@
// Start up Aladin Lite
aladin = A.aladin('#aladin-lite-div', {survey: "CDS/P/DSS2/color", target: 'M 1', fov: 0.2, showContextMenu: true, fullScreen: true});
var overlay = A.graphicOverlay({color: '#ee2345', lineWidth: 3, lineDash: [2, 2]});
/*aladin.addOverlay(overlay);
aladin.addOverlay(overlay);
overlay.addFootprints([
A.polygon([[83.64287, 22.01713], [83.59872, 22.01692], [83.59852, 21.97629], [83.64295, 21.97629]], {hoverColor: 'green'}),
A.polygon([[83.62807, 22.06330], [83.58397, 22.02280], [83.62792, 22.02258]]),
@@ -21,7 +21,7 @@
]);
overlay.add(A.circle(83.66067, 22.03081, 0.04, {color: 'cyan'})); // radius in degrees
overlay.add(A.vector(83.66067, 22.03081, 0.04, {color: 'cyan'})); // radius in degrees
*/
aladin.on("footprintClicked", (footprint, xyMouseCoords) => {
console.log("footprint clicked catched: ", footprint, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
})
@@ -35,7 +35,7 @@
console.log("Object hovered stopped: ", object, "mouse coords xy: ", xyMouseCoords.x, xyMouseCoords.y);
})
const cat = A.catalogFromVizieR('B/assocdata/obscore', 'M 1', 10, {onClick: 'showTable', selectionColor: "orange", hoverColor: 'red', limit: 10000});
const cat = A.catalogFromVizieR('B/assocdata/obscore', 'M 1', 10, {onClick: 'showTable', hoverColor: 'purple', limit: 10000});
aladin.addCatalog(cat);
});
</script>

View File

@@ -1,52 +0,0 @@
<!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/GALFAHI/GALFAHI-Narrow-DR2/");
//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>

View File

@@ -16,7 +16,7 @@
showSimbadPointerControl: true,
survey: 'P/allWISE/color', // set initial image survey
projection: 'AIT', // set a projection
fov: 360, // initial field of view in degrees
fov: 1.5, // initial field of view in degrees
target: 'orion', // initial target
cooFrame: 'icrs', // set galactic frame
reticleColor: '#ff89ff', // change reticle color

View File

@@ -25,9 +25,9 @@
aladin.setImageLayer(survey2);
setTimeout(() => {
/*setTimeout(() => {
aladin.removeHiPSFromFavorites(survey3)
}, 5000);
}, 10000);*/
aladin.addColormap('mycmap', ["lightblue", "red", "violet", "lightgreen"])

View File

@@ -1,8 +0,0 @@
nav > h2 {
color: blue;
font-size: medium;
}
nav > ul > li > a {
font-size: medium;
}

View File

@@ -1,7 +0,0 @@
var meta = document.createElement("meta");
meta.name = "viewport"
meta.content = "width=device-width, height=device-height, initial-scale=1.0, user-scalable=no"
document.querySelector("head").appendChild(
meta
)

View File

@@ -10,85 +10,13 @@
"allowUnknownTags": true,
"dictionaries": ["jsdoc","closure"]
},
"docdash": {
"typedefs": true,
"scripts": [
"jsdoc-custom-style.css",
"jsdoc-make-responsive.js"
],
"sectionOrder": [
"Namespaces",
"Classes",
"Modules",
"Externals",
"Events",
"Mixins",
"Interfaces",
"Global"
],
"openGraph": {
"title": "Aladin Lite API documentation",
"type": "website",
"image": "https://cds-astro.github.io/aladin-lite/aladin-logo.png",
"site_name": "Aladin Lite API documentation",
"url": "https://cds-astro.github.io/aladin-lite/"
},
"meta": {
"title": "Aladin Lite API documentation",
"description": "Aladin Lite API documentation",
"keyword": "astronomy"
},
"search": true,
"menu": {
"Aladin Lite portal": {
"href":"https://aladin.cds.unistra.fr/AladinLite",
"target":"_blank",
"class":"menu-item",
"id":"website_link"
},
"API examples": {
"href":"https://aladin.cds.unistra.fr/AladinLite/doc/API/examples",
"target":"_blank",
"class":"menu-item",
"id":"website_link"
},
"Documentation": {
"href":"https://aladin.cds.unistra.fr/AladinLite/doc/",
"target":"_blank",
"class":"menu-item",
"id":"website_link"
},
"Releases": {
"href":"https://aladin.cds.unistra.fr/AladinLite/doc/release",
"target":"_blank",
"class":"menu-item",
"id":"website_link"
},
"GitHub": {
"href":"https://github.com/cds-astro/aladin-lite",
"target":"_blank",
"class":"menu-item",
"id":"website_link"
}
}
},
"templates": {
"cleverLinks": true,
"monospaceLinks": true,
"default": {
"staticFiles": {
"include": [
"./jsdoc-custom-style.css",
"./jsdoc-make-responsive.js"
]
}
}
"monospaceLinks": true
},
"opts": {
"readme": "./README.md",
"destination": "./docs/",
"template": "node_modules/docdash",
"encoding": "utf8",
"verbose": true
"tutorials": "./tutorials"
}
}
}

View File

@@ -2,7 +2,7 @@
"homepage": "https://aladin.u-strasbg.fr/",
"name": "aladin-lite",
"type": "module",
"version": "3.6.0-beta",
"version": "3.5.1-beta",
"description": "An astronomical HiPS visualizer in the browser",
"author": "Thomas Boch and Matthieu Baumann",
"license": "GPL-3",
@@ -30,8 +30,8 @@
"HiPS"
],
"scripts": {
"wasm": "wasm-pack build ./src/core --target web --release --out-name core -- --features webgl2",
"wasm:dbg": "wasm-pack build --dev ./src/core --target web --out-name core -- --features=webgl2,dbg",
"wasm": "wasm-pack build ./src/core --target web --release --out-name core -- --features webgl2 -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort ",
"wasm:dbg": "wasm-pack build --dev ./src/core --target web --out-name core -- --features=webgl2,dbg -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort ",
"predeploy": "npm run build && rm -rf aladin-lite*.tgz && npm pack",
"deploy": "python3 deploy/deploy.py",
"build": "npm run wasm && vite build",
@@ -44,12 +44,11 @@
"test:build": "cd src/core && cargo test --release --features webgl2",
"test:playwright": "npx playwright test",
"test:update-snapshots": "npx playwright test --update-snapshots",
"doc": "jsdoc -c jsdoc.json src/js src/js/shapes src/js/libs/astro && cp aladin-logo.png docs/ && cp jsdoc-custom-style.css docs/ && cp jsdoc-make-responsive.js docs/",
"doc": "jsdoc -c jsdoc.json src/js src/js/shapes src/js/libs/astro && cp aladin-logo.png docs/",
"doc:dev": "npm run doc && open docs/index.html"
},
"devDependencies": {
"@playwright/test": "^1.47.0",
"docdash": "^2.0.2",
"jsdoc": "^4.0.2",
"vite": "^4.3.8",
"vite-plugin-glsl": "^1.1.2",

View File

@@ -22,7 +22,7 @@ url-lite = "0.1.0"
serde_json = "1.0.104"
serde-wasm-bindgen = "0.5"
enum_dispatch = "0.3.8"
wasm-bindgen = "0.2.92"
wasm-bindgen = "0.2.79"
wasm-streams = "0.3.0"
async-channel = "1.8.0"
mapproj = "0.3.0"
@@ -50,11 +50,13 @@ optional = true
[dependencies.healpix]
package = "cdshealpix"
version = "0.7.0"
git = "https://github.com/cds-astro/cds-healpix-rust"
branch = "master"
[dependencies.moclib]
package = "moc"
version = "0.17.0"
git = "https://github.com/bmatthieu3/cds-moc-rust"
branch = "overlap"
[dependencies.serde]
version = "^1.0.183"
@@ -80,7 +82,7 @@ features = [ "jpeg", "png",]
debug = true
[profile.release]
opt-level = 'z'
opt-level = "z"
debug = false
debug-assertions = false
overflow-checks = false

View File

@@ -9,7 +9,7 @@ js-sys = "0.3.47"
cgmath = "*"
serde = { version = "^1.0.59", features = ["derive"] }
serde-wasm-bindgen = "0.4"
wasm-bindgen = "0.2.92"
wasm-bindgen = "0.2.79"
colorgrad = "0.6.2"
[features]
@@ -76,5 +76,16 @@ incremental = true
codegen-units = 256
rpath = false
[profile.release]
opt-level = 'z'
debug = false
debug-assertions = false
overflow-checks = false
lto = true
panic = 'unwind'
incremental = false
codegen-units = 16
rpath = false
[package.metadata.wasm-pack.profile.release]
wasm-opt = true

View File

@@ -47,7 +47,6 @@ pub struct HiPSProperties {
hips_initial_fov: Option<f64>,
hips_initial_ra: Option<f64>,
hips_initial_dec: Option<f64>,
hips_cube_depth: Option<u32>,
// Parametrable by the user
#[allow(unused)]
@@ -79,11 +78,6 @@ impl HiPSProperties {
self.min_order
}
#[inline(always)]
pub fn get_cube_depth(&self) -> Option<u32> {
self.hips_cube_depth
}
#[inline(always)]
pub fn get_bitpix(&self) -> Option<i32> {
self.bitpix

View File

@@ -19,7 +19,7 @@ futures = "0.3.25"
colorgrad = "0.6.2"
[dependencies.wasm-bindgen]
version = "0.2.92"
version = "0.2.79"
[dev-dependencies]
fontdue = "0.7.2"
@@ -88,5 +88,16 @@ incremental = true
codegen-units = 256
rpath = false
[profile.release]
opt-level = 'z'
debug = false
debug-assertions = false
overflow-checks = false
lto = true
panic = 'unwind'
incremental = false
codegen-units = 16
rpath = false
[package.metadata.wasm-pack.profile.release]
wasm-opt = true

View File

@@ -19,18 +19,16 @@ where
}
}
}
use crate::texture::Tex3D;
use wasm_bindgen::JsValue;
use crate::texture::Texture2DArray;
impl<F> Image for Bitmap<F>
where
F: ImageFormat + Clone,
{
fn insert_into_3d_texture<T: Tex3D>(
&self,
textures: &T,
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
textures.tex_sub_image_3d_with_image_bitmap(offset.x, offset.y, offset.z, &self.image);
fn tex_sub_image_3d(&self, textures: &Texture2DArray, offset: &Vector3<i32>) -> Result<(), JsValue> {
textures[offset.z as usize]
.bind()
.tex_sub_image_2d_with_u32_and_u32_and_image_bitmap(offset.x, offset.y, &self.image);
Ok(())
}

View File

@@ -17,28 +17,29 @@ where
}
}
use crate::image::format::ImageFormat;
use crate::image::Image;
use crate::texture::Tex3D;
use cgmath::Vector3;
use wasm_bindgen::JsValue;
use crate::image::format::ImageFormat;
use crate::image::Image;
use crate::texture::Texture2DArray;
impl<F> Image for Canvas<F>
where
F: ImageFormat,
{
fn insert_into_3d_texture<T: Tex3D>(
fn tex_sub_image_3d(
&self,
// The texture array
textures: &T,
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
textures.tex_sub_image_3d_with_html_canvas_element(
offset.x,
offset.y,
offset.z,
&self.canvas,
);
textures[offset.z as usize]
.bind()
.tex_sub_image_2d_with_u32_and_u32_and_html_canvas_element(
offset.x,
offset.y,
&self.canvas,
);
Ok(())
}

View File

@@ -116,63 +116,64 @@ impl<'a> Fits<'a> {
}
}*/
use crate::{image::Image, texture::Tex3D};
use crate::image::Image;
use crate::Texture2DArray;
impl Image for Fits<'_> {
fn insert_into_3d_texture<T: Tex3D>(
fn tex_sub_image_3d(
&self,
// The texture array
textures: &T,
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
match &self.data {
Data::U8(data) => {
let view = unsafe { R8UI::view(&data) };
textures.tex_sub_image_3d_with_opt_array_buffer_view(
offset.x,
offset.y,
offset.z,
self.size.x,
self.size.y,
1,
Some(view.as_ref()),
);
textures[offset.z as usize]
.bind()
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
offset.x,
offset.y,
self.size.x,
self.size.y,
Some(view.as_ref()),
);
}
Data::I16(data) => {
let view = unsafe { R16I::view(&data) };
textures.tex_sub_image_3d_with_opt_array_buffer_view(
offset.x,
offset.y,
offset.z,
self.size.x,
self.size.y,
1,
Some(view.as_ref()),
);
textures[offset.z as usize]
.bind()
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
offset.x,
offset.y,
self.size.x,
self.size.y,
Some(view.as_ref()),
);
}
Data::I32(data) => {
let view = unsafe { R32I::view(&data) };
textures.tex_sub_image_3d_with_opt_array_buffer_view(
offset.x,
offset.y,
offset.z,
self.size.x,
self.size.y,
1,
Some(view.as_ref()),
);
textures[offset.z as usize]
.bind()
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
offset.x,
offset.y,
self.size.x,
self.size.y,
Some(view.as_ref()),
);
}
Data::F32(data) => {
let view = unsafe { R32F::view(&data) };
textures.tex_sub_image_3d_with_opt_array_buffer_view(
offset.x,
offset.y,
offset.z,
self.size.x,
self.size.y,
1,
Some(view.as_ref()),
);
textures[offset.z as usize]
.bind()
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
offset.x,
offset.y,
self.size.x,
self.size.y,
Some(view.as_ref()),
);
}
}

View File

@@ -41,7 +41,7 @@ impl ImageFormat for RGB8U {
const NUM_CHANNELS: usize = 3;
const FORMAT: u32 = WebGlRenderingCtx::RGB as u32;
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGB8 as i32;
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGB as i32;
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
const CHANNEL_TYPE: ChannelType = ChannelType::RGB8U;
@@ -71,7 +71,7 @@ impl ImageFormat for RGBA8U {
const NUM_CHANNELS: usize = 4;
const FORMAT: u32 = WebGlRenderingCtx::RGBA as u32;
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA8 as i32;
const INTERNAL_FORMAT: i32 = WebGlRenderingCtx::RGBA as i32;
const TYPE: u32 = WebGlRenderingCtx::UNSIGNED_BYTE;
const CHANNEL_TYPE: ChannelType = ChannelType::RGBA8U;

View File

@@ -17,28 +17,29 @@ where
}
}
use crate::image::format::ImageFormat;
use crate::image::Image;
use crate::texture::{Tex3D, Texture2DArray};
use cgmath::Vector3;
use wasm_bindgen::JsValue;
use crate::image::format::ImageFormat;
use crate::image::Image;
use crate::texture::Texture2DArray;
impl<F> Image for HTMLImage<F>
where
F: ImageFormat,
{
fn insert_into_3d_texture<T: Tex3D>(
fn tex_sub_image_3d(
&self,
// The texture array
textures: &T,
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
textures.tex_sub_image_3d_with_html_image_element(
offset.x,
offset.y,
offset.z,
&self.image,
);
textures[offset.z as usize]
.bind()
.tex_sub_image_2d_with_u32_and_u32_and_html_image_element(
offset.x,
offset.y,
&self.image,
);
Ok(())
}

View File

@@ -184,10 +184,10 @@ use self::html::HTMLImage;
use super::Texture2DArray;
use wasm_bindgen::JsValue;
pub trait Image {
fn insert_into_3d_texture<T: Tex3D>(
fn tex_sub_image_3d(
&self,
// The texture array
textures: &T,
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue>;
@@ -197,15 +197,15 @@ impl<'a, I> Image for &'a I
where
I: Image,
{
fn insert_into_3d_texture<T: Tex3D>(
fn tex_sub_image_3d(
&self,
// The texture array
textures: &T,
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
let image = &**self;
image.insert_into_3d_texture(textures, offset)?;
image.tex_sub_image_3d(textures, offset)?;
Ok(())
}
@@ -216,20 +216,22 @@ impl<I> Image for Rc<I>
where
I: Image,
{
fn insert_into_3d_texture<T: Tex3D>(
fn tex_sub_image_3d(
&self,
// The texture array
textures: &T,
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
let image = &**self;
image.insert_into_3d_texture(textures, offset)?;
image.tex_sub_image_3d(textures, offset)?;
Ok(())
}
}
use crate::Abort;
use std::sync::{Arc, Mutex};
/*impl<I> Image for Arc<Mutex<Option<I>>>
where
I: Image,
@@ -251,10 +253,7 @@ where
#[cfg(feature = "webgl2")]
use crate::image::format::{R16I, R32I, R64F, R8UI};
use crate::{
image::format::{R32F, RGB8U, RGBA8U},
texture::Tex3D,
};
use crate::image::format::{R32F, RGB8U, RGBA8U};
use bitmap::Bitmap;
use fits::Fits;
@@ -291,10 +290,10 @@ pub enum ImageType {
use cgmath::Vector3;
impl Image for ImageType {
fn insert_into_3d_texture<T: Tex3D>(
fn tex_sub_image_3d(
&self,
// The texture array
textures: &T,
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
@@ -308,23 +307,19 @@ impl Image for ImageType {
let mut bytes_reader = Cursor::new(raw_bytes.as_slice());
let fits_img = Fits::from_byte_slice(&mut bytes_reader)?;
fits_img.insert_into_3d_texture(textures, offset)?
fits_img.tex_sub_image_3d(textures, offset)?
}
ImageType::Canvas { canvas } => canvas.insert_into_3d_texture(textures, offset)?,
ImageType::ImageRgba8u { image } => image.insert_into_3d_texture(textures, offset)?,
ImageType::ImageRgb8u { image } => image.insert_into_3d_texture(textures, offset)?,
ImageType::HTMLImageRgba8u { image } => {
image.insert_into_3d_texture(textures, offset)?
}
ImageType::HTMLImageRgb8u { image } => {
image.insert_into_3d_texture(textures, offset)?
}
ImageType::RawRgb8u { image } => image.insert_into_3d_texture(textures, offset)?,
ImageType::RawRgba8u { image } => image.insert_into_3d_texture(textures, offset)?,
ImageType::RawR32f { image } => image.insert_into_3d_texture(textures, offset)?,
ImageType::RawR32i { image } => image.insert_into_3d_texture(textures, offset)?,
ImageType::RawR16i { image } => image.insert_into_3d_texture(textures, offset)?,
ImageType::RawR8ui { image } => image.insert_into_3d_texture(textures, offset)?,
ImageType::Canvas { canvas } => canvas.tex_sub_image_3d(textures, offset)?,
ImageType::ImageRgba8u { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::ImageRgb8u { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::HTMLImageRgba8u { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::HTMLImageRgb8u { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::RawRgb8u { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::RawRgba8u { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::RawR32f { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::RawR32i { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::RawR16i { image } => image.tex_sub_image_3d(textures, offset)?,
ImageType::RawR8ui { image } => image.tex_sub_image_3d(textures, offset)?,
}
Ok(())

View File

@@ -1,6 +1,5 @@
use crate::image::format::ImageFormat;
use crate::texture::pixel::Pixel;
use crate::texture::Tex3D;
#[derive(Debug)]
#[allow(dead_code)]
pub struct ImageBuffer<T>
@@ -32,14 +31,10 @@ where
Self { data, size }
}
pub fn from_encoded_raw_bytes(
raw_bytes: &[u8],
width: i32,
height: i32,
) -> Result<Self, JsValue> {
pub fn from_encoded_raw_bytes(raw_bytes: &[u8], width: i32, height: i32) -> Result<Self, JsValue> {
let mut decoded_bytes = match T::decode(raw_bytes).map_err(|e| JsValue::from_str(e))? {
Bytes::Borrowed(bytes) => bytes.to_vec(),
Bytes::Owned(bytes) => bytes,
Bytes::Owned(bytes) => bytes
};
let decoded_pixels = unsafe {
@@ -85,7 +80,12 @@ where
ImageBuffer::<T>::new(data, width, height)
}
pub fn tex_sub(&mut self, src: &Self, s: &ImageBufferView, d: &ImageBufferView) {
pub fn tex_sub(
&mut self,
src: &Self,
s: &ImageBufferView,
d: &ImageBufferView,
) {
let mut di = d.x;
let mut dj = d.y;
@@ -144,24 +144,24 @@ impl<I> Image for ImageBuffer<I>
where
I: ImageFormat,
{
fn insert_into_3d_texture<T: Tex3D>(
fn tex_sub_image_3d(
&self,
// The texture array
textures: &T,
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
let js_array =
<<<I as ImageFormat>::P as Pixel>::Container as ArrayBuffer>::new(&self.data);
textures.tex_sub_image_3d_with_opt_array_buffer_view(
offset.x,
offset.y,
offset.z,
self.width(),
self.height(),
1,
Some(js_array.as_ref()),
);
textures[offset.z as usize]
.bind()
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
offset.x,
offset.y,
self.size.x,
self.size.y,
Some(js_array.as_ref()),
);
Ok(())
}

View File

@@ -1,16 +1,14 @@
use {wasm_bindgen::prelude::*, web_sys::WebGlFramebuffer};
use crate::webgl_ctx::WebGlRenderingCtx;
// Internal format used for the framebuffer final texture
use crate::image::format::RGBA8U;
pub struct FrameBufferObject {
gl: WebGlContext,
fbo: WebGlFramebuffer,
pub texture: Texture2D,
}
use crate::texture::Texture2D;
use crate::webgl_ctx::WebGlContext;
use crate::texture::Texture2D;
impl FrameBufferObject {
pub fn new(gl: &WebGlContext, width: usize, height: usize) -> Result<Self, JsValue> {
@@ -19,7 +17,7 @@ impl FrameBufferObject {
.ok_or("failed to create framebuffer")?;
gl.bind_framebuffer(WebGlRenderingCtx::FRAMEBUFFER, Some(&fbo));
let texture = Texture2D::create_empty_with_format::<RGBA8U>(
let texture = Texture2D::create_empty_with_format::<crate::image::format::RGBA8U>(
gl,
width as i32,
height as i32,
@@ -62,39 +60,29 @@ impl FrameBufferObject {
self.texture.height() as usize,
)
{
drop(self.texture.clone());
self.gl
.bind_framebuffer(WebGlRenderingCtx::FRAMEBUFFER, Some(&self.fbo));
self.texture = Texture2D::create_empty_with_format::<RGBA8U>(
&self.gl,
width as i32,
height as i32,
&[
(
WebGlRenderingCtx::TEXTURE_MIN_FILTER,
WebGlRenderingCtx::LINEAR,
),
(
WebGlRenderingCtx::TEXTURE_MAG_FILTER,
WebGlRenderingCtx::LINEAR,
),
// Prevents s-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_S,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents t-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_T,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
],
)
.unwrap();
self.texture.attach_to_framebuffer();
self.gl
.bind_framebuffer(WebGlRenderingCtx::FRAMEBUFFER, None);
//let pixels = [0, 0, 0, 0].iter().cloned().cycle().take(4*height*width).collect::<Vec<_>>();
#[cfg(feature = "webgl2")]
self.texture
.bind_mut()
.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
width as i32,
height as i32,
WebGlRenderingCtx::SRGB8_ALPHA8 as i32,
WebGlRenderingCtx::RGBA,
WebGlRenderingCtx::UNSIGNED_BYTE,
None,
);
#[cfg(feature = "webgl1")]
self.texture
.bind_mut()
.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
width as i32,
height as i32,
WebGlRenderingCtx::RGBA as i32,
WebGlRenderingCtx::RGBA,
WebGlRenderingCtx::UNSIGNED_BYTE,
None,
);
}
}
@@ -118,6 +106,7 @@ impl FrameBufferObject {
self.bind();
// clear the fbo
self.gl.clear_color(0.0, 0.0, 0.0, 1.0);
self.gl.clear(WebGlRenderingCtx::COLOR_BUFFER_BIT);
// render all the things onto the fbo

View File

@@ -1,57 +1,199 @@
use crate::image::format::ImageFormat;
use web_sys::HtmlCanvasElement;
use web_sys::WebGlTexture;
use crate::Abort;
use crate::texture::Texture2DMeta;
use crate::webgl_ctx::WebGlContext;
use crate::webgl_ctx::WebGlRenderingCtx;
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::HtmlCanvasElement;
use web_sys::HtmlImageElement;
/// Some GPU texture relative:
// * Usual texture parameters when defining a texture
pub const TEX_PARAMS: &'static [(u32, u32); 4] = &[
(
WebGlRenderingCtx::TEXTURE_MIN_FILTER,
WebGlRenderingCtx::NEAREST,
),
(
WebGlRenderingCtx::TEXTURE_MAG_FILTER,
WebGlRenderingCtx::NEAREST,
),
// Prevents s-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_S,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents t-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_T,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
];
pub static mut CUR_IDX_TEX_UNIT: u8 = 0;
#[derive(Clone)]
pub struct Texture3D {
gl: WebGlContext,
#[allow(dead_code)]
struct Texture3DMeta {
pub format: u32,
pub internal_format: i32,
pub type_: u32,
texture: Option<WebGlTexture>,
metadata: Option<Rc<RefCell<Texture2DMeta>>>,
depth: i32,
pub width: u32,
pub height: u32,
}
use web_sys::WebGlTexture;
#[derive(Clone)]
pub struct Texture3D {
pub texture: Option<WebGlTexture>,
gl: WebGlContext,
metadata: Option<Rc<RefCell<Texture3DMeta>>>,
}
pub enum SamplerType {
Float,
Integer,
Unsigned,
}
use crate::image::format::ImageFormat;
//use super::pixel::PixelType;
use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
impl Texture3D {
pub fn create_empty<F: ImageFormat>(
/*pub fn create_from_path<P: AsRef<Path>, F: ImageFormat>(
gl: &WebGlContext,
// The weight of the individual textures
width: i32,
// Their height
height: i32,
// The depth of the cube
depth: i32,
name: &'static str,
src: &P,
tex_params: &'static [(u32, u32)],
) -> Result<Self, JsValue> {
) -> Result<Texture3D, JsValue> {
let image = HtmlImageElement::new().unwrap_abort();
let texture = gl.create_texture();
let onerror = {
Closure::wrap(Box::new(move || {
println!("Cannot load texture located at: {:?}", name);
}) as Box<dyn Fn()>)
};
gl.bind_texture(WebGlRenderingCtx::TEXTURE_3D, texture.as_ref());
let width = image.width();
let height = image.height();
for (pname, param) in tex_params.iter() {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_3D, *pname, *param as i32);
}
let metadata = Rc::new(RefCell::new(Texture3DMeta {
width: width,
height: height,
internal_format: F::INTERNAL_FORMAT,
format: F::FORMAT,
type_: F::TYPE,
}));
gl.tex_storage_3d(
WebGlRenderingCtx::TEXTURE_3D,
1,
F::INTERNAL_FORMAT as u32,
width,
height,
depth,
);
let onload = {
let image = image.clone();
let gl = gl.clone();
let texture = texture.clone();
let metadata = metadata.clone();
Closure::wrap(Box::new(move || {
gl.bind_texture(WebGlRenderingCtx::TEXTURE_2D, texture.as_ref());
for (pname, param) in tex_params.iter() {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D, *pname, *param as i32);
}
#[cfg(feature = "webgl2")]
gl.tex_image_2d_with_u32_and_u32_and_html_image_element(
WebGlRenderingCtx::TEXTURE_2D,
0,
F::INTERNAL_FORMAT,
F::FORMAT,
F::TYPE,
&image,
)
.expect("Texture 2D");
metadata.borrow_mut().width = image.width();
metadata.borrow_mut().height = image.height();
//gl.generate_mipmap(WebGl2RenderingContext::TEXTURE_2D);
}) as Box<dyn Fn()>)
};
image.set_onload(Some(onload.as_ref().unchecked_ref()));
image.set_onerror(Some(onerror.as_ref().unchecked_ref()));
image.set_cross_origin(Some(""));
image.set_src(src.as_ref().to_str().unwrap_abort());
onload.forget();
onerror.forget();
let gl = gl.clone();
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
Ok(Texture3D {
texture,
gl,
metadata: Some(metadata),
})
}*/
pub fn create_from_raw_pixels<F: ImageFormat>(
gl: &WebGlContext,
width: i32,
height: i32,
tex_params: &'static [(u32, u32)],
data: Option<&[<F::P as Pixel>::Item]>,
) -> Result<Texture3D, JsValue> {
let texture = Texture3D::create_empty_with_format::<F>(gl, width, height, tex_params)?;
if let Some(data) = data {
let buf_data = unsafe { F::view(data) };
texture
.bind()
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
0,
0,
width,
height,
Some(buf_data.as_ref()),
);
}
Ok(texture)
}
pub fn create_from_raw_bytes<F: ImageFormat>(
gl: &WebGlContext,
width: i32,
height: i32,
tex_params: &'static [(u32, u32)],
bytes: Option<&[u8]>,
) -> Result<Texture3D, JsValue> {
let texture = gl.create_texture();
gl.bind_texture(WebGlRenderingCtx::TEXTURE_2D, texture.as_ref());
for (pname, param) in tex_params.iter() {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D, *pname, *param as i32);
}
gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
WebGlRenderingCtx::TEXTURE_2D,
0,
F::INTERNAL_FORMAT,
width,
height,
0,
F::FORMAT,
F::TYPE,
bytes,
)
.expect("Texture 2D");
let gl = gl.clone();
let metadata = Some(Rc::new(RefCell::new(Texture3DMeta {
width: width as u32,
height: height as u32,
internal_format: F::INTERNAL_FORMAT,
@@ -61,21 +203,104 @@ impl Texture3D {
Ok(Texture3D {
texture,
gl: gl.clone(),
depth,
gl,
metadata,
})
}
pub fn generate_mipmap(&self) {
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_3D);
pub fn create_empty_unsized(
gl: &WebGlContext,
tex_params: &'static [(u32, u32)],
) -> Result<Texture3D, JsValue> {
let texture = gl.create_texture();
gl.bind_texture(WebGlRenderingCtx::TEXTURE_2D, texture.as_ref());
for (pname, param) in tex_params.iter() {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D, *pname, *param as i32);
}
let gl = gl.clone();
let metadata = None;
Ok(Texture3D {
texture,
gl,
metadata,
})
}
pub fn bind(&self) -> Texture3DBound {
self.gl
.bind_texture(WebGlRenderingCtx::TEXTURE_3D, self.texture.as_ref());
pub fn create_empty_with_format<F: ImageFormat>(
gl: &WebGlContext,
width: i32,
height: i32,
tex_params: &'static [(u32, u32)],
) -> Result<Texture3D, JsValue> {
let texture = gl.create_texture();
Texture3DBound { tex: self }
gl.bind_texture(WebGlRenderingCtx::TEXTURE_2D, texture.as_ref());
for (pname, param) in tex_params.iter() {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D, *pname, *param as i32);
}
gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
WebGlRenderingCtx::TEXTURE_2D,
0,
F::INTERNAL_FORMAT,
width,
height,
0,
F::FORMAT,
F::TYPE,
None,
)
.expect("Texture 2D");
let gl = gl.clone();
let metadata = Some(Rc::new(RefCell::new(Texture3DMeta {
width: width as u32,
height: height as u32,
internal_format: F::INTERNAL_FORMAT,
format: F::FORMAT,
type_: F::TYPE,
})));
Ok(Texture3D {
texture,
gl,
metadata,
})
}
pub fn attach_to_framebuffer(&self) {
self.gl.framebuffer_texture_2d(
WebGlRenderingCtx::FRAMEBUFFER,
WebGlRenderingCtx::COLOR_ATTACHMENT0,
WebGlRenderingCtx::TEXTURE_2D,
self.texture.as_ref(),
0,
);
}
pub fn get_size(&self) -> (u32, u32) {
(
self.metadata.as_ref().unwrap_abort().borrow().width,
self.metadata.as_ref().unwrap_abort().borrow().height,
)
}
pub fn width(&self) -> u32 {
self.metadata.as_ref().unwrap_abort().borrow().width
}
pub fn height(&self) -> u32 {
self.metadata.as_ref().unwrap_abort().borrow().height
}
pub fn active_texture(&self, idx_tex_unit: u8) -> &Self {
@@ -83,84 +308,162 @@ impl Texture3D {
.active_texture(WebGlRenderingCtx::TEXTURE0 + idx_tex_unit as u32);
self
}
pub fn bind(&self) -> Texture3DBound {
self.gl
.bind_texture(WebGlRenderingCtx::TEXTURE_2D, self.texture.as_ref());
Texture3DBound { texture: self }
}
pub fn bind_mut(&mut self) -> Texture3DBoundMut {
self.gl
.bind_texture(WebGlRenderingCtx::TEXTURE_2D, self.texture.as_ref());
Texture3DBoundMut { texture: self }
}
pub fn read_pixel(&self, x: i32, y: 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.attach_to_framebuffer();
self.gl.framebuffer_texture_2d(
WebGlRenderingCtx::READ_FRAMEBUFFER,
WebGlRenderingCtx::COLOR_ATTACHMENT0,
WebGlRenderingCtx::TEXTURE_2D,
self.texture.as_ref(),
0,
);
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(x, y, 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 Texture3D {
fn drop(&mut self) {
self.gl.delete_texture(self.texture.as_ref());
}
}
use super::CUR_IDX_TEX_UNIT;
use crate::shader::UniformType;
use web_sys::WebGlUniformLocation;
impl UniformType for Texture3D {
fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, tex: &Self) {
// free the texture unit
/*let i = (self.idx_texture_unit - WebGl2RenderingContext::TEXTURE0) as usize;
unsafe {
let _ = tex
// 1. Active the texture unit of the texture
.active_texture(CUR_IDX_TEX_UNIT)
// 2. Bind the texture to that texture unit
.bind();
gl.uniform1i(location, CUR_IDX_TEX_UNIT as i32);
CUR_IDX_TEX_UNIT += 1;
};
AVAILABLE_TEX_UNITS[i] = Some(self.idx_texture_unit);
}*/
}
}
use crate::Abort;
pub struct Texture3DBound<'a> {
tex: &'a Texture3D,
texture: &'a Texture3D,
}
impl<'a> Texture3DBound<'a> {
pub fn tex_sub_image_3d_with_html_image_element(
pub fn tex_sub_image_2d_with_u32_and_u32_and_html_image_element(
&self,
dx: i32,
dy: i32,
dz: i32,
image: &HtmlImageElement,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
let metadata = self.texture.metadata.as_ref().unwrap_abort().borrow();
self.tex
#[cfg(feature = "webgl2")]
self.texture
.gl
.tex_sub_image_3d_with_html_image_element(
WebGlRenderingCtx::TEXTURE_3D,
.tex_sub_image_2d_with_u32_and_u32_and_html_image_element(
WebGlRenderingCtx::TEXTURE_2D,
0,
dx,
dy,
dz,
image.width() as i32,
image.height() as i32,
1,
metadata.format,
metadata.type_,
image,
)
.expect("Sub texture 3d");
.expect("Sub texture 2d");
}
pub fn tex_sub_image_3d_with_html_canvas_element(
pub fn tex_sub_image_2d_with_u32_and_u32_and_html_canvas_element(
&self,
dx: i32,
dy: i32,
dz: i32,
canvas: &HtmlCanvasElement,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
let metadata = self.texture.metadata.as_ref().unwrap_abort().borrow();
self.tex
#[cfg(feature = "webgl2")]
self.texture
.gl
.tex_sub_image_3d_with_html_canvas_element(
WebGlRenderingCtx::TEXTURE_3D,
.tex_sub_image_2d_with_u32_and_u32_and_html_canvas_element(
WebGlRenderingCtx::TEXTURE_2D,
0,
dx,
dy,
dz,
canvas.width() as i32,
canvas.height() as i32,
1,
metadata.format,
metadata.type_,
canvas,
@@ -168,26 +471,22 @@ impl<'a> Texture3DBound<'a> {
.expect("Sub texture 2d");
}
pub fn tex_sub_image_3d_with_image_bitmap(
pub fn tex_sub_image_2d_with_u32_and_u32_and_image_bitmap(
&self,
dx: i32,
dy: i32,
dz: i32,
image: &web_sys::ImageBitmap,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
let metadata = self.texture.metadata.as_ref().unwrap_abort().borrow();
self.tex
#[cfg(feature = "webgl2")]
self.texture
.gl
.tex_sub_image_3d_with_image_bitmap(
WebGlRenderingCtx::TEXTURE_3D,
.tex_sub_image_2d_with_u32_and_u32_and_image_bitmap(
WebGlRenderingCtx::TEXTURE_2D,
0,
dx,
dy,
dz,
image.width() as i32,
image.height() as i32,
1,
metadata.format,
metadata.type_,
image,
@@ -195,29 +494,25 @@ impl<'a> Texture3DBound<'a> {
.expect("Sub texture 2d");
}
pub fn tex_sub_image_3d_with_opt_array_buffer_view(
pub fn tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
&self,
dx: i32,
dy: i32,
dz: i32,
w: i32,
h: i32,
d: i32,
width: i32, // Width of the image
height: i32, // Height of the image
image: Option<&js_sys::Object>,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
let metadata = self.texture.metadata.as_ref().unwrap_abort().borrow();
self.tex
self.texture
.gl
.tex_sub_image_3d_with_opt_array_buffer_view(
WebGlRenderingCtx::TEXTURE_3D,
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
WebGlRenderingCtx::TEXTURE_2D,
0,
dx,
dy,
dz,
w,
h,
d,
width,
height,
metadata.format,
metadata.type_,
image,
@@ -226,28 +521,24 @@ impl<'a> Texture3DBound<'a> {
}
#[allow(dead_code)]
pub fn tex_sub_image_3d_with_opt_u8_array(
pub fn tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_u8_array(
&self,
idx: i32,
dx: i32,
dy: i32,
w: i32,
h: i32,
d: i32,
width: i32, // Width of the image
height: i32, // Height of the image
pixels: Option<&[u8]>,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
self.tex
let metadata = self.texture.metadata.as_ref().unwrap_abort().borrow();
self.texture
.gl
.tex_sub_image_3d_with_opt_u8_array(
WebGlRenderingCtx::TEXTURE_3D,
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_u8_array(
WebGlRenderingCtx::TEXTURE_2D,
0,
dx,
dy,
idx,
w,
h,
d,
width,
height,
metadata.format,
metadata.type_,
pixels,
@@ -255,3 +546,70 @@ impl<'a> Texture3DBound<'a> {
.expect("Sub texture 2d");
}
}
pub struct Texture3DBoundMut<'a> {
texture &'a mut Texture3D,
}
impl<'a> Texture3DBoundMut<'a> {
#[allow(dead_code)]
pub fn tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
&mut self,
width: i32, // Width of the image
height: i32, // Height of the image
internal_format: i32,
src_format: u32,
src_type: u32,
pixels: Option<&[u8]>,
) {
self.texture
.gl
.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
WebGlRenderingCtx::TEXTURE_2D,
0,
internal_format as i32,
width as i32,
height as i32,
0,
src_format,
src_type,
pixels,
)
.expect("Sub texture 2d");
//self.texture.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_2D);
self.texture.metadata = Some(Rc::new(RefCell::new(Texture3DMeta {
format: src_format,
internal_format,
type_: src_type,
width: width as u32,
height: height as u32,
})));
}
pub fn tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
&self,
dx: i32,
dy: i32,
width: i32, // Width of the image
height: i32, // Height of the image
image: Option<&js_sys::Object>,
) {
let metadata = self.texture.metadata.as_ref().unwrap_abort().borrow();
self.texture
.gl
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
WebGlRenderingCtx::TEXTURE_2D,
0,
dx,
dy,
width,
height,
metadata.format,
metadata.type_,
image,
)
.expect("Sub texture 2d");
}
}

View File

@@ -1,336 +0,0 @@
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;
use crate::Abort;
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use web_sys::HtmlImageElement;
pub struct Texture2DArray {
gl: WebGlContext,
texture: Option<WebGlTexture>,
metadata: Option<Rc<RefCell<Texture2DMeta>>>,
pub num_slices: i32,
}
impl Texture2DArray {
pub fn create_empty<F: ImageFormat>(
gl: &WebGlContext,
// The weight of the individual textures
width: i32,
// Their height
height: i32,
// How many texture slices it contains
num_slices: i32,
tex_params: &'static [(u32, u32)],
) -> Result<Texture2DArray, JsValue> {
let texture = gl.create_texture();
gl.bind_texture(WebGlRenderingCtx::TEXTURE_2D_ARRAY, texture.as_ref());
for (pname, param) in tex_params.iter() {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D_ARRAY, *pname, *param as i32);
}
gl.tex_storage_3d(
WebGlRenderingCtx::TEXTURE_2D_ARRAY,
1,
F::INTERNAL_FORMAT as u32,
width,
height,
num_slices,
);
let gl = gl.clone();
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
width: width as u32,
height: height as u32,
internal_format: F::INTERNAL_FORMAT,
format: F::FORMAT,
type_: F::TYPE,
})));
Ok(Texture2DArray {
texture,
gl: gl.clone(),
num_slices,
metadata,
})
}
pub fn generate_mipmap(&self) {
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_2D_ARRAY);
}
pub fn bind(&self) -> Texture2DArrayBound {
self.gl
.bind_texture(WebGlRenderingCtx::TEXTURE_2D_ARRAY, self.texture.as_ref());
Texture2DArrayBound { tex: self }
}
pub fn active_texture(&self, idx_tex_unit: u8) -> &Self {
self.gl
.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 {
fn drop(&mut self) {
self.gl.delete_texture(self.texture.as_ref());
}
}
use super::CUR_IDX_TEX_UNIT;
use crate::shader::UniformType;
use web_sys::WebGlUniformLocation;
impl UniformType for Texture2DArray {
fn uniform(gl: &WebGlContext, location: Option<&WebGlUniformLocation>, tex: &Self) {
unsafe {
let _ = tex
// 1. Active the texture unit of the texture
.active_texture(CUR_IDX_TEX_UNIT)
// 2. Bind the texture to that texture unit
.bind();
gl.uniform1i(location, CUR_IDX_TEX_UNIT as i32);
CUR_IDX_TEX_UNIT += 1;
};
}
}
pub struct Texture2DArrayBound<'a> {
tex: &'a Texture2DArray,
}
impl<'a> Texture2DArrayBound<'a> {
pub fn tex_sub_image_3d_with_html_image_element(
&self,
dx: i32,
dy: i32,
idx: i32,
image: &HtmlImageElement,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
self.tex
.gl
.tex_sub_image_3d_with_html_image_element(
WebGlRenderingCtx::TEXTURE_2D_ARRAY,
0,
dx,
dy,
idx,
image.width() as i32,
image.height() as i32,
1,
metadata.format,
metadata.type_,
image,
)
.expect("Sub texture 3d");
}
pub fn tex_sub_image_3d_with_html_canvas_element(
&self,
dx: i32,
dy: i32,
idx: i32,
canvas: &HtmlCanvasElement,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
self.tex
.gl
.tex_sub_image_3d_with_html_canvas_element(
WebGlRenderingCtx::TEXTURE_2D_ARRAY,
0,
dx,
dy,
idx,
canvas.width() as i32,
canvas.height() as i32,
1,
metadata.format,
metadata.type_,
canvas,
)
.expect("Sub texture 2d");
}
pub fn tex_sub_image_3d_with_image_bitmap(
&self,
dx: i32,
dy: i32,
idx: i32,
image: &web_sys::ImageBitmap,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
self.tex
.gl
.tex_sub_image_3d_with_image_bitmap(
WebGlRenderingCtx::TEXTURE_2D_ARRAY,
0,
dx,
dy,
idx,
image.width() as i32,
image.height() as i32,
1,
metadata.format,
metadata.type_,
image,
)
.expect("Sub texture 2d");
}
pub fn tex_sub_image_3d_with_opt_array_buffer_view(
&self,
dx: i32,
dy: i32,
idx: i32,
w: i32,
h: i32,
image: Option<&js_sys::Object>,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
self.tex
.gl
.tex_sub_image_3d_with_opt_array_buffer_view(
WebGlRenderingCtx::TEXTURE_2D_ARRAY,
0,
dx,
dy,
idx,
w,
h,
1,
metadata.format,
metadata.type_,
image,
)
.expect("Sub texture 2d");
}
#[allow(dead_code)]
pub fn tex_sub_image_3d_with_opt_u8_array(
&self,
dx: i32,
dy: i32,
idx: i32,
w: i32,
h: i32,
pixels: Option<&[u8]>,
) {
let metadata = self.tex.metadata.as_ref().unwrap_abort().borrow();
self.tex
.gl
.tex_sub_image_3d_with_opt_u8_array(
WebGlRenderingCtx::TEXTURE_2D_ARRAY,
0,
dx,
dy,
idx,
w,
h,
1,
metadata.format,
metadata.type_,
pixels,
)
.expect("Sub texture 2d");
}
}

View File

@@ -1,15 +1,9 @@
pub mod array;
pub use array::Texture2DArray;
pub mod texture_array;
pub use texture_array::Texture2DArray;
pub mod pixel;
pub use pixel::*;
#[path = "3d.rs"]
pub mod mod_3d;
pub use mod_3d::Texture3D;
use web_sys::HtmlCanvasElement;
use web_sys::WebGlTexture;
use crate::webgl_ctx::WebGlContext;
use crate::webgl_ctx::WebGlRenderingCtx;
@@ -17,11 +11,34 @@ use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::HtmlImageElement;
/// Some GPU texture relative:
// * Usual texture parameters when defining a texture
pub const TEX_PARAMS: &'static [(u32, u32); 4] = &[
(
WebGlRenderingCtx::TEXTURE_MIN_FILTER,
WebGlRenderingCtx::NEAREST,
),
(
WebGlRenderingCtx::TEXTURE_MAG_FILTER,
WebGlRenderingCtx::NEAREST,
),
// Prevents s-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_S,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents t-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_T,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
];
pub static mut CUR_IDX_TEX_UNIT: u8 = 0;
#[derive(Clone)]
#[allow(dead_code)]
pub struct Texture2DMeta {
struct Texture2DMeta {
pub format: u32,
pub internal_format: i32,
pub type_: u32,
@@ -30,6 +47,7 @@ pub struct Texture2DMeta {
pub height: u32,
}
use web_sys::WebGlTexture;
#[derive(Clone)]
pub struct Texture2D {
pub texture: Option<WebGlTexture>,
@@ -59,9 +77,7 @@ impl Texture2D {
) -> Result<Texture2D, JsValue> {
let image = HtmlImageElement::new().unwrap_abort();
#[cfg(feature = "webgl2")]
let texture = gl.create_texture();
let onerror = {
Closure::wrap(Box::new(move || {
println!("Cannot load texture located at: {:?}", name);
@@ -79,7 +95,6 @@ impl Texture2D {
type_: F::TYPE,
}));
#[cfg(feature = "webgl2")]
let onload = {
let image = image.clone();
let gl = gl.clone();
@@ -93,20 +108,21 @@ impl Texture2D {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D, *pname, *param as i32);
}
gl.tex_storage_2d(
WebGlRenderingCtx::TEXTURE_2D,
1,
F::INTERNAL_FORMAT as u32,
width as i32,
height as i32,
);
gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_html_image_element(
#[cfg(feature = "webgl2")]
gl.tex_image_2d_with_u32_and_u32_and_html_image_element(
WebGlRenderingCtx::TEXTURE_2D,
0,
F::INTERNAL_FORMAT,
F::FORMAT,
F::TYPE,
&image,
)
.expect("Texture 2D");
#[cfg(feature = "webgl1")]
gl.tex_image_2d_with_u32_and_u32_and_image(
WebGlRenderingCtx::TEXTURE_2D,
0,
0,
width as i32,
height as i32,
F::INTERNAL_FORMAT,
F::FORMAT,
F::TYPE,
&image,
@@ -115,6 +131,8 @@ impl Texture2D {
metadata.borrow_mut().width = image.width();
metadata.borrow_mut().height = image.height();
//gl.generate_mipmap(WebGl2RenderingContext::TEXTURE_2D);
}) as Box<dyn Fn()>)
};
@@ -129,7 +147,6 @@ impl Texture2D {
let gl = gl.clone();
Ok(Texture2D {
#[cfg(feature = "webgl2")]
texture,
gl,
@@ -178,20 +195,13 @@ impl Texture2D {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D, *pname, *param as i32);
}
gl.tex_storage_2d(
WebGlRenderingCtx::TEXTURE_2D,
1,
F::INTERNAL_FORMAT as u32,
width,
height,
);
gl.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_u8_array(
gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
WebGlRenderingCtx::TEXTURE_2D,
0,
0,
0,
F::INTERNAL_FORMAT,
width,
height,
0,
F::FORMAT,
F::TYPE,
bytes,
@@ -216,6 +226,30 @@ impl Texture2D {
})
}
pub fn create_empty_unsized(
gl: &WebGlContext,
tex_params: &'static [(u32, u32)],
) -> Result<Texture2D, JsValue> {
let texture = gl.create_texture();
gl.bind_texture(WebGlRenderingCtx::TEXTURE_2D, texture.as_ref());
for (pname, param) in tex_params.iter() {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D, *pname, *param as i32);
}
let gl = gl.clone();
let metadata = None;
Ok(Texture2D {
texture,
gl,
metadata,
})
}
pub fn create_empty_with_format<F: ImageFormat>(
gl: &WebGlContext,
width: i32,
@@ -230,13 +264,18 @@ impl Texture2D {
gl.tex_parameteri(WebGlRenderingCtx::TEXTURE_2D, *pname, *param as i32);
}
gl.tex_storage_2d(
gl.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
WebGlRenderingCtx::TEXTURE_2D,
1,
F::INTERNAL_FORMAT as u32,
0,
F::INTERNAL_FORMAT,
width,
height,
);
0,
F::FORMAT,
F::TYPE,
None,
)
.expect("Texture 2D");
let gl = gl.clone();
let metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
@@ -265,10 +304,6 @@ impl Texture2D {
);
}
pub fn generate_mipmap(&self) {
self.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_2D);
}
pub fn get_size(&self) -> (u32, u32) {
(
self.metadata.as_ref().unwrap_abort().borrow().width,
@@ -297,6 +332,13 @@ impl Texture2D {
Texture2DBound { texture_2d: self }
}
pub fn bind_mut(&mut self) -> Texture2DBoundMut {
self.gl
.bind_texture(WebGlRenderingCtx::TEXTURE_2D, self.texture.as_ref());
Texture2DBoundMut { texture_2d: self }
}
pub fn read_pixel(&self, x: i32, y: i32) -> Result<JsValue, JsValue> {
// Create and bind the framebuffer
let reader = self.gl.create_framebuffer();
@@ -328,8 +370,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(0, 0, metadata.width as i32, metadata.height as i32);
.viewport(x, y, metadata.width as i32, metadata.height as i32);
#[cfg(feature = "webgl2")]
let value = match (metadata.format, metadata.type_) {
(WebGlRenderingCtx::RED_INTEGER, WebGlRenderingCtx::UNSIGNED_BYTE) => {
@@ -360,6 +401,24 @@ impl Texture2D {
"Pixel retrieval not implemented for that texture format.",
)),
};
#[cfg(feature = "webgl1")]
let value = match (*format, *type_) {
(WebGlRenderingCtx::LUMINANCE_ALPHA, WebGlRenderingCtx::FLOAT) => {
let p = <[f32; 1]>::read_pixel(&self.gl, x, y)?;
Ok(serde_wasm_bindgen::to_value(&p)?)
}
(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
@@ -563,176 +622,69 @@ impl<'a> Texture2DBound<'a> {
}
}
pub trait Tex3D {
fn tex_sub_image_3d_with_html_image_element(
&self,
dx: i32,
dy: i32,
dz: i32,
image: &HtmlImageElement,
);
fn tex_sub_image_3d_with_html_canvas_element(
&self,
dx: i32,
dy: i32,
dz: i32,
canvas: &HtmlCanvasElement,
);
fn tex_sub_image_3d_with_image_bitmap(
&self,
dx: i32,
dy: i32,
dz: i32,
image: &web_sys::ImageBitmap,
);
fn tex_sub_image_3d_with_opt_array_buffer_view(
&self,
dx: i32,
dy: i32,
dz: i32,
w: i32,
h: i32,
d: i32,
view: Option<&js_sys::Object>,
);
fn tex_sub_image_3d_with_opt_u8_array(
&self,
dx: i32,
dy: i32,
dz: i32,
w: i32,
h: i32,
d: i32,
pixels: Option<&[u8]>,
);
pub struct Texture2DBoundMut<'a> {
texture_2d: &'a mut Texture2D,
}
impl Tex3D for Texture3D {
fn tex_sub_image_3d_with_html_image_element(
&self,
dx: i32,
dy: i32,
dz: i32,
image: &HtmlImageElement,
) {
self.bind()
.tex_sub_image_3d_with_html_image_element(dx, dy, dz, image);
}
fn tex_sub_image_3d_with_html_canvas_element(
&self,
dx: i32,
dy: i32,
dz: i32,
canvas: &HtmlCanvasElement,
) {
self.bind()
.tex_sub_image_3d_with_html_canvas_element(dx, dy, dz, canvas);
}
fn tex_sub_image_3d_with_image_bitmap(
&self,
dx: i32,
dy: i32,
dz: i32,
image: &web_sys::ImageBitmap,
) {
self.bind()
.tex_sub_image_3d_with_image_bitmap(dx, dy, dz, image);
}
fn tex_sub_image_3d_with_opt_array_buffer_view(
&self,
dx: i32,
dy: i32,
dz: i32,
w: i32,
h: i32,
d: i32,
view: Option<&js_sys::Object>,
) {
self.bind()
.tex_sub_image_3d_with_opt_array_buffer_view(dx, dy, dz, w, h, d, view);
}
fn tex_sub_image_3d_with_opt_u8_array(
&self,
dx: i32,
dy: i32,
dz: i32,
w: i32,
h: i32,
d: i32,
impl<'a> Texture2DBoundMut<'a> {
#[allow(dead_code)]
pub fn tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
&mut self,
width: i32, // Width of the image
height: i32, // Height of the image
internal_format: i32,
src_format: u32,
src_type: u32,
pixels: Option<&[u8]>,
) {
self.bind()
.tex_sub_image_3d_with_opt_u8_array(dx, dy, dz, w, h, d, pixels);
}
}
impl Tex3D for Texture2DArray {
fn tex_sub_image_3d_with_html_image_element(
&self,
dx: i32,
dy: i32,
dz: i32,
image: &HtmlImageElement,
) {
self.bind()
.tex_sub_image_3d_with_html_image_element(dx, dy, dz, image);
}
fn tex_sub_image_3d_with_html_canvas_element(
&self,
dx: i32,
dy: i32,
dz: i32,
canvas: &HtmlCanvasElement,
) {
self.bind()
.tex_sub_image_3d_with_html_canvas_element(dx, dy, dz, canvas);
}
fn tex_sub_image_3d_with_image_bitmap(
&self,
dx: i32,
dy: i32,
dz: i32,
image: &web_sys::ImageBitmap,
) {
self.bind()
.tex_sub_image_3d_with_image_bitmap(dx, dy, dz, image);
}
fn tex_sub_image_3d_with_opt_array_buffer_view(
&self,
dx: i32,
dy: i32,
dz: i32,
w: i32,
h: i32,
_d: i32,
view: Option<&js_sys::Object>,
) {
self.bind()
.tex_sub_image_3d_with_opt_array_buffer_view(dx, dy, dz, w, h, view);
}
fn tex_sub_image_3d_with_opt_u8_array(
&self,
dx: i32,
dy: i32,
dz: i32,
w: i32,
h: i32,
_d: i32,
pixels: Option<&[u8]>,
) {
self.bind()
.tex_sub_image_3d_with_opt_u8_array(dx, dy, dz, w, h, pixels);
self.texture_2d
.gl
.tex_image_2d_with_i32_and_i32_and_i32_and_format_and_type_and_opt_u8_array(
WebGlRenderingCtx::TEXTURE_2D,
0,
internal_format as i32,
width as i32,
height as i32,
0,
src_format,
src_type,
pixels,
)
.expect("Sub texture 2d");
//self.texture_2d.gl.generate_mipmap(WebGlRenderingCtx::TEXTURE_2D);
self.texture_2d.metadata = Some(Rc::new(RefCell::new(Texture2DMeta {
format: src_format,
internal_format,
type_: src_type,
width: width as u32,
height: height as u32,
})));
}
pub fn tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
&self,
dx: i32,
dy: i32,
width: i32, // Width of the image
height: i32, // Height of the image
image: Option<&js_sys::Object>,
) {
let metadata = self.texture_2d.metadata.as_ref().unwrap_abort().borrow();
self.texture_2d
.gl
.tex_sub_image_2d_with_i32_and_i32_and_u32_and_type_and_opt_array_buffer_view(
WebGlRenderingCtx::TEXTURE_2D,
0,
dx,
dy,
width,
height,
metadata.format,
metadata.type_,
image,
)
.expect("Sub texture 2d");
}
}

View File

@@ -0,0 +1,54 @@
use crate::image::format::ImageFormat;
use crate::webgl_ctx::WebGlContext;
pub struct Texture2DArray {
pub textures: Vec<Texture2D>,
}
use std::ops::Index;
impl Index<usize> for Texture2DArray {
type Output = Texture2D;
fn index(&self, idx: usize) -> &Self::Output {
&self.textures[idx]
}
}
use super::Texture2D;
use wasm_bindgen::prelude::*;
impl Texture2DArray {
pub fn create_empty<F: ImageFormat>(
gl: &WebGlContext,
// The weight of the individual textures
width: i32,
// Their height
height: i32,
// How many texture slices it contains
num_slices: i32,
tex_params: &'static [(u32, u32)],
) -> Result<Texture2DArray, JsValue> {
let textures: Result<Vec<_>, _> = (0..num_slices)
.map(|_| Texture2D::create_empty_with_format::<F>(gl, width, height, tex_params))
.collect();
Ok(Texture2DArray {
textures: textures?,
})
}
}
const TEX_UNIFORMS_NAME: &[&str] = &["tex1", "tex2", "tex3", "tex4", "tex5"];
use crate::shader::{SendUniforms, ShaderBound};
impl SendUniforms for Texture2DArray {
fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> {
let num_tex = self.textures.len();
for (idx, tex) in self.textures.iter().enumerate() {
let loc = TEX_UNIFORMS_NAME[idx];
shader.attach_uniform(loc, tex);
}
shader.attach_uniform("num_tex", &(num_tex as i32));
shader
}
}

View File

@@ -39,7 +39,6 @@ impl WebGlContext {
// preserveDrawingBuffer enabled for exporting the view as a PNG
let context_options =
js_sys::JSON::parse("{\"antialias\":false, \"preserveDrawingBuffer\": true}")?;
//js_sys::JSON::parse("{\"antialias\":false}")?;
#[cfg(feature = "webgl2")]
let gl = Rc::new(

View File

@@ -1,7 +1,5 @@
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,
@@ -28,6 +26,7 @@ use al_core::colormap::{Colormap, Colormaps};
use al_core::WebGlContext;
use super::coosys;
use crate::Abort;
use al_api::{
coo_system::CooSystem,
grid::GridCfg,
@@ -84,6 +83,7 @@ pub struct App {
out_of_fov: bool,
//tasks_finished: bool,
catalog_loaded: bool,
start_time_frame: Time,
last_time_request_for_new_tiles: Time,
request_for_new_tiles: bool,
@@ -131,15 +131,19 @@ impl App {
//let exec = Rc::new(RefCell::new(TaskExecutor::new()));
let projection = ProjectionType::Sin(mapproj::zenithal::sin::Sin);
gl.enable(WebGl2RenderingContext::BLEND);
gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);
// TODO: https://caniuse.com/?search=scissor is not supported for safari <= 14.1
// When it will be supported nearly everywhere, we will need to uncomment this line to
// enable it
//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
@@ -152,7 +156,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 hipss storing the textures of the resolved tiles
// The surveys storing the textures of the resolved tiles
let layers = Layers::new(&gl, &projection)?;
let time_start_blending = Time::now();
@@ -181,12 +185,13 @@ impl App {
let tile_fetcher = TileFetcherQueue::new();
//let ui = Gui::new(aladin_div_name, &gl)?;
let start_time_frame = Time::now();
let last_time_request_for_new_tiles = Time::now();
let request_for_new_tiles = true;
let moc = MOCRenderer::new(&gl)?;
gl.clear_color(0.0, 0.0, 0.0, 1.0);
gl.clear_color(0.15, 0.15, 0.15, 1.0);
let (img_send, img_recv) = async_channel::unbounded::<ImageLayer>();
let (ack_img_send, ack_img_recv) = async_channel::unbounded::<ImageParams>();
@@ -200,6 +205,7 @@ impl App {
Ok(App {
gl,
start_time_frame,
//ui,
shaders,
@@ -254,33 +260,39 @@ impl App {
}
fn look_for_new_tiles(&mut self) -> Result<(), JsValue> {
// Move the views of the different active hipss
// Move the views of the different active surveys
self.tile_fetcher.clear();
// 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;
}
// Loop over the surveys
for survey in self.layers.values_mut_hips() {
if self.camera.get_texture_depth() == 0
&& self
.downloader
.borrow()
.is_queried(&query::Allsky::new(survey.get_config()).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 min_tile_depth = survey
.get_config()
.delta_depth()
.max(survey.get_config().get_min_depth_tile());
let mut ancestors = HashSet::new();
let creator_did = cfg.get_creator_did().to_string();
let root_url = cfg.get_root_url().to_string();
let format = cfg.get_format();
let creator_did = survey.get_config().get_creator_did().to_string();
let root_url = survey.get_config().get_root_url().to_string();
let format = survey.get_config().get_format();
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));
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,
));
// check if we are starting aladin lite or not.
// If so we want to retrieve only the tiles in the view and access them
@@ -294,21 +306,14 @@ impl App {
}
}
// Request for ancestor
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));
}
}
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,
));
}
}
}
@@ -344,7 +349,7 @@ impl App {
colormap,
&mut self.shaders,
&self.camera,
self.hipss.get_view().unwrap_abort(),
self.surveys.get_view().unwrap_abort(),
);
self.catalog_loaded = true;
self.request_redraw = true;
@@ -379,7 +384,7 @@ impl App {
colormap,
&mut self.shaders,
&self.camera,
self.hipss.get_view().unwrap_abort(),
self.surveys.get_view().unwrap_abort(),
);
self.catalog_loaded = true;
self.request_redraw = true;
@@ -394,6 +399,7 @@ 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;
@@ -522,9 +528,12 @@ impl App {
return self.inertia.is_some();
}
pub(crate) fn update(&mut self, dt: DeltaTime) -> Result<bool, JsValue> {
pub(crate) fn update(&mut self, _dt: DeltaTime) -> Result<bool, JsValue> {
self.start_time_frame = Time::now();
//let available_tiles = self.run_tasks(dt)?;
if let Some(inertia) = self.inertia.as_mut() {
inertia.apply(&mut self.camera, &self.projection, dt);
inertia.apply(&mut self.camera, &self.projection);
// Always request for new tiles while moving
self.request_for_new_tiles = true;
@@ -534,49 +543,223 @@ impl App {
let thresh_speed = inertia.get_start_ampl() * 1e-3;
let cur_speed = inertia.get_cur_speed();
// Create the javascript object to pass to the callback
/*let args: js_sys::Object = js_sys::Object::new();
let center = self.camera.get_center().lonlat();
js_sys::Reflect::set(
&args,
&"ra".into(),
&JsValue::from_f64(center.lon().to_degrees()),
)?;
js_sys::Reflect::set(
&args,
&"dec".into(),
&JsValue::from_f64(center.lat().to_degrees()),
)?;
js_sys::Reflect::set(&args, &"dragging".into(), &JsValue::from_bool(false))?;
js_sys::Reflect::set(&args, &"inertia".into(), &JsValue::from_bool(true))?;
// Position has changed, we call the callback
self.callback_position_changed
.call1(&JsValue::null(), &args)?;
*/
if cur_speed < thresh_speed {
self.inertia = None;
}
}
self.draw(false)?;
// Check for async retrieval
if let Ok(img) = self.img_recv.try_recv() {
let params = img.get_params();
self.layers.add_image(
img,
&mut self.camera,
&self.projection,
&mut self.tile_fetcher,
)?;
self.request_redraw = true;
// Send the ack to the js promise so that she finished
let ack_img_send = self.ack_img_send.clone();
wasm_bindgen_futures::spawn_local(async move {
ack_img_send.send(params).await.unwrap_throw();
})
}
// The rendering is done following these different situations:
// - the camera has moved
let has_camera_moved = self.camera.has_moved();
//let has_camera_recently_moved =
// ;
let _has_camera_zoomed = self.camera.has_zoomed();
{
// Newly available tiles must lead to
// 1. Surveys must be aware of the new available tiles
//self.hipss.set_available_tiles(&available_tiles);
// 2. Get the resolved tiles and push them to the image hipss
//self.surveys.set_available_tiles(&available_tiles);
// 2. Get the resolved tiles and push them to the image surveys
/*let is_there_new_available_tiles = self
.downloader
.get_resolved_tiles(/*&available_tiles, */&mut self.hipss);*/
.get_resolved_tiles(/*&available_tiles, */&mut self.surveys);*/
let rscs_received = self.downloader.borrow_mut().get_received_resources();
if self.request_for_new_tiles
//&& Time::now() - self.last_time_request_for_new_tiles > DeltaTime::from(200.0)
{
self.look_for_new_tiles()?;
let _num_tile_handled = 0;
let _tile_copied = false;
for rsc in rscs_received {
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();
self.request_for_new_tiles = false;
self.last_time_request_for_new_tiles = Time::now();
if cfg.get_format() == tile.format {
let delta_depth = cfg.delta_depth();
let fov_coverage = self.camera.get_cov(cfg.get_frame());
let included_or_near_coverage = tile
.cell()
.get_texture_cell(delta_depth)
.get_tile_cells(delta_depth)
.any(|neighbor_tile_cell| {
fov_coverage.intersects_cell(&neighbor_tile_cell)
});
//let is_tile_root = tile.cell().depth() == delta_depth;
//let _depth = tile.cell().depth();
// do not perform tex_sub costly GPU calls while the camera is zooming
if tile.cell().is_root() || included_or_near_coverage {
//let is_missing = tile.missing();
/*self.tile_fetcher.notify_tile(
&tile,
true,
false,
&mut self.downloader,
);*/
let Tile {
cell,
image,
time_req,
..
} = tile;
/*let image = if is_missing {
// Otherwise we push nothing, it is probably the case where:
// - an request error occured on a valid tile
// - the tile is not present, e.g. chandra HiPS have not the 0, 1 and 2 order tiles
None
} else {
Some(image)
};*/
use al_core::image::ImageType;
use fitsrs::fits::Fits;
use std::io::Cursor;
//if let Some(image) = image.as_ref() {
match &*image.lock().unwrap_abort() {
Some(ImageType::FitsImage {
raw_bytes: raw_bytes_buf,
}) => {
// check if the metadata has not been set
if !cfg.fits_metadata {
let num_bytes = raw_bytes_buf.length() as usize;
let mut raw_bytes = vec![0; num_bytes];
raw_bytes_buf.copy_to(&mut raw_bytes[..]);
let mut bytes_reader =
Cursor::new(raw_bytes.as_slice());
let Fits { hdu } =
Fits::from_reader(&mut bytes_reader).map_err(
|_| JsValue::from_str("Parsing fits error"),
)?;
let header = hdu.get_header();
let bscale = if let Some(
fitsrs::card::Value::Float(bscale),
) = header.get(b"BSCALE ")
{
*bscale as f32
} else {
1.0
};
let bzero = if let Some(
fitsrs::card::Value::Float(bzero),
) = header.get(b"BZERO ")
{
*bzero as f32
} else {
0.0
};
let blank = if let Some(
fitsrs::card::Value::Float(blank),
) = header.get(b"BLANK ")
{
*blank as f32
} else {
std::f32::NAN
};
cfg.set_fits_metadata(bscale, bzero, blank);
}
}
_ => (),
};
//}
match &*image.lock().unwrap_abort() {
Some(img) => {
survey.add_tile(&cell, img, time_req)?;
self.request_redraw = true;
self.time_start_blending = Time::now();
}
None => (),
};
}
}
}
/*} else {
self.downloader.delay_rsc(Resource::Tile(tile));
}*/
}
Resource::Allsky(allsky) => {
let hips_cdid = allsky.get_hips_cdid();
if let Some(survey) = 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();
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(),
);
self.tile_fetcher.append_base_tile(query);
}
}
} else {
// tell the survey to not download tiles which order is <= 3 because the allsky
// give them already
survey.add_allsky(allsky)?;
// Once received ask for redraw
self.request_redraw = true;
}
}
}
Resource::PixelMetadata(metadata) => {
if let Some(hips) = self.layers.get_mut_hips_from_cdid(&metadata.hips_cdid)
{
let cfg = hips.get_config_mut();
if let Some(metadata) = *metadata.value.lock().unwrap_abort() {
cfg.blank = metadata.blank;
cfg.offset = metadata.offset;
cfg.scale = metadata.scale;
}
}
}
Resource::Moc(moc) => {
let moc_hips_cdid = moc.get_hips_cdid();
//let url = &moc_url[..moc_url.find("/Moc.fits").unwrap_abort()];
if let Some(hips) = self.layers.get_mut_hips_from_cdid(moc_hips_cdid) {
let request::moc::Moc { moc, .. } = moc;
if let Some(moc) = &*moc.lock().unwrap_abort() {
hips.set_moc(moc.clone());
self.request_for_new_tiles = true;
self.request_redraw = true;
};
}
}
}
}
// Tiles are fetched if:
@@ -596,206 +779,52 @@ impl App {
}
}
let rscs_received = self.downloader.borrow_mut().get_received_resources();
// The update from the camera
//self.layers.update(&mut self.camera, &self.projection);
let mut tile_copied = false;
if self.request_for_new_tiles
//&& Time::now() - self.last_time_request_for_new_tiles > DeltaTime::from(200.0)
{
self.look_for_new_tiles()?;
for rsc in rscs_received {
match rsc {
Resource::Tile(tile) => {
//if !_has_camera_zoomed {
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();
let fov_coverage = self.camera.get_cov(cfg.get_frame());
let included_or_near_coverage = tile
.cell()
.get_texture_cell(delta_depth)
.get_tile_cells(delta_depth)
.any(|neighbor_tile_cell| {
fov_coverage.intersects_cell(&neighbor_tile_cell)
});
//let is_tile_root = tile.cell().depth() == delta_depth;
//let _depth = tile.cell().depth();
// do not perform tex_sub costly GPU calls while the camera is zooming
if tile.cell().is_root() || included_or_near_coverage {
//let is_missing = tile.missing();
/*self.tile_fetcher.notify_tile(
&tile,
true,
false,
&mut self.downloader,
);*/
/*let image = if is_missing {
// Otherwise we push nothing, it is probably the case where:
// - an request error occured on a valid tile
// - the tile is not present, e.g. chandra HiPS have not the 0, 1 and 2 order tiles
None
} else {
Some(image)
};*/
use al_core::image::ImageType;
use fitsrs::fits::Fits;
use std::io::Cursor;
//if let Some(image) = image.as_ref() {
match &*tile.image.borrow() {
Some(ImageType::FitsImage {
raw_bytes: raw_bytes_buf,
}) => {
// check if the metadata has not been set
if !cfg.fits_metadata {
let num_bytes = raw_bytes_buf.length() as usize;
let mut raw_bytes = vec![0; num_bytes];
raw_bytes_buf.copy_to(&mut raw_bytes[..]);
let mut bytes_reader =
Cursor::new(raw_bytes.as_slice());
let Fits { hdu } = Fits::from_reader(&mut bytes_reader)
.map_err(|_| {
JsValue::from_str("Parsing fits error")
})?;
let header = hdu.get_header();
let bscale =
if let Some(fitsrs::card::Value::Float(bscale)) =
header.get(b"BSCALE ")
{
*bscale as f32
} else {
1.0
};
let bzero =
if let Some(fitsrs::card::Value::Float(bzero)) =
header.get(b"BZERO ")
{
*bzero as f32
} else {
0.0
};
let blank =
if let Some(fitsrs::card::Value::Float(blank)) =
header.get(b"BLANK ")
{
*blank as f32
} else {
std::f32::NAN
};
cfg.set_fits_metadata(bscale, bzero, blank);
}
}
_ => (),
};
//}
let image = tile.image.clone();
match &*image.borrow() {
Some(img) => {
if tile_copied {
self.downloader
.borrow_mut()
.delay(Resource::Tile(tile));
continue;
}
self.request_redraw = true;
tile_copied = true;
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();
}
None => (),
};
}
}
}
}
Resource::Allsky(allsky) => {
let hips_cdid = allsky.get_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 = 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 = hips.get_tile_query(&cell);
self.tile_fetcher.append_base_tile(query);
}
}
} else {
// tell the hips to not download tiles which order is <= 3 because the allsky
// give them already
hips.add_allsky(allsky)?;
// Once received ask for redraw
self.request_redraw = true;
}
}
}
Resource::PixelMetadata(metadata) => {
if let Some(hips) = self.layers.get_mut_hips_from_cdid(&metadata.hips_cdid) {
let cfg = hips.get_config_mut();
if let Some(metadata) = &*metadata.value.borrow() {
cfg.blank = metadata.blank;
cfg.offset = metadata.offset;
cfg.scale = metadata.scale;
}
}
}
Resource::Moc(moc) => {
let moc_hips_cdid = moc.get_hips_cdid();
//let url = &moc_url[..moc_url.find("/Moc.fits").unwrap_abort()];
if let Some(hips) = self.layers.get_mut_hips_from_cdid(moc_hips_cdid) {
let request::moc::Moc { moc, .. } = moc;
if let Some(moc) = &*moc.borrow() {
hips.set_moc(moc.clone());
self.request_for_new_tiles = true;
self.request_redraw = true;
};
}
}
}
self.request_for_new_tiles = false;
self.last_time_request_for_new_tiles = Time::now();
}
// - there is at least one tile in its blending phase
let blending_anim_occuring =
(Time::now() - self.time_start_blending) < BLENDING_ANIM_DURATION;
self.rendering = blending_anim_occuring
| has_camera_moved
| self.camera.has_zoomed()
| self.request_redraw
| self.inertia.is_some();
// Check for async retrieval
if let Ok(img) = self.img_recv.try_recv() {
let params = img.get_params();
self.layers.add_image(
img,
&mut self.camera,
&self.projection,
&mut self.tile_fetcher,
)?;
self.request_redraw = true;
// Reset the flags about the user action
self.camera.reset();
// Send the ack to the js promise so that she finished
let ack_img_send = self.ack_img_send.clone();
wasm_bindgen_futures::spawn_local(async move {
ack_img_send.send(params).await.unwrap_throw();
})
}
self.rendering = blending_anim_occuring | has_camera_moved | self.request_redraw /*| start_fading*/;
self.request_redraw = false;
self.draw(false)?;
Ok(has_camera_moved)
}
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(hips) = self.layers.get_hips_from_layer(layer) {
hips.read_pixel(&lonlat, &self.camera)
if let Some(survey) = self.layers.get_hips_from_layer(layer) {
survey.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 {
@@ -869,64 +898,57 @@ impl App {
self.layers.reset_frame();*/
//let scene_redraw = self.rendering | force_render;
let scene_redraw = true;
let scene_redraw = self.rendering | force_render;
//let mut ui = self.ui.lock();
//let ui_redraw = ui.redraw_needed();
//if scene_redraw || ui_redraw {
if scene_redraw {
self.request_redraw = false;
let shaders = &mut self.shaders;
let gl = self.gl.clone();
let camera = &mut self.camera;
let grid = &mut self.grid;
let moc = &mut self.moc;
let projection = &self.projection;
let layers = &mut self.layers;
let catalogs = &self.manager;
let colormaps = &self.colormaps;
let fbo_view = &self._fbo_view;
let final_rendering_pass = &self._final_rendering_pass;
//fbo_view.draw_onto(
// move || {
//let catalogs = &self.manager;
// Render the scene
// Clear all the screen first (only the region set by the scissor)
gl.clear(WebGl2RenderingContext::COLOR_BUFFER_BIT);
// set the blending options
layers.draw(camera, shaders, colormaps, projection)?;
self.gl
.clear(web_sys::WebGl2RenderingContext::COLOR_BUFFER_BIT);
self.layers.draw(
&mut self.camera,
&mut self.shaders,
&self.colormaps,
&self.projection,
)?;
// Draw the catalog
//let fbo_view = &self.fbo_view;
//catalogs.draw(&gl, shaders, camera, colormaps, fbo_view)?;
//catalogs.draw(&gl, shaders, camera, colormaps, None, self.projection)?;
/*gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);*/
moc.draw(camera, projection, shaders)?;
self.moc.draw(
&mut self.camera,
&self.projection,
&mut self.shaders,
//&mut self.line_renderer,
)?;
gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);
grid.draw(camera, projection, shaders)?;
//self.line_renderer.begin();
//Time::measure_perf("moc draw", || {
// Ok(())
// },
// None,
//)?;
// Ok(())
//})?;
//final_rendering_pass.draw_on_screen(fbo_view, &mut self.shaders)?;
self.grid
.draw(&self.camera, &self.projection, &mut self.shaders)?;
//self.line_renderer.end();
//self.line_renderer
// .draw(&mut self.shaders, &self.camera, &self.projection)?;
//let dpi = self.camera.get_dpi();
//ui.draw(&gl, dpi)?;
// Reset the flags about the user action
self.camera.reset();
/*if self.rendering {
self.layers.reset_frame();
self.moc.reset_frame();
}*/
}
Ok(())
@@ -961,14 +983,14 @@ impl App {
Ok(())
}
pub(crate) fn add_hips(
pub(crate) fn add_image_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_hips(
let hips = self.layers.add_image_hips(
&self.gl,
hips_cfg,
&mut self.camera,
@@ -1253,25 +1275,18 @@ impl App {
self.layers.get_layer_cfg(layer)
}
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"))?;
pub(crate) fn set_hips_url(&mut self, cdid: &String, new_url: String) -> Result<(), JsValue> {
self.layers.set_survey_url(cdid, new_url.clone())?;
self.request_for_new_tiles = true;
//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);
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(())
}
}
Ok(())
}
pub(crate) fn set_image_hips_color_cfg(
pub(crate) fn set_image_survey_color_cfg(
&mut self,
layer: String,
meta: ImageMetadata,
@@ -1279,19 +1294,19 @@ impl App {
let old_meta = self.layers.get_layer_cfg(&layer)?;
// Set the new meta
// keep the old meta data
let new_img_ext = meta.img_format;
let new_img_fmt = meta.img_format;
self.layers
.set_layer_cfg(layer.clone(), meta, &mut self.camera, &self.projection)?;
if old_meta.img_format != new_img_ext {
if old_meta.img_format != new_img_fmt {
// 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_image_ext(new_img_ext)?;
hips.set_img_format(new_img_fmt)?;
// Relaunch the base tiles for the hips to be ready with the new url
// Relaunch the base tiles for the survey to be ready with the new url
self.tile_fetcher
.launch_starting_hips_requests(hips, self.downloader.clone());
@@ -1359,9 +1374,7 @@ impl App {
self.camera
.set_aperture(self.camera.get_aperture(), &self.projection);
// resize the view fbo
let screen_size = self.camera.get_screen_size();
self._fbo_view
.resize(screen_size.x as usize, screen_size.y as usize);
//self.fbo_view.resize(w as usize, h as usize);
// resize the ui fbo
//self.fbo_ui.resize(w as usize, h as usize);
@@ -1372,8 +1385,8 @@ impl App {
self.request_redraw = true;
}
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_survey_url(&mut self, cdid: &String, new_url: String) -> Result<(), JsValue> {
self.layers.set_survey_url(cdid, new_url)
}
pub(crate) fn set_catalog_opacity(
@@ -1409,7 +1422,7 @@ impl App {
}
pub(crate) fn set_grid_cfg(&mut self, cfg: GridCfg) -> Result<(), JsValue> {
self.grid.set_cfg(cfg)?;
self.grid.set_cfg(cfg, &self.camera, &self.projection)?;
self.request_redraw = true;
Ok(())

View File

@@ -83,7 +83,7 @@ use crate::LonLatT;
use cgmath::{SquareMatrix, Vector4};
use wasm_bindgen::JsCast;
const MAX_DPI_LIMIT: f32 = 2.0;
const MAX_DPI_LIMIT: f32 = 3.0;
use crate::math;
use crate::time::Time;
use crate::Abort;
@@ -337,7 +337,7 @@ impl CameraViewPort {
self.last_user_action
};
let can_unzoom_more = match proj {
let _can_unzoom_more = match proj {
ProjectionType::Tan(_)
| ProjectionType::Mer(_)
//| ProjectionType::Air(_)
@@ -351,45 +351,32 @@ impl CameraViewPort {
let aperture_start: Angle<f64> = ArcDeg(proj.aperture_start()).into();
self.clip_zoom_factor = if aperture > aperture_start {
//al_core::log(&format!("a: {:?}, as: {:?}", aperture, aperture_start));
if can_unzoom_more {
aperture.0 / aperture_start.0
self.aperture = aperture.min(aperture_start);
// Compute the new clip zoom factor
let a = aperture.abs();
let v0 = math::lonlat::radec_to_xyzw(-a / 2.0, Angle(0.0));
let v1 = math::lonlat::radec_to_xyzw(a / 2.0, Angle(0.0));
// Vertex in the WCS of the FOV
self.clip_zoom_factor = if self.width < self.height {
if let (Some(p0), Some(p1)) =
(proj.world_to_clip_space(&v0), proj.world_to_clip_space(&v1))
{
(0.5 * (p1.x - p0.x).abs()).min(1.0)
} else {
1.0
}
} else {
// Compute the new clip zoom factor
let a = aperture.abs();
let v0 = math::lonlat::radec_to_xyzw(-a / 2.0, Angle(0.0));
let v1 = math::lonlat::radec_to_xyzw(a / 2.0, Angle(0.0));
// Vertex in the WCS of the FOV
if self.width < self.height {
if let (Some(p0), Some(p1)) =
(proj.world_to_clip_space(&v0), proj.world_to_clip_space(&v1))
{
(0.5 * (p1.x - p0.x).abs()).min(1.0)
} else {
1.0
}
if let (Some(p0), Some(p1)) =
(proj.world_to_clip_space(&v0), proj.world_to_clip_space(&v1))
{
(0.5 * (p1.x - p0.x).abs()).min(1.0)
} else {
if let (Some(p0), Some(p1)) =
(proj.world_to_clip_space(&v0), proj.world_to_clip_space(&v1))
{
(0.5 * (p1.x - p0.x).abs()).min(1.0)
} else {
1.0
}
1.0
}
};
self.aperture = aperture.min(aperture_start);
//self.aperture = aperture;
//al_core::log(&format!("zoom factor {:?}", self.clip_zoom_factor));
//console_log(&format!("clip factor {:?}", self.aperture));
// Project this vertex into the screen

View File

@@ -11,6 +11,7 @@ pub struct Downloader {
queried_list: HashSet<QueryId>,
cache: Cache<QueryId, Resource>,
queried_cached_ids: Vec<QueryId>,
}
use crate::fifo_cache::Cache;
@@ -23,10 +24,12 @@ impl Downloader {
let requests = Vec::with_capacity(32);
let queried_list = HashSet::with_capacity(64);
let cache = Cache::new();
let queried_cached_ids = Vec::with_capacity(64);
Self {
requests,
queried_list,
cache,
queried_cached_ids,
}
}
// Returns true if the fetch has been done
@@ -81,8 +84,10 @@ impl Downloader {
self.queried_list.remove(&query_id);
}
while let Some(r) = self.cache.extract_new() {
rscs.push(r);
while let Some(id) = self.queried_cached_ids.pop() {
if let Some(rsc) = self.cache.extract(&id) {
rscs.push(rsc);
}
}
rscs
@@ -92,18 +97,8 @@ impl Downloader {
self.queried_list.contains(id)
}
pub fn delay(&mut self, r: Resource) {
match r {
Resource::Tile(tile) => {
let k = format!(
"{:?}{:?}/{:?}",
tile.get_hips_cdid(),
tile.cell.depth(),
tile.cell.idx()
);
self.cache.insert(k, Resource::Tile(tile));
}
_ => unimplemented!(),
}
pub fn _delay_rsc(&mut self, rsc: Resource) {
self.queried_cached_ids.push(rsc.id().clone());
self.cache.insert(rsc.id().clone(), rsc);
}
}

View File

@@ -20,52 +20,36 @@ 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;
use crate::{healpix::cell::HEALPixCell, survey::config::HiPSConfig};
impl Tile {
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();
pub fn new(
cell: &HEALPixCell,
hips_cdid: String,
hips_url: String,
format: ImageFormatType,
) -> Self {
let ext = format.get_ext_file();
let HEALPixCell(depth, idx) = *cell;
let dir_idx = (idx / 10000) * 10000;
let mut url = format!("{}/Norder{}/Dir{}/Npix{}", hips_url, depth, dir_idx, idx);
// 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!(
"{}{}{}{}{}",
hips_cdid,
depth,
idx,
channel.unwrap_or(0),
ext
let url = format!(
"{}/Norder{}/Dir{}/Npix{}.{}",
hips_url, depth, dir_idx, idx, ext
);
let id = format!("{}{}{}{}", hips_cdid, depth, idx, ext);
Tile {
hips_cdid: hips_cdid.to_string(),
hips_cdid,
url,
cell: *cell,
format,
id,
channel,
}
}
}
@@ -84,7 +68,6 @@ 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
@@ -93,31 +76,16 @@ pub struct Allsky {
}
impl Allsky {
pub fn new(cfg: &HiPSConfig, channel: Option<u32>) -> Self {
pub fn new(cfg: &HiPSConfig) -> 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 mut url = format!("{}/Norder3/Allsky", cfg.get_root_url());
let url = format!("{}/Norder3/Allsky.{}", cfg.get_root_url(), 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)
);
let id = format!("{}Allsky{}", cfg.get_creator_did(), ext);
Allsky {
tile_size,
@@ -126,7 +94,6 @@ impl Allsky {
url,
format,
id,
channel,
}
}
}

View File

@@ -14,7 +14,6 @@ pub struct AllskyRequest {
pub url: Url,
pub depth_tile: u8,
pub id: QueryId,
pub channel: Option<u32>,
request: Request<Vec<ImageType>>,
}
@@ -81,7 +80,6 @@ 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;
@@ -214,7 +212,6 @@ impl From<query::Allsky> for AllskyRequest {
depth_tile,
url,
request,
channel: slice,
}
}
}
@@ -307,23 +304,21 @@ fn handle_allsky_fits<F: ImageFormat>(
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 image: Arc<Mutex<Option<Vec<ImageType>>>>,
pub time_req: Time,
pub depth_tile: u8,
pub hips_cdid: CreatorDid,
url: Url,
pub channel: Option<u32>,
}
use crate::Abort;
impl Allsky {
pub fn missing(&self) -> bool {
self.image.borrow().is_none()
self.image.lock().unwrap_abort().is_none()
}
pub fn get_hips_cdid(&self) -> &CreatorDid {
@@ -342,7 +337,6 @@ impl<'a> From<&'a AllskyRequest> for Option<Allsky> {
hips_cdid,
depth_tile,
url,
channel,
..
} = request;
if request.is_resolved() {
@@ -356,7 +350,6 @@ impl<'a> From<&'a AllskyRequest> for Option<Allsky> {
hips_cdid: hips_cdid.clone(),
url: url.clone(),
depth_tile: *depth_tile,
channel: *channel,
})
} else {
None

View File

@@ -132,11 +132,10 @@ 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>>>,
pub value: Arc<Mutex<Option<Metadata>>>,
pub hips_cdid: CreatorDid,
pub url: String,
}

View File

@@ -102,10 +102,9 @@ 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 moc: Arc<Mutex<Option<HEALPixCoverage>>>,
pub params: al_api::moc::MOC,
pub hips_cdid: Url,
}

View File

@@ -8,11 +8,12 @@ pub mod tile;
/* ------------------------------------- */
use crate::time::Time;
use std::cell::{Cell, RefCell};
use std::cell::Cell;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
pub type Url = String;
pub struct Request<R> {
data: Rc<RefCell<Option<R>>>,
data: Arc<Mutex<Option<R>>>,
time_request: Time,
// Flag telling if the tile has been copied so that
// the HtmlImageElement can be reused to download another tile
@@ -26,6 +27,7 @@ pub enum ResolvedStatus {
Failed,
Found,
}
use crate::Abort;
use std::future::Future;
use wasm_bindgen::JsValue;
impl<R> Request<R>
@@ -40,7 +42,7 @@ where
let resolved = Rc::new(Cell::new(ResolvedStatus::NotResolved));
let time_request = Time::now();
let data = Rc::new(RefCell::new(None));
let data = Arc::new(Mutex::new(None));
{
let data_cloned = data.clone();
@@ -49,7 +51,7 @@ where
let fut = async move {
let resp = f.await;
if let Ok(resp) = resp {
data_cloned.replace(Some(resp));
*(data_cloned.lock().unwrap_abort()) = Some(resp);
resolved_cloned.set(ResolvedStatus::Found);
} else {
resolved_cloned.set(ResolvedStatus::Failed);
@@ -125,14 +127,13 @@ pub enum Resource {
Moc(Moc),
}
/*
impl Resource {
pub fn id(&self) -> &String {
match self {
Resource::Tile(tile) => &format!("{:?}:{:?}", tile.cell.depth(), tile.cell.idx()),
Resource::Tile(tile) => tile.get_hips_cdid(),
Resource::Allsky(allsky) => allsky.get_hips_cdid(),
Resource::PixelMetadata(PixelMetadata { hips_cdid, .. }) => hips_cdid,
Resource::Moc(moc) => moc.get_hips_cdid(),
}
}
}*/
}

View File

@@ -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,
channel: Option<u32>,
request: Request<ImageType>,
}
impl From<TileRequest> for RequestType {
@@ -59,7 +59,6 @@ impl From<query::Tile> for TileRequest {
url,
hips_cdid,
id,
channel: slice,
} = query;
let url_clone = url.clone();
@@ -181,20 +180,17 @@ impl From<query::Tile> for TileRequest {
hips_cdid,
url,
request,
channel: slice,
}
}
}
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 image: Arc<Mutex<Option<ImageType>>>,
pub time_req: Time,
pub cell: HEALPixCell,
pub format: ImageFormatType,
pub channel: Option<u32>,
hips_cdid: CreatorDid,
url: Url,
}
@@ -203,7 +199,7 @@ use crate::Abort;
impl Tile {
#[inline(always)]
pub fn missing(&self) -> bool {
self.image.borrow().is_none()
self.image.lock().unwrap_abort().is_none()
}
#[inline(always)]
@@ -220,6 +216,11 @@ impl Tile {
pub fn cell(&self) -> &HEALPixCell {
&self.cell
}
/*#[inline(always)]
pub fn query(&self) -> query::Tile {
query::Tile::new(&self.cell, self.hips_url.clone(), self.format)
}*/
}
impl<'a> From<&'a TileRequest> for Option<Tile> {
@@ -230,7 +231,6 @@ impl<'a> From<&'a TileRequest> for Option<Tile> {
hips_cdid,
url,
format,
channel,
..
} = request;
if request.is_resolved() {
@@ -245,7 +245,6 @@ impl<'a> From<&'a TileRequest> for Option<Tile> {
hips_cdid: hips_cdid.clone(),
url: url.clone(),
format: *format,
channel: *channel,
})
} else {
None

View File

@@ -10,12 +10,15 @@ use crate::Abort;
use std::hash::Hash;
impl<K, V> Cache<K, V>
where
K: Clone + std::cmp::Eq + Hash,
K: Clone + std::cmp::Eq + Hash
{
pub fn new() -> Self {
let data = HashMap::with_capacity(SIZE_RESOURCE_CACHE);
let order = VecDeque::with_capacity(SIZE_RESOURCE_CACHE);
Cache { data, order }
Cache {
data,
order
}
}
pub fn insert(&mut self, key: K, val: V) {
@@ -28,15 +31,11 @@ where
self.order.push_back(key);
}
pub fn extract_new(&mut self) -> Option<V> {
if let Some(k) = self.order.pop_back() {
self.data.remove(&k)
} else {
None
}
pub fn extract(&mut self, key: &K) -> Option<V> {
self.data.remove(key)
}
pub fn contains(&self, key: &K) -> bool {
self.data.contains_key(key)
}
}
}

View File

@@ -3,7 +3,7 @@ use cgmath::Vector3;
use crate::camera::CameraViewPort;
use crate::math::angle::ToAngle;
use crate::math::projection::ProjectionType;
use crate::time::{DeltaTime, Time};
use crate::time::Time;
/// State for inertia
pub struct Inertia {
@@ -26,7 +26,7 @@ impl Inertia {
}
}
pub fn apply(&mut self, camera: &mut CameraViewPort, proj: &ProjectionType, dt: DeltaTime) {
pub fn apply(&mut self, camera: &mut CameraViewPort, proj: &ProjectionType) {
let t = ((Time::now() - self.time_start).as_millis() / 1000.0) as f64;
// Undamped angular frequency of the oscillator
// From wiki: https://en.wikipedia.org/wiki/Harmonic_oscillator
@@ -35,11 +35,9 @@ impl Inertia {
// where:
// * k is the stiffness of the ressort
// * m is its mass
let w0 = 10.0;
let w0 = 5.0;
// The angular distance goes from d0 to 0.0
//self.speed = self.ampl * ((-w0 * t).exp());
// The angular distance goes from d0 to 0.0
self.speed = self.ampl * (w0 * t + 1.0) * ((-w0 * t).exp());
self.speed = self.ampl * ((-w0 * t).exp());
/*let alpha = 1_f32 + (0_f32 - 1_f32) * (10_f32 * t + 1_f32) * (-10_f32 * t).exp();
let alpha = alpha * alpha;
let fov = start_fov * (1_f32 - alpha) + goal_fov * alpha;*/

View File

@@ -106,6 +106,7 @@ mod inertia;
pub mod math;
pub mod renderable;
mod shader;
mod survey;
mod tile_fetcher;
mod time;
@@ -320,13 +321,13 @@ impl WebClient {
Ok(self.app.get_norder())
}
/// Set new image hips
/// Set new image surveys
///
/// Send the image hips to render inside the Aladin Lite view
/// Send the image surveys to render inside the Aladin Lite view
///
/// # Arguments
///
/// * `hips` - A list/array of hips. A hips is a javascript object
/// * `surveys` - A list/array of survey. A survey 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 +363,19 @@ impl WebClient {
///
/// # Panics
///
/// * 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
/// * 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
/// limited to 4.
#[wasm_bindgen(js_name = addHiPS)]
pub fn add_hips(
pub fn add_image_hips(
&mut self,
hips: JsValue,
files: Option<HiPSLocalFiles>,
) -> Result<(), JsValue> {
// Deserialize the hips objects that compose the hips
// Deserialize the survey objects that compose the survey
let hips = serde_wasm_bindgen::from_value(hips)?;
self.app.add_hips(hips, files)?;
self.app.add_image_hips(hips, files)?;
Ok(())
}
@@ -410,7 +411,7 @@ impl WebClient {
#[wasm_bindgen(js_name = removeLayer)]
pub fn remove_layer(&mut self, layer: String) -> Result<(), JsValue> {
// Deserialize the hips objects that compose the hips
// Deserialize the survey objects that compose the survey
self.app.remove_layer(&layer)?;
Ok(())
@@ -418,7 +419,7 @@ impl WebClient {
#[wasm_bindgen(js_name = renameLayer)]
pub fn rename_layer(&mut self, layer: String, new_layer: String) -> Result<(), JsValue> {
// Deserialize the hips objects that compose the hips
// Deserialize the survey objects that compose the survey
self.app.rename_layer(&layer, &new_layer)
}
@@ -428,7 +429,7 @@ impl WebClient {
first_layer: String,
second_layer: String,
) -> Result<(), JsValue> {
// Deserialize the hips objects that compose the hips
// Deserialize the survey objects that compose the survey
self.app.swap_layers(&first_layer, &second_layer)
}
@@ -444,15 +445,15 @@ impl WebClient {
// Set a new color associated with a layer
#[wasm_bindgen(js_name = setImageMetadata)]
pub fn set_hips_color_cfg(&mut self, layer: String, meta: JsValue) -> Result<(), JsValue> {
pub fn set_survey_color_cfg(&mut self, layer: String, meta: JsValue) -> Result<(), JsValue> {
let meta = serde_wasm_bindgen::from_value(meta)?;
self.app.set_image_hips_color_cfg(layer, meta)
self.app.set_image_survey_color_cfg(layer, meta)
}
#[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 = 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 = setBackgroundColor)]
@@ -504,9 +505,11 @@ impl WebClient {
/// * `fov` - The field of view in degrees
#[wasm_bindgen(js_name = setFieldOfView)]
pub fn set_fov(&mut self, fov: f64) -> Result<(), JsValue> {
//let fov = fov as f32;
let fov = ArcDeg(fov).into();
self.app.set_fov(fov);
//self.projection.set_fov(&mut self.app, ArcDeg(fov).into());
Ok(())
}
@@ -963,7 +966,7 @@ impl WebClient {
/// Read the pixel value
///
/// The current implementation only returns the pixel value
/// of the first hips of the `layer` specified.
/// of the first survey of the `layer` specified.
///
/// # Returns
///
@@ -975,7 +978,7 @@ impl WebClient {
///
/// * `x` - The x screen coordinate in pixels
/// * `y` - The y screen coordinate in pixels
/// * `base_url` - The base url of the hips identifying it
/// * `base_url` - The base url of the survey 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())?;

View File

@@ -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,6 +105,7 @@ 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
@@ -112,5 +113,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()
}

View File

@@ -258,9 +258,11 @@ impl Manager {
fbo: Option<&FrameBufferObject>,
projection: &ProjectionType,
) -> Result<(), JsValue> {
gl.enable(WebGl2RenderingContext::BLEND);
for catalog in self.catalogs.values() {
catalog.draw(gl, shaders, self, camera, colormaps, fbo, projection)?;
}
gl.disable(WebGl2RenderingContext::BLEND);
Ok(())
}

View File

@@ -10,6 +10,7 @@ pub struct RenderPass {
use crate::ShaderManager;
impl RenderPass {
pub fn new(gl: &WebGlContext) -> Result<RenderPass, JsValue> {
let positions = vec![0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0];
let indices = vec![0u8, 1, 2, 1, 3, 2];
let mut vao = VertexArrayObject::new(gl);
@@ -48,23 +49,14 @@ impl RenderPass {
})
}
pub fn draw_on_screen(
&self,
fbo: &FrameBufferObject,
shaders: &mut ShaderManager,
) -> Result<(), JsValue> {
//self.gl.enable(WebGl2RenderingContext::BLEND);
/*self.gl.blend_func(
pub fn draw_on_screen(&self, fbo: &FrameBufferObject, shaders: &mut ShaderManager) -> Result<(), JsValue> {
self.gl.enable(WebGl2RenderingContext::BLEND);
self.gl.blend_func(
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA,
); // premultiplied alpha*/
); // premultiplied alpha
let shader = crate::shader::get_shader(
&self.gl,
shaders,
"passes_post_vertex_100es.vert",
"passes_post_fragment_100es.frag",
)?;
let shader = crate::shader::get_shader(&self.gl, shaders, "PostVS", "PostFS")?;
shader
.bind(&self.gl)
@@ -77,7 +69,7 @@ impl RenderPass {
0,
);
//self.gl.disable(WebGl2RenderingContext::BLEND);
self.gl.disable(WebGl2RenderingContext::BLEND);
Ok(())
}

View File

@@ -114,7 +114,12 @@ impl ProjetedGrid {
Ok(grid)
}
pub fn set_cfg(&mut self, new_cfg: GridCfg) -> Result<(), JsValue> {
pub fn set_cfg(
&mut self,
new_cfg: GridCfg,
_camera: &CameraViewPort,
_projection: &ProjectionType,
) -> Result<(), JsValue> {
let GridCfg {
color,
opacity,
@@ -160,6 +165,10 @@ impl ProjetedGrid {
if let Some(enabled) = enabled {
self.enabled = enabled;
/*if !self.enabled {
self.text_renderer.clear_text_canvas();
}*/
}
Ok(())
@@ -285,6 +294,7 @@ impl ProjetedGrid {
let num_instances = buf.len() / 4;
self.gl.enable(WebGl2RenderingContext::BLEND);
crate::shader::get_shader(&self.gl, shaders, "line_inst_ndc.vert", "line_base.frag")?
.bind(&self.gl)
.attach_uniform("u_color", &self.color)
@@ -297,6 +307,7 @@ impl ProjetedGrid {
0,
num_instances as i32,
);
self.gl.disable(WebGl2RenderingContext::BLEND);
}
Ok(())

View File

@@ -1,745 +0,0 @@
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;
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::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 buffer::HiPS2DBuffer;
use texture::HpxTexture2D;
use super::raytracing::RayTracer;
use super::uv::{TileCorner, TileUVW};
use cgmath::Matrix;
use wasm_bindgen::JsValue;
use web_sys::WebGl2RenderingContext;
pub struct TextureToDraw<'a, 'b> {
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 HpxTexture2D,
ending_texture: &'a HpxTexture2D,
cell: &'b HEALPixCell,
) -> TextureToDraw<'a, 'b> {
TextureToDraw {
starting_texture,
ending_texture,
cell,
}
}
}
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,
"hips_rasterizer_raster.vert",
"hips_rasterizer_color.frag",
)
} else {
if config.tex_storing_unsigned_int {
crate::shader::get_shader(
gl,
shaders,
"hips_rasterizer_raster.vert",
"hips_rasterizer_grayscale_to_colormap_u.frag",
)
} else if config.tex_storing_integers {
crate::shader::get_shader(
gl,
shaders,
"hips_rasterizer_raster.vert",
"hips_rasterizer_grayscale_to_colormap_i.frag",
)
} else {
crate::shader::get_shader(
gl,
shaders,
"hips_rasterizer_raster.vert",
"hips_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 HiPS2D {
//color: Color,
// The image survey texture buffer
buffer: HiPS2DBuffer,
// 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_start: Vec<f32>,
//#[cfg(feature = "webgl1")]
// layout (location = 2) in vec3 uv_end;
uv_end: Vec<f32>,
//#[cfg(feature = "webgl1")]
// layout (location = 3) in float time_tile_received;
time_tile_received: Vec<f32>,
idx_vertices: Vec<u16>,
num_idx: usize,
vao: VertexArrayObject,
gl: WebGlContext,
footprint_moc: Option<HEALPixCoverage>,
// A buffer storing the cells in the view
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);
// 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_start = vec![];
let uv_end = vec![];
let time_tile_received = vec![];
let idx_vertices = vec![];
#[cfg(feature = "webgl2")]
vao.bind_for_update()
.add_array_buffer_single(
2,
"ndc_pos",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData::<f32>(&position),
)
.add_array_buffer_single(
3,
"uv_start",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData::<f32>(&uv_start),
)
.add_array_buffer_single(
3,
"uv_end",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData::<f32>(&uv_end),
)
.add_array_buffer_single(
1,
"time_tile_received",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData::<f32>(&time_tile_received),
)
// Set the element buffer
.add_element_buffer(
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData::<u16>(&idx_vertices),
)
.unbind();
let num_idx = 0;
let buffer = HiPS2DBuffer::new(gl, config)?;
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,
num_idx,
vao,
gl,
position,
uv_start,
uv_end,
time_tile_received,
idx_vertices,
footprint_moc,
hpx_cells_in_view,
})
}
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) && !self.update_priority_tile(tile_cell)
} else {
!self.update_priority_tile(tile_cell)
}
});
Some(tile_cells_iter)
}
pub fn contains_tile(&self, cell: &HEALPixCell) -> bool {
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) {
let raytracing = camera.is_raytracing(projection);
if raytracing {
return;
}
// rasterizer mode
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 {
self.recompute_vertices(camera, projection);
}
}
// returns a boolean if the view cells has changed with respect to the last frame
pub 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 recompute_vertices(&mut self, camera: &mut CameraViewPort, projection: &ProjectionType) {
self.position.clear();
self.uv_start.clear();
self.uv_end.clear();
self.time_tile_received.clear();
self.idx_vertices.clear();
let cfg = self.buffer.config();
// Get the coo system transformation matrix
let channel = cfg.get_format().get_channel();
// Retrieve the model and inverse model matrix
let mut off_indices = 0;
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)
};
if let Some(cell) = 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,
cell,
))
} else {
// no blending here
Some(TextureToDraw::new(
ending_cell_in_tex,
ending_cell_in_tex,
cell,
))
}
} else {
Some(TextureToDraw::new(
ending_cell_in_tex,
ending_cell_in_tex,
cell,
))
}
} else {
None
}
} else {
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.buffer.get_nearest_parent(&parent_cell)
{
if let Some(starting_cell_in_tex) =
self.buffer.get(&grand_parent_cell)
{
Some(TextureToDraw::new(
starting_cell_in_tex,
ending_cell_in_tex,
cell,
))
} else {
// no blending
Some(TextureToDraw::new(
ending_cell_in_tex,
ending_cell_in_tex,
cell,
))
}
} else {
Some(TextureToDraw::new(
ending_cell_in_tex,
ending_cell_in_tex,
cell,
))
}
} else {
unreachable!();
}
} else {
None
}
};
if let Some(TextureToDraw {
cell,
starting_texture,
ending_texture,
}) = texture_to_draw
{
let uv_0 = TileUVW::new(cell, starting_texture, cfg);
let uv_1 = TileUVW::new(cell, ending_texture, cfg);
let d01s = uv_0[TileCorner::BottomRight].x - uv_0[TileCorner::BottomLeft].x;
let d02s = uv_0[TileCorner::TopLeft].y - uv_0[TileCorner::BottomLeft].y;
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 start_time = ending_texture.start_time().as_millis();
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;
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_start = [
uv_0[TileCorner::BottomLeft].x + hj0 * d01s,
uv_0[TileCorner::BottomLeft].y + hi0 * d02s,
uv_0[TileCorner::BottomLeft].z,
];
let uv_end = [
uv_1[TileCorner::BottomLeft].x + hj0 * d01e,
uv_1[TileCorner::BottomLeft].y + hi0 * d02e,
uv_1[TileCorner::BottomLeft].z,
];
self.uv_start.extend(uv_start);
self.uv_end.extend(uv_end);
self.time_tile_received.push(start_time);
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();
self.idx_vertices.extend(patch_indices_iter);
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);
}
}
}
self.num_idx = self.idx_vertices.len();
let mut vao = self.vao.bind_for_update();
vao.update_array(
"ndc_pos",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.position),
)
.update_array(
"uv_start",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.uv_start),
)
.update_array(
"uv_end",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.uv_end),
)
.update_array(
"time_tile_received",
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.time_tile_received),
)
.update_element_array(
WebGl2RenderingContext::DYNAMIC_DRAW,
VecData(&self.idx_vertices),
);
}
// 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.buffer.contains_tile(cell) {
// The cell is present in the survey, we update its priority
self.buffer.update_priority(cell);
true
} else {
false
}
}
pub fn add_tile<I: Image>(
&mut self,
cell: &HEALPixCell,
image: I,
time_request: Time,
) -> Result<(), JsValue> {
self.buffer.push(&cell, image, time_request)
}
pub fn add_allsky(&mut self, allsky: Allsky) -> Result<(), JsValue> {
self.buffer.push_allsky(allsky)
}
/* 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()
}
pub fn draw(
&self,
shaders: &mut ShaderManager,
colormaps: &Colormaps,
camera: &CameraViewPort,
raytracer: &RayTracer,
cfg: &ImageMetadata,
proj: &ProjectionType,
) -> Result<(), JsValue> {
// Get the coo system transformation matrix
let selected_frame = camera.get_coo_system();
let hips_cfg = self.buffer.config();
let hips_frame = hips_cfg.get_frame();
let c = selected_frame.to(hips_frame);
let raytracing = camera.is_raytracing(proj);
let config = self.get_config();
//self.gl.enable(WebGl2RenderingContext::BLEND);
let ImageMetadata {
color,
opacity,
blend_cfg,
..
} = cfg;
// Add starting fading
//let fading = self.get_fading_factor();
//let opacity = opacity * fading;
// Get the colormap from the color
let cmap = colormaps.get(color.cmap_name.as_ref());
blend_cfg.enable(&self.gl, || {
if raytracing {
let w2v = c * (*camera.get_w2m());
let shader = get_raytracer_shader(cmap, &self.gl, shaders, &config)?;
let shader = shader.bind(&self.gl);
shader
.attach_uniforms_from(camera)
.attach_uniforms_from(&self.buffer)
// send the cmap appart from the color config
.attach_uniforms_with_params_from(cmap, colormaps)
.attach_uniforms_from(color)
.attach_uniform("model", &w2v)
.attach_uniform("current_time", &utils::get_current_time())
.attach_uniform("opacity", opacity)
.attach_uniforms_from(colormaps);
raytracer.draw(&shader);
} else {
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 shader = get_raster_shader(cmap, &self.gl, shaders, &config)?.bind(&self.gl);
shader
.attach_uniforms_from(&self.buffer)
// send the cmap appart from the color config
.attach_uniforms_with_params_from(cmap, colormaps)
.attach_uniforms_from(color)
.attach_uniforms_from(camera)
.attach_uniform("inv_model", &v2w)
.attach_uniform("current_time", &utils::get_current_time())
.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(self.num_idx as i32),
WebGl2RenderingContext::UNSIGNED_SHORT,
0,
);
}
Ok(())
})?;
//self.gl.disable(WebGl2RenderingContext::BLEND);
Ok(())
}
}

View File

@@ -1,205 +0,0 @@
use std::collections::HashMap;
use crate::CameraViewPort;
use crate::LonLatT;
use al_core::image::Image;
use al_core::WebGlContext;
use super::texture::HpxTexture3D;
use crate::downloader::request::allsky::Allsky;
use crate::healpix::cell::HEALPixCell;
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, HpxTexture3D>,
config: HiPSConfig,
available_tiles_during_frame: bool,
gl: WebGlContext,
}
impl HiPS3DBuffer {
pub fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue> {
let textures = HashMap::new();
let available_tiles_during_frame = false;
let gl = gl.clone();
Ok(Self {
config,
textures,
available_tiles_during_frame,
gl,
})
}
pub fn push_allsky(&mut self, allsky: Allsky) -> Result<(), JsValue> {
let Allsky {
image,
time_req,
depth_tile,
channel,
..
} = allsky;
{
let mutex_locked = image.borrow();
let images = mutex_locked.as_ref().unwrap_abort();
for (idx, image) in images.iter().enumerate() {
self.push(
&HEALPixCell(depth_tile, idx as u64),
image,
time_req,
channel.map(|c| c as u16).unwrap_or(0),
)?;
}
}
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>(
&mut self,
cell: &HEALPixCell,
image: I,
time_request: Time,
slice_idx: u16,
) -> Result<(), JsValue> {
let tex = if let Some(tex) = self.textures.get_mut(cell) {
tex
} else {
self.textures
.insert(*cell, HpxTexture3D::new(*cell, time_request));
self.textures.get_mut(cell).unwrap()
};
// copy to the 3D textured block
tex.append(image, slice_idx, &self.config, &self.gl)?;
self.available_tiles_during_frame = true;
Ok(())
}
// Return if tiles did become available
pub 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
}
// Tell if a texture is available meaning all its sub tiles
// must have been written for the GPU
pub fn contains_tile(&self, texture_cell: &HEALPixCell, slice: u16) -> bool {
self.get(texture_cell)
.map_or(false, |t| t.contains_slice(slice))
}
/// Accessors
pub fn get(&self, cell: &HEALPixCell) -> Option<&HpxTexture3D> {
self.textures.get(cell)
}
pub fn config(&self) -> &HiPSConfig {
&self.config
}
pub fn config_mut(&mut self) -> &mut HiPSConfig {
&mut self.config
}
}
impl HpxTileBuffer for HiPS3DBuffer {
type T = HpxTexture3D;
fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<Self, JsValue> {
let textures = HashMap::new();
let available_tiles_during_frame = false;
let gl = gl.clone();
Ok(Self {
config,
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> {
self.config.set_image_ext(ext)?;
let channel = self.config.get_format().get_channel();
self.textures.clear();
//self.ready = false;
self.available_tiles_during_frame = true;
Ok(())
}
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
}
}
use al_core::shader::SendUniforms;
use al_core::shader::ShaderBound;
impl SendUniforms for HiPS3DBuffer {
// Send only the allsky textures
fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> {
shader.attach_uniforms_from(&self.config)
}
}
impl Drop for HiPS3DBuffer {
fn drop(&mut self) {
// drop all the 3D block textures
self.textures.clear();
}
}

View File

@@ -1,662 +0,0 @@
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;
let shader = get_raster_shader(cmap, &self.gl, shaders, &hips_cfg)?;
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, || {
// Bind the shader at each draw of a cell to not exceed the max number of tex image units bindable
// to a shader. It is 32 in my case
let shaderbound = shader.bind(&self.gl);
shaderbound
.attach_uniform(
"tex",
self.buffer
.get(cell)
.unwrap()
.get_3d_block_from_slice(*slice_idx as u16)
.unwrap(),
)
.attach_uniforms_from(&self.buffer)
.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()
}
}

View File

@@ -1,395 +0,0 @@
use crate::renderable::hips::d2::texture::HpxTexture2D;
use crate::{healpix::cell::HEALPixCell, time::Time};
use al_core::image::format::{
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 wasm_bindgen::JsValue;
pub struct HpxTexture3D {
tile_cell: HEALPixCell,
// Precomputed uniq number
uniq: i32,
// The time the texture has been received
// If the texture contains multiple tiles, then the receiving time
// is set when all the tiles have been copied to the buffer
start_time: Option<Time>,
// The time request of the texture is the time request
// of the first tile being inserted in it
// It is then only given in the constructor of Texture
// This is approximate, it should correspond to the minimum
// of the time requests of the cells currenlty contained in the
// texture. But this is too expensive because at each tile inserted
// in the buffer, one should reevalute the priority of the texture
// in the buffer's binary heap.
time_request: Time,
// 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. 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;
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 blocks = [0; 512];
let block_indices = Vec::new();
Self {
tile_cell,
uniq,
time_request,
start_time,
textures,
blocks,
block_indices,
}
}
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));
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;
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) => {
let prev_block = if i > 0 {
self.block_indices.get(i - 1)
} else {
None
};
let cur_block = self.block_indices.get(i);
match (prev_block, cur_block) {
(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) as usize;
self.textures[block_idx].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;
// 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<I: Image>(
&mut self,
image: I,
slice: u16,
cfg: &HiPSConfig,
gl: &WebGlContext,
) -> Result<(), JsValue> {
let block_idx = (slice >> 5) as usize;
let texture = if let Some(texture) = self.textures[block_idx as usize].as_ref() {
texture
} else {
let tile_size = cfg.get_tile_size();
let params = &[
(
WebGlRenderingCtx::TEXTURE_MIN_FILTER,
WebGlRenderingCtx::NEAREST,
),
(
WebGlRenderingCtx::TEXTURE_MAG_FILTER,
WebGlRenderingCtx::NEAREST,
),
// Prevents s-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_S,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents t-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_T,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents r-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_R,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
];
let texture = match cfg.get_format().get_channel() {
ChannelType::RGBA32F => {
Texture3D::create_empty::<RGBA32F>(gl, tile_size, tile_size, 32, params)
}
ChannelType::RGB32F => {
Texture3D::create_empty::<RGB32F>(gl, tile_size, tile_size, 32, params)
}
ChannelType::RGBA8U => {
Texture3D::create_empty::<RGBA8U>(gl, tile_size, tile_size, 32, params)
}
ChannelType::RGB8U => {
Texture3D::create_empty::<RGB8U>(gl, tile_size, tile_size, 32, params)
}
ChannelType::R32F => {
Texture3D::create_empty::<R32F>(gl, tile_size, tile_size, 32, params)
}
ChannelType::R64F => {
Texture3D::create_empty::<R64F>(gl, tile_size, tile_size, 32, params)
}
ChannelType::R8UI => {
Texture3D::create_empty::<R8UI>(gl, tile_size, tile_size, 32, params)
}
ChannelType::R16I => {
Texture3D::create_empty::<R16I>(gl, tile_size, tile_size, 32, params)
}
ChannelType::R32I => {
Texture3D::create_empty::<R32I>(gl, tile_size, tile_size, 32, params)
}
};
self.textures[block_idx] = Some(texture?);
self.textures[block_idx].as_ref().unwrap()
};
let slice_idx = slice & 0x1f;
// if there is already something, do not tex sub
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());
Ok(())
}
// Cell must be contained in the texture
pub fn contains_slice(&self, slice: u16) -> bool {
let block_idx = (slice >> 5) as usize;
let idx_in_block = slice & 0x1f;
(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
fn start_time(&self) -> Time {
if let Some(t) = self.start_time {
t
} else {
Time::now()
}
}
fn time_request(&self) -> Time {
self.time_request
}
fn cell(&self) -> &HEALPixCell {
&self.tile_cell
}
}
use std::cmp::Ordering;
impl PartialOrd for HpxTexture3D {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.uniq.partial_cmp(&other.uniq)
}
}
use crate::Abort;
impl Ord for HpxTexture3D {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap_abort()
}
}
impl PartialEq for HpxTexture3D {
fn eq(&self, other: &Self) -> bool {
self.uniq == other.uniq
}
}
impl Eq for HpxTexture3D {}
/*
pub struct TextureUniforms<'a> {
texture: &'a HpxTexture3D,
name: String,
}
impl<'a> TextureUniforms<'a> {
pub fn new(texture: &Texture, idx_texture: i32) -> TextureUniforms {
let name = format!("textures_tiles[{}].", idx_texture);
TextureUniforms { texture, name }
}
}
use al_core::shader::{SendUniforms, ShaderBound};
impl<'a> SendUniforms for TextureUniforms<'a> {
fn attach_uniforms<'b>(&self, shader: &'b ShaderBound<'b>) -> &'b ShaderBound<'b> {
shader
.attach_uniform(&format!("{}{}", self.name, "uniq"), &self.texture.uniq)
.attach_uniform(
&format!("{}{}", self.name, "texture_idx"),
&self.texture.idx,
)
.attach_uniform(
&format!("{}{}", self.name, "empty"),
//&((self.texture.full as u8) as f32),
&0.0,
)
.attach_uniform(
&format!("{}{}", self.name, "start_time"),
&self.texture.start_time(),
);
shader
}
}
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,69 +0,0 @@
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
}

View File

@@ -6,12 +6,16 @@ pub struct Triangulation {
pub idx: Vec<u16>,
}
use crate::math::projection::domain::sdf::{self, ProjDef, ProjDefType};
use crate::math::projection::domain::sdf::{
ProjDefType,
ProjDef,
self
};
impl Triangulation {
pub(super) fn build(proj_def: &ProjDefType) -> Triangulation {
let (mut vertices, mut idx) = (Vec::new(), Vec::new());
// get the validity domain
// get the validity domain
let root = Face::new(Vector2::new(-1_f64, -1_f64), Vector2::new(1_f64, 1_f64));
let children = root.split(2);
@@ -106,7 +110,7 @@ impl Face {
off_idx,
off_idx + 2,
off_idx + 3,
]
]
}
};*/
let idx = [
@@ -179,7 +183,7 @@ fn recursive_triangulation(
vertices: &mut Vec<Vector2<f64>>,
idx: &mut Vec<u16>,
depth: u8,
proj_def: &ProjDefType,
proj_def: &ProjDefType
) {
//let (farthest_vertex, dir_farthest_vertex) = face.get_farthest_vertex();
@@ -206,7 +210,7 @@ fn recursive_triangulation(
vertices,
idx,
depth - 1,
proj_def,
proj_def
);
// top-right
recursive_triangulation(
@@ -214,7 +218,7 @@ fn recursive_triangulation(
vertices,
idx,
depth - 1,
proj_def,
proj_def
);
// bottom-left
recursive_triangulation(
@@ -222,7 +226,7 @@ fn recursive_triangulation(
vertices,
idx,
depth - 1,
proj_def,
proj_def
);
// bottom-right
recursive_triangulation(
@@ -230,7 +234,7 @@ fn recursive_triangulation(
vertices,
idx,
depth - 1,
proj_def,
proj_def
);
}
} else {
@@ -254,163 +258,131 @@ fn recursive_triangulation(
match (bl_in, br_in, tr_in, tl_in) {
// 0 VERTEX case
(false, false, false, false) => {}
(false, false, false, false) => {},
// 1 VERTEX cases
// 1 triangle to plot
// (x bl, br, tr, tl)
(true, false, false, false) => {
let u =
sdf::ray_marching(&tl, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&br, &D_TO_WEST, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&tl, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&br, &D_TO_WEST, proj_def).expect("should intersect domain");
face.add_triangle(&[bl, v, u], vertices, idx);
}
},
// (bl, x br, tr, tl)
(false, true, false, false) => {
let u =
sdf::ray_marching(&bl, &D_TO_EAST, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&tr, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&bl, &D_TO_EAST, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&tr, &D_TO_SOUTH, proj_def).expect("should intersect domain");
face.add_triangle(&[br, v, u], vertices, idx);
}
},
// (bl, br, x tr, tl)
(false, false, true, false) => {
let v =
sdf::ray_marching(&br, &D_TO_NORTH, proj_def).expect("should intersect domain");
let u =
sdf::ray_marching(&tl, &D_TO_EAST, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&br, &D_TO_NORTH, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&tl, &D_TO_EAST, proj_def).expect("should intersect domain");
face.add_triangle(&[tr, u, v], vertices, idx);
}
},
// (bl, br, tr, x tl)
(false, false, false, true) => {
let u =
sdf::ray_marching(&bl, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&tr, &D_TO_WEST, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&bl, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&tr, &D_TO_WEST, proj_def).expect("should intersect domain");
face.add_triangle(&[tl, u, v], vertices, idx);
}
},
// 2 VERTICES cases
// (bl, x br, tr, x tl)
(false, true, false, true) => {
let u =
sdf::ray_marching(&bl, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&bl, &D_TO_EAST, proj_def).expect("should intersect domain");
let w =
sdf::ray_marching(&tr, &D_TO_WEST, proj_def).expect("should intersect domain");
let x =
sdf::ray_marching(&tr, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&bl, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&bl, &D_TO_EAST, proj_def).expect("should intersect domain");
let w = sdf::ray_marching(&tr, &D_TO_WEST, proj_def).expect("should intersect domain");
let x = sdf::ray_marching(&tr, &D_TO_SOUTH, proj_def).expect("should intersect domain");
face.add_triangle(&[u, w, tl], vertices, idx);
face.add_triangle(&[u, v, w], vertices, idx);
face.add_triangle(&[v, x, w], vertices, idx);
face.add_triangle(&[v, br, x], vertices, idx);
}
},
// (x bl, br, x tr, tl)
(true, false, true, false) => {
let u =
sdf::ray_marching(&tl, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&tl, &D_TO_EAST, proj_def).expect("should intersect domain");
let w =
sdf::ray_marching(&br, &D_TO_WEST, proj_def).expect("should intersect domain");
let x =
sdf::ray_marching(&br, &D_TO_NORTH, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&tl, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&tl, &D_TO_EAST, proj_def).expect("should intersect domain");
let w = sdf::ray_marching(&br, &D_TO_WEST, proj_def).expect("should intersect domain");
let x = sdf::ray_marching(&br, &D_TO_NORTH, proj_def).expect("should intersect domain");
face.add_triangle(&[bl, w, u], vertices, idx);
face.add_triangle(&[w, x, u], vertices, idx);
face.add_triangle(&[x, v, u], vertices, idx);
face.add_triangle(&[x, tr, v], vertices, idx);
}
},
// (bl, br, x tr, x tl)
(false, false, true, true) => {
let u =
sdf::ray_marching(&bl, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&br, &D_TO_NORTH, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&bl, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&br, &D_TO_NORTH, proj_def).expect("should intersect domain");
face.add_triangle(&[v, tl, u], vertices, idx);
face.add_triangle(&[v, tr, tl], vertices, idx);
}
},
// (x bl, x br, tr, tl)
(true, true, false, false) => {
let u =
sdf::ray_marching(&tl, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&tr, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&tl, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&tr, &D_TO_SOUTH, proj_def).expect("should intersect domain");
face.add_triangle(&[u, bl, v], vertices, idx);
face.add_triangle(&[v, bl, br], vertices, idx);
}
},
// (x bl, br, tr, x tl)
(true, false, false, true) => {
let u =
sdf::ray_marching(&tr, &D_TO_WEST, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&br, &D_TO_WEST, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&tr, &D_TO_WEST, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&br, &D_TO_WEST, proj_def).expect("should intersect domain");
face.add_triangle(&[bl, u, tl], vertices, idx);
face.add_triangle(&[u, bl, v], vertices, idx);
}
},
// (bl, x br, x tr, tl)
(false, true, true, false) => {
let u =
sdf::ray_marching(&tl, &D_TO_EAST, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&bl, &D_TO_EAST, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&tl, &D_TO_EAST, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&bl, &D_TO_EAST, proj_def).expect("should intersect domain");
face.add_triangle(&[br, tr, u], vertices, idx);
face.add_triangle(&[br, u, v], vertices, idx);
}
},
// 3 VERTICES cases
// (x bl, x br, x tr, tl)
(true, true, true, false) => {
let u =
sdf::ray_marching(&tl, &D_TO_EAST, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&tl, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&tl, &D_TO_EAST, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&tl, &D_TO_SOUTH, proj_def).expect("should intersect domain");
face.add_triangle(&[u, v, bl], vertices, idx);
face.add_triangle(&[u, bl, tr], vertices, idx);
face.add_triangle(&[tr, bl, br], vertices, idx);
}
},
// (bl, x br, x tr, x tl)
(false, true, true, true) => {
let u =
sdf::ray_marching(&bl, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&bl, &D_TO_EAST, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&bl, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&bl, &D_TO_EAST, proj_def).expect("should intersect domain");
face.add_triangle(&[tl, u, tr], vertices, idx);
face.add_triangle(&[tr, u, v], vertices, idx);
face.add_triangle(&[v, br, tr], vertices, idx);
}
},
// (x bl, br, x tr, x tl)
(true, false, true, true) => {
let u =
sdf::ray_marching(&br, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&br, &D_TO_WEST, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&br, &D_TO_NORTH, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&br, &D_TO_WEST, proj_def).expect("should intersect domain");
face.add_triangle(&[tl, bl, v], vertices, idx);
face.add_triangle(&[u, tl, v], vertices, idx);
face.add_triangle(&[tr, tl, u], vertices, idx);
}
},
// (x bl, x br, tr, x tl)
(true, true, false, true) => {
let u =
sdf::ray_marching(&tr, &D_TO_WEST, proj_def).expect("should intersect domain");
let v =
sdf::ray_marching(&tr, &D_TO_SOUTH, proj_def).expect("should intersect domain");
let u = sdf::ray_marching(&tr, &D_TO_WEST, proj_def).expect("should intersect domain");
let v = sdf::ray_marching(&tr, &D_TO_SOUTH, proj_def).expect("should intersect domain");
face.add_triangle(&[bl, u, tl], vertices, idx);
face.add_triangle(&[bl, v, u], vertices, idx);
face.add_triangle(&[bl, br, v], vertices, idx);
}
},
// full case must not happen
_ => unreachable!(),
}

View File

@@ -12,27 +12,43 @@ impl<T> Deref for UV<T> {
}
}
use super::config::HiPSConfig;
use super::d2::texture::HpxTexture2D;
use crate::healpix::cell::HEALPixCell;
use crate::renderable::hips::HpxTile;
use crate::{
healpix::cell::HEALPixCell,
survey::{config::HiPSConfig, texture::Texture},
};
pub struct TileUVW([Vector3<f32>; 4]);
impl TileUVW {
// The texture cell passed must be a child of texture
pub fn new(cell: &HEALPixCell, texture: &HpxTexture2D, cfg: &HiPSConfig) -> TileUVW {
pub fn new(
cell: &HEALPixCell,
texture: &Texture,
cfg: &HiPSConfig,
) -> TileUVW {
// Index of the texture in the total set of textures
let texture_idx = texture.idx();
// Index of the slice of textures
let num_textures_by_slice = cfg.num_textures_by_slice();
// Index of the texture in its slice
let idx_in_slice = texture_idx % num_textures_by_slice;
// Index of the column of the texture in its slice
let num_textures_by_side_slice = cfg.num_textures_by_side_slice();
let idx_col_in_slice = idx_in_slice / num_textures_by_side_slice;
// Index of the row of the texture in its slice
let idx_row_in_slice = idx_in_slice % num_textures_by_side_slice;
// Row and column indexes of the tile in its texture
let (idx_col_in_tex, idx_row_in_tex) = cell.offset_in_parent(texture.cell());
let num_textures_by_side_slice_f32 = num_textures_by_side_slice as f32;
let nside = (1 << (cell.depth() - texture.cell().depth())) as f32;
let u = (idx_row_in_tex as f32) / nside;
let v = (idx_col_in_tex as f32) / nside;
let u = ((idx_row_in_slice as f32) + ((idx_row_in_tex as f32) / nside)) / num_textures_by_side_slice_f32;
let v = ((idx_col_in_slice as f32) + ((idx_col_in_tex as f32) / nside)) / num_textures_by_side_slice_f32;
let ds = 1_f32 / nside;
let ds = 1_f32 / (num_textures_by_side_slice_f32 * nside);
let w = texture_idx as f32;
let w = (texture_idx as f32) / (num_textures_by_slice as f32);
TileUVW([
Vector3::new(u, v, w),
Vector3::new(u + ds, v, w),

View File

@@ -2,7 +2,6 @@ pub mod cuts;
pub mod grid;
pub mod subdivide_texture;
use al_core::webgl_ctx::WebGlRenderingCtx;
use std::fmt::Debug;
use std::marker::Unpin;
use std::vec;
@@ -71,6 +70,7 @@ pub struct Image {
coo_sys: CooSystem,
}
use al_core::pixel::Pixel;
use al_core::texture::TEX_PARAMS;
use fitsrs::hdu::header::extension;
use fitsrs::hdu::AsyncHDU;
use futures::io::BufReader;
@@ -151,26 +151,7 @@ impl Image {
gl,
width as i32,
height as i32,
&[
(
WebGlRenderingCtx::TEXTURE_MIN_FILTER,
WebGlRenderingCtx::NEAREST_MIPMAP_NEAREST,
),
(
WebGlRenderingCtx::TEXTURE_MAG_FILTER,
WebGlRenderingCtx::NEAREST,
),
// Prevents s-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_S,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents t-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_T,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
],
TEX_PARAMS,
Some(slice),
)?;
@@ -188,10 +169,6 @@ impl Image {
.await?
};
for tex in &textures {
tex.generate_mipmap();
}
let start = cuts.start * scale + offset;
let end = cuts.end * scale + offset;
@@ -671,7 +648,7 @@ impl Image {
return Ok(());
}
//self.gl.enable(WebGl2RenderingContext::BLEND);
self.gl.enable(WebGl2RenderingContext::BLEND);
let ImageMetadata {
color,
@@ -749,7 +726,7 @@ impl Image {
//self.gl.enable(WebGl2RenderingContext::CULL_FACE);
//self.gl.disable(WebGl2RenderingContext::BLEND);
self.gl.disable(WebGl2RenderingContext::BLEND);
Ok(())
}

View File

@@ -5,7 +5,7 @@ use futures::AsyncReadExt;
use super::cuts;
use al_core::image::format::ImageFormat;
use al_core::texture::pixel::Pixel;
use al_core::webgl_ctx::WebGlRenderingCtx;
use al_core::texture::TEX_PARAMS;
use al_core::Texture2D;
use al_core::WebGlContext;
use std::ops::Range;
@@ -35,33 +35,12 @@ where
];
for _ in 0..num_textures {
let tex_chunk = Texture2D::create_empty_with_format::<F>(
tex_chunks.push(Texture2D::create_empty_with_format::<F>(
gl,
max_tex_size as i32,
max_tex_size as i32,
&[
(
WebGlRenderingCtx::TEXTURE_MIN_FILTER,
WebGlRenderingCtx::NEAREST_MIPMAP_NEAREST,
),
(
WebGlRenderingCtx::TEXTURE_MAG_FILTER,
WebGlRenderingCtx::NEAREST,
),
// Prevents s-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_S,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents t-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_T,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
],
)?;
tex_chunk.generate_mipmap();
tex_chunks.push(tex_chunk);
TEX_PARAMS,
)?);
}
let mut pixels_written = 0;

View File

@@ -351,13 +351,13 @@ impl RasterizedLineRenderer {
camera: &CameraViewPort,
proj: &ProjectionType,
) -> Result<(), JsValue> {
//self.gl.enable(WebGl2RenderingContext::BLEND);
/*self.gl.blend_func_separate(
self.gl.enable(WebGl2RenderingContext::BLEND);
self.gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);*/
);
//self.gl.disable(WebGl2RenderingContext::CULL_FACE);
{
@@ -425,7 +425,7 @@ impl RasterizedLineRenderer {
_ => (),
}
}
//self.gl.disable(WebGl2RenderingContext::BLEND);
self.gl.disable(WebGl2RenderingContext::BLEND);
Ok(())
}

View File

@@ -553,7 +553,7 @@ impl MOCIntern {
let view2world = camera.get_m2w();
let icrs2world = view2world * icrs2view;
//self.gl.enable(WebGl2RenderingContext::BLEND);
self.gl.enable(WebGl2RenderingContext::BLEND);
crate::shader::get_shader(&self.gl, shaders, "moc_base.vert", "moc_base.frag")?
.bind(&self.gl)
@@ -569,7 +569,7 @@ impl MOCIntern {
0,
);
//self.gl.disable(WebGl2RenderingContext::BLEND);
self.gl.disable(WebGl2RenderingContext::BLEND);
}
}
Ok(())

View File

@@ -14,6 +14,8 @@ use crate::tile_fetcher::TileFetcherQueue;
use al_core::image::format::ChannelType;
pub use hips::HiPS;
pub use catalog::Manager;
use al_api::color::ColorRGB;
@@ -28,11 +30,10 @@ use al_core::VertexArrayObject;
use al_core::WebGlContext;
use crate::camera::CameraViewPort;
use crate::renderable::hips::config::HiPSConfig;
use crate::shader::ShaderId;
use crate::shader::ShaderManager;
use crate::Abort;
use crate::ProjectionType;
use crate::{shader::ShaderManager, survey::config::HiPSConfig};
// Recursively compute the number of subdivision needed for a cell
// to not be too much skewed
@@ -41,9 +42,6 @@ use hips::raytracing::RayTracer;
use std::collections::HashMap;
use hips::d2::HiPS2D;
use hips::d3::HiPS3D;
use wasm_bindgen::JsValue;
use web_sys::WebGl2RenderingContext;
@@ -55,12 +53,10 @@ 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
hipses: HashMap<CreatorDid, HiPS>,
surveys: 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
@@ -80,9 +76,9 @@ pub struct Layers {
}
const DEFAULT_BACKGROUND_COLOR: ColorRGB = ColorRGB {
r: 0.0,
g: 0.0,
b: 0.0,
r: 0.05,
g: 0.05,
b: 0.05,
};
fn get_backgroundcolor_shader<'a>(
@@ -124,8 +120,7 @@ impl ImageLayer {
impl Layers {
pub fn new(gl: &WebGlContext, projection: &ProjectionType) -> Result<Self, JsValue> {
let hipses = HashMap::new();
let surveys = HashMap::new();
let images = HashMap::new();
let meta = HashMap::new();
let ids = HashMap::new();
@@ -159,7 +154,7 @@ impl Layers {
let background_color = DEFAULT_BACKGROUND_COLOR;
Ok(Layers {
hipses,
surveys,
images,
meta,
@@ -175,10 +170,19 @@ impl Layers {
})
}
pub fn set_hips_url(&mut self, cdid: &CreatorDid, new_url: String) -> Result<(), JsValue> {
if let Some(hips) = self.hipses.get_mut(cdid) {
pub fn set_survey_url(&mut self, cdid: &CreatorDid, new_url: String) -> Result<(), JsValue> {
if let Some(survey) = self.surveys.get_mut(cdid) {
// update the root_url
hips.get_config_mut().set_root_url(new_url.clone());
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();
}
}*/
Ok(())
} else {
@@ -187,8 +191,8 @@ impl Layers {
}
/*pub fn reset_frame(&mut self) {
for hips in self.hips.values_mut() {
hips.reset_frame();
for survey in self.surveys.values_mut() {
survey.reset_frame();
}
}*/
@@ -216,15 +220,15 @@ impl Layers {
let raytracer = &self.raytracer;
let raytracing = camera.is_raytracing(projection);
// Check whether a hips to plot is allsky
// Check whether a survey 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(hips) = self.hipses.get(cdid) {
let hips_cfg = hips.get_config();
(hips.is_allsky() || hips_cfg.get_format().get_channel() == ChannelType::RGB8U)
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)
&& meta.opacity == 1.0
} else {
// image fits case
@@ -256,6 +260,8 @@ impl Layers {
);
}
// The first layer must be paint independently of its alpha channel
self.gl.enable(WebGl2RenderingContext::BLEND);
// Pre loop over the layers to see if a HiPS is entirely covering those behind
// so that we do not have to render those
let mut idx_start_layer = 0;
@@ -263,13 +269,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(hips) = self.hipses.get_mut(id) {
let hips_cfg = hips.get_config();
if let Some(survey) = self.surveys.get_mut(id) {
let hips_cfg = survey.get_config();
let fully_covering_hips = (hips.is_allsky()
let fully_covering_survey = (survey.is_allsky()
|| hips_cfg.get_format().get_channel() == ChannelType::RGB8U)
&& meta.opacity == 1.0;
if fully_covering_hips {
if fully_covering_survey {
idx_start_layer = idx_layer;
}
}
@@ -279,19 +285,13 @@ 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 hips if necessary
// 1. Update the survey if necessary
let id = self.ids.get(layer).expect("Url should be found");
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)?;
}
}
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)?;
} else if let Some(images) = self.images.get_mut(id) {
// 2. Draw it if its opacity is not null
for image in images {
@@ -301,6 +301,14 @@ impl Layers {
}
}
self.gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);
self.gl.disable(WebGl2RenderingContext::BLEND);
Ok(())
}
@@ -339,14 +347,14 @@ impl Layers {
Ok(id_layer)
} else {
// Resource not needed anymore
if let Some(hips) = self.hipses.remove(&id) {
if let Some(s) = self.surveys.remove(&id) {
// A HiPS has been found and removed
let hips_frame = hips.get_config().get_frame();
let hips_frame = s.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(hips.get_config().get_creator_did());
tile_fetcher.delete_hips_local_files(s.get_config().get_creator_did());
Ok(id_layer)
} else if let Some(_) = self.images.remove(&id) {
@@ -354,7 +362,7 @@ impl Layers {
Ok(id_layer)
} else {
Err(JsValue::from_str(&format!(
"Url found {:?} is associated to no 2D HiPSes.",
"Url found {:?} is associated to no surveys.",
id
)))
}
@@ -409,7 +417,7 @@ impl Layers {
Ok(())
}
pub fn add_hips(
pub fn add_image_hips(
&mut self,
gl: &WebGlContext,
hips: HiPSCfg,
@@ -445,13 +453,13 @@ impl Layers {
camera.set_longitude_reversed(longitude_reversed, proj);
// 3. Add the image hips
// 3. Add the image survey
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
.hipses
.surveys
.keys()
.any(|hips_cdid| hips_cdid == &creator_did);
@@ -470,21 +478,16 @@ impl Layers {
}*/
camera.register_view_frame(cfg.get_frame(), proj);
let hips = if cfg.get_cube_depth().is_some() {
// HiPS cube
HiPS::D3(HiPS3D::new(cfg, gl)?)
} else {
HiPS::D2(HiPS2D::new(cfg, gl)?)
};
let hips = HiPS::new(cfg, gl)?;
// add the frame to the camera
self.hipses.insert(creator_did.clone(), hips);
self.surveys.insert(creator_did.clone(), hips);
}
self.ids.insert(layer.clone(), creator_did.clone());
let hips = self
.hipses
.surveys
.get(&creator_did)
.ok_or(JsValue::from_str("HiPS not found"))?;
Ok(hips)
@@ -565,15 +568,15 @@ impl Layers {
&mut self,
layer: String,
meta: ImageMetadata,
camera: &CameraViewPort,
camera: &mut CameraViewPort,
projection: &ProjectionType,
) -> Result<(), JsValue> {
let layer_ref = layer.as_str();
/*if let Some(meta_old) = self.meta.get(layer_ref) {
if let Some(meta_old) = self.meta.get(layer_ref) {
if !meta_old.visible() && meta.visible() {
if let Some(hips) = self.get_mut_hips_from_layer(layer_ref) {
hips.recompute_vertices(camera, projection);
if let Some(survey) = self.get_mut_hips_from_layer(layer_ref) {
survey.recompute_vertices(camera, projection);
}
if let Some(images) = self.get_mut_image_from_layer(layer_ref) {
@@ -593,8 +596,8 @@ impl Layers {
for idx in 0..layer_idx {
let cur_layer = self.layers[idx].clone();
if let Some(hips) = self.get_mut_hips_from_layer(&cur_layer) {
hips.recompute_vertices(camera, projection);
if let Some(survey) = self.get_mut_hips_from_layer(&cur_layer) {
survey.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)?;
@@ -602,9 +605,9 @@ impl Layers {
}
}
}
}*/
}
// Expect the image hips to be found in the hash map
// Expect the image survey 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)))
})?;
@@ -617,24 +620,32 @@ impl Layers {
pub fn get_hips_from_layer(&self, layer: &str) -> Option<&HiPS> {
self.ids
.get(layer)
.map(|cdid| self.hipses.get(cdid))
.map(|cdid| self.surveys.get(cdid))
.flatten()
}
pub fn get_mut_hips_from_layer(&mut self, layer: &str) -> Option<&mut HiPS> {
if let Some(cdid) = self.ids.get_mut(layer) {
self.hipses.get_mut(cdid)
self.surveys.get_mut(cdid)
} else {
None
}
}
pub fn get_mut_hips_from_cdid(&mut self, cdid: &str) -> Option<&mut HiPS> {
self.hipses.get_mut(cdid)
self.surveys.get_mut(cdid)
}
pub fn get_mut_hipses(&mut self) -> impl Iterator<Item = &mut HiPS> {
self.hipses.values_mut()
pub fn get_hips_from_cdid(&mut self, cdid: &str) -> Option<&HiPS> {
self.surveys.get(cdid)
}
pub fn values_hips(&self) -> impl Iterator<Item = &HiPS> {
self.surveys.values()
}
pub fn values_mut_hips(&mut self) -> impl Iterator<Item = &mut HiPS> {
self.surveys.values_mut()
}
// Fits images getters

View File

@@ -176,13 +176,13 @@ impl PolylineRenderer {
camera: &CameraViewPort,
proj: &ProjectionType,
) -> Result<(), JsValue> {
//self.gl.enable(WebGl2RenderingContext::BLEND);
/*self.gl.blend_func_separate(
self.gl.enable(WebGl2RenderingContext::BLEND);
self.gl.blend_func_separate(
WebGl2RenderingContext::SRC_ALPHA,
WebGl2RenderingContext::ONE_MINUS_SRC_ALPHA,
WebGl2RenderingContext::ONE,
WebGl2RenderingContext::ONE,
);*/
);
// draw the instanced lines
let icrs2view = CooSystem::ICRS.to(camera.get_coo_system());
@@ -203,7 +203,7 @@ impl PolylineRenderer {
self.num_instances as i32,
);
//self.gl.disable(WebGl2RenderingContext::BLEND);
self.gl.disable(WebGl2RenderingContext::BLEND);
Ok(())
}

View File

@@ -0,0 +1,40 @@
struct BitVector<const N: usize>([u64; N]);
impl<const N: usize> Default for BitVector<N> {
fn default() -> Self {
Self([0_u64; N])
}
}
impl<const N: usize> BitVector<N> {
pub fn new_empty() -> Self {
Self::default()
}
pub fn set(&mut self, i: usize) {
debug_assert!(i < (N << 6));
let j = i >> 6;
let k = i & 0x3f;
self.0[j] |= 1 << k;
}
pub fn get(&self, i: usize) -> bool {
debug_assert!(i < (N << 6));
let j = i >> 6;
let k = i & 0x3f;
(self.0[j] >> k) & 0x1 == 1
}
}
#[cfg(test)]
mod tests {
use super::BitVector;
#[test]
fn test_bitvector_basic_op() {
let mut bv: BitVector<32> = BitVector::new_empty();
bv.set(64);
assert!(bv.get(64));
}
}

View File

@@ -4,28 +4,27 @@ 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};
#[cfg(feature = "webgl2")]
use al_core::image::format::{R16I, R32I, R8UI};
use al_core::image::format::{R32F, R64F, RGB8U, RGBA8U};
use al_core::image::Image;
use al_core::shader::{SendUniforms, ShaderBound};
use al_core::texture::TEX_PARAMS;
use al_core::Texture2DArray;
use al_core::WebGlContext;
use super::texture::{HpxTexture2D, HpxTexture2DUniforms};
use super::config::HiPSConfig;
use super::texture::Texture;
use super::texture::TextureUniforms;
use crate::downloader::request::allsky::Allsky;
use crate::healpix::cell::HEALPixCell;
use crate::healpix::cell::NUM_HPX_TILES_DEPTH_ZERO;
use crate::renderable::hips::config::HiPSConfig;
use crate::math::lonlat::LonLatT;
use crate::time::Time;
use crate::Abort;
use crate::JsValue;
@@ -61,24 +60,24 @@ impl Ord for TextureCellItem {
}
}
impl From<HpxTexture2D> for TextureCellItem {
fn from(texture: HpxTexture2D) -> Self {
impl From<Texture> for TextureCellItem {
fn from(texture: Texture) -> Self {
let time_request = texture.time_request();
let cell = *texture.cell();
Self { cell, time_request }
}
}
impl From<&HpxTexture2D> for TextureCellItem {
fn from(texture: &HpxTexture2D) -> Self {
impl From<&Texture> for TextureCellItem {
fn from(texture: &Texture) -> Self {
let time_request = texture.time_request();
let cell = *texture.cell();
Self { cell, time_request }
}
}
impl From<&mut HpxTexture2D> for TextureCellItem {
fn from(texture: &mut HpxTexture2D) -> Self {
impl From<&mut Texture> for TextureCellItem {
fn from(texture: &mut Texture) -> Self {
let time_request = texture.time_request();
let cell = *texture.cell();
@@ -124,23 +123,30 @@ impl HEALPixCellHeap {
}
}
use crate::renderable::hips::HpxTileBuffer;
// Fixed sized binary heap
pub struct HiPS2DBuffer {
pub struct ImageSurveyTextures {
// Some information about the HiPS
config: HiPSConfig,
pub config: HiPSConfig,
heap: HEALPixCellHeap,
num_root_textures_available: u8,
//num_root_textures_available: usize,
size: usize,
textures: HashMap<HEALPixCell, HpxTexture2D>,
base_textures: [HpxTexture2D; NUM_HPX_TILES_DEPTH_ZERO],
pub textures: HashMap<HEALPixCell, Texture>,
pub base_textures: [Texture; NUM_HPX_TILES_DEPTH_ZERO],
//pub cutoff_values_tile: Rc<RefCell<HashMap<HEALPixCell, (f32, f32)>>>,
// Array of 2D textures
texture_2d_array: Texture2DArray,
pub texture_2d_array: Texture2DArray,
// A boolean ensuring the root textures
// have already been loaded
//ready: bool,
pub start_time: Option<Time>,
available_tiles_during_frame: bool,
//num_base_textures: usize,
//exec: Rc<RefCell<TaskExecutor>>,
}
// Define a set of textures compatible with the HEALPix tile format and size
@@ -149,41 +155,128 @@ fn create_texture_array<F: ImageFormat>(
config: &HiPSConfig,
) -> Result<Texture2DArray, JsValue> {
let texture_size = config.get_texture_size();
let num_textures_by_side_slice = config.num_textures_by_side_slice();
let num_slices = config.num_slices();
Texture2DArray::create_empty::<F>(
gl,
texture_size,
texture_size,
// 256 is a consensus for targetting the maximum GPU architectures. We create a 128 slices to optimize performance
128,
&[
(
WebGlRenderingCtx::TEXTURE_MIN_FILTER,
// apply mipmapping
WebGlRenderingCtx::NEAREST_MIPMAP_NEAREST,
),
(
WebGlRenderingCtx::TEXTURE_MAG_FILTER,
WebGlRenderingCtx::NEAREST,
),
// Prevents s-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_S,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
// Prevents t-coordinate wrapping (repeating)
(
WebGlRenderingCtx::TEXTURE_WRAP_T,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
(
WebGlRenderingCtx::TEXTURE_WRAP_R,
WebGlRenderingCtx::CLAMP_TO_EDGE,
),
],
texture_size * num_textures_by_side_slice,
texture_size * num_textures_by_side_slice,
num_slices,
TEX_PARAMS,
)
}
impl HiPS2DBuffer {
impl ImageSurveyTextures {
pub fn new(gl: &WebGlContext, config: HiPSConfig) -> Result<ImageSurveyTextures, JsValue> {
let size = config.num_textures() - 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 ready = false;
//let num_root_textures_available = 0;
let available_tiles_during_frame = false;
let start_time = None;
//let num_base_textures = 0;
Ok(ImageSurveyTextures {
config,
heap,
size,
//num_root_textures_available,
textures,
base_textures,
//num_base_textures,
texture_2d_array,
available_tiles_during_frame,
//ready,
start_time,
})
}
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;
self.start_time = None;
Ok(())
}
pub fn push_allsky(&mut self, allsky: Allsky) -> Result<(), JsValue> {
let Allsky {
image,
@@ -193,16 +286,163 @@ impl HiPS2DBuffer {
} = allsky;
{
let mutex_locked = image.borrow();
let mutex_locked = image.lock().unwrap_abort();
let images = mutex_locked.as_ref().unwrap_abort();
for (idx, image) in images.iter().enumerate() {
self.push(&HEALPixCell(depth_tile, idx as u64), image, time_req)?;
}
}
//self.set_ready();
Ok(())
}
/*pub fn set_ready(&mut self) {
self.ready = true;
// The survey is ready
self.start_time = Some(Time::now());
self.num_root_textures_available = NUM_HPX_TILES_DEPTH_ZERO;
}*/
// 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 + std::fmt::Debug>(
&mut self,
cell: &HEALPixCell,
image: I,
time_request: Time,
) -> Result<(), JsValue> {
if !self.contains_tile(cell) {
let dd = self.config.delta_depth();
// Get the texture cell in which the tile has to be
let tex_cell = cell.get_texture_cell(dd);
let tex_cell_is_root = tex_cell.is_root();
if !tex_cell_is_root && !self.textures.contains_key(&tex_cell) {
// The texture is not among the essential ones
// (i.e. is not a root texture)
let texture = if self.is_heap_full() {
// Pop the oldest requested texture
let oldest_texture = self.heap.pop().unwrap_abort();
// Ensure this is not a base texture
debug_assert!(!oldest_texture.is_root());
// Remove it from the textures HashMap
let mut texture = self.textures.remove(&oldest_texture.cell).expect(
"Texture (oldest one) has not been found in the buffer of textures",
);
// Clear and assign it to tex_cell
/*let idx = if tex_cell_is_root {
self.num_base_textures += 1;
Some(tex_cell.idx() as i32)
} else {
None
};*/
texture.replace(&tex_cell, time_request);
texture
} else {
// The heap buffer is not full, let's create a new
// texture with an unique idx
// The idx is computed based on the current size of the buffer
/*let idx = if tex_cell_is_root {
self.num_base_textures += 1;
tex_cell.idx() as usize
} else {
//NUM_HPX_TILES_DEPTH_ZERO + (self.heap.len() - self.num_base_textures)
self.heap.len()
};*/
//let idx = NUM_HPX_TILES_DEPTH_ZERO + (self.heap.len() - self.num_base_textures);
let idx = NUM_HPX_TILES_DEPTH_ZERO + self.heap.len();
Texture::new(&tex_cell, idx as i32, time_request)
};
// Push it to the buffer
self.heap.push(&texture);
self.textures.insert(tex_cell, texture);
}
// At this point, the texture that should contain the tile
// is in the buffer
// and the tile is not already in any textures of the buffer
// We can safely push it
// First get the texture
let texture = if !tex_cell_is_root {
self.textures
.get_mut(&tex_cell)
.expect("the cell has to be in the tile buffer")
} else {
let HEALPixCell(_, idx) = tex_cell;
&mut self.base_textures[idx as usize]
};
//let missing = image.is_none();
send_to_gpu(
cell,
texture,
image,
&self.texture_2d_array,
&mut self.config,
)?;
texture.append(
cell, // The tile cell
&self.config,
//missing,
);
self.available_tiles_during_frame = true;
//self.ready = true;
/*if self.start_time.is_none() {
self.start_time = Some(Time::now());
}*/
/*if tex_cell.is_root(self.config.delta_depth()) && texture.is_available() {
self.num_root_textures_available += 1;
debug_assert!(self.num_root_textures_available <= NUM_HPX_TILES_DEPTH_ZERO);
if self.num_root_textures_available == NUM_HPX_TILES_DEPTH_ZERO {
self.ready = true;
// The survey is ready
//self.start_time = Some(Time::now());
}
}*/
}
Ok(())
}
// Return if tiles did become available
pub 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) {
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
@@ -214,12 +454,12 @@ impl HiPS2DBuffer {
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)
self.base_textures[idx as usize].contains(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)
texture.contains(cell)
} else {
// The texture in which cell should be is not present
false
@@ -227,14 +467,6 @@ impl HiPS2DBuffer {
}
}
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*/) {
@@ -269,291 +501,53 @@ impl HiPS2DBuffer {
self.heap.update_entry(tex_cell_item);
}
pub fn push<I: Image>(
&mut self,
cell: &HEALPixCell,
image: I,
time_request: Time,
) -> Result<(), JsValue> {
if !self.contains_tile(cell) {
let dd = self.config.delta_depth();
// Get the texture cell in which the tile has to be
let tex_cell = cell.get_texture_cell(dd);
let tex_cell_is_root = tex_cell.is_root();
if !tex_cell_is_root && !self.textures.contains_key(&tex_cell) {
// The texture is not among the essential ones
// (i.e. is not a root texture)
let texture = if self.is_heap_full() {
// Pop the oldest requested texture
let oldest_texture = self.heap.pop().unwrap_abort();
// Ensure this is not a base texture
debug_assert!(!oldest_texture.is_root());
// Remove it from the textures HashMap
let mut texture = self.textures.remove(&oldest_texture.cell).expect(
"Texture (oldest one) has not been found in the buffer of textures",
);
texture.replace(&tex_cell, time_request);
texture
} else {
let idx = NUM_HPX_TILES_DEPTH_ZERO + self.heap.len();
HpxTexture2D::new(&tex_cell, idx as i32, time_request)
};
// Push it to the buffer
self.heap.push(&texture);
self.textures.insert(tex_cell, texture);
}
if tex_cell_is_root {
self.num_root_textures_available += 1;
if self.num_root_textures_available == 12 {
self.texture_2d_array.generate_mipmap()
}
}
// At this point, the texture that should contain the tile
// is in the buffer
// and the tile is not already in any textures of the buffer
// We can safely push it
// First get the texture
let texture = if !tex_cell_is_root {
self.textures
.get_mut(&tex_cell)
.expect("the cell has to be in the tile buffer")
} else {
let HEALPixCell(_, idx) = tex_cell;
&mut self.base_textures[idx as usize]
};
send_to_gpu(
cell,
texture,
image,
&self.texture_2d_array,
&mut self.config,
)?;
texture.append(
cell, // The tile cell
&self.config,
);
self.available_tiles_during_frame = true;
}
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
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
}
// Tell if a texture is available meaning all its sub tiles
// must have been written for the GPU
fn contains(&self, cell: &HEALPixCell) -> bool {
if let Some(t) = self.get(cell) {
t.is_full()
} else {
false
}
}
/// 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 {
self.textures.get(cell)
}
}
fn config(&self) -> &HiPSConfig {
&self.config
}
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);
// 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();
let cfg = &self.config;
// Index of the texture in the total set of textures
let texture_idx = texture.idx();
// Index of the slice of textures
let num_textures_by_slice = cfg.num_textures_by_slice();
let idx_slice = texture_idx / num_textures_by_slice;
// Index of the texture in its slice
let idx_in_slice = texture_idx % num_textures_by_slice;
// Index of the column of the texture in its slice
let num_textures_by_side_slice = cfg.num_textures_by_side_slice();
let idx_col_in_slice = idx_in_slice / num_textures_by_side_slice;
// Index of the row of the texture in its slice
let idx_row_in_slice = idx_in_slice % num_textures_by_side_slice;
// The size of the global texture containing the tiles
let texture_size = cfg.get_texture_size();
// Offset in the slice in pixels
let mut pos_tex = Vector3::new(
(dy * (texture_size as f64)) as i32,
(dx * (texture_size as f64)) as i32,
texture_idx,
let mut offset = Vector3::new(
(idx_row_in_slice as i32) * texture_size + ((dy * (texture_size as f64)) as i32),
(idx_col_in_slice as i32) * texture_size + ((dx * (texture_size as f64)) as i32),
idx_slice,
);
// Offset in the slice in pixels
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()
if self.config.tex_storing_fits {
let mut uvy = offset.y as f32 / 4096.0;
uvy = self.config.size_tile_uv
+ 2.0 * self.config.size_tile_uv * (uvy / self.config.size_tile_uv).floor()
- uvy;
pos_tex.y = (uvy * texture_size) as i32;
offset.y = (uvy * 4096.0) as i32;
}
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)
Ok(offset)
} else {
Err(JsValue::from_str(&format!(
"{:?} not loaded in the GPU, please wait before trying again.",
@@ -561,11 +555,80 @@ impl HpxTileBuffer for 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 is_ready(&self) -> bool {
self.ready
}*/
// Get the textures in the buffer
// The resulting array is uniq sorted
/*fn get_allsky_textures(&self) -> [Option<&Texture>; NUM_HPX_TILES_DEPTH_ZERO] {
//debug_assert!(self.is_ready());
/*let mut textures = self.textures.values().collect::<Vec<_>>();
textures.sort_unstable();
textures*/
[
self.textures.get(&HEALPixCell(0, 0)),
self.textures.get(&HEALPixCell(0, 1)),
self.textures.get(&HEALPixCell(0, 2)),
self.textures.get(&HEALPixCell(0, 3)),
self.textures.get(&HEALPixCell(0, 4)),
self.textures.get(&HEALPixCell(0, 5)),
self.textures.get(&HEALPixCell(0, 6)),
self.textures.get(&HEALPixCell(0, 7)),
self.textures.get(&HEALPixCell(0, 8)),
self.textures.get(&HEALPixCell(0, 9)),
self.textures.get(&HEALPixCell(0, 10)),
self.textures.get(&HEALPixCell(0, 11)),
]
}*/
pub fn get_texture_array(&self) -> &Texture2DArray {
&self.texture_2d_array
}
}
fn send_to_gpu<I: Image>(
cell: &HEALPixCell,
texture: &HpxTexture2D,
texture: &Texture,
image: I,
texture_array: &Texture2DArray,
cfg: &mut HiPSConfig,
@@ -573,7 +636,17 @@ fn send_to_gpu<I: Image>(
// Index of the texture in the total set of textures
let texture_idx = texture.idx();
// Index of the slice of textures
let idx_slice = texture_idx;
let num_textures_by_slice = cfg.num_textures_by_slice();
let idx_slice = texture_idx / num_textures_by_slice;
// Index of the texture in its slice
let idx_in_slice = texture_idx % num_textures_by_slice;
// Index of the column of the texture in its slice
let num_textures_by_side_slice = cfg.num_textures_by_side_slice();
let idx_col_in_slice = idx_in_slice / num_textures_by_side_slice;
// Index of the row of the texture in its slice
let idx_row_in_slice = idx_in_slice % num_textures_by_side_slice;
// Row and column indexes of the tile in its texture
let delta_depth = cfg.delta_depth();
let (idx_col_in_tex, idx_row_in_tex) = cell.get_offset_in_texture_cell(delta_depth);
@@ -585,17 +658,17 @@ fn send_to_gpu<I: Image>(
// Offset in the slice in pixels
let offset = Vector3::new(
(idx_row_in_tex as i32) * tile_size,
(idx_col_in_tex as i32) * tile_size,
(idx_row_in_slice as i32) * texture_size + (idx_row_in_tex as i32) * tile_size,
(idx_col_in_slice as i32) * texture_size + (idx_col_in_tex as i32) * tile_size,
idx_slice,
);
image.insert_into_3d_texture(texture_array, &offset)?;
image.tex_sub_image_3d(&texture_array, &offset)?;
Ok(())
}
impl SendUniforms for HiPS2DBuffer {
impl SendUniforms for ImageSurveyTextures {
// Send only the allsky textures
fn attach_uniforms<'a>(&self, shader: &'a ShaderBound<'a>) -> &'a ShaderBound<'a> {
// Send the textures
@@ -610,21 +683,25 @@ impl SendUniforms for HiPS2DBuffer {
let cell = HEALPixCell(0, idx as u64);
let texture = self.get(&cell).unwrap();
let texture_uniforms = HpxTexture2DUniforms::new(texture, idx as i32);
let texture_uniforms = TextureUniforms::new(texture, idx as i32);
shader.attach_uniforms_from(&texture_uniforms);
/*else {
let texture = &Texture::new(&cell, idx as i32, Time::now());
let texture_uniforms = TextureUniforms::new(texture, idx as i32);
shader.attach_uniforms_from(&texture_uniforms);
}*/
}
//}
let shader = shader
.attach_uniforms_from(&self.config)
.attach_uniform("tex", &self.texture_2d_array)
.attach_uniform("num_slices", &(self.texture_2d_array.num_slices as i32));
.attach_uniforms_from(&self.texture_2d_array);
shader
}
}
impl Drop for HiPS2DBuffer {
impl Drop for ImageSurveyTextures {
fn drop(&mut self) {
// Cleanup the heap
self.heap.clear();

View File

@@ -1,11 +1,141 @@
use al_api::hips::ImageExt;
use al_core::image::format::{ChannelType, ImageFormatType};
use al_core::{image::format::ImageFormat, image::raw::ImageBuffer};
#[derive(Debug)]
pub struct EmptyTileImage {
inner: ImageType,
}
use al_core::{image::ImageType, pixel::Pixel};
impl EmptyTileImage {
fn new(size: i32, channel: ChannelType) -> EmptyTileImage {
debug_assert!(math::utils::is_power_of_two(size));
let inner = match channel {
ChannelType::RGBA8U => {
let image = ImageBuffer::<RGBA8U>::allocate(
&<<RGBA8U as ImageFormat>::P as Pixel>::BLACK,
size,
size,
);
ImageType::RawRgba8u { image }
}
ChannelType::RGB8U => {
let image = ImageBuffer::<RGB8U>::allocate(
&<<RGB8U as ImageFormat>::P as Pixel>::BLACK,
size,
size,
);
ImageType::RawRgb8u { image }
}
ChannelType::R32F => {
let image = ImageBuffer::<R32F>::allocate(
&<<R32F as ImageFormat>::P as Pixel>::BLACK,
size,
size,
);
ImageType::RawR32f { image }
}
ChannelType::R64F => {
let image = ImageBuffer::<R32F>::allocate(
&<<R32F as ImageFormat>::P as Pixel>::BLACK,
size,
size,
);
ImageType::RawR32f { image }
}
#[cfg(feature = "webgl2")]
ChannelType::R8UI => {
let image = ImageBuffer::<R8UI>::allocate(
&<<R8UI as ImageFormat>::P as Pixel>::BLACK,
size,
size,
);
ImageType::RawR8ui { image }
}
#[cfg(feature = "webgl2")]
ChannelType::R16I => {
let image = ImageBuffer::<R16I>::allocate(
&<<R16I as ImageFormat>::P as Pixel>::BLACK,
size,
size,
);
ImageType::RawR16i { image }
}
#[cfg(feature = "webgl2")]
ChannelType::R32I => {
let image = ImageBuffer::<R32I>::allocate(
&<<R32I as ImageFormat>::P as Pixel>::BLACK,
size,
size,
);
ImageType::RawR32i { image }
}
_ => todo!(),
};
EmptyTileImage {
inner,
//pixel_fill,
}
}
}
use al_core::{
image::{
format::{R16I, R32F, R32I, R8UI},
Image,
},
Texture2DArray,
};
use cgmath::Vector3;
impl Image for EmptyTileImage {
fn tex_sub_image_3d(
&self,
// The texture array
textures: &Texture2DArray,
// An offset to write the image in the texture array
offset: &Vector3<i32>,
) -> Result<(), JsValue> {
self.inner.tex_sub_image_3d(textures, offset)
}
}
use al_core::image::format::{ChannelType, ImageFormatType, RGB8U, RGBA8U};
//use super::TileArrayBuffer;
/*use super::{ArrayF32, ArrayF64, ArrayI16, ArrayI32, ArrayU8};
fn create_black_tile(format: FormatImageType, width: i32, value: f32) -> TileArrayBufferImage {
let _num_channels = format.get_num_channels() as i32;
match format {
FormatImageType::JPG => TileArrayBufferImage::U8(JPG::create_black_tile(width)),
FormatImageType::PNG => TileArrayBufferImage::U8(PNG::create_black_tile(width)),
FormatImageType::FITS(_fits) => match format.get_type() {
WebGl2RenderingContext::FLOAT => {
TileArrayBufferImage::F32(FITS::create_black_tile(width, value))
}
WebGl2RenderingContext::INT => {
TileArrayBufferImage::I32(FITS::create_black_tile(width, value as i32))
}
WebGl2RenderingContext::SHORT => {
TileArrayBufferImage::I16(FITS::create_black_tile(width, value as i16))
}
WebGl2RenderingContext::UNSIGNED_BYTE => {
TileArrayBufferImage::U8(FITS::create_black_tile(width, value as u8))
}
_ => unimplemented!(),
},
_ => unimplemented!(),
}
}*/
#[derive(Debug)]
pub struct HiPSConfig {
pub root_url: String,
// HiPS image format
// TODO: Make that independant of the HiPS but of the ImageFormat
pub empty_image: EmptyTileImage,
// The size of the texture images
pub texture_size: i32,
@@ -15,14 +145,12 @@ pub struct HiPSConfig {
delta_depth: u8,
min_depth_tile: u8,
min_depth_texture: u8,
// the number of slices for cubes
cube_depth: Option<u32>,
// Num tiles per texture
num_tiles_per_texture: usize,
// Max depth of the current HiPS tiles
max_depth_texture: u8,
max_depth_tile: u8,
num_textures: usize,
pub is_allsky: bool,
@@ -52,6 +180,10 @@ use crate::HiPSProperties;
use al_api::coo_system::CooSystem;
use wasm_bindgen::JsValue;
const NUM_TEXTURES_BY_SIDE_SLICE: i32 = 8;
const NUM_TEXTURES_BY_SLICE: i32 = NUM_TEXTURES_BY_SIDE_SLICE * NUM_TEXTURES_BY_SIDE_SLICE;
const NUM_SLICES: i32 = 1;
impl HiPSConfig {
/// Define a HiPS configuration
///
@@ -62,9 +194,9 @@ impl HiPSConfig {
pub fn new(properties: &HiPSProperties, img_ext: ImageExt) -> Result<HiPSConfig, JsValue> {
let root_url = properties.get_url();
let creator_did = properties.get_creator_did().to_string();
let cube_depth = properties.get_cube_depth();
// Define the size of the 2d texture array depending on the
// characterics of the client
let num_textures = (NUM_TEXTURES_BY_SLICE * NUM_SLICES) as usize;
let max_depth_tile = properties.get_max_order();
let tile_size = properties.get_tile_size();
@@ -153,6 +285,8 @@ impl HiPSConfig {
}
};*/
let empty_image = EmptyTileImage::new(tile_size, format.get_channel());
let texture_size = std::cmp::min(512, tile_size << max_depth_tile);
//let texture_size = tile_size;
let num_tile_per_side_texture = (texture_size / tile_size) as usize;
@@ -161,7 +295,7 @@ impl HiPSConfig {
let num_tiles_per_texture = num_tile_per_side_texture * num_tile_per_side_texture;
let max_depth_texture = max_depth_tile - delta_depth;
let size_tile_uv = 1_f32 / ((1 << delta_depth) as f32);
let size_tile_uv = 1_f32 / ((8 << delta_depth) as f32);
let frame = properties.get_frame();
let sky_fraction = properties.get_sky_fraction().unwrap_or(1.0);
@@ -178,6 +312,8 @@ impl HiPSConfig {
creator_did,
// HiPS name
root_url: root_url.to_string(),
// Tile size & blank tile data
empty_image,
// Texture config
// The size of the texture images
texture_size,
@@ -190,6 +326,7 @@ impl HiPSConfig {
max_depth_tile,
min_depth_texture,
min_depth_tile,
num_textures,
is_allsky,
@@ -202,20 +339,19 @@ impl HiPSConfig {
tex_storing_integers,
tex_storing_unsigned_int,
// the number of slices in a cube
cube_depth,
size_tile_uv,
frame,
bitpix,
format,
tile_size,
//dataproduct_subtype,
//colored,
};
Ok(hips_config)
}
pub fn set_image_ext(&mut self, ext: ImageExt) -> Result<(), JsValue> {
pub fn set_image_fmt(&mut self, ext: ImageExt) -> Result<(), JsValue> {
let format = match ext {
ImageExt::Fits => {
// Check the bitpix to determine the internal format of the tiles
@@ -284,6 +420,20 @@ impl HiPSConfig {
self.format = format;
// Recompute the empty image
self.empty_image = EmptyTileImage::new(self.tile_size, self.format.get_channel());
// 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(())
}
@@ -297,10 +447,6 @@ 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;
@@ -359,6 +505,26 @@ impl HiPSConfig {
self.frame
}
#[inline(always)]
pub fn num_textures(&self) -> usize {
self.num_textures
}
#[inline(always)]
pub fn num_textures_by_side_slice(&self) -> i32 {
NUM_TEXTURES_BY_SIDE_SLICE
}
#[inline(always)]
pub fn num_textures_by_slice(&self) -> i32 {
NUM_TEXTURES_BY_SLICE
}
#[inline(always)]
pub fn num_slices(&self) -> i32 {
NUM_SLICES
}
#[inline(always)]
pub fn get_format(&self) -> ImageFormatType {
self.format
@@ -368,6 +534,11 @@ impl HiPSConfig {
pub fn is_colored(&self) -> bool {
self.format.is_colored()
}
#[inline(always)]
pub fn get_default_image(&self) -> &EmptyTileImage {
&self.empty_image
}
}
use al_core::shader::{SendUniforms, ShaderBound};

View File

@@ -0,0 +1,4 @@
pub mod bitvector;
pub mod buffer;
pub mod config;
pub mod texture;

View File

@@ -2,7 +2,7 @@ use crate::{healpix::cell::HEALPixCell, time::Time};
use std::collections::HashSet;
pub struct HpxTexture2D {
pub struct Texture {
texture_cell: HEALPixCell,
// Precomputed uniq number
uniq: i32,
@@ -34,22 +34,19 @@ pub struct HpxTexture2D {
//missing: bool,
}
use crate::renderable::hips::config::HiPSConfig;
use super::config::HiPSConfig;
use crate::renderable::hips::HpxTile;
impl HpxTexture2D {
pub fn new(cell: &HEALPixCell, idx: i32, time_request: Time) -> Self {
impl Texture {
pub fn new(texture_cell: &HEALPixCell, idx: i32, time_request: Time) -> Texture {
let tiles = HashSet::new();
let start_time = None;
let full = false;
let texture_cell = *cell;
let texture_cell = *texture_cell;
let uniq = texture_cell.uniq();
//let missing = true;
let num_tiles_written = 0;
Self {
Texture {
texture_cell,
uniq,
time_request,
@@ -58,42 +55,14 @@ impl HpxTexture2D {
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) {
pub fn append(&mut self, cell: &HEALPixCell, cfg: &HiPSConfig /*, missing: bool */) {
let texture_cell = cell.get_texture_cell(cfg.delta_depth());
debug_assert!(texture_cell == self.texture_cell);
debug_assert!(!self.full);
@@ -126,12 +95,19 @@ impl HpxTexture2D {
}
}
}
}
impl HpxTile for HpxTexture2D {
// 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
}
// Getter
// Returns the current time if the texture is not full
fn start_time(&self) -> Time {
pub fn start_time(&self) -> Time {
if self.is_full() {
self.start_time.unwrap_abort()
} else {
@@ -139,49 +115,80 @@ impl HpxTile for HpxTexture2D {
}
}
fn time_request(&self) -> Time {
pub fn time_request(&self) -> Time {
self.time_request
}
fn cell(&self) -> &HEALPixCell {
pub 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 HpxTexture2D {
impl PartialOrd for Texture {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.uniq.partial_cmp(&other.uniq)
}
}
use crate::Abort;
impl Ord for HpxTexture2D {
impl Ord for Texture {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap_abort()
}
}
impl PartialEq for HpxTexture2D {
impl PartialEq for Texture {
fn eq(&self, other: &Self) -> bool {
self.uniq == other.uniq
}
}
impl Eq for HpxTexture2D {}
impl Eq for Texture {}
pub struct HpxTexture2DUniforms<'a> {
texture: &'a HpxTexture2D,
pub struct TextureUniforms<'a> {
texture: &'a Texture,
name: String,
}
impl<'a> HpxTexture2DUniforms<'a> {
pub fn new(texture: &'a HpxTexture2D, idx_texture: i32) -> Self {
impl<'a> TextureUniforms<'a> {
pub fn new(texture: &Texture, idx_texture: i32) -> TextureUniforms {
let name = format!("textures_tiles[{}].", idx_texture);
HpxTexture2DUniforms { texture, name }
TextureUniforms { texture, name }
}
}
use al_core::shader::{SendUniforms, ShaderBound};
impl<'a> SendUniforms for HpxTexture2DUniforms<'a> {
impl<'a> SendUniforms for TextureUniforms<'a> {
fn attach_uniforms<'b>(&self, shader: &'b ShaderBound<'b>) -> &'b ShaderBound<'b> {
shader
.attach_uniform(&format!("{}{}", self.name, "uniq"), &self.texture.uniq)

View File

@@ -1,4 +1,5 @@
use crate::downloader::{query, Downloader};
use crate::renderable::HiPS;
use crate::time::{DeltaTime, Time};
use crate::Abort;
@@ -9,8 +10,6 @@ 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>,
@@ -31,6 +30,7 @@ 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,7 +52,13 @@ impl HiPSLocalFiles {
}
pub fn insert(&mut self, depth: u8, ipix: u64, ext: ImageExt, file: web_sys::File) {
let tiles_per_fmt = &mut self.tiles[ext as usize];
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],
};
tiles_per_fmt[depth as usize].insert(ipix, file);
}
@@ -215,13 +221,7 @@ 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,
match hips {
HiPS::D2(_) => None,
HiPS::D3(h) => Some(h.get_slice() as u32),
},
));
downloader.borrow_mut().fetch(query::Allsky::new(cfg));
} else if cfg.get_min_depth_tile() == 0 {
#[cfg(target_arch = "wasm32")]
{
@@ -231,7 +231,12 @@ 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(hips.get_tile_query(tile_cell)) {
if let Ok(query) = self.check_in_file_list(query::Tile::new(
tile_cell,
hips_cdid.clone(),
hips_url.clone(),
hips_fmt,
)) {
let dl = downloader.clone();
crate::utils::set_timeout(

View File

@@ -1,5 +1,5 @@
#version 300 es
precision lowp float;
precision highp float;
precision mediump int;
layout (location = 0) in vec2 ndc_pos;

View File

@@ -1,8 +1,8 @@
#version 300 es
precision lowp float;
precision lowp sampler2D;
precision lowp isampler2D;
precision lowp usampler2D;
precision highp float;
precision highp sampler2D;
precision highp isampler2D;
precision highp usampler2D;
precision mediump int;
out vec4 out_frag_color;
@@ -11,30 +11,7 @@ in vec2 frag_uv;
uniform isampler2D tex;
uniform float opacity;
uniform float scale;
uniform float offset;
uniform float blank;
uniform float min_value;
uniform float max_value;
uniform int H;
uniform float reversed;
#include ./../colormaps/colormap.glsl;
#include ./../hips/transfer_funcs.glsl;
#include ./../hips/tonal_corrections.glsl;
vec4 apply_colormap_to_grayscale(float x, float a) {
float alpha = x * scale + offset;
alpha = transfer_func(H, alpha, min_value, max_value);
// apply reversed
alpha = mix(alpha, 1.0 - alpha, reversed);
vec4 new_color = mix(colormap_f(alpha) * a, vec4(0.0), float(x == blank || isnan(x)));
return apply_tonal(new_color);
}
#include ../hips/color.glsl;
void main() {
ivec4 color = texture(tex, frag_uv);

View File

@@ -1,8 +1,8 @@
#version 300 es
precision lowp float;
precision lowp sampler2D;
precision lowp isampler2D;
precision lowp usampler2D;
precision highp float;
precision highp sampler2D;
precision highp isampler2D;
precision highp usampler2D;
precision mediump int;
out vec4 out_frag_color;
@@ -11,30 +11,7 @@ in vec2 frag_uv;
uniform sampler2D tex;
uniform float opacity;
uniform float scale;
uniform float offset;
uniform float blank;
uniform float min_value;
uniform float max_value;
uniform int H;
uniform float reversed;
#include ./../colormaps/colormap.glsl;
#include ./../hips/transfer_funcs.glsl;
#include ./../hips/tonal_corrections.glsl;
vec4 apply_colormap_to_grayscale(float x, float a) {
float alpha = x * scale + offset;
alpha = transfer_func(H, alpha, min_value, max_value);
// apply reversed
alpha = mix(alpha, 1.0 - alpha, reversed);
vec4 new_color = mix(colormap_f(alpha) * a, vec4(0.0), float(x == blank || isnan(x)));
return apply_tonal(new_color);
}
#include ../hips/color.glsl;
void main() {
vec4 color = texture(tex, frag_uv);

View File

@@ -1,8 +1,8 @@
#version 300 es
precision lowp float;
precision lowp sampler2D;
precision lowp isampler2D;
precision lowp usampler2D;
precision highp float;
precision highp sampler2D;
precision highp isampler2D;
precision highp usampler2D;
precision mediump int;
out vec4 out_frag_color;
@@ -11,30 +11,7 @@ in vec2 frag_uv;
uniform usampler2D tex;
uniform float opacity;
uniform float scale;
uniform float offset;
uniform float blank;
uniform float min_value;
uniform float max_value;
uniform int H;
uniform float reversed;
#include ./../colormaps/colormap.glsl;
#include ./../hips/transfer_funcs.glsl;
#include ./../hips/tonal_corrections.glsl;
vec4 apply_colormap_to_grayscale(float x, float a) {
float alpha = x * scale + offset;
alpha = transfer_func(H, alpha, min_value, max_value);
// apply reversed
alpha = mix(alpha, 1.0 - alpha, reversed);
vec4 new_color = mix(colormap_f(alpha) * a, vec4(0.0), float(x == blank || isnan(x)));
return apply_tonal(new_color);
}
#include ../hips/color.glsl;
void main() {
uvec4 color = texture(tex, frag_uv);

View File

@@ -1,3 +1,10 @@
//const int MAX_NUM_TEX = 3;
uniform sampler2D tex1;
uniform sampler2D tex2;
//uniform sampler2D tex3;
uniform int num_tex;
uniform float scale;
uniform float offset;
uniform float blank;
@@ -6,8 +13,6 @@ uniform float min_value;
uniform float max_value;
uniform int H;
uniform float reversed;
uniform float size_tile_uv;
uniform int tex_storing_fits;
@@ -18,7 +23,16 @@ uniform int tex_storing_fits;
#include ./hsv.glsl;
vec4 get_pixels(vec3 uv) {
return texture(tex, uv);
/*if (idx_texture == 0) {
return texture(tex1, uv.xy);
} else if (idx_texture == 1) {
return texture(tex2, uv.xy);
} else {
return vec4(0.0, 1.0, 0.0, 1.0);
}*/
int idx_texture = int(uv.z);
return mix(texture(tex1, uv.xy), texture(tex2, uv.xy), float(idx_texture));
}
vec3 reverse_uv(vec3 uv) {
@@ -26,6 +40,7 @@ vec3 reverse_uv(vec3 uv) {
return uv;
}
uniform float reversed;
vec4 get_color_from_texture(vec3 UV) {
vec4 color = get_pixels(UV);

View File

@@ -1,3 +1,8 @@
//const int MAX_NUM_TEX = 3;
uniform isampler2D tex1;
uniform isampler2D tex2;
//uniform isampler2D tex3;
uniform int num_tex;
uniform float scale;
uniform float offset;
@@ -17,7 +22,19 @@ uniform int tex_storing_fits;
#include ./tonal_corrections.glsl;
ivec4 get_pixels(vec3 uv) {
return ivec4(texture(tex, uv));
/*int idx_texture = int(uv.z);
if (idx_texture == 0) {
return texture(tex1, uv.xy);
} else if (idx_texture == 1) {
return texture(tex2, uv.xy);
} else if (idx_texture == 2) {
return texture(tex3, uv.xy);
} else {
return ivec4(0, 0, 0, 1);
}*/
//return texture(tex1, uv.xy);
int idx_texture = int(uv.z);
return ivec4(mix(vec4(texture(tex1, uv.xy)), vec4(texture(tex2, uv.xy)), float(idx_texture)));
}
vec3 reverse_uv(vec3 uv) {

View File

@@ -1,3 +1,9 @@
//const int MAX_NUM_TEX = 3;
uniform usampler2D tex1;
uniform usampler2D tex2;
//uniform usampler2D tex3;
uniform int num_tex;
uniform float scale;
uniform float offset;
uniform float blank;
@@ -16,7 +22,20 @@ uniform int tex_storing_fits;
#include ./tonal_corrections.glsl;
uvec4 get_pixels(vec3 uv) {
return uvec4(texture(tex, uv));
/*int idx_texture = int(uv.z);
if (idx_texture == 0) {
return texture(tex1, uv.xy);
} else if (idx_texture == 1) {
return texture(tex2, uv.xy);
} else if (idx_texture == 2) {
return texture(tex3, uv.xy);
} else {
return uvec4(0, 0, 0, 1);
}*/
//return texture(tex1, uv.xy);
//int idx_texture = int(uv.z);
int idx_texture = int(uv.z);
return uvec4(mix(vec4(texture(tex1, uv.xy)), vec4(texture(tex2, uv.xy)), float(idx_texture)));
}
vec3 reverse_uv(vec3 uv) {

View File

@@ -1,14 +1,14 @@
#version 300 es
precision lowp float;
precision lowp sampler2DArray;
precision lowp isampler2DArray;
precision lowp usampler2DArray;
uniform sampler2DArray tex;
precision highp float;
precision highp sampler2D;
precision highp isampler2D;
precision mediump int;
in vec3 frag_uv_start;
in vec3 frag_uv_end;
in float frag_blending_factor;
in float m_start;
in float m_end;
out vec4 out_frag_color;
uniform float opacity;

View File

@@ -1,14 +1,14 @@
#version 300 es
precision lowp float;
precision lowp sampler2DArray;
precision lowp isampler2DArray;
precision lowp usampler2DArray;
uniform sampler2DArray tex;
precision highp float;
precision highp sampler2D;
precision highp isampler2D;
precision mediump int;
in vec3 frag_uv_start;
in vec3 frag_uv_end;
in float frag_blending_factor;
in float m_start;
in float m_end;
out vec4 out_frag_color;

View File

@@ -1,14 +1,14 @@
#version 300 es
precision lowp float;
precision lowp sampler2DArray;
precision lowp isampler2DArray;
precision lowp usampler2DArray;
uniform isampler2DArray tex;
precision highp float;
precision highp sampler2D;
precision highp isampler2D;
precision mediump int;
in vec3 frag_uv_start;
in vec3 frag_uv_end;
in float frag_blending_factor;
in float m_start;
in float m_end;
out vec4 out_frag_color;

View File

@@ -1,14 +1,15 @@
#version 300 es
precision lowp float;
precision lowp sampler2DArray;
precision lowp isampler2DArray;
precision lowp usampler2DArray;
uniform usampler2DArray tex;
precision highp float;
precision highp sampler2D;
precision highp isampler2D;
precision highp usampler2D;
precision mediump int;
in vec3 frag_uv_start;
in vec3 frag_uv_end;
in float frag_blending_factor;
in float m_start;
in float m_end;
out vec4 out_frag_color;

View File

@@ -1,15 +1,20 @@
#version 300 es
precision lowp float;
precision highp float;
precision mediump int;
//layout (location = 0) in vec3 position;
layout (location = 0) in vec2 lonlat;
layout (location = 1) in vec3 uv_start;
layout (location = 2) in vec3 uv_end;
layout (location = 3) in float time_tile_received;
layout (location = 4) in float m0;
layout (location = 5) in float m1;
out vec3 frag_uv_start;
out vec3 frag_uv_end;
out float frag_blending_factor;
out float m_start;
out float m_end;
// current time in ms
uniform mat4 inv_model;
@@ -31,4 +36,6 @@ void main() {
frag_uv_start = uv_start;
frag_uv_end = uv_end;
frag_blending_factor = min((current_time - time_tile_received) / 200.0, 1.0);
m_start = m0;
m_end = m1;
}

View File

@@ -1,5 +1,8 @@
#version 300 es
precision lowp float;
precision highp float;
precision highp sampler2D;
precision highp usampler2D;
precision highp isampler2D;
precision mediump int;
out vec4 out_frag_color;

View File

@@ -1,5 +1,5 @@
#version 300 es
precision lowp float;
precision highp float;
precision mediump int;
layout (location = 0) in vec2 pos_clip_space;

View File

@@ -1,12 +1,10 @@
#version 300 es
precision lowp float;
precision lowp sampler2DArray;
precision lowp usampler2DArray;
precision lowp isampler2DArray;
precision highp float;
precision highp sampler2D;
precision highp usampler2D;
precision highp isampler2D;
precision mediump int;
uniform sampler2DArray tex;
in vec2 out_clip_pos;
in vec3 frag_pos;
out vec4 out_frag_color;
@@ -21,7 +19,7 @@ struct Tile {
uniform Tile textures_tiles[12];
#include ../color.glsl;
#include ../../projection/hpx_proj.glsl;
#include ../../projection/hpx.glsl;
uniform float opacity;
@@ -32,14 +30,22 @@ vec4 get_tile_color(vec3 pos) {
vec2 uv = vec2(result.dy, result.dx);
Tile tile = textures_tiles[idx];
vec2 offset = uv;
vec3 UV = vec3(offset, float(tile.texture_idx));
int idx_texture = tile.texture_idx >> 6;
int off = tile.texture_idx & 0x3F;
float idx_row = float(off >> 3); // in [0; 7]
float idx_col = float(off & 0x7); // in [0; 7]
vec2 offset = (vec2(idx_col, idx_row) + uv)*0.125;
vec3 UV = vec3(offset, float(idx_texture));
vec4 color = get_color_from_texture(UV);
color.a *= (1.0 - tile.empty);
return color;
}
uniform sampler2D position_tex;
uniform mat4 model;
void main() {
// Get the HEALPix cell idx and the uv in the texture
vec4 c = get_tile_color(normalize(frag_pos));

View File

@@ -1,8 +1,8 @@
#version 300 es
precision lowp float;
precision lowp sampler2DArray;
precision lowp sampler2DArray;
precision lowp isampler2DArray;
precision highp float;
precision highp sampler2D;
precision highp usampler2D;
precision highp isampler2D;
precision mediump int;
in vec3 frag_pos;
@@ -19,8 +19,6 @@ struct Tile {
uniform Tile textures_tiles[12];
uniform float opacity;
uniform sampler2DArray tex;
struct TileColor {
Tile tile;
vec4 color;
@@ -28,24 +26,45 @@ struct TileColor {
};
#include ../color.glsl;
#include ../../projection/hpx_proj.glsl;
#include ../../projection/hpx.glsl;
vec4 get_tile_color(vec3 pos) {
HashDxDy result = hash_with_dxdy(0, pos.zxy);
int idx = result.idx;
vec2 uv = vec2(result.dy, result.dx);
Tile tile = textures_tiles[idx];
vec2 offset = uv;
vec3 UV = vec3(offset, float(tile.texture_idx));
int idx_texture = tile.texture_idx >> 6;
int off = tile.texture_idx & 0x3F;
float idx_row = float(off >> 3); // in [0; 7]
float idx_col = float(off & 0x7); // in [0; 7]
vec2 offset = (vec2(idx_col, idx_row) + uv)*0.125;
vec3 UV = vec3(offset, float(idx_texture));
vec4 color = get_colormap_from_grayscale_texture(UV);
// handle empty tiles
//vec4 c1 = mix(c, blank_color, tile.empty);
//vec4 c2 = mix(c, colormap_f(0.0), tile.empty);
//vec4 color = mix(c1, c2, first_survey);
// For empty tiles we set the alpha of the pixel to 0.0
// so that what is behind will be plotted
color.a *= (1.0 - tile.empty);
return color;
}
uniform sampler2D position_tex;
uniform mat4 model;
void main() {
/*vec2 uv = out_clip_pos * 0.5 + 0.5;
vec3 n = texture(position_tex, uv).rgb;
vec3 frag_pos = vec3(model * vec4(n, 1.0));*/
vec4 c = get_tile_color(normalize(frag_pos));
out_frag_color = c;
out_frag_color.a = out_frag_color.a * opacity;

View File

@@ -1,12 +1,10 @@
#version 300 es
precision lowp float;
precision lowp sampler2DArray;
precision lowp usampler2DArray;
precision lowp isampler2DArray;
precision highp float;
precision highp sampler2D;
precision highp usampler2D;
precision highp isampler2D;
precision mediump int;
uniform isampler2DArray tex;
in vec3 frag_pos;
in vec2 out_clip_pos;
out vec4 out_frag_color;
@@ -23,24 +21,46 @@ uniform Tile textures_tiles[12];
uniform float opacity;
#include ../color_i.glsl;
#include ../../projection/hpx_proj.glsl;
#include ../../projection/hpx.glsl;
vec4 get_tile_color(vec3 pos) {
HashDxDy result = hash_with_dxdy(0, pos.zxy);
HashDxDy result = hash_with_dxdy(0, pos.zxy);
int idx = result.idx;
vec2 uv = vec2(result.dy, result.dx);
Tile tile = textures_tiles[idx];
vec2 offset = uv;
vec3 UV = vec3(offset, float(tile.texture_idx));
int idx_texture = tile.texture_idx >> 6;
int off = tile.texture_idx & 0x3F;
float idx_row = float(off >> 3); // in [0; 7]
float idx_col = float(off & 0x7); // in [0; 7]
vec2 offset = (vec2(idx_col, idx_row) + uv)*0.125;
vec3 UV = vec3(offset, float(idx_texture));
vec4 color = get_colormap_from_grayscale_texture(UV);
// handle empty tiles
//vec4 c1 = mix(c, blank_color, tile.empty);
//vec4 c2 = mix(c, colormap_f(0.0), tile.empty);
//vec4 color = mix(c1, c2, first_survey);
// For empty tiles we set the alpha of the pixel to 0.0
// so that what is behind will be plotted
color.a *= (1.0 - tile.empty);
return color;
}
uniform sampler2D position_tex;
uniform mat4 model;
void main() {
/*vec2 uv = out_clip_pos * 0.5 + 0.5;
vec3 n = texture(position_tex, uv).rgb;
vec3 frag_pos = vec3(model * vec4(n, 1.0));*/
vec4 c = get_tile_color(normalize(frag_pos));
out_frag_color = c;
out_frag_color.a = out_frag_color.a * opacity;

View File

@@ -1,12 +1,10 @@
#version 300 es
precision lowp float;
precision lowp sampler2DArray;
precision lowp usampler2DArray;
precision lowp isampler2DArray;
precision highp float;
precision highp sampler2D;
precision highp usampler2D;
precision highp isampler2D;
precision mediump int;
uniform usampler2DArray tex;
in vec3 frag_pos;
in vec2 out_clip_pos;
out vec4 out_frag_color;
@@ -23,24 +21,45 @@ uniform Tile textures_tiles[12];
uniform float opacity;
#include ../color_u.glsl;
#include ../../projection/hpx_proj.glsl;
#include ../../projection/hpx.glsl;
vec4 get_tile_color(vec3 pos) {
HashDxDy result = hash_with_dxdy(0, pos.zxy);
int idx = result.idx;
vec2 uv = vec2(result.dy, result.dx);
Tile tile = textures_tiles[idx];
vec2 offset = uv;
vec3 UV = vec3(offset, float(tile.texture_idx));
int idx_texture = tile.texture_idx >> 6;
int off = tile.texture_idx & 0x3F;
float idx_row = float(off >> 3); // in [0; 7]
float idx_col = float(off & 0x7); // in [0; 7]
vec2 offset = (vec2(idx_col, idx_row) + uv)*0.125;
vec3 UV = vec3(offset, float(idx_texture));
vec4 color = get_colormap_from_grayscale_texture(UV);
// handle empty tiles
//vec4 c1 = mix(c, blank_color, tile.empty);
//vec4 c2 = mix(c, colormap_f(0.0), tile.empty);
//vec4 color = mix(c1, c2, first_survey);
// For empty tiles we set the alpha of the pixel to 0.0
// so that what is behind will be plotted
color.a *= (1.0 - tile.empty);
return color;
}
uniform sampler2D position_tex;
uniform mat4 model;
void main() {
/*vec2 uv = out_clip_pos * 0.5 + 0.5;
vec3 n = texture(position_tex, uv).rgb;
vec3 frag_pos = vec3(model * vec4(n, 1.0));*/
vec4 c = get_tile_color(normalize(frag_pos));
out_frag_color = c;
out_frag_color.a = out_frag_color.a * opacity;

View File

@@ -1,5 +1,5 @@
#version 300 es
precision lowp float;
precision highp float;
precision mediump int;
layout (location = 0) in vec2 pos_clip_space;
@@ -14,6 +14,7 @@ uniform mat4 model;
void main() {
vec2 uv = pos_clip_space * 0.5 + 0.5;
//world_pos = check_inversed_longitude(world_pos);
frag_pos = vec3(model * vec4(pos_world_space, 1.0));

View File

@@ -1,21 +0,0 @@
#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;
}

View File

@@ -1,22 +0,0 @@
#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(vec3(frag_uv.xy, mod(frag_uv.z, 32.0) / 32.0));
out_frag_color = color;
out_frag_color.a = out_frag_color.a * opacity;
}

View File

@@ -1,22 +0,0 @@
#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(vec3(frag_uv.xy, mod(frag_uv.z, 32.0) / 32.0));
out_frag_color = color;
out_frag_color.a = out_frag_color.a * opacity;
}

View File

@@ -1,22 +0,0 @@
#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(vec3(frag_uv.xy, mod(frag_uv.z, 32.0) / 32.0));
out_frag_color = color;
out_frag_color.a = out_frag_color.a * opacity;
}

View File

@@ -1,26 +0,0 @@
#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;
}

View File

@@ -8,6 +8,8 @@ in vec2 frag_uv;
uniform sampler2D tex;
uniform float opacity;
#include ../hips/color.glsl;
void main() {
out_frag_color = texture(tex, vec2(frag_uv.x, 1.0 - frag_uv.y));
out_frag_color.a = out_frag_color.a * opacity;

View File

@@ -0,0 +1,26 @@
#version 300 es
precision mediump float;
in vec2 v_tc;
out vec4 color;
uniform sampler2D fbo_tex;
// 0-255 sRGB from 0-1 linear
vec3 srgb_from_linear(vec3 rgb) {
bvec3 cutoff = lessThan(rgb, vec3(0.0031308));
vec3 lower = rgb * vec3(3294.6);
vec3 higher = vec3(269.025) * pow(rgb, vec3(1.0 / 2.4)) - vec3(14.025);
return mix(higher, lower, vec3(cutoff));
}
// 0-255 sRGBA from 0-1 linear
vec4 srgba_from_linear(vec4 rgba) {
return vec4(srgb_from_linear(rgba.rgb), 255.0 * rgba.a);
}
void main() {
color = texture(fbo_tex, v_tc);
//color = srgba_from_linear(color) / 255.;
}

View File

@@ -0,0 +1,10 @@
#version 300 es
precision mediump float;
layout (location = 0) in vec2 a_pos;
out vec2 v_tc;
void main() {
gl_Position = vec4(a_pos * 2. - 1., 0.0, 1.0);
v_tc = a_pos;
}

Some files were not shown because too many files have changed in this diff Show More