Compare commits
5 Commits
19fab8ec65
...
v1.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02d2e9ed1d | ||
|
|
b1c66f055a | ||
|
|
7670707d0d | ||
|
|
bf05c62feb | ||
|
|
de40d2b6af |
@@ -30,7 +30,8 @@
|
|||||||
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(f''Release creee: id={d.get\\(\"\"id\"\", \"\"ERREUR\"\"\\)} tag={d.get\\(\"\"tag_name\"\", \"\"?\"\"\\)}''\\); print\\(d.get\\(''message'',''''\\)\\) if ''message'' in d else None\")",
|
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(f''Release creee: id={d.get\\(\"\"id\"\", \"\"ERREUR\"\"\\)} tag={d.get\\(\"\"tag_name\"\", \"\"?\"\"\\)}''\\); print\\(d.get\\(''message'',''''\\)\\) if ''message'' in d else None\")",
|
||||||
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(f'' OK: {d.get\\(\"\"name\"\",\"\"?\"\"\\)} \\({d.get\\(\"\"size\"\",0\\)//1024//1024}MB\\)''\\)\")",
|
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(f'' OK: {d.get\\(\"\"name\"\",\"\"?\"\"\\)} \\({d.get\\(\"\"size\"\",0\\)//1024//1024}MB\\)''\\)\")",
|
||||||
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(f''OK: {d.get\\(\"\"name\"\",d.get\\(\"\"message\"\",\"\"?\"\"\\)\\)} size={d.get\\(\"\"size\"\",0\\)//1024//1024}MB''\\)\")",
|
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); print\\(f''OK: {d.get\\(\"\"name\"\",d.get\\(\"\"message\"\",\"\"?\"\"\\)\\)} size={d.get\\(\"\"size\"\",0\\)//1024//1024}MB''\\)\")",
|
||||||
"Bash(python3 -c \":*)"
|
"Bash(python3 -c \":*)",
|
||||||
|
"mcp__ide__getDiagnostics"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-render-blender",
|
"name": "multi-render-blender",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "multi-render-blender",
|
"name": "multi-render-blender",
|
||||||
"version": "1.2.0",
|
"version": "1.3.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^34.0.0",
|
"electron": "^34.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-render-blender",
|
"name": "multi-render-blender",
|
||||||
"version": "1.2.0",
|
"version": "1.5.0",
|
||||||
"description": "Application Electron pour piloter des rendus Blender multi-cameras",
|
"description": "Application Electron pour piloter des rendus Blender multi-cameras",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
39
release.sh
39
release.sh
@@ -3,6 +3,18 @@ set -euo pipefail
|
|||||||
|
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
############################################
|
||||||
|
# Options CLI
|
||||||
|
############################################
|
||||||
|
BUMP_ARG=""
|
||||||
|
|
||||||
|
while getopts "i:" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
i) BUMP_ARG="$OPTARG" ;;
|
||||||
|
*) echo "Usage: $0 [-i patch|minor|major]"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
############################################
|
############################################
|
||||||
# Chargement du token
|
# Chargement du token
|
||||||
############################################
|
############################################
|
||||||
@@ -30,21 +42,30 @@ CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|||||||
echo "Version actuelle: v$CURRENT_VERSION"
|
echo "Version actuelle: v$CURRENT_VERSION"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo "Comment incrementer la version ?"
|
if [ -n "$BUMP_ARG" ]; then
|
||||||
echo " 1) patch"
|
case "$BUMP_ARG" in
|
||||||
echo " 2) minor"
|
patch) npm version patch --no-git-tag-version ;;
|
||||||
echo " 3) major"
|
minor) npm version minor --no-git-tag-version ;;
|
||||||
echo " 4) garder ($CURRENT_VERSION)"
|
major) npm version major --no-git-tag-version ;;
|
||||||
echo ""
|
*) echo "Erreur: -i accepte patch, minor ou major"; exit 1 ;;
|
||||||
read -p "Choix [1/2/3/4]: " BUMP_CHOICE
|
esac
|
||||||
|
else
|
||||||
|
echo "Comment incrementer la version ?"
|
||||||
|
echo " 1) patch"
|
||||||
|
echo " 2) minor"
|
||||||
|
echo " 3) major"
|
||||||
|
echo " 4) garder ($CURRENT_VERSION)"
|
||||||
|
echo ""
|
||||||
|
read -p "Choix [1/2/3/4]: " BUMP_CHOICE
|
||||||
|
|
||||||
case "$BUMP_CHOICE" in
|
case "$BUMP_CHOICE" in
|
||||||
1) npm version patch --no-git-tag-version ;;
|
1) npm version patch --no-git-tag-version ;;
|
||||||
2) npm version minor --no-git-tag-version ;;
|
2) npm version minor --no-git-tag-version ;;
|
||||||
3) npm version major --no-git-tag-version ;;
|
3) npm version major --no-git-tag-version ;;
|
||||||
4) echo "Version inchangee." ;;
|
4) echo "Version inchangee." ;;
|
||||||
*) echo "Choix invalide"; exit 1 ;;
|
*) echo "Choix invalide"; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
VERSION=$(node -p "require('./package.json').version")
|
VERSION=$(node -p "require('./package.json').version")
|
||||||
TAG="v$VERSION"
|
TAG="v$VERSION"
|
||||||
|
|||||||
@@ -13,13 +13,56 @@ const BlenderProcess = {
|
|||||||
|
|
||||||
let str_safe_name = str_camera_name.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
let str_safe_name = str_camera_name.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
||||||
|
|
||||||
let str_python_expr = [
|
let list_python_lines = [
|
||||||
"import bpy",
|
"import bpy",
|
||||||
"scene=bpy.context.scene",
|
"scene=bpy.context.scene",
|
||||||
"scene.camera=bpy.data.objects['" + str_safe_name + "']",
|
"scene.camera=bpy.data.objects['" + str_safe_name + "']",
|
||||||
"scene.render.resolution_x=" + nb_resolution_x,
|
"scene.render.resolution_x=" + nb_resolution_x,
|
||||||
"scene.render.resolution_y=" + nb_resolution_y,
|
"scene.render.resolution_y=" + nb_resolution_y,
|
||||||
].join(";");
|
];
|
||||||
|
|
||||||
|
if (obj_params.obj_render_settings) {
|
||||||
|
let obj_rs = obj_params.obj_render_settings;
|
||||||
|
if (obj_rs.str_engine) {
|
||||||
|
list_python_lines.push("scene.render.engine='" + obj_rs.str_engine + "'");
|
||||||
|
}
|
||||||
|
if (obj_rs.nb_resolution_percentage !== undefined) {
|
||||||
|
list_python_lines.push("scene.render.resolution_percentage=" + obj_rs.nb_resolution_percentage);
|
||||||
|
}
|
||||||
|
if (obj_rs.is_film_transparent !== undefined) {
|
||||||
|
list_python_lines.push("scene.render.film_transparent=" + (obj_rs.is_film_transparent ? "True" : "False"));
|
||||||
|
}
|
||||||
|
if (obj_rs.str_engine === "CYCLES") {
|
||||||
|
if (obj_rs.nb_samples !== undefined) {
|
||||||
|
list_python_lines.push("scene.cycles.samples=" + obj_rs.nb_samples);
|
||||||
|
}
|
||||||
|
if (obj_rs.str_device) {
|
||||||
|
list_python_lines.push("scene.cycles.device='" + obj_rs.str_device + "'");
|
||||||
|
}
|
||||||
|
if (obj_rs.is_denoise !== undefined) {
|
||||||
|
list_python_lines.push("scene.cycles.use_denoising=" + (obj_rs.is_denoise ? "True" : "False"));
|
||||||
|
}
|
||||||
|
} else if (obj_rs.str_engine === "BLENDER_EEVEE" || obj_rs.str_engine === "BLENDER_EEVEE_NEXT") {
|
||||||
|
if (obj_rs.nb_samples !== undefined) {
|
||||||
|
list_python_lines.push("try:\n scene.eevee.taa_render_samples=" + obj_rs.nb_samples + "\nexcept:\n try:\n scene.eevee.samples=" + obj_rs.nb_samples + "\n except:pass");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let str_python_expr = list_python_lines.join(";");
|
||||||
|
|
||||||
|
if (obj_params.list_collections && obj_params.list_collections.length > 0) {
|
||||||
|
str_python_expr += "\ndef _slc(lc,n,v):"
|
||||||
|
+ "\n for c in lc.children:"
|
||||||
|
+ "\n if c.name==n:c.exclude=v;return"
|
||||||
|
+ "\n _slc(c,n,v)\n";
|
||||||
|
for (let obj_col of obj_params.list_collections) {
|
||||||
|
let str_col_safe = obj_col.str_name.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
||||||
|
let str_val = obj_col.is_hide_render ? "True" : "False";
|
||||||
|
str_python_expr += "bpy.data.collections['" + str_col_safe + "'].hide_render=" + str_val
|
||||||
|
+ ";_slc(bpy.context.view_layer.layer_collection,'" + str_col_safe + "'," + str_val + ")\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let list_args = [
|
let list_args = [
|
||||||
"-b", str_blend_path,
|
"-b", str_blend_path,
|
||||||
|
|||||||
@@ -4,12 +4,25 @@ const PathResolver = require("./PathResolver.js");
|
|||||||
const STR_SCENE_MARKER = "SCENE_JSON:";
|
const STR_SCENE_MARKER = "SCENE_JSON:";
|
||||||
|
|
||||||
const STR_PYTHON_EXPR = [
|
const STR_PYTHON_EXPR = [
|
||||||
"import bpy, json, sys;",
|
"import bpy, json, sys",
|
||||||
"s=bpy.context.scene;",
|
"\ns=bpy.context.scene",
|
||||||
"cams=[o.name for o in bpy.data.objects if o.type=='CAMERA'];",
|
"\ncams=[o.name for o in bpy.data.objects if o.type=='CAMERA']",
|
||||||
"info={'list_cameras':cams,'obj_scene':{'nb_resolution_x':s.render.resolution_x,'nb_resolution_y':s.render.resolution_y,'nb_frame_start':s.frame_start,'nb_frame_end':s.frame_end,'nb_frame_step':s.frame_step}};",
|
"\ncols=[]",
|
||||||
"sys.stdout.write('SCENE_JSON:' + json.dumps(info) + '\\n');",
|
"\ndef _wlc(lc,d):",
|
||||||
"sys.stdout.flush()",
|
"\n for c in lc.children:",
|
||||||
|
"\n cols.append({'str_name':c.name,'nb_depth':d,'is_hide_render':bpy.data.collections[c.name].hide_render,'is_exclude':c.exclude})",
|
||||||
|
"\n _wlc(c,d+1)",
|
||||||
|
"\n_wlc(bpy.context.view_layer.layer_collection,0)",
|
||||||
|
"\nrs={'str_engine':s.render.engine,'nb_resolution_percentage':s.render.resolution_percentage,'is_film_transparent':s.render.film_transparent}",
|
||||||
|
"\ntry:\n rs['nb_cycles_samples']=s.cycles.samples;rs['str_cycles_device']=s.cycles.device;rs['is_cycles_denoise']=s.cycles.use_denoising",
|
||||||
|
"\nexcept:pass",
|
||||||
|
"\ntry:\n rs['nb_eevee_samples']=s.eevee.taa_render_samples",
|
||||||
|
"\nexcept:",
|
||||||
|
"\n try:\n rs['nb_eevee_samples']=s.eevee.samples",
|
||||||
|
"\n except:pass",
|
||||||
|
"\ninfo={'list_cameras':cams,'obj_scene':{'nb_resolution_x':s.render.resolution_x,'nb_resolution_y':s.render.resolution_y,'nb_frame_start':s.frame_start,'nb_frame_end':s.frame_end,'nb_frame_step':s.frame_step},'obj_render_settings':rs,'list_collections':cols}",
|
||||||
|
"\nsys.stdout.write('SCENE_JSON:' + json.dumps(info) + '\\n')",
|
||||||
|
"\nsys.stdout.flush()",
|
||||||
].join("");
|
].join("");
|
||||||
|
|
||||||
const CameraParser = {
|
const CameraParser = {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
const BlenderProcess = require("./BlenderProcess.js");
|
const BlenderProcess = require("./BlenderProcess.js");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
const os = require("os");
|
||||||
const { Notification } = require("electron");
|
const { Notification } = require("electron");
|
||||||
|
|
||||||
const STR_STATUS_IDLE = "idle";
|
const STR_STATUS_IDLE = "idle";
|
||||||
const STR_STATUS_RUNNING = "running";
|
const STR_STATUS_RUNNING = "running";
|
||||||
const STR_STATUS_PAUSED = "paused";
|
const STR_STATUS_PAUSED = "paused";
|
||||||
|
const NB_PLACEHOLDER_MAX_SIZE = 512;
|
||||||
|
|
||||||
class QueueManager {
|
class QueueManager {
|
||||||
constructor(obj_window) {
|
constructor(obj_window) {
|
||||||
@@ -17,6 +19,10 @@ class QueueManager {
|
|||||||
this.nb_last_render_ms = 0;
|
this.nb_last_render_ms = 0;
|
||||||
this.str_last_image_path = null;
|
this.str_last_image_path = null;
|
||||||
this.obj_notification_config = { is_notify_each_image: false, is_notify_all_done: true };
|
this.obj_notification_config = { is_notify_each_image: false, is_notify_all_done: true };
|
||||||
|
this.str_hostname = os.hostname();
|
||||||
|
this.nb_total_render_ms = 0;
|
||||||
|
this.nb_completed_renders = 0;
|
||||||
|
this.map_remote_avgs = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
set_notification_config(obj_config) {
|
set_notification_config(obj_config) {
|
||||||
@@ -36,7 +42,12 @@ class QueueManager {
|
|||||||
this.str_status = STR_STATUS_RUNNING;
|
this.str_status = STR_STATUS_RUNNING;
|
||||||
this.nb_last_render_ms = 0;
|
this.nb_last_render_ms = 0;
|
||||||
this.str_last_image_path = null;
|
this.str_last_image_path = null;
|
||||||
|
this.nb_total_render_ms = 0;
|
||||||
|
this.nb_completed_renders = 0;
|
||||||
|
this.map_remote_avgs = {};
|
||||||
this.str_overwrite_mode = obj_config.str_overwrite_mode || "overwrite";
|
this.str_overwrite_mode = obj_config.str_overwrite_mode || "overwrite";
|
||||||
|
this.list_collections = obj_config.list_collections || [];
|
||||||
|
this.obj_render_settings = obj_config.obj_render_settings || null;
|
||||||
|
|
||||||
this._send_log("File de rendu construite : " + this.list_queue.length + " elements.");
|
this._send_log("File de rendu construite : " + this.list_queue.length + " elements.");
|
||||||
this._send_progress();
|
this._send_progress();
|
||||||
@@ -190,6 +201,8 @@ class QueueManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._check_remote_completions();
|
||||||
|
|
||||||
// Batch skip : boucle iterative pour eviter un stack overflow recursif
|
// Batch skip : boucle iterative pour eviter un stack overflow recursif
|
||||||
let nb_skip_count = 0;
|
let nb_skip_count = 0;
|
||||||
while (this.nb_current_index < this.list_queue.length && this.str_overwrite_mode === "skip") {
|
while (this.nb_current_index < this.list_queue.length && this.str_overwrite_mode === "skip") {
|
||||||
@@ -209,10 +222,20 @@ class QueueManager {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nb_size === 0) {
|
if (nb_size === 0) {
|
||||||
this._send_log("Placeholder vide detecte, re-rendu : " + obj_check.str_camera_name + " F" + obj_check.nb_frame);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nb_size > NB_PLACEHOLDER_MAX_SIZE) {
|
||||||
obj_check.str_status = "skipped";
|
obj_check.str_status = "skipped";
|
||||||
|
try {
|
||||||
|
obj_check.str_done_date = fs.statSync(obj_check.str_expected_file).mtime.toISOString();
|
||||||
|
} catch (obj_date_err) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj_check.str_status = "rendering_remote";
|
||||||
|
this._read_placeholder(obj_check);
|
||||||
|
}
|
||||||
this.nb_current_index++;
|
this.nb_current_index++;
|
||||||
nb_skip_count++;
|
nb_skip_count++;
|
||||||
}
|
}
|
||||||
@@ -239,13 +262,26 @@ class QueueManager {
|
|||||||
try {
|
try {
|
||||||
if (fs.existsSync(obj_item.str_expected_file)) {
|
if (fs.existsSync(obj_item.str_expected_file)) {
|
||||||
let nb_recheck_size = fs.statSync(obj_item.str_expected_file).size;
|
let nb_recheck_size = fs.statSync(obj_item.str_expected_file).size;
|
||||||
if (nb_recheck_size > 0) {
|
if (nb_recheck_size > NB_PLACEHOLDER_MAX_SIZE) {
|
||||||
obj_item.str_status = "skipped";
|
obj_item.str_status = "skipped";
|
||||||
|
try {
|
||||||
|
obj_item.str_done_date = fs.statSync(obj_item.str_expected_file).mtime.toISOString();
|
||||||
|
} catch (obj_d_err) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
this._send_log("Skip : " + obj_item.str_camera_name + " F" + obj_item.nb_frame + " (existant)");
|
this._send_log("Skip : " + obj_item.str_camera_name + " F" + obj_item.nb_frame + " (existant)");
|
||||||
this.nb_current_index++;
|
this.nb_current_index++;
|
||||||
this._send_progress();
|
this._send_progress();
|
||||||
this._process_next();
|
this._process_next();
|
||||||
return;
|
return;
|
||||||
|
} else if (nb_recheck_size > 0) {
|
||||||
|
obj_item.str_status = "rendering_remote";
|
||||||
|
this._read_placeholder(obj_item);
|
||||||
|
this._send_log("Skip : " + obj_item.str_camera_name + " F" + obj_item.nb_frame + " (en cours par " + (obj_item.str_remote_hostname || "?") + ")");
|
||||||
|
this.nb_current_index++;
|
||||||
|
this._send_progress();
|
||||||
|
this._process_next();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (obj_recheck_err) {
|
} catch (obj_recheck_err) {
|
||||||
@@ -261,7 +297,7 @@ class QueueManager {
|
|||||||
if (!fs.existsSync(str_dir)) {
|
if (!fs.existsSync(str_dir)) {
|
||||||
fs.mkdirSync(str_dir, { recursive: true });
|
fs.mkdirSync(str_dir, { recursive: true });
|
||||||
}
|
}
|
||||||
fs.writeFileSync(obj_item.str_expected_file, "");
|
fs.writeFileSync(obj_item.str_expected_file, this._get_placeholder_content());
|
||||||
} catch (obj_file_err) {
|
} catch (obj_file_err) {
|
||||||
this._send_log("ERREUR creation placeholder : " + obj_file_err.message);
|
this._send_log("ERREUR creation placeholder : " + obj_file_err.message);
|
||||||
}
|
}
|
||||||
@@ -280,6 +316,8 @@ class QueueManager {
|
|||||||
nb_resolution_y: obj_item.nb_resolution_y,
|
nb_resolution_y: obj_item.nb_resolution_y,
|
||||||
str_format: obj_item.str_format,
|
str_format: obj_item.str_format,
|
||||||
str_output_path: obj_item.str_output_path,
|
str_output_path: obj_item.str_output_path,
|
||||||
|
list_collections: this.list_collections,
|
||||||
|
obj_render_settings: this.obj_render_settings,
|
||||||
fn_on_stdout: (str_data) => {
|
fn_on_stdout: (str_data) => {
|
||||||
this._send_log(str_data.trim());
|
this._send_log(str_data.trim());
|
||||||
},
|
},
|
||||||
@@ -296,6 +334,9 @@ class QueueManager {
|
|||||||
|
|
||||||
obj_item.str_status = "done";
|
obj_item.str_status = "done";
|
||||||
this.nb_last_render_ms = Date.now() - nb_start;
|
this.nb_last_render_ms = Date.now() - nb_start;
|
||||||
|
this.nb_total_render_ms += this.nb_last_render_ms;
|
||||||
|
this.nb_completed_renders++;
|
||||||
|
obj_item.str_done_date = new Date().toISOString();
|
||||||
|
|
||||||
let str_image = obj_result.str_rendered_file || obj_item.str_expected_file;
|
let str_image = obj_result.str_rendered_file || obj_item.str_expected_file;
|
||||||
this.str_last_image_path = str_image;
|
this.str_last_image_path = str_image;
|
||||||
@@ -316,7 +357,7 @@ class QueueManager {
|
|||||||
if (this.str_overwrite_mode === "skip" && fs.existsSync(obj_item.str_expected_file)) {
|
if (this.str_overwrite_mode === "skip" && fs.existsSync(obj_item.str_expected_file)) {
|
||||||
try {
|
try {
|
||||||
let obj_stats = fs.statSync(obj_item.str_expected_file);
|
let obj_stats = fs.statSync(obj_item.str_expected_file);
|
||||||
if (obj_stats.size === 0) {
|
if (obj_stats.size <= NB_PLACEHOLDER_MAX_SIZE) {
|
||||||
fs.unlinkSync(obj_item.str_expected_file);
|
fs.unlinkSync(obj_item.str_expected_file);
|
||||||
}
|
}
|
||||||
} catch (obj_cleanup_err) {
|
} catch (obj_cleanup_err) {
|
||||||
@@ -351,14 +392,54 @@ class QueueManager {
|
|||||||
let list_skipped = [];
|
let list_skipped = [];
|
||||||
let list_stopped = [];
|
let list_stopped = [];
|
||||||
let list_skipped_paths = [];
|
let list_skipped_paths = [];
|
||||||
|
let list_rendering_remote = [];
|
||||||
|
let list_item_results = [];
|
||||||
|
|
||||||
|
let nb_avg = this.nb_completed_renders > 0
|
||||||
|
? Math.round(this.nb_total_render_ms / this.nb_completed_renders)
|
||||||
|
: 0;
|
||||||
|
|
||||||
for (let nb_i = 0; nb_i < this.list_queue.length; nb_i++) {
|
for (let nb_i = 0; nb_i < this.list_queue.length; nb_i++) {
|
||||||
if (this.list_queue[nb_i].str_status === "skipped") {
|
let obj_q = this.list_queue[nb_i];
|
||||||
|
if (obj_q.str_status === "skipped") {
|
||||||
list_skipped.push(nb_i);
|
list_skipped.push(nb_i);
|
||||||
list_skipped_paths.push({ nb_index: nb_i, str_path: this.list_queue[nb_i].str_expected_file });
|
list_skipped_paths.push({ nb_index: nb_i, str_path: obj_q.str_expected_file });
|
||||||
} else if (this.list_queue[nb_i].str_status === "stopped") {
|
list_item_results.push({
|
||||||
|
nb_index: nb_i,
|
||||||
|
str_type: "done",
|
||||||
|
str_date: obj_q.str_done_date || null,
|
||||||
|
str_resolution: obj_q.nb_resolution_x + "x" + obj_q.nb_resolution_y,
|
||||||
|
});
|
||||||
|
} else if (obj_q.str_status === "stopped") {
|
||||||
list_stopped.push(nb_i);
|
list_stopped.push(nb_i);
|
||||||
|
} else if (obj_q.str_status === "rendering_remote") {
|
||||||
|
list_rendering_remote.push(nb_i);
|
||||||
|
list_item_results.push({
|
||||||
|
nb_index: nb_i,
|
||||||
|
str_type: "rendering_remote",
|
||||||
|
str_remote_hostname: obj_q.str_remote_hostname || "?",
|
||||||
|
nb_remote_avg_ms: obj_q.nb_remote_avg_ms || 0,
|
||||||
|
});
|
||||||
|
} else if (obj_q.str_status === "done") {
|
||||||
|
list_item_results.push({
|
||||||
|
nb_index: nb_i,
|
||||||
|
str_type: "done",
|
||||||
|
str_date: obj_q.str_done_date || null,
|
||||||
|
str_resolution: obj_q.nb_resolution_x + "x" + obj_q.nb_resolution_y,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let list_machine_avgs = [];
|
||||||
|
if (nb_avg > 0) {
|
||||||
|
list_machine_avgs.push({ str_hostname: this.str_hostname, nb_avg_ms: nb_avg });
|
||||||
|
}
|
||||||
|
for (let str_h of Object.keys(this.map_remote_avgs)) {
|
||||||
|
if (this.map_remote_avgs[str_h] > 0) {
|
||||||
|
list_machine_avgs.push({ str_hostname: str_h, nb_avg_ms: this.map_remote_avgs[str_h] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._send_event("render-progress", {
|
this._send_event("render-progress", {
|
||||||
nb_current: this.nb_current_index,
|
nb_current: this.nb_current_index,
|
||||||
nb_total: this.list_queue.length,
|
nb_total: this.list_queue.length,
|
||||||
@@ -370,9 +451,57 @@ class QueueManager {
|
|||||||
list_skipped: list_skipped,
|
list_skipped: list_skipped,
|
||||||
list_stopped: list_stopped,
|
list_stopped: list_stopped,
|
||||||
list_skipped_paths: list_skipped_paths,
|
list_skipped_paths: list_skipped_paths,
|
||||||
|
list_rendering_remote: list_rendering_remote,
|
||||||
|
list_item_results: list_item_results,
|
||||||
|
str_hostname: this.str_hostname,
|
||||||
|
nb_avg_render_ms: nb_avg,
|
||||||
|
list_machine_avgs: list_machine_avgs,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_get_placeholder_content() {
|
||||||
|
let nb_avg = this.nb_completed_renders > 0
|
||||||
|
? Math.round(this.nb_total_render_ms / this.nb_completed_renders)
|
||||||
|
: 0;
|
||||||
|
return JSON.stringify({ str_hostname: this.str_hostname, nb_avg_ms: nb_avg });
|
||||||
|
}
|
||||||
|
|
||||||
|
_read_placeholder(obj_item) {
|
||||||
|
try {
|
||||||
|
let str_content = fs.readFileSync(obj_item.str_expected_file, "utf-8");
|
||||||
|
let obj_data = JSON.parse(str_content);
|
||||||
|
obj_item.str_remote_hostname = obj_data.str_hostname || "?";
|
||||||
|
obj_item.nb_remote_avg_ms = obj_data.nb_avg_ms || 0;
|
||||||
|
if (obj_data.str_hostname && obj_data.nb_avg_ms > 0) {
|
||||||
|
this.map_remote_avgs[obj_data.str_hostname] = obj_data.nb_avg_ms;
|
||||||
|
}
|
||||||
|
} catch (obj_parse_err) {
|
||||||
|
obj_item.str_remote_hostname = "?";
|
||||||
|
obj_item.nb_remote_avg_ms = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_check_remote_completions() {
|
||||||
|
for (let obj_q of this.list_queue) {
|
||||||
|
if (obj_q.str_status !== "rendering_remote") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(obj_q.str_expected_file)) {
|
||||||
|
let nb_size = fs.statSync(obj_q.str_expected_file).size;
|
||||||
|
if (nb_size > NB_PLACEHOLDER_MAX_SIZE) {
|
||||||
|
obj_q.str_status = "skipped";
|
||||||
|
obj_q.str_done_date = fs.statSync(obj_q.str_expected_file).mtime.toISOString();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
obj_q.str_status = "pending";
|
||||||
|
}
|
||||||
|
} catch (obj_check_err) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_send_log(str_message) {
|
_send_log(str_message) {
|
||||||
this._send_event("log", str_message);
|
this._send_event("log", str_message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
<div class="container-fluid p-3">
|
<div class="container-fluid p-3">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
|
|
||||||
<!-- ── Left Column : File + Cameras ─────────────── -->
|
<!-- ── Left Column : File + Settings ──────────── -->
|
||||||
<div class="col-md-4 d-flex flex-column gap-3">
|
<div class="col-md-3 d-flex flex-column gap-3">
|
||||||
|
|
||||||
<!-- Blend file selection -->
|
<!-- Blend file selection -->
|
||||||
<div class="card bg-dark border-secondary">
|
<div class="card bg-dark border-secondary">
|
||||||
@@ -99,6 +99,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Render settings -->
|
||||||
|
<div class="card bg-dark border-secondary">
|
||||||
|
<div class="card-header border-secondary">
|
||||||
|
<i class="mdi mdi-tune-vertical me-1"></i>Proprietes de rendu
|
||||||
|
</div>
|
||||||
|
<div class="card-body" id="container_render_settings">
|
||||||
|
<div class="text-center text-light-emphasis py-2">
|
||||||
|
Chargez un fichier .blend
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Render mode -->
|
<!-- Render mode -->
|
||||||
<div class="card bg-dark border-secondary">
|
<div class="card bg-dark border-secondary">
|
||||||
<div class="card-header border-secondary">
|
<div class="card-header border-secondary">
|
||||||
@@ -132,15 +144,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ── Center Column : Cameras + Config ──────────── -->
|
||||||
|
<div class="col-md-3 d-flex flex-column gap-3">
|
||||||
|
|
||||||
<!-- Camera list -->
|
<!-- Camera list -->
|
||||||
<div class="card bg-dark border-secondary flex-grow-1">
|
<div class="card bg-dark border-secondary">
|
||||||
<div class="card-header border-secondary d-flex justify-content-between align-items-center">
|
<div class="card-header border-secondary d-flex justify-content-between align-items-center">
|
||||||
<span><i class="mdi mdi-camera-outline me-1"></i>Cameras</span>
|
<span><i class="mdi mdi-camera-outline me-1"></i>Cameras</span>
|
||||||
<span id="badge_camera_count" class="badge bg-secondary">0</span>
|
<span id="badge_camera_count" class="badge bg-secondary">0</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<div id="container_camera_list" class="list-group list-group-flush overflow-auto" style="max-height: 400px;">
|
<div id="container_camera_list" class="list-group list-group-flush overflow-auto" style="max-height: 300px;">
|
||||||
<div class="text-center text-light-emphasis py-4">
|
<div class="text-center text-light-emphasis py-4">
|
||||||
<i class="mdi mdi-camera-off-outline d-block mb-2" style="font-size: 2rem;"></i>
|
<i class="mdi mdi-camera-off-outline d-block mb-2" style="font-size: 2rem;"></i>
|
||||||
Chargez un fichier .blend
|
Chargez un fichier .blend
|
||||||
@@ -148,13 +164,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Collections -->
|
||||||
|
<div class="card bg-dark border-secondary">
|
||||||
|
<div class="card-header border-secondary d-flex justify-content-between align-items-center">
|
||||||
|
<span><i class="mdi mdi-folder-multiple-outline me-1"></i>Collections</span>
|
||||||
|
<div class="d-flex align-items-center gap-2">
|
||||||
|
<button id="btn_reset_collections" class="btn btn-sm btn-outline-secondary py-0 px-1"
|
||||||
|
title="Restaurer les valeurs originales">
|
||||||
|
<i class="mdi mdi-undo-variant" style="font-size: 0.75rem;"></i>
|
||||||
|
</button>
|
||||||
|
<span id="badge_collection_count" class="badge bg-secondary">0</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div id="container_collection_list" class="list-group list-group-flush overflow-auto" style="max-height: 250px;">
|
||||||
|
<div class="text-center text-light-emphasis py-3">
|
||||||
|
<i class="mdi mdi-folder-off-outline d-block mb-2" style="font-size: 1.5rem;"></i>
|
||||||
|
Chargez un fichier .blend
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ── Center Column : Camera Config + Controls ── -->
|
|
||||||
<div class="col-md-4 d-flex flex-column gap-3">
|
|
||||||
|
|
||||||
<!-- Camera config -->
|
<!-- Camera config -->
|
||||||
<div class="card bg-dark border-secondary">
|
<div class="card bg-dark border-secondary flex-grow-1">
|
||||||
<div class="card-header border-secondary">
|
<div class="card-header border-secondary">
|
||||||
<i class="mdi mdi-cog-outline me-1"></i>Configuration : <span id="label_selected_camera">-</span>
|
<i class="mdi mdi-cog-outline me-1"></i>Configuration : <span id="label_selected_camera">-</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -164,6 +198,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ── Right Column : Controls + Queue + Preview + Console ── -->
|
||||||
|
<div class="col-md-6 d-flex flex-column gap-3">
|
||||||
|
|
||||||
<!-- Render controls -->
|
<!-- Render controls -->
|
||||||
<div class="card bg-dark border-secondary">
|
<div class="card bg-dark border-secondary">
|
||||||
@@ -202,6 +240,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Render queue + Preview side by side -->
|
||||||
|
<div class="row g-3 flex-grow-1">
|
||||||
|
<div class="col-6 d-flex flex-column">
|
||||||
<!-- Render queue -->
|
<!-- Render queue -->
|
||||||
<div class="card bg-dark border-secondary flex-grow-1">
|
<div class="card bg-dark border-secondary flex-grow-1">
|
||||||
<div class="card-header border-secondary d-flex justify-content-between align-items-center">
|
<div class="card-header border-secondary d-flex justify-content-between align-items-center">
|
||||||
@@ -220,17 +261,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-6 d-flex flex-column">
|
||||||
<!-- ── Right Column : Preview + Console ─────────── -->
|
|
||||||
<div class="col-md-4 d-flex flex-column gap-3">
|
|
||||||
|
|
||||||
<!-- Preview -->
|
<!-- Preview -->
|
||||||
<div class="card bg-dark border-secondary">
|
<div class="card bg-dark border-secondary flex-grow-1">
|
||||||
<div class="card-header border-secondary">
|
<div class="card-header border-secondary">
|
||||||
<i class="mdi mdi-image-outline me-1"></i>Preview
|
<i class="mdi mdi-image-outline me-1"></i>Preview
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-2 text-center" id="container_preview">
|
<div class="card-body p-2 text-center" id="container_preview">
|
||||||
<div class="preview-placeholder d-flex align-items-center justify-content-center" style="min-height: 300px;">
|
<div class="preview-placeholder d-flex align-items-center justify-content-center" style="min-height: 200px;">
|
||||||
<div class="text-light-emphasis">
|
<div class="text-light-emphasis">
|
||||||
<i class="mdi mdi-image-off-outline d-block mb-2" style="font-size: 3rem;"></i>
|
<i class="mdi mdi-image-off-outline d-block mb-2" style="font-size: 3rem;"></i>
|
||||||
Aucun rendu disponible
|
Aucun rendu disponible
|
||||||
@@ -238,9 +276,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Console logs -->
|
<!-- Console logs -->
|
||||||
<div class="card bg-dark border-secondary flex-grow-1">
|
<div class="card bg-dark border-secondary">
|
||||||
<div class="card-header border-secondary d-flex justify-content-between align-items-center">
|
<div class="card-header border-secondary d-flex justify-content-between align-items-center">
|
||||||
<span><i class="mdi mdi-console me-1"></i>Console</span>
|
<span><i class="mdi mdi-console me-1"></i>Console</span>
|
||||||
<button id="btn_clear_console" class="btn btn-sm btn-outline-secondary" title="Vider">
|
<button id="btn_clear_console" class="btn btn-sm btn-outline-secondary" title="Vider">
|
||||||
@@ -248,7 +288,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<div id="container_console" class="console-output overflow-auto p-2" style="max-height: 300px; min-height: 200px;">
|
<div id="container_console" class="console-output overflow-auto p-2" style="max-height: 200px; min-height: 150px;">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -261,7 +301,9 @@
|
|||||||
|
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
<script src="scripts/ConsoleLog.js"></script>
|
<script src="scripts/ConsoleLog.js"></script>
|
||||||
|
<script src="scripts/RenderSettings.js"></script>
|
||||||
<script src="scripts/CameraList.js"></script>
|
<script src="scripts/CameraList.js"></script>
|
||||||
|
<script src="scripts/CollectionList.js"></script>
|
||||||
<script src="scripts/CameraConfig.js"></script>
|
<script src="scripts/CameraConfig.js"></script>
|
||||||
<script src="scripts/RenderQueue.js"></script>
|
<script src="scripts/RenderQueue.js"></script>
|
||||||
<script src="scripts/PreviewPanel.js"></script>
|
<script src="scripts/PreviewPanel.js"></script>
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ const App = {
|
|||||||
|
|
||||||
init: () => {
|
init: () => {
|
||||||
ConsoleLog.init();
|
ConsoleLog.init();
|
||||||
|
RenderSettings.init();
|
||||||
CameraList.init(App._on_camera_select);
|
CameraList.init(App._on_camera_select);
|
||||||
|
CollectionList.init();
|
||||||
CameraConfig.init();
|
CameraConfig.init();
|
||||||
RenderQueue.init();
|
RenderQueue.init();
|
||||||
PreviewPanel.init();
|
PreviewPanel.init();
|
||||||
@@ -70,6 +72,12 @@ const App = {
|
|||||||
obj_radio_both.addEventListener("change", () => { App._update_output_example(); });
|
obj_radio_both.addEventListener("change", () => { App._update_output_example(); });
|
||||||
obj_input_frame_prefix.addEventListener("input", () => { App._update_output_example(); });
|
obj_input_frame_prefix.addEventListener("input", () => { App._update_output_example(); });
|
||||||
obj_input_frame_padding.addEventListener("input", () => { App._update_output_example(); });
|
obj_input_frame_padding.addEventListener("input", () => { App._update_output_example(); });
|
||||||
|
|
||||||
|
let obj_btn_reset_cols = document.getElementById("btn_reset_collections");
|
||||||
|
obj_btn_reset_cols.addEventListener("click", () => {
|
||||||
|
CollectionList.reset_to_original();
|
||||||
|
ConsoleLog.add("Collections restaurees aux valeurs originales.");
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_bind_render_events: () => {
|
_bind_render_events: () => {
|
||||||
@@ -129,6 +137,18 @@ const App = {
|
|||||||
|
|
||||||
CameraList.set_cameras(obj_result.list_cameras, obj_result.obj_scene);
|
CameraList.set_cameras(obj_result.list_cameras, obj_result.obj_scene);
|
||||||
CameraConfig.clear();
|
CameraConfig.clear();
|
||||||
|
|
||||||
|
if (obj_result.obj_render_settings) {
|
||||||
|
RenderSettings.set_from_blend(obj_result.obj_render_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj_result.list_collections) {
|
||||||
|
CollectionList.set_collections(obj_result.list_collections);
|
||||||
|
ConsoleLog.add(obj_result.list_collections.length + " collection(s) trouvee(s).");
|
||||||
|
} else {
|
||||||
|
CollectionList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
ConsoleLog.add(obj_result.list_cameras.length + " camera(s) trouvee(s).");
|
ConsoleLog.add(obj_result.list_cameras.length + " camera(s) trouvee(s).");
|
||||||
App._update_start_button();
|
App._update_start_button();
|
||||||
})
|
})
|
||||||
@@ -188,6 +208,8 @@ const App = {
|
|||||||
nb_frame_padding: nb_frame_padding,
|
nb_frame_padding: nb_frame_padding,
|
||||||
str_output_path: App.str_output_path,
|
str_output_path: App.str_output_path,
|
||||||
list_cameras: list_cameras,
|
list_cameras: list_cameras,
|
||||||
|
list_collections: CollectionList.get_overrides(),
|
||||||
|
obj_render_settings: RenderSettings.get_settings(),
|
||||||
};
|
};
|
||||||
|
|
||||||
RenderQueue.build_display(str_mode, list_cameras);
|
RenderQueue.build_display(str_mode, list_cameras);
|
||||||
@@ -249,6 +271,7 @@ const App = {
|
|||||||
nb_frame_padding: nb_frame_padding,
|
nb_frame_padding: nb_frame_padding,
|
||||||
str_output_path: App.str_output_path,
|
str_output_path: App.str_output_path,
|
||||||
list_cameras: list_cameras,
|
list_cameras: list_cameras,
|
||||||
|
list_collections: CollectionList.get_overrides(),
|
||||||
};
|
};
|
||||||
|
|
||||||
RenderQueue.build_display(str_mode, list_cameras);
|
RenderQueue.build_display(str_mode, list_cameras);
|
||||||
@@ -284,6 +307,8 @@ const App = {
|
|||||||
nb_frame_padding: nb_frame_padding,
|
nb_frame_padding: nb_frame_padding,
|
||||||
str_output_path: App.str_output_path,
|
str_output_path: App.str_output_path,
|
||||||
list_cameras: CameraList.list_cameras,
|
list_cameras: CameraList.list_cameras,
|
||||||
|
list_collections: CollectionList.list_collections,
|
||||||
|
obj_render_settings: RenderSettings.get_settings(),
|
||||||
};
|
};
|
||||||
|
|
||||||
window.api.save_config(obj_config)
|
window.api.save_config(obj_config)
|
||||||
@@ -338,6 +363,8 @@ const App = {
|
|||||||
|
|
||||||
App._update_output_example();
|
App._update_output_example();
|
||||||
|
|
||||||
|
RenderSettings.set_from_config(obj_config);
|
||||||
|
|
||||||
if (obj_config.list_cameras && obj_config.list_cameras.length > 0) {
|
if (obj_config.list_cameras && obj_config.list_cameras.length > 0) {
|
||||||
CameraList.list_cameras = obj_config.list_cameras;
|
CameraList.list_cameras = obj_config.list_cameras;
|
||||||
CameraList.str_selected_camera = null;
|
CameraList.str_selected_camera = null;
|
||||||
@@ -347,6 +374,15 @@ const App = {
|
|||||||
obj_badge.textContent = String(obj_config.list_cameras.length);
|
obj_badge.textContent = String(obj_config.list_cameras.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (obj_config.list_collections && obj_config.list_collections.length > 0) {
|
||||||
|
CollectionList.list_collections = obj_config.list_collections;
|
||||||
|
CollectionList.render();
|
||||||
|
let obj_badge_col = document.getElementById("badge_collection_count");
|
||||||
|
obj_badge_col.textContent = String(obj_config.list_collections.length);
|
||||||
|
} else {
|
||||||
|
CollectionList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
CameraConfig.clear();
|
CameraConfig.clear();
|
||||||
App._update_start_button();
|
App._update_start_button();
|
||||||
ConsoleLog.add("Configuration importee.");
|
ConsoleLog.add("Configuration importee.");
|
||||||
|
|||||||
133
src/renderer/scripts/CollectionList.js
Normal file
133
src/renderer/scripts/CollectionList.js
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
const CollectionList = {
|
||||||
|
list_collections: [],
|
||||||
|
|
||||||
|
init: () => {
|
||||||
|
// Peuple lors du chargement du .blend
|
||||||
|
},
|
||||||
|
|
||||||
|
set_collections: (list_raw) => {
|
||||||
|
CollectionList.list_collections = [];
|
||||||
|
|
||||||
|
if (!list_raw || list_raw.length === 0) {
|
||||||
|
CollectionList.render();
|
||||||
|
let obj_badge = document.getElementById("badge_collection_count");
|
||||||
|
obj_badge.textContent = "0";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let obj_raw of list_raw) {
|
||||||
|
let is_hidden = obj_raw.is_hide_render || obj_raw.is_exclude;
|
||||||
|
CollectionList.list_collections.push({
|
||||||
|
str_name: obj_raw.str_name,
|
||||||
|
nb_depth: obj_raw.nb_depth,
|
||||||
|
is_original_hide_render: is_hidden,
|
||||||
|
is_original_exclude: obj_raw.is_exclude,
|
||||||
|
is_hide_render: is_hidden,
|
||||||
|
has_override: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectionList.render();
|
||||||
|
|
||||||
|
let obj_badge = document.getElementById("badge_collection_count");
|
||||||
|
obj_badge.textContent = String(CollectionList.list_collections.length);
|
||||||
|
},
|
||||||
|
|
||||||
|
get_overrides: () => {
|
||||||
|
let list_overrides = [];
|
||||||
|
for (let obj_col of CollectionList.list_collections) {
|
||||||
|
list_overrides.push({
|
||||||
|
str_name: obj_col.str_name,
|
||||||
|
is_hide_render: obj_col.is_hide_render,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return list_overrides;
|
||||||
|
},
|
||||||
|
|
||||||
|
render: () => {
|
||||||
|
let obj_container = document.getElementById("container_collection_list");
|
||||||
|
obj_container.innerHTML = "";
|
||||||
|
|
||||||
|
if (CollectionList.list_collections.length === 0) {
|
||||||
|
obj_container.innerHTML = '<div class="text-center text-light-emphasis py-3">'
|
||||||
|
+ '<i class="mdi mdi-folder-off-outline d-block mb-2" style="font-size: 1.5rem;"></i>'
|
||||||
|
+ "Chargez un fichier .blend"
|
||||||
|
+ "</div>";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let obj_col of CollectionList.list_collections) {
|
||||||
|
let obj_item = document.createElement("div");
|
||||||
|
obj_item.classList.add("list-group-item", "bg-dark", "text-light",
|
||||||
|
"border-secondary", "d-flex", "align-items-center", "gap-2", "py-1");
|
||||||
|
|
||||||
|
let nb_padding = 0.75 + obj_col.nb_depth * 1.2;
|
||||||
|
obj_item.style.paddingLeft = nb_padding + "rem";
|
||||||
|
|
||||||
|
let obj_checkbox = document.createElement("input");
|
||||||
|
obj_checkbox.type = "checkbox";
|
||||||
|
obj_checkbox.classList.add("form-check-input");
|
||||||
|
obj_checkbox.checked = !obj_col.is_hide_render;
|
||||||
|
obj_checkbox.addEventListener("change", () => {
|
||||||
|
obj_col.is_hide_render = !obj_checkbox.checked;
|
||||||
|
obj_col.has_override = (obj_col.is_hide_render !== obj_col.is_original_hide_render);
|
||||||
|
CollectionList.render();
|
||||||
|
});
|
||||||
|
|
||||||
|
let obj_icon = document.createElement("i");
|
||||||
|
obj_icon.classList.add("mdi");
|
||||||
|
if (obj_col.is_hide_render) {
|
||||||
|
obj_icon.classList.add("mdi-folder-off-outline", "text-muted");
|
||||||
|
} else {
|
||||||
|
obj_icon.classList.add("mdi-folder-outline");
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj_label = document.createElement("span");
|
||||||
|
obj_label.classList.add("flex-grow-1", "collection-name");
|
||||||
|
obj_label.textContent = obj_col.str_name;
|
||||||
|
if (obj_col.is_hide_render) {
|
||||||
|
obj_label.classList.add("text-muted");
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj_indicator = document.createElement("small");
|
||||||
|
obj_indicator.classList.add("collection-original-badge");
|
||||||
|
|
||||||
|
if (obj_col.has_override) {
|
||||||
|
obj_indicator.classList.add("text-warning");
|
||||||
|
obj_indicator.innerHTML = '<i class="mdi mdi-pencil-outline"></i>';
|
||||||
|
obj_indicator.title = "Modifie (original : "
|
||||||
|
+ (obj_col.is_original_hide_render ? "masque" : "visible") + ")";
|
||||||
|
} else if (obj_col.is_original_hide_render) {
|
||||||
|
obj_indicator.classList.add("text-muted");
|
||||||
|
obj_indicator.innerHTML = '<i class="mdi mdi-eye-off-outline"></i>';
|
||||||
|
obj_indicator.title = "Masque dans le .blend";
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_item.appendChild(obj_checkbox);
|
||||||
|
obj_item.appendChild(obj_icon);
|
||||||
|
obj_item.appendChild(obj_label);
|
||||||
|
obj_item.appendChild(obj_indicator);
|
||||||
|
|
||||||
|
obj_container.appendChild(obj_item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reset_to_original: () => {
|
||||||
|
for (let obj_col of CollectionList.list_collections) {
|
||||||
|
obj_col.is_hide_render = obj_col.is_original_hide_render;
|
||||||
|
obj_col.has_override = false;
|
||||||
|
}
|
||||||
|
CollectionList.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
clear: () => {
|
||||||
|
CollectionList.list_collections = [];
|
||||||
|
let obj_container = document.getElementById("container_collection_list");
|
||||||
|
obj_container.innerHTML = '<div class="text-center text-light-emphasis py-3">'
|
||||||
|
+ '<i class="mdi mdi-folder-off-outline d-block mb-2" style="font-size: 1.5rem;"></i>'
|
||||||
|
+ "Chargez un fichier .blend"
|
||||||
|
+ "</div>";
|
||||||
|
let obj_badge = document.getElementById("badge_collection_count");
|
||||||
|
obj_badge.textContent = "0";
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -40,7 +40,7 @@ const ProgressBar = {
|
|||||||
let obj_frame_label = document.getElementById("label_current_frame");
|
let obj_frame_label = document.getElementById("label_current_frame");
|
||||||
obj_frame_label.textContent = nb_frame !== null && nb_frame !== undefined ? String(nb_frame) : "-";
|
obj_frame_label.textContent = nb_frame !== null && nb_frame !== undefined ? String(nb_frame) : "-";
|
||||||
|
|
||||||
RenderQueue.update_progress(nb_current, obj_data.nb_last_render_ms || 0, obj_data.str_last_image_path || null, obj_data.list_skipped || [], obj_data.list_stopped || [], obj_data.list_skipped_paths || []);
|
RenderQueue.update_progress(obj_data);
|
||||||
},
|
},
|
||||||
|
|
||||||
reset: () => {
|
reset: () => {
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ const RenderQueue = {
|
|||||||
nb_total_render_ms: 0,
|
nb_total_render_ms: 0,
|
||||||
nb_completed_renders: 0,
|
nb_completed_renders: 0,
|
||||||
nb_last_current: 0,
|
nb_last_current: 0,
|
||||||
|
list_machine_avgs: [],
|
||||||
|
nb_local_avg_ms: 0,
|
||||||
|
str_hostname: "",
|
||||||
|
|
||||||
init: () => {
|
init: () => {
|
||||||
// Initialized on demand
|
// Initialized on demand
|
||||||
@@ -13,6 +16,9 @@ const RenderQueue = {
|
|||||||
RenderQueue.nb_total_render_ms = 0;
|
RenderQueue.nb_total_render_ms = 0;
|
||||||
RenderQueue.nb_completed_renders = 0;
|
RenderQueue.nb_completed_renders = 0;
|
||||||
RenderQueue.nb_last_current = 0;
|
RenderQueue.nb_last_current = 0;
|
||||||
|
RenderQueue.list_machine_avgs = [];
|
||||||
|
RenderQueue.nb_local_avg_ms = 0;
|
||||||
|
RenderQueue.str_hostname = "";
|
||||||
|
|
||||||
let list_enabled = [];
|
let list_enabled = [];
|
||||||
for (let obj_cam of list_cameras) {
|
for (let obj_cam of list_cameras) {
|
||||||
@@ -32,6 +38,7 @@ const RenderQueue = {
|
|||||||
str_image_path: null,
|
str_image_path: null,
|
||||||
obj_dom_el: null,
|
obj_dom_el: null,
|
||||||
obj_dom_icon: null,
|
obj_dom_icon: null,
|
||||||
|
obj_dom_result: null,
|
||||||
str_dom_status: null,
|
str_dom_status: null,
|
||||||
is_click_bound: false,
|
is_click_bound: false,
|
||||||
});
|
});
|
||||||
@@ -60,6 +67,7 @@ const RenderQueue = {
|
|||||||
str_image_path: null,
|
str_image_path: null,
|
||||||
obj_dom_el: null,
|
obj_dom_el: null,
|
||||||
obj_dom_icon: null,
|
obj_dom_icon: null,
|
||||||
|
obj_dom_result: null,
|
||||||
str_dom_status: null,
|
str_dom_status: null,
|
||||||
is_click_bound: false,
|
is_click_bound: false,
|
||||||
});
|
});
|
||||||
@@ -101,12 +109,20 @@ const RenderQueue = {
|
|||||||
obj_frame.classList.add("text-light-emphasis");
|
obj_frame.classList.add("text-light-emphasis");
|
||||||
obj_frame.textContent = "F" + obj_item.nb_frame;
|
obj_frame.textContent = "F" + obj_item.nb_frame;
|
||||||
|
|
||||||
|
let obj_result = document.createElement("small");
|
||||||
|
obj_result.classList.add("text-light-emphasis", "queue-item-result");
|
||||||
|
obj_result.style.minWidth = "140px";
|
||||||
|
obj_result.style.textAlign = "right";
|
||||||
|
obj_result.style.fontSize = "0.75em";
|
||||||
|
|
||||||
obj_el.appendChild(obj_icon);
|
obj_el.appendChild(obj_icon);
|
||||||
obj_el.appendChild(obj_name);
|
obj_el.appendChild(obj_name);
|
||||||
obj_el.appendChild(obj_frame);
|
obj_el.appendChild(obj_frame);
|
||||||
|
obj_el.appendChild(obj_result);
|
||||||
|
|
||||||
obj_item.obj_dom_el = obj_el;
|
obj_item.obj_dom_el = obj_el;
|
||||||
obj_item.obj_dom_icon = obj_icon;
|
obj_item.obj_dom_icon = obj_icon;
|
||||||
|
obj_item.obj_dom_result = obj_result;
|
||||||
obj_item.str_dom_status = "pending";
|
obj_item.str_dom_status = "pending";
|
||||||
|
|
||||||
obj_fragment.appendChild(obj_el);
|
obj_fragment.appendChild(obj_el);
|
||||||
@@ -115,7 +131,21 @@ const RenderQueue = {
|
|||||||
obj_container.appendChild(obj_fragment);
|
obj_container.appendChild(obj_fragment);
|
||||||
},
|
},
|
||||||
|
|
||||||
update_progress: (nb_current, nb_last_render_ms, str_last_image_path, list_skipped, list_stopped, list_skipped_paths) => {
|
update_progress: (obj_data) => {
|
||||||
|
let nb_current = obj_data.nb_current || 0;
|
||||||
|
let nb_last_render_ms = obj_data.nb_last_render_ms || 0;
|
||||||
|
let str_last_image_path = obj_data.str_last_image_path || null;
|
||||||
|
let list_skipped = obj_data.list_skipped || [];
|
||||||
|
let list_stopped = obj_data.list_stopped || [];
|
||||||
|
let list_skipped_paths = obj_data.list_skipped_paths || [];
|
||||||
|
let list_rendering_remote = obj_data.list_rendering_remote || [];
|
||||||
|
let list_item_results = obj_data.list_item_results || [];
|
||||||
|
let list_machine_avgs = obj_data.list_machine_avgs || [];
|
||||||
|
|
||||||
|
RenderQueue.str_hostname = obj_data.str_hostname || "";
|
||||||
|
RenderQueue.nb_local_avg_ms = obj_data.nb_avg_render_ms || 0;
|
||||||
|
RenderQueue.list_machine_avgs = list_machine_avgs;
|
||||||
|
|
||||||
if (nb_current > RenderQueue.nb_last_current && nb_last_render_ms > 0) {
|
if (nb_current > RenderQueue.nb_last_current && nb_last_render_ms > 0) {
|
||||||
RenderQueue.nb_total_render_ms += nb_last_render_ms;
|
RenderQueue.nb_total_render_ms += nb_last_render_ms;
|
||||||
RenderQueue.nb_completed_renders++;
|
RenderQueue.nb_completed_renders++;
|
||||||
@@ -134,9 +164,17 @@ const RenderQueue = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build result map for quick lookup
|
||||||
|
let map_results = {};
|
||||||
|
for (let obj_r of list_item_results) {
|
||||||
|
map_results[obj_r.nb_index] = obj_r;
|
||||||
|
}
|
||||||
|
|
||||||
for (let nb_i = 0; nb_i < RenderQueue.list_items.length; nb_i++) {
|
for (let nb_i = 0; nb_i < RenderQueue.list_items.length; nb_i++) {
|
||||||
if (list_stopped && list_stopped.indexOf(nb_i) !== -1) {
|
if (list_stopped && list_stopped.indexOf(nb_i) !== -1) {
|
||||||
RenderQueue.list_items[nb_i].str_status = "stopped";
|
RenderQueue.list_items[nb_i].str_status = "stopped";
|
||||||
|
} else if (list_rendering_remote && list_rendering_remote.indexOf(nb_i) !== -1) {
|
||||||
|
RenderQueue.list_items[nb_i].str_status = "rendering_remote";
|
||||||
} else if (list_skipped && list_skipped.indexOf(nb_i) !== -1) {
|
} else if (list_skipped && list_skipped.indexOf(nb_i) !== -1) {
|
||||||
RenderQueue.list_items[nb_i].str_status = "skipped";
|
RenderQueue.list_items[nb_i].str_status = "skipped";
|
||||||
} else if (nb_i < nb_current) {
|
} else if (nb_i < nb_current) {
|
||||||
@@ -146,6 +184,11 @@ const RenderQueue = {
|
|||||||
} else {
|
} else {
|
||||||
RenderQueue.list_items[nb_i].str_status = "pending";
|
RenderQueue.list_items[nb_i].str_status = "pending";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store result info on item
|
||||||
|
if (map_results[nb_i]) {
|
||||||
|
RenderQueue.list_items[nb_i].obj_result = map_results[nb_i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderQueue._update_time_display();
|
RenderQueue._update_time_display();
|
||||||
@@ -163,7 +206,9 @@ const RenderQueue = {
|
|||||||
let is_needs_click = (obj_item.str_status === "done" || obj_item.str_status === "skipped")
|
let is_needs_click = (obj_item.str_status === "done" || obj_item.str_status === "skipped")
|
||||||
&& obj_item.str_image_path && !obj_item.is_click_bound;
|
&& obj_item.str_image_path && !obj_item.is_click_bound;
|
||||||
|
|
||||||
if (obj_item.str_status === obj_item.str_dom_status && !is_needs_click) {
|
let is_status_changed = obj_item.str_status !== obj_item.str_dom_status;
|
||||||
|
|
||||||
|
if (!is_status_changed && !is_needs_click) {
|
||||||
if (obj_item.str_status === "rendering") {
|
if (obj_item.str_status === "rendering") {
|
||||||
obj_rendering_el = obj_item.obj_dom_el;
|
obj_rendering_el = obj_item.obj_dom_el;
|
||||||
}
|
}
|
||||||
@@ -189,10 +234,18 @@ const RenderQueue = {
|
|||||||
} else if (obj_item.str_status === "stopped") {
|
} else if (obj_item.str_status === "stopped") {
|
||||||
str_icon = "mdi-stop-circle";
|
str_icon = "mdi-stop-circle";
|
||||||
str_color = "text-warning";
|
str_color = "text-warning";
|
||||||
|
} else if (obj_item.str_status === "rendering_remote") {
|
||||||
|
str_icon = "mdi-desktop-classic";
|
||||||
|
str_color = "text-warning";
|
||||||
}
|
}
|
||||||
|
|
||||||
obj_item.obj_dom_icon.className = "mdi " + str_icon + " " + str_color;
|
obj_item.obj_dom_icon.className = "mdi " + str_icon + " " + str_color;
|
||||||
|
|
||||||
|
// Update result column
|
||||||
|
if (obj_item.obj_dom_result) {
|
||||||
|
RenderQueue._update_result_cell(obj_item);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_needs_click) {
|
if (is_needs_click) {
|
||||||
obj_item.obj_dom_el.classList.add("queue-item-clickable");
|
obj_item.obj_dom_el.classList.add("queue-item-clickable");
|
||||||
let str_path = obj_item.str_image_path;
|
let str_path = obj_item.str_image_path;
|
||||||
@@ -210,6 +263,45 @@ const RenderQueue = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_update_result_cell: (obj_item) => {
|
||||||
|
let obj_r = obj_item.obj_result;
|
||||||
|
if (!obj_r) {
|
||||||
|
obj_item.obj_dom_result.textContent = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj_r.str_type === "done") {
|
||||||
|
let str_date = "";
|
||||||
|
if (obj_r.str_date) {
|
||||||
|
let obj_d = new Date(obj_r.str_date);
|
||||||
|
let str_day = String(obj_d.getDate()).padStart(2, "0");
|
||||||
|
let str_month = String(obj_d.getMonth() + 1).padStart(2, "0");
|
||||||
|
let str_hours = String(obj_d.getHours()).padStart(2, "0");
|
||||||
|
let str_minutes = String(obj_d.getMinutes()).padStart(2, "0");
|
||||||
|
str_date = str_day + "/" + str_month + " " + str_hours + ":" + str_minutes;
|
||||||
|
}
|
||||||
|
let str_res = obj_r.str_resolution || "";
|
||||||
|
obj_item.obj_dom_result.textContent = str_date + (str_date && str_res ? " | " : "") + str_res;
|
||||||
|
obj_item.obj_dom_result.className = "text-success queue-item-result";
|
||||||
|
obj_item.obj_dom_result.style.minWidth = "140px";
|
||||||
|
obj_item.obj_dom_result.style.textAlign = "right";
|
||||||
|
obj_item.obj_dom_result.style.fontSize = "0.75em";
|
||||||
|
} else if (obj_r.str_type === "rendering_remote") {
|
||||||
|
let str_host = obj_r.str_remote_hostname || "?";
|
||||||
|
let str_avg = "";
|
||||||
|
if (obj_r.nb_remote_avg_ms > 0) {
|
||||||
|
str_avg = " ~" + RenderQueue._format_duration(obj_r.nb_remote_avg_ms) + "/i";
|
||||||
|
}
|
||||||
|
obj_item.obj_dom_result.textContent = str_host + str_avg;
|
||||||
|
obj_item.obj_dom_result.className = "text-warning queue-item-result";
|
||||||
|
obj_item.obj_dom_result.style.minWidth = "140px";
|
||||||
|
obj_item.obj_dom_result.style.textAlign = "right";
|
||||||
|
obj_item.obj_dom_result.style.fontSize = "0.75em";
|
||||||
|
} else {
|
||||||
|
obj_item.obj_dom_result.textContent = "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mark_existing: (list_existing) => {
|
mark_existing: (list_existing) => {
|
||||||
for (let obj_existing of list_existing) {
|
for (let obj_existing of list_existing) {
|
||||||
if (obj_existing.nb_index < RenderQueue.list_items.length) {
|
if (obj_existing.nb_index < RenderQueue.list_items.length) {
|
||||||
@@ -226,22 +318,55 @@ const RenderQueue = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RenderQueue.nb_completed_renders === 0) {
|
let nb_local_avg = RenderQueue.nb_local_avg_ms;
|
||||||
|
if (nb_local_avg === 0 && RenderQueue.nb_completed_renders > 0) {
|
||||||
|
nb_local_avg = Math.round(RenderQueue.nb_total_render_ms / RenderQueue.nb_completed_renders);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nb_local_avg === 0) {
|
||||||
obj_label.innerHTML = "";
|
obj_label.innerHTML = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nb_avg_ms = RenderQueue.nb_total_render_ms / RenderQueue.nb_completed_renders;
|
|
||||||
let nb_remaining_count = 0;
|
let nb_remaining_count = 0;
|
||||||
for (let obj_item of RenderQueue.list_items) {
|
for (let obj_item of RenderQueue.list_items) {
|
||||||
if (obj_item.str_status !== "done" && obj_item.str_status !== "skipped") {
|
if (obj_item.str_status !== "done" && obj_item.str_status !== "skipped" && obj_item.str_status !== "rendering_remote") {
|
||||||
nb_remaining_count++;
|
nb_remaining_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let nb_remaining_ms = nb_avg_ms * nb_remaining_count;
|
// Part 1 : temps moyen machine actuelle /i
|
||||||
obj_label.innerHTML = '<i class="mdi mdi-clock-outline me-1"></i>'
|
let str_local_avg = RenderQueue._format_duration(nb_local_avg) + "/i";
|
||||||
+ RenderQueue._format_duration(nb_remaining_ms);
|
|
||||||
|
// Part 2 : temps restant si machine seule
|
||||||
|
let nb_remaining_solo_ms = nb_local_avg * nb_remaining_count;
|
||||||
|
let str_remaining_solo = RenderQueue._format_duration(nb_remaining_solo_ms);
|
||||||
|
|
||||||
|
// Part 3 : temps restant multi-machines
|
||||||
|
let list_avgs = RenderQueue.list_machine_avgs;
|
||||||
|
let nb_machines_with_data = 0;
|
||||||
|
let nb_sum_avgs = 0;
|
||||||
|
for (let obj_m of list_avgs) {
|
||||||
|
if (obj_m.nb_avg_ms > 0) {
|
||||||
|
nb_sum_avgs += obj_m.nb_avg_ms;
|
||||||
|
nb_machines_with_data++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let str_remaining_multi = "";
|
||||||
|
if (nb_machines_with_data > 1) {
|
||||||
|
let nb_avg_of_avgs = nb_sum_avgs / nb_machines_with_data;
|
||||||
|
let nb_remaining_multi_ms = (nb_avg_of_avgs * nb_remaining_count) / nb_machines_with_data;
|
||||||
|
str_remaining_multi = RenderQueue._format_duration(nb_remaining_multi_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
let str_display = '<i class="mdi mdi-clock-outline me-1"></i>'
|
||||||
|
+ str_local_avg + " | " + str_remaining_solo;
|
||||||
|
if (str_remaining_multi) {
|
||||||
|
str_display += " | " + str_remaining_multi;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_label.innerHTML = str_display;
|
||||||
},
|
},
|
||||||
|
|
||||||
_format_duration: (nb_ms) => {
|
_format_duration: (nb_ms) => {
|
||||||
|
|||||||
152
src/renderer/scripts/RenderSettings.js
Normal file
152
src/renderer/scripts/RenderSettings.js
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
const RenderSettings = {
|
||||||
|
obj_settings: null,
|
||||||
|
|
||||||
|
init: () => {
|
||||||
|
RenderSettings.obj_settings = {
|
||||||
|
str_engine: "CYCLES",
|
||||||
|
nb_samples: 128,
|
||||||
|
str_device: "GPU",
|
||||||
|
is_denoise: true,
|
||||||
|
is_film_transparent: false,
|
||||||
|
nb_resolution_percentage: 100,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
set_from_blend: (obj_render) => {
|
||||||
|
if (!obj_render) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj_s = RenderSettings.obj_settings;
|
||||||
|
obj_s.str_engine = obj_render.str_engine || "CYCLES";
|
||||||
|
obj_s.nb_resolution_percentage = obj_render.nb_resolution_percentage || 100;
|
||||||
|
obj_s.is_film_transparent = !!obj_render.is_film_transparent;
|
||||||
|
|
||||||
|
if (obj_render.str_cycles_device) {
|
||||||
|
obj_s.str_device = obj_render.str_cycles_device;
|
||||||
|
}
|
||||||
|
if (obj_render.is_cycles_denoise !== undefined) {
|
||||||
|
obj_s.is_denoise = obj_render.is_cycles_denoise;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj_render.nb_cycles_samples !== undefined) {
|
||||||
|
obj_s.nb_samples = obj_render.nb_cycles_samples;
|
||||||
|
} else if (obj_render.nb_eevee_samples !== undefined) {
|
||||||
|
obj_s.nb_samples = obj_render.nb_eevee_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSettings.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
set_from_config: (obj_config) => {
|
||||||
|
if (!obj_config || !obj_config.obj_render_settings) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj_src = obj_config.obj_render_settings;
|
||||||
|
let obj_s = RenderSettings.obj_settings;
|
||||||
|
if (obj_src.str_engine !== undefined) { obj_s.str_engine = obj_src.str_engine; }
|
||||||
|
if (obj_src.nb_samples !== undefined) { obj_s.nb_samples = obj_src.nb_samples; }
|
||||||
|
if (obj_src.str_device !== undefined) { obj_s.str_device = obj_src.str_device; }
|
||||||
|
if (obj_src.is_denoise !== undefined) { obj_s.is_denoise = obj_src.is_denoise; }
|
||||||
|
if (obj_src.is_film_transparent !== undefined) { obj_s.is_film_transparent = obj_src.is_film_transparent; }
|
||||||
|
if (obj_src.nb_resolution_percentage !== undefined) { obj_s.nb_resolution_percentage = obj_src.nb_resolution_percentage; }
|
||||||
|
|
||||||
|
RenderSettings.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
get_settings: () => {
|
||||||
|
return Object.assign({}, RenderSettings.obj_settings);
|
||||||
|
},
|
||||||
|
|
||||||
|
render: () => {
|
||||||
|
let obj_container = document.getElementById("container_render_settings");
|
||||||
|
if (!obj_container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj_s = RenderSettings.obj_settings;
|
||||||
|
let is_cycles = obj_s.str_engine === "CYCLES";
|
||||||
|
|
||||||
|
let str_html = '<div class="row g-2">'
|
||||||
|
+ ' <div class="col-12">'
|
||||||
|
+ ' <label class="form-label form-label-sm">Moteur de rendu</label>'
|
||||||
|
+ ' <select class="form-select form-select-sm bg-dark text-light border-secondary" id="select_engine">'
|
||||||
|
+ ' <option value="CYCLES"' + (obj_s.str_engine === "CYCLES" ? " selected" : "") + ">Cycles</option>"
|
||||||
|
+ ' <option value="BLENDER_EEVEE_NEXT"' + (obj_s.str_engine === "BLENDER_EEVEE_NEXT" ? " selected" : "") + ">EEVEE</option>"
|
||||||
|
+ ' <option value="BLENDER_EEVEE"' + (obj_s.str_engine === "BLENDER_EEVEE" ? " selected" : "") + ">EEVEE (Legacy)</option>"
|
||||||
|
+ ' <option value="BLENDER_WORKBENCH"' + (obj_s.str_engine === "BLENDER_WORKBENCH" ? " selected" : "") + ">Workbench</option>"
|
||||||
|
+ " </select>"
|
||||||
|
+ " </div>"
|
||||||
|
+ ' <div class="col-6">'
|
||||||
|
+ ' <label class="form-label form-label-sm">Samples</label>'
|
||||||
|
+ ' <input type="number" class="form-control form-control-sm bg-dark text-light border-secondary" id="input_samples" value="' + obj_s.nb_samples + '" min="1">'
|
||||||
|
+ " </div>"
|
||||||
|
+ ' <div class="col-6">'
|
||||||
|
+ ' <label class="form-label form-label-sm">Resolution %</label>'
|
||||||
|
+ ' <input type="number" class="form-control form-control-sm bg-dark text-light border-secondary" id="input_res_percent" value="' + obj_s.nb_resolution_percentage + '" min="1" max="1000">'
|
||||||
|
+ " </div>"
|
||||||
|
+ ' <div class="col-12' + (is_cycles ? "" : " d-none") + '" id="container_device">'
|
||||||
|
+ ' <label class="form-label form-label-sm">Device</label>'
|
||||||
|
+ ' <select class="form-select form-select-sm bg-dark text-light border-secondary" id="select_device">'
|
||||||
|
+ ' <option value="GPU"' + (obj_s.str_device === "GPU" ? " selected" : "") + ">GPU</option>"
|
||||||
|
+ ' <option value="CPU"' + (obj_s.str_device === "CPU" ? " selected" : "") + ">CPU</option>"
|
||||||
|
+ " </select>"
|
||||||
|
+ " </div>"
|
||||||
|
+ ' <div class="col-6">'
|
||||||
|
+ ' <div class="form-check form-check-sm mt-1">'
|
||||||
|
+ ' <input class="form-check-input" type="checkbox" id="check_denoise"' + (obj_s.is_denoise ? " checked" : "") + ">"
|
||||||
|
+ ' <label class="form-check-label" for="check_denoise">Denoising</label>'
|
||||||
|
+ " </div>"
|
||||||
|
+ " </div>"
|
||||||
|
+ ' <div class="col-6">'
|
||||||
|
+ ' <div class="form-check form-check-sm mt-1">'
|
||||||
|
+ ' <input class="form-check-input" type="checkbox" id="check_film_transparent"' + (obj_s.is_film_transparent ? " checked" : "") + ">"
|
||||||
|
+ ' <label class="form-check-label" for="check_film_transparent">Transparent</label>'
|
||||||
|
+ " </div>"
|
||||||
|
+ " </div>"
|
||||||
|
+ "</div>";
|
||||||
|
|
||||||
|
obj_container.innerHTML = str_html;
|
||||||
|
RenderSettings._bind_events();
|
||||||
|
},
|
||||||
|
|
||||||
|
_bind_events: () => {
|
||||||
|
let obj_select_engine = document.getElementById("select_engine");
|
||||||
|
let obj_input_samples = document.getElementById("input_samples");
|
||||||
|
let obj_input_res_percent = document.getElementById("input_res_percent");
|
||||||
|
let obj_select_device = document.getElementById("select_device");
|
||||||
|
let obj_check_denoise = document.getElementById("check_denoise");
|
||||||
|
let obj_check_transparent = document.getElementById("check_film_transparent");
|
||||||
|
|
||||||
|
obj_select_engine.addEventListener("change", () => {
|
||||||
|
RenderSettings.obj_settings.str_engine = obj_select_engine.value;
|
||||||
|
let obj_device_container = document.getElementById("container_device");
|
||||||
|
if (obj_select_engine.value === "CYCLES") {
|
||||||
|
obj_device_container.classList.remove("d-none");
|
||||||
|
} else {
|
||||||
|
obj_device_container.classList.add("d-none");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
obj_input_samples.addEventListener("change", () => {
|
||||||
|
RenderSettings.obj_settings.nb_samples = parseInt(obj_input_samples.value, 10) || 128;
|
||||||
|
});
|
||||||
|
|
||||||
|
obj_input_res_percent.addEventListener("change", () => {
|
||||||
|
RenderSettings.obj_settings.nb_resolution_percentage = parseInt(obj_input_res_percent.value, 10) || 100;
|
||||||
|
});
|
||||||
|
|
||||||
|
obj_select_device.addEventListener("change", () => {
|
||||||
|
RenderSettings.obj_settings.str_device = obj_select_device.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
obj_check_denoise.addEventListener("change", () => {
|
||||||
|
RenderSettings.obj_settings.is_denoise = obj_check_denoise.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
obj_check_transparent.addEventListener("change", () => {
|
||||||
|
RenderSettings.obj_settings.is_film_transparent = obj_check_transparent.checked;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -39,7 +39,8 @@ body.has-update-banner .container-fluid {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-md-4 {
|
.col-md-3,
|
||||||
|
.col-md-6 {
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
@@ -75,6 +76,30 @@ body.has-update-banner .container-fluid {
|
|||||||
border-color: #495057 !important;
|
border-color: #495057 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Collection list ────────────────────────────────────────── */
|
||||||
|
|
||||||
|
#container_collection_list .list-group-item {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding-top: 0.25rem;
|
||||||
|
padding-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collection-name {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collection-original-badge {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collection-original-badge .mdi {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Preview ────────────────────────────────────────────────── */
|
/* ── Preview ────────────────────────────────────────────────── */
|
||||||
|
|
||||||
.preview-image {
|
.preview-image {
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"str_version": "1.2.0"
|
"str_version": "1.5.0"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user