Compare commits
11 Commits
v3.6.0-bet
...
select-imp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c9c4cf9a9 | ||
|
|
ea8af8acb3 | ||
|
|
fac6c045f4 | ||
|
|
b778ce380a | ||
|
|
d3e0bb4fbc | ||
|
|
81e1eaddee | ||
|
|
51af4fa2f4 | ||
|
|
ef86dbd06d | ||
|
|
45f77feeb1 | ||
|
|
b8820d6f19 | ||
|
|
98d877b937 |
2
.github/workflows/api_doc.yml
vendored
@@ -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
|
||||
|
||||
4
.github/workflows/test.yml
vendored
@@ -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
|
||||
|
||||
@@ -13,7 +13,6 @@ A new [API technical documentation](https://cds-astro.github.io/aladin-lite/) is
|
||||
|
||||
[](https://github.com/cds-astro/aladin-lite/actions/workflows/test.yml)
|
||||
[](https://cds-astro.github.io/aladin-lite)
|
||||
[](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>
|
||||
```
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 962 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 1.6 MiB |
@@ -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');
|
||||
});
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
|
||||
aladin.setImageLayer(survey2);
|
||||
|
||||
setTimeout(() => {
|
||||
/*setTimeout(() => {
|
||||
aladin.removeHiPSFromFavorites(survey3)
|
||||
}, 5000);
|
||||
}, 10000);*/
|
||||
|
||||
|
||||
aladin.addColormap('mycmap', ["lightblue", "red", "violet", "lightgreen"])
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
nav > h2 {
|
||||
color: blue;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
nav > ul > li > a {
|
||||
font-size: medium;
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
78
jsdoc.json
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
54
src/core/al-core/src/texture/texture_array.rs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;*/
|
||||
|
||||
@@ -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())?;
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -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
|
||||
}
|
||||
@@ -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!(),
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
40
src/core/src/survey/bitvector.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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};
|
||||
4
src/core/src/survey/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod bitvector;
|
||||
pub mod buffer;
|
||||
pub mod config;
|
||||
pub mod texture;
|
||||
@@ -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)
|
||||
@@ -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(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#version 300 es
|
||||
precision lowp float;
|
||||
precision highp float;
|
||||
precision mediump int;
|
||||
|
||||
layout (location = 0) in vec2 ndc_pos;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#version 300 es
|
||||
precision lowp float;
|
||||
precision highp float;
|
||||
precision mediump int;
|
||||
|
||||
layout (location = 0) in vec2 pos_clip_space;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
26
src/glsl/webgl2/passes/post_fragment_100es.glsl
Normal 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.;
|
||||
}
|
||||
10
src/glsl/webgl2/passes/post_vertex_100es.glsl
Normal 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;
|
||||
}
|
||||