diff --git a/index.html b/index.html
index a7dd919..cdf7ec2 100644
--- a/index.html
+++ b/index.html
@@ -857,6 +857,7 @@
NormalMaps from photos
+
diff --git a/javascripts/ambientOccMap.js b/javascripts/ambientOccMap.js
index 90e7a50..5dc03b4 100644
--- a/javascripts/ambientOccMap.js
+++ b/javascripts/ambientOccMap.js
@@ -56,6 +56,7 @@ NMO_AmbientOccMap = new function(){
this.uniforms;
this.height_map_tex;
this.gaussian_shader_y, this.gaussian_shader_x;
+ this.renderTarget;
this.createAmbientOcclusionTexture = function(){
this.createGPUbasedAOTexture();
@@ -154,6 +155,7 @@ NMO_AmbientOccMap = new function(){
this.renderer.setSize( w, h );
this.composer.setSize( w, h );
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
this.renderTarget = new THREE.WebGLRenderTarget( w, h, renderTargetParameters );
this.composer.reset(this.renderTarget);
this.composer.render( 1 / 60 );
@@ -222,6 +224,7 @@ NMO_AmbientOccMap = new function(){
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
this.renderTarget = new THREE.WebGLRenderTarget( w, h, renderTargetParameters );
this.composer = new THREE.EffectComposer( this.renderer, this.renderTarget );
//renderer_aomap.render( scene_aomap, camera_aomap, renderTarget );
@@ -279,4 +282,4 @@ NMO_AmbientOccMap = new function(){
// this.timer = 0;
//}
};
-}
\ No newline at end of file
+}
diff --git a/javascripts/displaceMap.js b/javascripts/displaceMap.js
index aa5af40..87f254b 100644
--- a/javascripts/displaceMap.js
+++ b/javascripts/displaceMap.js
@@ -48,6 +48,7 @@ NMO_DisplacementMap = new function(){
this.uniforms;
this.height_map_tex;
this.gaussian_shader_y, this.gaussian_shader_x;
+ this.renderTarget;
this.createDisplacementMap = function(){
this.createGPUbasedDisplacementTexture();
@@ -158,6 +159,7 @@ NMO_DisplacementMap = new function(){
this.renderer.setSize( w, h );
this.composer.setSize( w, h );
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
this.renderTarget = new THREE.WebGLRenderTarget( w, h, renderTargetParameters );
this.composer.reset(this.renderTarget);
this.composer.render( 1 / 60 );
@@ -222,8 +224,9 @@ NMO_DisplacementMap = new function(){
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
this.renderTarget = new THREE.WebGLRenderTarget( w, h, renderTargetParameters );
- this.composer = new THREE.EffectComposer( this.renderer, renderTarget );
+ this.composer = new THREE.EffectComposer( this.renderer, this.renderTarget );
//renderer_aomap.render( scene_aomap, camera_aomap, renderTarget );
//renderer_aomap.render( scene_aomap, camera_aomap );
//this.composer_aomap.setSize( w, h );
@@ -317,4 +320,4 @@ NMO_DisplacementMap = new function(){
}
return imageData;
};
-}
\ No newline at end of file
+}
diff --git a/javascripts/filedrop.js b/javascripts/filedrop.js
index f44867a..502b4a6 100644
--- a/javascripts/filedrop.js
+++ b/javascripts/filedrop.js
@@ -63,31 +63,39 @@ NMO_FileDrop = new function(){
const includeDisplacement = document.getElementById('displacement_tick').checked;
const includeAmbient = document.getElementById('ambient_tick').checked;
const includeSpecular = document.getElementById('specular_tick').checked;
+ const fileNameInput = document.getElementById('file_name');
+ const batchInput = document.getElementById('select_multiple_height_files');
+ const originalFileName = fileNameInput.value;
+ const selectedMaps = [];
+
+ if (includeNormal)
+ selectedMaps.push({ type: "NormalMap", suffix: "normal" });
+ if (includeDisplacement)
+ selectedMaps.push({ type: "DisplacementMap", suffix: "displacement" });
+ if (includeAmbient)
+ selectedMaps.push({ type: "AmbientOcclusionMap", suffix: "ambient" });
+ if (includeSpecular)
+ selectedMaps.push({ type: "SpecularMap", suffix: "specular" });
+
+ if (selectedMaps.length === 0)
+ return;
- for (let i = 0; i < files.length; i++) {
- await this.readImage(files[i], "height", "", async (name) => {
- const baseName = name.replace(/\.[^/.]+$/, "");
-
- if (includeNormal) {
- document.getElementById('file_name').value = `${baseName}_normal`;
- await NMO_Main.downloadImage("NormalMap");
- }
-
- if (includeDisplacement) {
- document.getElementById('file_name').value = `${baseName}_displacement`;
- await NMO_Main.downloadImage("DisplacementMap");
- }
-
- if (includeAmbient) {
- document.getElementById('file_name').value = `${baseName}_ambient`;
- await NMO_Main.downloadImage("AmbientOcclusionMap");
- }
-
- if (includeSpecular) {
- document.getElementById('file_name').value = `${baseName}_specular`;
- await NMO_Main.downloadImage("SpecularMap");
- }
- }, files[i].name);
+ try {
+ for (let i = 0; i < files.length; i++) {
+ await this.readImage(files[i], "height", "", async (name) => {
+ const baseName = name.replace(/\.[^/.]+$/, "");
+
+ for (let mapIndex = 0; mapIndex < selectedMaps.length; mapIndex++) {
+ const map = selectedMaps[mapIndex];
+ fileNameInput.value = `${baseName}_${map.suffix}`;
+ await NMO_Main.downloadImage(map.type);
+ }
+ }, files[i].name);
+ }
+ }
+ finally {
+ fileNameInput.value = originalFileName;
+ batchInput.value = "";
}
};
diff --git a/javascripts/main.js b/javascripts/main.js
index 3049bcf..e57bb46 100644
--- a/javascripts/main.js
+++ b/javascripts/main.js
@@ -304,14 +304,26 @@ var NMO_Main = new function(){
NMO_SpecularMap.createSpecularTexture();
};
- this.download_all_btn.addEventListener('click', function (e) {
- NMO_Main.downloadImage("NormalMap");
- NMO_Main.downloadImage("DisplacementMap");
- NMO_Main.downloadImage("AmbientOcclusionMap");
- NMO_Main.downloadImage("SpecularMap");
+ this.wait = function(ms){
+ return new Promise(function(resolve){
+ setTimeout(resolve, ms);
+ });
+ };
+
+ this.finishDownload = async function(blob, file_name){
+ saveAs(blob, file_name);
+ // Give the browser a moment to register each programmatic save before the next one.
+ await this.wait(150);
+ };
+
+ this.download_all_btn.addEventListener('click', async function (e) {
+ await NMO_Main.downloadImage("NormalMap");
+ await NMO_Main.downloadImage("DisplacementMap");
+ await NMO_Main.downloadImage("AmbientOcclusionMap");
+ await NMO_Main.downloadImage("SpecularMap");
});
- this.download_btn.addEventListener('click', function (e) {
+ this.download_btn.addEventListener('click', function (e) {
if (document.getElementById('normal_map').style.cssText != "display: none;"){
NMO_Main.downloadImage("NormalMap");
}
@@ -327,12 +339,11 @@ var NMO_Main = new function(){
});
- this.downloadImage = function(type){
+ this.downloadImage = async function(type){
console.log("Downloading image");
- var qual = 0.9;
var file_name = "download";
var canvas = document.createElement("canvas");
-
+
var file_type = NMO_Main.getImageType();
var image_type = "image/png";
if (file_type == "jpg")
@@ -342,7 +353,7 @@ var NMO_Main = new function(){
canvas.width = NMO_NormalMap.normal_canvas.width;
canvas.height = NMO_NormalMap.normal_canvas.height;
var context = canvas.getContext('2d');
- if (file_type == "png")
+ if (file_type == "png")
context.globalAlpha = $('#transparency_nmb').val() / 100;
context.drawImage(NMO_NormalMap.normal_canvas,0,0);
file_name="NormalMap";
@@ -351,7 +362,7 @@ var NMO_Main = new function(){
canvas.width = NMO_DisplacementMap.displacement_canvas.width;
canvas.height = NMO_DisplacementMap.displacement_canvas.height;
var context = canvas.getContext('2d');
- if (file_type == "png")
+ if (file_type == "png")
context.globalAlpha = $('#transparency_nmb').val() / 100;
context.drawImage(NMO_DisplacementMap.displacement_canvas,0,0);
file_name="DisplacementMap";
@@ -360,7 +371,7 @@ var NMO_Main = new function(){
canvas.width = NMO_AmbientOccMap.ao_canvas.width;
canvas.height = NMO_AmbientOccMap.ao_canvas.height;
var context = canvas.getContext('2d');
- if (file_type == "png")
+ if (file_type == "png")
context.globalAlpha = $('#transparency_nmb').val() / 100;
context.drawImage(NMO_AmbientOccMap.ao_canvas,0,0);
file_name="AmbientOcclusionMap";
@@ -369,28 +380,41 @@ var NMO_Main = new function(){
canvas.width = NMO_SpecularMap.specular_canvas.width;
canvas.height = NMO_SpecularMap.specular_canvas.height;
var context = canvas.getContext('2d');
- if (file_type == "png")
+ if (file_type == "png")
context.globalAlpha = $('#transparency_nmb').val() / 100;
context.drawImage(NMO_SpecularMap.specular_canvas,0,0);
file_name="SpecularMap";
}
-
+
if (document.getElementById('file_name').value != "")
file_name = document.getElementById('file_name').value;
-
-
-
+
var qual = $('#file_jpg_qual_nmb').val() / 100;
- if (file_type == "tiff"){
- CanvasToTIFF.toBlob(canvas, function(blob) {
- saveAs(blob, file_name + ".tif");
- });
- }
- else{
- canvas.toBlob(function(blob) {
- saveAs(blob, file_name + "." + file_type);
- }, image_type, qual);
- }
+ var blob = await new Promise(function(resolve, reject) {
+ if (file_type == "tiff"){
+ CanvasToTIFF.toBlob(canvas, function(generatedBlob) {
+ if (!generatedBlob){
+ reject(new Error("Could not create TIFF blob."));
+ return;
+ }
+ resolve(generatedBlob);
+ });
+ }
+ else{
+ canvas.toBlob(function(generatedBlob) {
+ if (!generatedBlob){
+ reject(new Error("Could not create image blob."));
+ return;
+ }
+ resolve(generatedBlob);
+ }, image_type, qual);
+ }
+ });
+
+ if (file_type == "tiff")
+ await NMO_Main.finishDownload(blob, file_name + ".tif");
+ else
+ await NMO_Main.finishDownload(blob, file_name + "." + file_type);
}
this.resetNormalMapSettings = function() {
@@ -490,4 +514,4 @@ var NMO_Main = new function(){
NMO_SpecularMap.setSpecularSetting('spec_range', initialRange);
NMO_SpecularMap.setSpecularSetting('spec_falloff', initialFallOffType);
};
-}
\ No newline at end of file
+}
diff --git a/javascripts/renderNormalview.js b/javascripts/renderNormalview.js
index d100938..a45e947 100644
--- a/javascripts/renderNormalview.js
+++ b/javascripts/renderNormalview.js
@@ -26,6 +26,7 @@ var NMO_RenderNormalview = new function(){
this.renderer_Normalview;
this.composer_Normalview;
+ this.renderTarget;
this.scene_Normalview;
this.camera_Normalview;
this.gaussian_shader_y, this.gaussian_shader_x, this.gaussian_shader;
@@ -149,8 +150,9 @@ var NMO_RenderNormalview = new function(){
//composer_Normalview.addPass( copyPass );
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
- renderTarget = new THREE.WebGLRenderTarget( NMO_FileDrop.height_image.width, NMO_FileDrop.height_image.height, renderTargetParameters );
- this.composer_Normalview = new THREE.EffectComposer( this.renderer_Normalview, renderTarget );
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
+ this.renderTarget = new THREE.WebGLRenderTarget( NMO_FileDrop.height_image.width, NMO_FileDrop.height_image.height, renderTargetParameters );
+ this.composer_Normalview = new THREE.EffectComposer( this.renderer_Normalview, this.renderTarget );
this.composer_Normalview.setSize( NMO_FileDrop.height_image.width, NMO_FileDrop.height_image.height );
this.composer_Normalview.addPass( this.NormalRenderScene );
this.composer_Normalview.addPass( this.gaussian_shader_y );
@@ -216,8 +218,9 @@ var NMO_RenderNormalview = new function(){
this.renderer_Normalview.setSize( img.naturalWidth, img.naturalHeight );
this.composer_Normalview.setSize( img.naturalWidth, img.naturalHeight );
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
- renderTarget = new THREE.WebGLRenderTarget( img.width, img.height, renderTargetParameters );
- this.composer_Normalview.reset(renderTarget);
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
+ this.renderTarget = new THREE.WebGLRenderTarget( img.width, img.height, renderTargetParameters );
+ this.composer_Normalview.reset(this.renderTarget);
}
else if (map === "pictures"){
@@ -240,8 +243,9 @@ var NMO_RenderNormalview = new function(){
this.renderer_Normalview.setSize( img.naturalWidth, img.naturalHeight );
this.composer_Normalview.setSize( img.naturalWidth, img.naturalHeight );
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
- renderTarget = new THREE.WebGLRenderTarget( img.width, img.height, renderTargetParameters );
- this.composer_Normalview.reset(renderTarget);
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
+ this.renderTarget = new THREE.WebGLRenderTarget( img.width, img.height, renderTargetParameters );
+ this.composer_Normalview.reset(this.renderTarget);
this.picture_above_map.needsUpdate = true;
this.picture_left_map.needsUpdate = true;
@@ -324,4 +328,4 @@ var NMO_RenderNormalview = new function(){
NMO_AmbientOccMap.createAmbientOcclusionTexture();
};
-}
\ No newline at end of file
+}
diff --git a/javascripts/renderTargetUtils.js b/javascripts/renderTargetUtils.js
new file mode 100644
index 0000000..e48bc30
--- /dev/null
+++ b/javascripts/renderTargetUtils.js
@@ -0,0 +1,31 @@
+/*
+ * Author: Christian Petry
+ * Homepage: www.petry-christian.de
+ *
+ * License: MIT
+ * Copyright (c) 2014 Christian Petry
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+var NMO_RenderTargetUtils = new function(){
+ this.disposeRenderTarget = function(instance){
+ if (instance.renderTarget){
+ instance.renderTarget.dispose();
+ instance.renderTarget = null;
+ }
+ };
+}
diff --git a/javascripts/specularMap.js b/javascripts/specularMap.js
index cdef86c..c2e14d5 100644
--- a/javascripts/specularMap.js
+++ b/javascripts/specularMap.js
@@ -58,6 +58,7 @@ NMO_SpecularMap = new function(){
this.uniforms;
this.height_map_tex;
this.gaussian_shader_y, this.gaussian_shader_x;
+ this.renderTarget;
this.setSpecularSetting = function(element, v){
if (element == "spec_strength")
@@ -177,6 +178,7 @@ NMO_SpecularMap = new function(){
this.renderer.setSize( w, h );
this.composer.setSize( w, h );
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
this.renderTarget = new THREE.WebGLRenderTarget( w, h, renderTargetParameters );
this.composer.reset(this.renderTarget);
this.composer.render( 1 / 60 );
@@ -246,6 +248,7 @@ NMO_SpecularMap = new function(){
var renderTargetParameters = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat, stencilBufer: false };
+ NMO_RenderTargetUtils.disposeRenderTarget(this);
this.renderTarget = new THREE.WebGLRenderTarget( w, h, renderTargetParameters );
this.composer = new THREE.EffectComposer( this.renderer, this.renderTarget );
//this.renderer.render( scene, camera, this.renderTarget );
@@ -269,4 +272,4 @@ NMO_SpecularMap = new function(){
//console.log("Specular: " + (Date.now() - start));
};
-}
\ No newline at end of file
+}