Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web updates: parse other ui params, loading visual feedback, alert user on error, documentation #1738

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions webassembly/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,12 @@ F3D is a fast and minimalist 3D viewer. Implemented in C++, it has been cross-co

While the webassembly module might be quite large (~14MB), it is self contained and requires no external dependency.

The current web build parses some parameters provided as url-params, via a hash search-query:
- `model` and `extension` let you pass a model to load via its url. Extension can be provided in case it is not obvious to detect it automatically. In case extension is provided, the loader will enforce it, otherwise, it can try to get file type from header if available, otherwise from url.
- `axis, grid, fxaa, tone, ssao, ambient` can be set to false to disable toggle
- `up` can take values +Y or +Z

Some passed model urls might be stored on servers which do not set the Cross-Origin request header parameter. In that case, you can still load these with plugins like Allow-Cors that do exist for chrome, firefox etc.

Example url: https://f3d.app/web#up=+Y&axis=false&ssao=true&model=https://groups.csail.mit.edu/graphics/classes/6.837/F03/models/teapot.obj

76 changes: 66 additions & 10 deletions webassembly/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ <h1 class="title">F3D Web</h1>
</div>
</div>
</div>
<div class="event-log" style="position: absolute; z-index: 10; bottom: 50px; width: 100%; display: none;">
<p style="text-align: center;""> Loading 3D object...</p>
<progress class="progress is-primary" id="progressEl" value="0" max="100" style="transition: all 2s; width: 500px; margin: auto;"> 30% </progress>
</div>
</section>
<script type="text/javascript" src="f3d.js"></script>
<script type="text/javascript">
Expand Down Expand Up @@ -139,13 +143,24 @@ <h1 class="title">F3D Web</h1>
};

// setup file open event
document.querySelector('#file-selector')
.addEventListener('change', (evt) => {
const progressEl = document.querySelector("#progressEl");
const fileSelector = document.querySelector('#file-selector');
fileSelector.addEventListener('change', (evt) => {
for (const file of evt.target.files) {
const reader = new FileReader();
reader.addEventListener('loadend', (e) => {
progressEl.textContent = "100%";
progressEl.value = 100;
Module.FS.writeFile(file.name, new Uint8Array(reader.result));
openFile(file.name);
progressEl.parentElement.style.display = "none"
});
reader.addEventListener('progress', (evt) => {
console.log(evt)
const progress = Math.floor(100 * evt.loaded / evt.total);
progressEl.parentElement.style.display = "block"
progressEl.value = progress;
progressEl.textContent = `${progress}%`;
});
reader.readAsArrayBuffer(file);
}
Expand All @@ -161,13 +176,21 @@ <h1 class="title">F3D Web</h1>
Module.engineInstance.getWindow().render();
});
};

mapToggleIdToOption('grid', 'render.grid.enable');
mapToggleIdToOption('axis', 'interactor.axis');
mapToggleIdToOption('fxaa', 'render.effect.anti_aliasing');
mapToggleIdToOption('tone', 'render.effect.tone_mapping');
mapToggleIdToOption('ssao', 'render.effect.ambient_occlusion');
mapToggleIdToOption('ambient', 'render.hdri.ambient');

// Storing dom el ids to f3d option mappings since also useful for url-param parsing
const idOptionMappings = [
['grid', 'render.grid.enable'],
['axis', 'interactor.axis'],
['fxaa', 'render.effect.anti_aliasing'],
['tone', 'render.effect.tone_mapping'],
['ssao', 'render.effect.ambient_occlusion'],
['ambient', 'render.hdri.ambient'],
]
// This assumes all toggles are 'on' before mapping their state to options
// Ok after f3d(settings) where settings = {..., setupOptions} which toggles some options
for (let [id, option] of idOptionMappings) {
mapToggleIdToOption(id, option);
}

switchDark = () => {
document.documentElement.classList.add('theme-dark');
Expand Down Expand Up @@ -233,8 +256,8 @@ <h1 class="title">F3D Web</h1>
}
throw new Error(`Could not parse filename/extension from either urlparam extension, response header content-disposition, nor filename present in url`);
}
// Parse search-query model url-param or load default model file
function load_from_url(){
// Parse search-query model url-param or load default model file
// const params = new URLSearchParams(window.location.search);
// Replace first hash with question mark to have real search query parsing and avoid leading # in first parsed urlparam
const params = new URLSearchParams(window.location.hash.replace(/^#/, '?'));
Expand All @@ -255,10 +278,43 @@ <h1 class="title">F3D Web</h1>
openFile(filename);
});
})
.catch(function (error) {
console.log('error caught during fetch', error)
alert('Error occurred while fetching the model at provided url (passed as url-param). \n\nThis might be a CORS issue (you can avoid it by using a Allow-CORS plugin) because server does not allow cross-origin requests, or the url to the file is wrong. \n\nComplete error message: ' + error.message)
});
} else {
// load the file located in the virtual filesystem
openFile('f3d.vtp');
}

// Parse other options like #axis=false&grid=false&fxaa=false&tone=false&ssao=false&ambient=false
const options = Module.engineInstance.getOptions()
for (let [id, option] of idOptionMappings) {
// Set f3d option parameter values
const parsed_param_value = params.get(id);
if (parsed_param_value && parsed_param_value.toLowerCase() === 'false') {
// we can use toggle, set_string, set_integer, set_color
// sad thing is toggle requires knowing the param state beforehand, rather than setting it explicitly
options.toggle(option)

// Sync UI elements with params value
document.querySelector('#' + id).checked = false;
}
}

// Parse up vector and update UI, up is either +Z or +Y
const parsed_up_value = params.get('up');
if (parsed_up_value) {
options.set_string('scene.up_direction', parsed_up_value);
if (parsed_up_value == '+Y') {
document.getElementById('z-up').classList.remove('is-active');
document.getElementById('y-up').classList.add('is-active');
openFile(document.getElementById('file-name').innerHTML);
}
}

// Needs re-render to update F3D options
Module.engineInstance.getWindow().render();
}
addEventListener("hashchange", (event) => {load_from_url()});
load_from_url();
Expand Down