Merge branch 'main' into u1-hf

This commit is contained in:
SoftFever
2026-09-23 13:13:32 +08:00
committed by GitHub
108 changed files with 3870 additions and 320 deletions
+8
View File
@@ -413,6 +413,14 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
api="$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/actions/caches"
# The save step reports success even when its tar failed, so keep
# the older entries unless the new one is listed.
if ! curl -sSf -H "Authorization: Bearer $GH_TOKEN" \
"$api?ref=$GITHUB_REF&key=$CCACHE_ENTRY" \
| jq -e --arg entry "$CCACHE_ENTRY" 'any(.actions_caches[]; .key == $entry)' > /dev/null; then
echo "$CCACHE_ENTRY was not saved; keeping the older entries."
exit 0
fi
curl -sSf -H "Authorization: Bearer $GH_TOKEN" \
"$api?ref=$GITHUB_REF&key=ccache-$CCACHE_LEG-&per_page=100" \
| jq -r --arg prefix "ccache-$CCACHE_LEG-" --argjson run "$GITHUB_RUN_ID" \
+7
View File
@@ -798,6 +798,13 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
# The save step reports success even when its tar failed, so keep
# the older entries unless the new one is listed.
if ! gh cache list --ref "$GITHUB_REF" --key "$CCACHE_ENTRY" --json key \
| jq -e --arg entry "$CCACHE_ENTRY" 'any(.[]; .key == $entry)' > /dev/null; then
echo "$CCACHE_ENTRY was not saved; keeping the older entries."
exit 0
fi
gh cache list --ref "$GITHUB_REF" --key "ccache-$CCACHE_LEG-" --limit 100 --json id,key \
| jq -r --arg prefix "ccache-$CCACHE_LEG-" --argjson run "$GITHUB_RUN_ID" \
'.[] | select((.key | ltrimstr($prefix) | split("-")[0] | tonumber?) < $run) | .id' \
+52 -8
View File
@@ -5,8 +5,9 @@
# re-sliced on its own to see whether it changes the G-code
# harness - the GUI-vs-CLI parity harness (metrics only, never fails)
# Both test the latest successful build_all.yml Linux AppImage from main, with
# sources checked out at the commit that build was made from. Nothing here
# gates a build or a PR.
# sources checked out at the commit that build was made from; a manual run can
# name another branch, or pin one build by its run id. Nothing here gates a
# build or a PR.
name: Parity Nightly
on:
@@ -20,9 +21,13 @@ on:
required: false
default: "main"
build_branch:
description: "branch whose latest successful build_all artifact to test"
description: "branch whose newest successful build_all artifact to test (a PR build is the PR merged into its base; sources are checked out at the PR head)"
required: false
default: "main"
build_run_id:
description: "build_all run id to test instead of build_branch's newest (same PR caveat)"
required: false
default: ""
fixtures:
description: "harness fixture ids, space-separated (empty = all)"
required: false
@@ -50,14 +55,53 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
BRANCH: ${{ inputs.build_branch || 'main' }}
RUN_ID: ${{ inputs.build_run_id }}
SCHEDULED: ${{ github.event_name == 'schedule' }}
run: |
set -euo pipefail
gh run list --workflow build_all.yml \
--branch "${{ inputs.build_branch || 'main' }}" \
--status success --limit 1 --json databaseId,headSha \
--jq '"run_id=\(.[0].databaseId)\nhead_sha=\(.[0].headSha)"' \
>> "$GITHUB_OUTPUT"
if [ -n "$RUN_ID" ]; then
[[ $RUN_ID =~ ^[0-9]+$ ]] || { echo "build_run_id must be a numeric run id, got '$RUN_ID'" >&2; exit 1; }
# a pinned build is read directly, not through a search; it must come
# from this repository, because the later jobs check out its commit here
found=$(gh api "repos/$GH_REPO/actions/runs/$RUN_ID" --jq \
'select(.path == ".github/workflows/build_all.yml" and .conclusion == "success"
and .head_repository.full_name == env.GH_REPO)
| "\(.id) \(.head_sha) \(.created_at)"')
[ -n "$found" ] || { echo "run $RUN_ID is not a successful build_all run of $GH_REPO" >&2; exit 1; }
else
# GitHub serves filtered run listings (branch=, status=, head_sha=, ...)
# from a search index that has returned weeks-old results, while the
# unfiltered listing stays current, so list unfiltered and filter here.
# The repository check keeps out fork PRs whose branch has the same
# name. A feature branch is normally built only for its PR, and a PR
# build compiles the PR merged into its base rather than head_sha, so
# a build of the branch itself (push or dispatch) is preferred when
# the same page has one.
pick='([.workflow_runs[] | select(.head_branch == env.BRANCH and .conclusion == "success"
and .head_repository.full_name == env.GH_REPO)]
| map(select(.event != "pull_request"))[0] // .[0])
| select(.) | "\(.id) \(.head_sha) \(.created_at)"'
# a page of 100 runs spans about a day and a half; a manual run may
# target a branch that last built weeks ago
pages=3
if [ "$SCHEDULED" != true ]; then pages=20; fi
found=""
for page in $(seq "$pages"); do
found=$(gh api "repos/$GH_REPO/actions/workflows/build_all.yml/runs?per_page=100&page=$page" --jq "$pick")
if [ -n "$found" ]; then break; fi
done
[ -n "$found" ] || { echo "no successful $BRANCH build among the last $((pages * 100)) build_all runs; pass build_run_id to test an older one" >&2; exit 1; }
fi
read -r run_id head_sha created <<< "$found"
# the nightly fails rather than report on a stale build
if [ "$SCHEDULED" = true ] && [ $(( $(date +%s) - $(date -d "$created" +%s) )) -gt 172800 ]; then
echo "newest $BRANCH build $run_id is from $created, over 48 hours old" >&2
exit 1
fi
printf 'run_id=%s\nhead_sha=%s\n' "$run_id" "$head_sha" >> "$GITHUB_OUTPUT"
cat "$GITHUB_OUTPUT"
echo "Testing build [$run_id](https://github.com/$GH_REPO/actions/runs/$run_id) of \`$head_sha\`, built $created" >> "$GITHUB_STEP_SUMMARY"
effect:
name: Override sweep effect stage (shard ${{ matrix.shard }})
@@ -198,6 +198,6 @@
"0.4"
],
"z_hop_types": [
"Normal Lift"
"Auto Lift"
]
}
@@ -198,6 +198,6 @@
"0.4"
],
"z_hop_types": [
"Normal Lift"
"Auto Lift"
]
}
@@ -198,6 +198,6 @@
"0.4"
],
"z_hop_types": [
"Normal Lift"
"Auto Lift"
]
}
+197 -1
View File
@@ -1,6 +1,6 @@
{
"name": "Prusa",
"version": "02.04.00.07",
"version": "02.04.00.08",
"force_update": "0",
"description": "Prusa configurations",
"machine_model_list": [
@@ -20,6 +20,10 @@
"name": "Prusa CORE One L HF",
"sub_path": "machine/Prusa CORE One L HF.json"
},
{
"name": "Prusa CORE One MMU3",
"sub_path": "machine/Prusa CORE One MMU3.json"
},
{
"name": "Prusa MINI",
"sub_path": "machine/Prusa MINI.json"
@@ -702,6 +706,26 @@
"name": "0.25mm Speed @MINIIS",
"sub_path": "process/0.25mm Speed @MINIIS.json"
},
{
"name": "0.15mm BALANCED @COREONE0.4 + MMU3",
"sub_path": "process/0.15mm BALANCED @COREONE0.4 + MMU3.json"
},
{
"name": "0.20mm BALANCED @COREONE0.4 + MMU3",
"sub_path": "process/0.20mm BALANCED @COREONE0.4 + MMU3.json"
},
{
"name": "0.25mm BALANCED @COREONE0.4 + MMU3",
"sub_path": "process/0.25mm BALANCED @COREONE0.4 + MMU3.json"
},
{
"name": "0.25mm SPEED @COREONE0.4 + MMU3",
"sub_path": "process/0.25mm SPEED @COREONE0.4 + MMU3.json"
},
{
"name": "0.25mm STRUCTURAL @COREONE0.4 + MMU3",
"sub_path": "process/0.25mm STRUCTURAL @COREONE0.4 + MMU3.json"
},
{
"name": "0.05mm DETAIL @MK4S 0.25",
"sub_path": "process/0.05mm DETAIL @MK4S 0.25.json"
@@ -1114,6 +1138,14 @@
"name": "0.05mm DETAIL @CORE One L 0.25",
"sub_path": "process/0.05mm DETAIL @CORE One L 0.25.json"
},
{
"name": "0.07mm DETAIL @COREONE0.25 + MMU3",
"sub_path": "process/0.07mm DETAIL @COREONE0.25 + MMU3.json"
},
{
"name": "0.12mm SPEED @COREONE0.25 + MMU3",
"sub_path": "process/0.12mm SPEED @COREONE0.25 + MMU3.json"
},
{
"name": "0.12mm STRUCTURAL @CORE One 0.25",
"sub_path": "process/0.12mm STRUCTURAL @CORE One 0.25.json"
@@ -1134,6 +1166,10 @@
"name": "0.15mm STRUCTURAL @MK4S 0.25",
"sub_path": "process/0.15mm STRUCTURAL @MK4S 0.25.json"
},
{
"name": "0.12mm STRUCTURAL @COREONE0.3 + MMU3",
"sub_path": "process/0.12mm STRUCTURAL @COREONE0.3 + MMU3.json"
},
{
"name": "0.16mm SPEED @MK4S 0.3",
"sub_path": "process/0.16mm SPEED @MK4S 0.3.json"
@@ -1158,6 +1194,10 @@
"name": "0.10mm FAST DETAIL @CORE One L 0.4",
"sub_path": "process/0.10mm FAST DETAIL @CORE One L 0.4.json"
},
{
"name": "0.15mm SPEED @COREONE0.4 + MMU3",
"sub_path": "process/0.15mm SPEED @COREONE0.4 + MMU3.json"
},
{
"name": "0.15mm SPEED @CORE One HF 0.4",
"sub_path": "process/0.15mm SPEED @CORE One HF 0.4.json"
@@ -1166,6 +1206,22 @@
"name": "0.15mm SPEED @CORE One L HF 0.4",
"sub_path": "process/0.15mm SPEED @CORE One L HF 0.4.json"
},
{
"name": "0.15mm STRUCTURAL @COREONE0.6 + MMU3",
"sub_path": "process/0.15mm STRUCTURAL @COREONE0.6 + MMU3.json"
},
{
"name": "0.20mm SOLUBLE FULL @COREONE0.4 + MMU3",
"sub_path": "process/0.20mm SOLUBLE FULL @COREONE0.4 + MMU3.json"
},
{
"name": "0.20mm SOLUBLE INTERFACE @COREONE0.4 + MMU3",
"sub_path": "process/0.20mm SOLUBLE INTERFACE @COREONE0.4 + MMU3.json"
},
{
"name": "0.20mm SPEED @COREONE0.4 + MMU3",
"sub_path": "process/0.20mm SPEED @COREONE0.4 + MMU3.json"
},
{
"name": "0.20mm SPEED @CORE One HF 0.5",
"sub_path": "process/0.20mm SPEED @CORE One HF 0.5.json"
@@ -1198,6 +1254,10 @@
"name": "0.25mm SPEED @MK4S HF0.5",
"sub_path": "process/0.25mm SPEED @MK4S HF0.5.json"
},
{
"name": "0.20mm SPEED @COREONE0.6 + MMU3",
"sub_path": "process/0.20mm SPEED @COREONE0.6 + MMU3.json"
},
{
"name": "0.20mm SPEED @CORE One HF 0.6",
"sub_path": "process/0.20mm SPEED @CORE One HF 0.6.json"
@@ -1222,6 +1282,10 @@
"name": "0.15mm STRUCTURAL @CORE One L 0.4",
"sub_path": "process/0.15mm STRUCTURAL @CORE One L 0.4.json"
},
{
"name": "0.20mm STRUCTURAL @COREONE0.4 + MMU3",
"sub_path": "process/0.20mm STRUCTURAL @COREONE0.4 + MMU3.json"
},
{
"name": "0.25mm STRUCTURAL @CORE One HF 0.4",
"sub_path": "process/0.25mm STRUCTURAL @CORE One HF 0.4.json"
@@ -1230,6 +1294,10 @@
"name": "0.25mm STRUCTURAL @CORE One L HF 0.4",
"sub_path": "process/0.25mm STRUCTURAL @CORE One L HF 0.4.json"
},
{
"name": "0.25mm SPEED @COREONE0.6 + MMU3",
"sub_path": "process/0.25mm SPEED @COREONE0.6 + MMU3.json"
},
{
"name": "0.25mm SPEED @CORE One HF 0.6",
"sub_path": "process/0.25mm SPEED @CORE One HF 0.6.json"
@@ -1262,6 +1330,10 @@
"name": "0.30mm STRUCTURAL @CORE One L HF 0.8",
"sub_path": "process/0.30mm STRUCTURAL @CORE One L HF 0.8.json"
},
{
"name": "0.32mm SPEED @COREONE0.6 + MMU3",
"sub_path": "process/0.32mm SPEED @COREONE0.6 + MMU3.json"
},
{
"name": "0.32mm SPEED @CORE One HF 0.6",
"sub_path": "process/0.32mm SPEED @CORE One HF 0.6.json"
@@ -1318,6 +1390,18 @@
"name": "0.55mm SPEED @CORE One L HF 0.8",
"sub_path": "process/0.55mm SPEED @CORE One L HF 0.8.json"
},
{
"name": "0.05mm DETAIL @COREONE0.25 + MMU3",
"sub_path": "process/0.05mm DETAIL @COREONE0.25 + MMU3.json"
},
{
"name": "0.12mm STRUCTURAL @COREONE0.25 + MMU3",
"sub_path": "process/0.12mm STRUCTURAL @COREONE0.25 + MMU3.json"
},
{
"name": "0.15mm SPEED @COREONE0.25 + MMU3",
"sub_path": "process/0.15mm SPEED @COREONE0.25 + MMU3.json"
},
{
"name": "0.15mm STRUCTURAL @CORE One 0.25",
"sub_path": "process/0.15mm STRUCTURAL @CORE One 0.25.json"
@@ -1338,6 +1422,10 @@
"name": "0.20mm SPEED @MK4S 0.3",
"sub_path": "process/0.20mm SPEED @MK4S 0.3.json"
},
{
"name": "0.16mm STRUCTURAL @COREONE0.3 + MMU3",
"sub_path": "process/0.16mm STRUCTURAL @COREONE0.3 + MMU3.json"
},
{
"name": "0.20mm STRUCTURAL @CORE One 0.3",
"sub_path": "process/0.20mm STRUCTURAL @CORE One 0.3.json"
@@ -1346,6 +1434,10 @@
"name": "0.20mm STRUCTURAL @CORE One L 0.3",
"sub_path": "process/0.20mm STRUCTURAL @CORE One L 0.3.json"
},
{
"name": "0.10mm FAST DETAIL @COREONE0.4 + MMU3",
"sub_path": "process/0.10mm FAST DETAIL @COREONE0.4 + MMU3.json"
},
{
"name": "0.25mm STRUCTURAL @CORE One 0.5",
"sub_path": "process/0.25mm STRUCTURAL @CORE One 0.5.json"
@@ -1370,6 +1462,30 @@
"name": "0.32mm SPEED @MK4S HF0.5",
"sub_path": "process/0.32mm SPEED @MK4S HF0.5.json"
},
{
"name": "0.20mm STRUCTURAL @COREONE0.6 + MMU3",
"sub_path": "process/0.20mm STRUCTURAL @COREONE0.6 + MMU3.json"
},
{
"name": "0.15mm STRUCTURAL @COREONE0.4 + MMU3",
"sub_path": "process/0.15mm STRUCTURAL @COREONE0.4 + MMU3.json"
},
{
"name": "0.25mm STRUCTURAL @COREONE0.6 + MMU3",
"sub_path": "process/0.25mm STRUCTURAL @COREONE0.6 + MMU3.json"
},
{
"name": "0.32mm STRUCTURAL @COREONE0.6 + MMU3",
"sub_path": "process/0.32mm STRUCTURAL @COREONE0.6 + MMU3.json"
},
{
"name": "0.15mm STRUCTURAL @COREONE0.25 + MMU3",
"sub_path": "process/0.15mm STRUCTURAL @COREONE0.25 + MMU3.json"
},
{
"name": "0.16mm SPEED @COREONE0.3 + MMU3",
"sub_path": "process/0.16mm SPEED @COREONE0.3 + MMU3.json"
},
{
"name": "0.20mm SPEED @CORE One 0.3",
"sub_path": "process/0.20mm SPEED @CORE One 0.3.json"
@@ -1378,6 +1494,10 @@
"name": "0.20mm SPEED @CORE One L 0.3",
"sub_path": "process/0.20mm SPEED @CORE One L 0.3.json"
},
{
"name": "0.20mm STRUCTURAL @COREONE0.3 + MMU3",
"sub_path": "process/0.20mm STRUCTURAL @COREONE0.3 + MMU3.json"
},
{
"name": "0.32mm STRUCTURAL @CORE One HF 0.5",
"sub_path": "process/0.32mm STRUCTURAL @CORE One HF 0.5.json"
@@ -1393,6 +1513,10 @@
{
"name": "0.32mm SPEED @CORE One L HF 0.5",
"sub_path": "process/0.32mm SPEED @CORE One L HF 0.5.json"
},
{
"name": "0.20mm SPEED @COREONE0.3 + MMU3",
"sub_path": "process/0.20mm SPEED @COREONE0.3 + MMU3.json"
}
],
"filament_list": [
@@ -2032,6 +2156,10 @@
"name": "Generic ABS @Prusa CORE One HF 0.8",
"sub_path": "filament/Generic ABS @Prusa CORE One HF 0.8.json"
},
{
"name": "Generic ABS @Prusa CORE One MMU3",
"sub_path": "filament/Generic ABS @Prusa CORE One MMU3.json"
},
{
"name": "Generic ABS @Prusa MK4S 0.6",
"sub_path": "filament/Generic ABS @Prusa MK4S 0.6.json"
@@ -2112,6 +2240,10 @@
"name": "Generic ASA @Prusa CORE One HF 0.8",
"sub_path": "filament/Generic ASA @Prusa CORE One HF 0.8.json"
},
{
"name": "Generic ASA @Prusa CORE One MMU3",
"sub_path": "filament/Generic ASA @Prusa CORE One MMU3.json"
},
{
"name": "Generic ASA @Prusa MK4S 0.6",
"sub_path": "filament/Generic ASA @Prusa MK4S 0.6.json"
@@ -2160,6 +2292,10 @@
"name": "Prusament ASA @CORE One HF 0.8",
"sub_path": "filament/Prusament ASA @CORE One HF 0.8.json"
},
{
"name": "Prusament ASA @CORE One MMU3",
"sub_path": "filament/Prusament ASA @CORE One MMU3.json"
},
{
"name": "Prusament ASA @MK4S 0.6",
"sub_path": "filament/Prusament ASA @MK4S 0.6.json"
@@ -2192,6 +2328,10 @@
"name": "Generic TPU @Prusa CORE One 0.8",
"sub_path": "filament/Generic TPU @Prusa CORE One 0.8.json"
},
{
"name": "Generic TPU @Prusa CORE One MMU3",
"sub_path": "filament/Generic TPU @Prusa CORE One MMU3.json"
},
{
"name": "Generic PA @Prusa",
"sub_path": "filament/Generic PA @Prusa.json"
@@ -2240,6 +2380,10 @@
"name": "Prusament PA-CF @CORE One 0.8",
"sub_path": "filament/Prusament PA-CF @CORE One 0.8.json"
},
{
"name": "Prusament PA-CF @CORE One MMU3",
"sub_path": "filament/Prusament PA-CF @CORE One MMU3.json"
},
{
"name": "Prusament PA11 Carbon Fiber @MK4S 0.6",
"sub_path": "filament/Prusament PA11 Carbon Fiber @MK4S 0.6.json"
@@ -2300,6 +2444,10 @@
"name": "Prusament PC Blend @CORE One HF 0.8",
"sub_path": "filament/Prusament PC Blend @CORE One HF 0.8.json"
},
{
"name": "Prusament PC Blend @CORE One MMU3",
"sub_path": "filament/Prusament PC Blend @CORE One MMU3.json"
},
{
"name": "Prusament PC Blend @MK4S 0.6",
"sub_path": "filament/Prusament PC Blend @MK4S 0.6.json"
@@ -2332,6 +2480,10 @@
"name": "Prusament PC-CF @CORE One 0.8",
"sub_path": "filament/Prusament PC-CF @CORE One 0.8.json"
},
{
"name": "Prusament PC-CF @CORE One MMU3",
"sub_path": "filament/Prusament PC-CF @CORE One MMU3.json"
},
{
"name": "Prusament PC Blend Carbon Fiber @MK4S 0.6",
"sub_path": "filament/Prusament PC Blend Carbon Fiber @MK4S 0.6.json"
@@ -2380,6 +2532,10 @@
"name": "Generic PETG @Prusa CORE One HF 0.8",
"sub_path": "filament/Generic PETG @Prusa CORE One HF 0.8.json"
},
{
"name": "Generic PETG @Prusa CORE One MMU3",
"sub_path": "filament/Generic PETG @Prusa CORE One MMU3.json"
},
{
"name": "Generic PETG @Prusa MK4S 0.6",
"sub_path": "filament/Generic PETG @Prusa MK4S 0.6.json"
@@ -2460,6 +2616,10 @@
"name": "Prusament PETG @CORE One HF 0.8",
"sub_path": "filament/Prusament PETG @CORE One HF 0.8.json"
},
{
"name": "Prusament PETG @CORE One MMU3",
"sub_path": "filament/Prusament PETG @CORE One MMU3.json"
},
{
"name": "Prusament PETG @MK4S 0.6",
"sub_path": "filament/Prusament PETG @MK4S 0.6.json"
@@ -2516,6 +2676,10 @@
"name": "Generic PLA @Prusa CORE One HF 0.8",
"sub_path": "filament/Generic PLA @Prusa CORE One HF 0.8.json"
},
{
"name": "Generic PLA @Prusa CORE One MMU3",
"sub_path": "filament/Generic PLA @Prusa CORE One MMU3.json"
},
{
"name": "Generic PLA @Prusa MK4S 0.6",
"sub_path": "filament/Generic PLA @Prusa MK4S 0.6.json"
@@ -2584,6 +2748,10 @@
"name": "Generic PLA Silk @Prusa CORE One 0.8",
"sub_path": "filament/Generic PLA Silk @Prusa CORE One 0.8.json"
},
{
"name": "Generic PLA Silk @Prusa CORE One MMU3",
"sub_path": "filament/Generic PLA Silk @Prusa CORE One MMU3.json"
},
{
"name": "Generic PLA-CF @Prusa",
"sub_path": "filament/Generic PLA-CF @Prusa.json"
@@ -2628,6 +2796,10 @@
"name": "Prusament PLA @CORE One HF 0.8",
"sub_path": "filament/Prusament PLA @CORE One HF 0.8.json"
},
{
"name": "Prusament PLA @CORE One MMU3",
"sub_path": "filament/Prusament PLA @CORE One MMU3.json"
},
{
"name": "Prusament PLA @MK4S 0.6",
"sub_path": "filament/Prusament PLA @MK4S 0.6.json"
@@ -2668,6 +2840,10 @@
"name": "Prusament rPLA @CORE One 0.8",
"sub_path": "filament/Prusament rPLA @CORE One 0.8.json"
},
{
"name": "Prusament rPLA @CORE One MMU3",
"sub_path": "filament/Prusament rPLA @CORE One MMU3.json"
},
{
"name": "Prusament rPLA @MK4S 0.6",
"sub_path": "filament/Prusament rPLA @MK4S 0.6.json"
@@ -2740,6 +2916,10 @@
"name": "Prusament PVB @CORE One 0.8",
"sub_path": "filament/Prusament PVB @CORE One 0.8.json"
},
{
"name": "Prusament PVB @CORE One MMU3",
"sub_path": "filament/Prusament PVB @CORE One MMU3.json"
},
{
"name": "Prusament PVB @MK4S 0.6",
"sub_path": "filament/Prusament PVB @MK4S 0.6.json"
@@ -3018,6 +3198,10 @@
"name": "fdm_machine_common_xl_5t",
"sub_path": "machine/fdm_machine_common_xl_5t.json"
},
{
"name": "Prusa CORE One MMU3 0.4 nozzle",
"sub_path": "machine/Prusa CORE One MMU3 0.4 nozzle.json"
},
{
"name": "Prusa CORE One 0.5 nozzle",
"sub_path": "machine/Prusa CORE One 0.5 nozzle.json"
@@ -3090,6 +3274,18 @@
"name": "Prusa XL 5T 0.8 nozzle",
"sub_path": "machine/Prusa XL 5T 0.8 nozzle.json"
},
{
"name": "Prusa CORE One MMU3 0.25 nozzle",
"sub_path": "machine/Prusa CORE One MMU3 0.25 nozzle.json"
},
{
"name": "Prusa CORE One MMU3 0.3 nozzle",
"sub_path": "machine/Prusa CORE One MMU3 0.3 nozzle.json"
},
{
"name": "Prusa CORE One MMU3 0.6 nozzle",
"sub_path": "machine/Prusa CORE One MMU3 0.6 nozzle.json"
},
{
"name": "Prusa MK4S HF0.5 nozzle",
"sub_path": "machine/Prusa MK4S HF0.5 nozzle.json"
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

@@ -0,0 +1,53 @@
{
"type": "filament",
"name": "Generic ABS @Prusa CORE One MMU3",
"inherits": "Generic ABS @Prusa CORE One",
"from": "system",
"setting_id": "TM5fcvhbo1lgzsU6",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"2.5"
],
"filament_cooling_initial_speed": [
"5"
],
"filament_cooling_moves": [
"3"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 42.4194 42.4194 42.4194 42.4194 42.4194| 0.05 42.4387 0.45 42.4387 0.95 42.4387 1.45 42.4387 1.95 42.4387 2.45 42.4387 2.95 42.4387 3.45 42.4387 3.95 42.4387 4.45 42.4387 4.95 42.4387"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"26.5"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n\nM142 S40 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"60"
],
"filament_unloading_speed_start": [
"60"
],
"idle_temperature": [
"130"
]
}
@@ -0,0 +1,53 @@
{
"type": "filament",
"name": "Generic ASA @Prusa CORE One MMU3",
"inherits": "Generic ASA @Prusa CORE One",
"from": "system",
"setting_id": "0uAHoCupgHmVYVEx",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"2.5"
],
"filament_cooling_initial_speed": [
"5"
],
"filament_cooling_moves": [
"3"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 42.4194 42.4194 42.4194 42.4194 42.4194| 0.05 42.4387 0.45 42.4387 0.95 42.4387 1.45 42.4387 1.95 42.4387 2.45 42.4387 2.95 42.4387 3.45 42.4387 3.95 42.4387 4.45 42.4387 4.95 42.4387"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"26.5"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n\nM142 S40 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"60"
],
"filament_unloading_speed_start": [
"60"
],
"idle_temperature": [
"130"
]
}
@@ -0,0 +1,53 @@
{
"type": "filament",
"name": "Generic PETG @Prusa CORE One MMU3",
"inherits": "Generic PETG @Prusa CORE One",
"from": "system",
"setting_id": "JutuB6ct5A1l2Biz",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"2.5"
],
"filament_cooling_initial_speed": [
"5"
],
"filament_cooling_moves": [
"3"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 42.4194 42.4194 42.4194 42.4194 42.4194| 0.05 42.4387 0.45 42.4387 0.95 42.4387 1.45 42.4387 1.95 42.4387 2.45 42.4387 2.95 42.4387 3.45 42.4387 3.95 42.4387 4.45 42.4387 4.95 42.4387"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"26.5"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"60"
],
"filament_unloading_speed_start": [
"60"
],
"idle_temperature": [
"130"
]
}
@@ -0,0 +1,53 @@
{
"type": "filament",
"name": "Generic PLA @Prusa CORE One MMU3",
"inherits": "Generic PLA @Prusa CORE One",
"from": "system",
"setting_id": "haNaA1KFlYeqtfIg",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"3.5"
],
"filament_cooling_initial_speed": [
"10"
],
"filament_cooling_moves": [
"2"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 40.1613 40.3548 40.4516 40.3548 40.2581| 0.05 40.1483 0.45 40.3419 0.95 40.3419 1.45 40.3419 1.95 40.3419 2.45 40.3419 2.95 40.3419 3.45 40.3419 3.95 40.3419 4.45 40.3419 4.95 40.3419"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"29"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.03{elsif nozzle_diameter[filament_extruder_id]==0.5}0.022{elsif nozzle_diameter[filament_extruder_id]==0.6}0.019{elsif nozzle_diameter[filament_extruder_id]==0.8}0.013{elsif nozzle_diameter[filament_extruder_id]==0.25}0.1{elsif nozzle_diameter[filament_extruder_id]==0.3}0.07{else}0{endif} ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"40"
],
"filament_unloading_speed_start": [
"30"
],
"idle_temperature": [
"170"
]
}
@@ -0,0 +1,53 @@
{
"type": "filament",
"name": "Generic PLA Silk @Prusa CORE One MMU3",
"inherits": "Generic PLA Silk @Prusa CORE One",
"from": "system",
"setting_id": "MMarDGtK4f7u78gA",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"3.5"
],
"filament_cooling_initial_speed": [
"10"
],
"filament_cooling_moves": [
"2"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 40.1613 40.3548 40.4516 40.3548 40.2581| 0.05 40.1483 0.45 40.3419 0.95 40.3419 1.45 40.3419 1.95 40.3419 2.45 40.3419 2.95 40.3419 3.45 40.3419 3.95 40.3419 4.45 40.3419 4.95 40.3419"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"29"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[0]==0.4}0.03{elsif nozzle_diameter[0]==0.5}0.022{elsif nozzle_diameter[0]==0.6}0.018{elsif nozzle_diameter[0]==0.8}0.012{elsif nozzle_diameter[0]==0.25}0.12{elsif nozzle_diameter[0]==0.3}0.075{else}0{endif} ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"40"
],
"filament_unloading_speed_start": [
"30"
],
"idle_temperature": [
"170"
]
}
@@ -0,0 +1,53 @@
{
"type": "filament",
"name": "Generic TPU @Prusa CORE One MMU3",
"inherits": "Generic TPU @Prusa CORE One",
"from": "system",
"setting_id": "pYEUfg7uqu2LGw2n",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"3.4"
],
"filament_cooling_initial_speed": [
"2.2"
],
"filament_cooling_moves": [
"4"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"28"
],
"filament_loading_speed_start": [
"3"
],
"filament_ramming_parameters": [
"120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
],
"filament_stamping_distance": [
"0"
],
"filament_stamping_loading_speed": [
"0"
],
"filament_start_gcode": [
"M900 K0 ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"90"
],
"filament_unloading_speed_start": [
"100"
],
"idle_temperature": [
"150"
]
}
@@ -0,0 +1,54 @@
{
"type": "filament",
"name": "Prusament ASA @CORE One MMU3",
"inherits": "Prusament ASA @CORE One",
"from": "system",
"setting_id": "pESQ8XminojyIGyw",
"filament_id": "OFmFwUWM",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"2.5"
],
"filament_cooling_initial_speed": [
"5"
],
"filament_cooling_moves": [
"3"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 42.4194 42.4194 42.4194 42.4194 42.4194| 0.05 42.4387 0.45 42.4387 0.95 42.4387 1.45 42.4387 1.95 42.4387 2.45 42.4387 2.95 42.4387 3.45 42.4387 3.95 42.4387 4.45 42.4387 4.95 42.4387"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"26.5"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.02{elsif nozzle_diameter[filament_extruder_id]==0.5}0.018{elsif nozzle_diameter[filament_extruder_id]==0.6}0.012{elsif nozzle_diameter[filament_extruder_id]==0.8}0.01{elsif nozzle_diameter[filament_extruder_id]==0.25}0.09{elsif nozzle_diameter[filament_extruder_id]==0.3}0.065{else}0{endif} ; Filament gcode\n\nM142 S40 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"60"
],
"filament_unloading_speed_start": [
"60"
],
"idle_temperature": [
"130"
]
}
@@ -0,0 +1,54 @@
{
"type": "filament",
"name": "Prusament PA-CF @CORE One MMU3",
"inherits": "Prusament PA-CF @CORE One",
"from": "system",
"setting_id": "DsvJLtFStnmOCm1m",
"filament_id": "OF54SvEe",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"2.5"
],
"filament_cooling_initial_speed": [
"5"
],
"filament_cooling_moves": [
"3"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 42.4194 42.4194 42.4194 42.4194 42.4194| 0.05 42.4387 0.45 42.4387 0.95 42.4387 1.45 42.4387 1.95 42.4387 2.45 42.4387 2.95 42.4387 3.45 42.4387 3.95 42.4387 4.45 42.4387 4.95 42.4387"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"26.5"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n\nM142 S45 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"60"
],
"filament_unloading_speed_start": [
"60"
],
"idle_temperature": [
"130"
]
}
@@ -0,0 +1,54 @@
{
"type": "filament",
"name": "Prusament PC Blend @CORE One MMU3",
"inherits": "Prusament PC Blend @CORE One",
"from": "system",
"setting_id": "VjMN8MwtU3BG5cA9",
"filament_id": "OFvDbkFq",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"2.5"
],
"filament_cooling_initial_speed": [
"5"
],
"filament_cooling_moves": [
"3"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 42.4194 42.4194 42.4194 42.4194 42.4194| 0.05 42.4387 0.45 42.4387 0.95 42.4387 1.45 42.4387 1.95 42.4387 2.45 42.4387 2.95 42.4387 3.45 42.4387 3.95 42.4387 4.45 42.4387 4.95 42.4387"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"26.5"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n\nM142 S45 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"60"
],
"filament_unloading_speed_start": [
"60"
],
"idle_temperature": [
"150"
]
}
@@ -0,0 +1,54 @@
{
"type": "filament",
"name": "Prusament PC-CF @CORE One MMU3",
"inherits": "Prusament PC-CF @CORE One",
"from": "system",
"setting_id": "hTcuccoINAUJ4PfR",
"filament_id": "OFjz0a3m",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"2.5"
],
"filament_cooling_initial_speed": [
"5"
],
"filament_cooling_moves": [
"3"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 42.4194 42.4194 42.4194 42.4194 42.4194| 0.05 42.4387 0.45 42.4387 0.95 42.4387 1.45 42.4387 1.95 42.4387 2.45 42.4387 2.95 42.4387 3.45 42.4387 3.95 42.4387 4.45 42.4387 4.95 42.4387"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"26.5"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.05{elsif nozzle_diameter[filament_extruder_id]==0.5}0.035{elsif nozzle_diameter[filament_extruder_id]==0.6}0.025{elsif nozzle_diameter[filament_extruder_id]==0.8}0.016{elsif nozzle_diameter[filament_extruder_id]==0.25}0.14{elsif nozzle_diameter[filament_extruder_id]==0.3}0.09{else}0{endif} ; Filament gcode\n\nM142 S45 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"60"
],
"filament_unloading_speed_start": [
"60"
],
"idle_temperature": [
"150"
]
}
@@ -0,0 +1,54 @@
{
"type": "filament",
"name": "Prusament PETG @CORE One MMU3",
"inherits": "Prusament PETG @CORE One",
"from": "system",
"setting_id": "ypQNV38FrfRu9QSd",
"filament_id": "OFkR8E2c",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"2.5"
],
"filament_cooling_initial_speed": [
"5"
],
"filament_cooling_moves": [
"3"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 42.4194 42.4194 42.4194 42.4194 42.4194| 0.05 42.4387 0.45 42.4387 0.95 42.4387 1.45 42.4387 1.95 42.4387 2.45 42.4387 2.95 42.4387 3.45 42.4387 3.95 42.4387 4.45 42.4387 4.95 42.4387"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"26.5"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.053{elsif nozzle_diameter[filament_extruder_id]==0.5}0.042{elsif nozzle_diameter[filament_extruder_id]==0.6}0.032{elsif nozzle_diameter[filament_extruder_id]==0.8}0.018{elsif nozzle_diameter[filament_extruder_id]==0.25}0.18{elsif nozzle_diameter[filament_extruder_id]==0.3}0.1{else}0{endif} ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"60"
],
"filament_unloading_speed_start": [
"60"
],
"idle_temperature": [
"130"
]
}
@@ -0,0 +1,54 @@
{
"type": "filament",
"name": "Prusament PLA @CORE One MMU3",
"inherits": "Prusament PLA @CORE One",
"from": "system",
"setting_id": "HSqoQhcjRqpny2g2",
"filament_id": "OFnO4wnf",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"3.5"
],
"filament_cooling_initial_speed": [
"10"
],
"filament_cooling_moves": [
"2"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 40.1613 40.3548 40.4516 40.3548 40.2581| 0.05 40.1483 0.45 40.3419 0.95 40.3419 1.45 40.3419 1.95 40.3419 2.45 40.3419 2.95 40.3419 3.45 40.3419 3.95 40.3419 4.45 40.3419 4.95 40.3419"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"29"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"40"
],
"filament_unloading_speed_start": [
"30"
],
"idle_temperature": [
"170"
]
}
@@ -0,0 +1,57 @@
{
"type": "filament",
"name": "Prusament PVB @CORE One MMU3",
"inherits": "Prusament PVB @CORE One",
"from": "system",
"setting_id": "IXUO4uCgUY1p5jIo",
"filament_id": "OFh7mvPO",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"3.5"
],
"filament_cooling_initial_speed": [
"10"
],
"filament_cooling_moves": [
"2"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_minimal_purge_on_wipe_tower": [
"15"
],
"filament_ramming_parameters": [
"250 100 40.1613 40.3548 40.4516 40.3548 40.2581| 0.05 40.1483 0.45 40.3419 0.95 40.3419 1.45 40.3419 1.95 40.3419 2.45 40.3419 2.95 40.3419 3.45 40.3419 3.95 40.3419 4.45 40.3419 4.95 40.3419"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"29"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"40"
],
"filament_unloading_speed_start": [
"30"
],
"idle_temperature": [
"170"
]
}
@@ -0,0 +1,54 @@
{
"type": "filament",
"name": "Prusament rPLA @CORE One MMU3",
"inherits": "Prusament rPLA @CORE One",
"from": "system",
"setting_id": "n0gSFPBaa7PQ1Y1x",
"filament_id": "OFWRITFw",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle",
"Prusa CORE One MMU3 0.25 nozzle",
"Prusa CORE One MMU3 0.3 nozzle",
"Prusa CORE One MMU3 0.6 nozzle"
],
"filament_cooling_final_speed": [
"3.5"
],
"filament_cooling_initial_speed": [
"10"
],
"filament_cooling_moves": [
"2"
],
"filament_extruder_variant": [
"Direct Drive Standard"
],
"filament_loading_speed": [
"10"
],
"filament_loading_speed_start": [
"50"
],
"filament_ramming_parameters": [
"250 100 40.1613 40.3548 40.4516 40.3548 40.2581| 0.05 40.1483 0.45 40.3419 0.95 40.3419 1.45 40.3419 1.95 40.3419 2.45 40.3419 2.95 40.3419 3.45 40.3419 3.95 40.3419 4.45 40.3419 4.95 40.3419"
],
"filament_stamping_distance": [
"45"
],
"filament_stamping_loading_speed": [
"29"
],
"filament_start_gcode": [
"M572 S{if nozzle_diameter[filament_extruder_id]==0.4}0.036{elsif nozzle_diameter[filament_extruder_id]==0.5}0.025{elsif nozzle_diameter[filament_extruder_id]==0.6}0.022{elsif nozzle_diameter[filament_extruder_id]==0.8}0.014{elsif nozzle_diameter[filament_extruder_id]==0.25}0.12{elsif nozzle_diameter[filament_extruder_id]==0.3}0.08{else}0{endif} ; Filament gcode\n\nM142 S36 ; set heatbreak target temp"
],
"filament_unloading_speed": [
"40"
],
"filament_unloading_speed_start": [
"30"
],
"idle_temperature": [
"170"
]
}
@@ -0,0 +1,18 @@
{
"type": "machine",
"name": "Prusa CORE One MMU3 0.25 nozzle",
"inherits": "Prusa CORE One MMU3 0.4 nozzle",
"from": "system",
"setting_id": "8VtAsgGqtUUBmaxH",
"instantiation": "true",
"default_print_profile": "0.12mm SPEED @COREONE0.25 + MMU3",
"max_layer_height": "0.15",
"min_layer_height": "0.05",
"nozzle_diameter": [
"0.25"
],
"printer_model": "Prusa CORE One MMU3",
"printer_variant": "0.25",
"retraction_length": "0.8",
"z_hop": "0.15"
}
@@ -0,0 +1,18 @@
{
"type": "machine",
"name": "Prusa CORE One MMU3 0.3 nozzle",
"inherits": "Prusa CORE One MMU3 0.4 nozzle",
"from": "system",
"setting_id": "EiPXZjRoFcw95gWA",
"instantiation": "true",
"default_print_profile": "0.16mm STRUCTURAL @COREONE0.3 + MMU3",
"max_layer_height": "0.22",
"min_layer_height": "0.05",
"nozzle_diameter": [
"0.3"
],
"printer_model": "Prusa CORE One MMU3",
"printer_variant": "0.3",
"retraction_length": "0.7",
"z_hop": "0.15"
}
@@ -0,0 +1,40 @@
{
"type": "machine",
"name": "Prusa CORE One MMU3 0.4 nozzle",
"inherits": "Prusa CORE One 0.4 nozzle",
"from": "system",
"setting_id": "7NzvROXEkMpOMzJ5",
"instantiation": "true",
"before_layer_change_gcode": ";BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]",
"change_filament_gcode": "",
"cooling_tube_length": "20",
"cooling_tube_retraction": "45",
"default_filament_profile": "Prusament PLA @CORE One MMU3",
"default_print_profile": "0.20mm SPEED @COREONE0.4 + MMU3",
"extra_loading_move": "-52",
"layer_change_gcode": ";AFTER_LAYER_CHANGE\n;[layer_z]\n",
"machine_end_gcode": "{if layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+1, max_print_height)} F720 ; Move print head up{endif}\nM140 S0 ; turn off heatbed\nM141 S0 ; disable chamber control\nM107 ; turn off fan\nG1 X242 Y211 F10200 ; park\n{if layer_z < max_print_height}G1 Z{z_offset+min(max_layer_z+50, max_print_height)} F720 ; Move bed down{endif}\nM702 ; unload the current filament\nM104 S0 ; turn off temperature\nG4 ; wait\nM572 S0 ; reset PA\nM84 X Y E ; disable motors\n; max_layer_z = [max_layer_z]",
"machine_load_filament_time": "10.9",
"machine_max_speed_z": [
"12",
"40"
],
"machine_start_gcode": "M17 ; enable steppers\nM862.1 P[nozzle_diameter] A{(printer_notes=~/.*ABRASIVE_NOZZLE.*/ ? 1 : 0)} F{(printer_notes=~/.*HF_NOZZLE.*/ ? 1 : 0)} ; nozzle check\nM862.3 P \"COREONE\" ; printer model check\nM862.5 P2 ; g-code level check\nM862.6 P \"Input shaper\" ; FW feature check\nM862.6 P \"MMU3\" ; FW feature check\nM115 U6.4.0+11974\n\n; setup MMU\nM708 A0x0b X5 ; extra load distance\nM708 A0x0d X140 ; unload feedrate\nM708 A0x11 X140 ; load feedrate\nM708 A0x14 X50 ; slow feedrate\nM708 A0x1e X12 ; Pulley current to ~200mA\nM708 A0x12 X90 ; selector feedrate mm/s\nM708 A0x13 X400 ; idler feedrate deg/s\nM708 A0x0f X400 ; selector acceleration mm/s2\n\nM555 X{(min(print_bed_max[0], first_layer_print_min[0] + 32) - 32)} Y{(max(0, first_layer_print_min[1]) - 4)} W{((min(print_bed_max[0], max(first_layer_print_min[0] + 32, first_layer_print_max[0])))) - ((min(print_bed_max[0], first_layer_print_min[0] + 32) - 32))} H{((first_layer_print_max[1])) - ((max(0, first_layer_print_min[1]) - 4))} ; define print area\n\nG90 ; use absolute coordinates\nM83 ; extruder relative mode\n\n{if chamber_temperature[initial_tool] > 35} \n; we need to preheat the chamber\nM140 S115 ; set bed temp for chamber heating\n{else} \n; just set the selected bed temp otherwise\nM140 S[first_layer_bed_temperature] ; set bed temp\n{endif}\nM109 R{((filament_notes[initial_tool]=~/.*HT_MBL10.*/) ? (first_layer_temperature[initial_tool] - 10) : (filament_type[initial_tool] == \"PC\" or filament_type[initial_tool] == \"PA\") ? (first_layer_temperature[initial_tool] - 25) : (filament_type[initial_tool] == \"FLEX\") ? 210 : (filament_type[initial_tool]=~/.*PET.*/) ? 175 : 170)} ; wait for temp\n\nM84 E ; turn off E motor\n\nG28 ; home all without mesh bed level\n\n; -- Chamber Temperature Control --\n{if chamber_temperature[initial_tool] > 35} ; if we need to heat the chamber\n; min chamber temp section\nM104 T{initial_tool} S{if idle_temperature[initial_tool] == 0}100{else}{idle_temperature[initial_tool]}{endif} ; set idle temp\nG1 Z10 F720 ; set bed position\nG1 X242 Y-9 F4800 ; set print head position\nM191 S{chamber_temperature[initial_tool]} ; wait for minimal chamber temp\nM141 S0 ; set nominal chamber temp\nM107\nM140 S[first_layer_bed_temperature] ; set bed temp\n\n{else}\nM141 S{if chamber_temperature[initial_tool] == 0}20{else}{chamber_temperature[initial_tool]}{endif} ; set nominal chamber temp\n{endif}\n\n{if first_layer_bed_temperature[initial_tool]<=60}M106 S70{endif}\nG0 Z40 F10000\nM104 T{initial_tool} S{if idle_temperature[initial_tool] == 0}100{else}{idle_temperature[initial_tool]}{endif}\nM190 R[first_layer_bed_temperature] ; wait for bed temp\nM107\n\nG29 G ; absorb heat\n\nM109 R{((filament_notes[0]=~/.*HT_MBL10.*/) ? (first_layer_temperature[0] - 10) : (filament_type[0] == \"PC\" or filament_type[0] == \"PA\") ? (first_layer_temperature[0] - 25) : (filament_type[0] == \"FLEX\") ? 210 : 170)} ; wait for MBL temp\n\nM302 S160 ; lower cold extrusion limit to 160C\n\n{if filament_type[initial_tool]==\"FLEX\"}\nG1 E-4 F2400 ; retraction\n{else}\nG1 E-2 F2400 ; retraction\n{endif}\n\nM84 E ; turn off E motor\n\n; --- Mesh Bed Leveling (MBL) ---\n\nG29 P9 X208 Y-2.5 W32 H4 ; limited MBL\nM84 E ; turn off E motor\n\nG29 P1 ; invalidate MBL and probe print area\nG29 P1 X150 Y0 W100 H20 C ; probe near purge area\nG29 P3.2 ; MBL interpolation\nG29 P3.13 ; MBL extrapolation outside probe area\nG29 A ; activate MBL\n\n; prepare for purge\nM104 S{first_layer_temperature[initial_tool]}\nG0 X249 Y-2.5 Z15 F4800 ; move away and ready for the purge\nM109 S{first_layer_temperature[initial_tool]}\n\nG92 E0\nM569 S0 E ; set spreadcycle mode for extruder\n\nM591 S0 ; disable stuck detection\n\nT[initial_tool]\nG1 E{parking_pos_retraction + extra_loading_move - 15} F1000 ; load to the nozzle\n\n;\n; Extrude purge line\n;\nG92 E0 ; reset extruder position\nG1 E{(filament_type[initial_tool] == \"FLEX\" ? 4 : 2)} F2400 ; deretraction after the initial one before nozzle cleaning\nG0 E5 X235 Z0.2 F500 ; purge\nG0 X145 E36 F500 ; purge\nG0 X135 E4 F500 ; purge\nG0 X125 E4 F650 ; purge\nG0 X122 Z0.05 F8000 ; wipe, move close to the bed\nG0 X119 Z0.2 F8000 ; wipe, move quickly away from the bed\n\nM591 R ; restore stuck detection\n\nG92 E0\nM221 S100 ; set flow to 100%",
"machine_unload_filament_time": "8.9",
"nozzle_diameter": [
"0.4"
],
"nozzle_height": "4",
"parking_pos_retraction": "84",
"printer_extruder_id": [
"1"
],
"printer_extruder_variant": [
"Direct Drive Standard"
],
"printer_model": "Prusa CORE One MMU3",
"printer_notes": "Don't remove the following keywords! These keywords are used in the \"compatible printer\" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_MODEL_COREONEMMU3\nPRINTER_MODEL_MK4\nCOREMMU\nRAMMING_EXTRA\nPG\nNO_TEMPLATES\nThe MK4 marker enables WipeTower2 cold ramming and filament monitoring control for the CORE One MMU3.",
"printer_variant": "0.4",
"single_extruder_multi_material": "1",
"wipe_tower_type": "type2"
}
@@ -0,0 +1,19 @@
{
"type": "machine",
"name": "Prusa CORE One MMU3 0.6 nozzle",
"inherits": "Prusa CORE One MMU3 0.4 nozzle",
"from": "system",
"setting_id": "rFDxiYXLDZVYHqe8",
"instantiation": "true",
"default_filament_profile": "Prusament PLA @CORE One MMU3",
"default_print_profile": "0.20mm SPEED @COREONE0.6 + MMU3",
"max_layer_height": "0.40",
"min_layer_height": "0.15",
"nozzle_diameter": [
"0.6"
],
"printer_model": "Prusa CORE One MMU3",
"printer_variant": "0.6",
"retraction_length": "0.7",
"wipe": "0"
}
@@ -0,0 +1,12 @@
{
"type": "machine_model",
"name": "Prusa CORE One MMU3",
"bed_model": "coreone_bed.stl",
"bed_texture": "coreone.svg",
"default_materials": "Generic ABS @Prusa CORE One MMU3;Generic ASA @Prusa CORE One MMU3;Generic PETG @Prusa CORE One MMU3;Generic PLA @Prusa CORE One MMU3;Generic PLA Silk @Prusa CORE One MMU3;Generic TPU @Prusa CORE One MMU3",
"family": "Prusa",
"hotend_model": "",
"machine_tech": "FFF",
"model_id": "Prusa_CORE_One_MMU3",
"nozzle_diameter": "0.25;0.3;0.4;0.6"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.05mm DETAIL @COREONE0.25 + MMU3",
"inherits": "0.05mm DETAIL @CORE One 0.25",
"from": "system",
"setting_id": "GZ9p7JXzPU3Widdg",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.25 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.07mm DETAIL @COREONE0.25 + MMU3",
"inherits": "0.07mm DETAIL @CORE One 0.25",
"from": "system",
"setting_id": "9ffM9tc7XMSNHnGB",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.25 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.10mm FAST DETAIL @COREONE0.4 + MMU3",
"inherits": "0.10mm FAST DETAIL @CORE One 0.4",
"from": "system",
"setting_id": "5l28K1bE8lfuaXF1",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.12mm SPEED @COREONE0.25 + MMU3",
"inherits": "0.12mm SPEED @CORE One 0.25",
"from": "system",
"setting_id": "YjbMEvZ8ALzK2qHf",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.25 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.12mm STRUCTURAL @COREONE0.25 + MMU3",
"inherits": "0.12mm STRUCTURAL @CORE One 0.25",
"from": "system",
"setting_id": "g8Bp93DCAwTo5G0s",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.25 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.12mm STRUCTURAL @COREONE0.3 + MMU3",
"inherits": "0.12mm STRUCTURAL @CORE One 0.3",
"from": "system",
"setting_id": "XmhM0qI0mXLbBMwv",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.3 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,70 @@
{
"type": "process",
"name": "0.15mm BALANCED @COREONE0.4 + MMU3",
"inherits": "0.20mm Standard @MK4",
"from": "system",
"setting_id": "gU24xfFrPejGfV1D",
"instantiation": "true",
"bridge_acceleration": "1500",
"brim_type": "no_brim",
"default_acceleration": "3000",
"elefant_foot_compensation": "0.2",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"initial_layer_acceleration": "500",
"initial_layer_infill_speed": "100",
"initial_layer_line_width": "0.5",
"inner_wall_line_width": "0.45",
"internal_solid_infill_line_width": "0.45",
"line_width": "0.45",
"outer_wall_line_width": "0.45",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"raft_first_layer_expansion": "3",
"resolution": "0",
"seam_gap": "15%",
"sparse_infill_line_width": "0.45",
"sparse_infill_pattern": "grid",
"support_base_pattern_spacing": "2",
"support_bottom_interface_spacing": "0.2",
"support_interface_bottom_layers": "0",
"support_interface_spacing": "0.2",
"support_interface_top_layers": "3",
"support_line_width": "0.4",
"support_speed": "120",
"top_surface_acceleration": "2000",
"top_surface_line_width": "0.42",
"travel_acceleration": "7000",
"travel_speed": "350",
"wall_loops": "2",
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"bridge_speed": "45",
"bottom_shell_layers": "4",
"inner_wall_acceleration": "3000",
"inner_wall_speed": "150",
"internal_bridge_speed": "45",
"internal_solid_infill_acceleration": "6000",
"internal_solid_infill_speed": "150",
"layer_height": "0.15",
"outer_wall_acceleration": "2500",
"overhang_2_4_speed": "25",
"overhang_3_4_speed": "50",
"overhang_4_4_speed": "80%",
"small_perimeter_speed": "170",
"sparse_infill_acceleration": "5000",
"sparse_infill_speed": "150",
"support_bottom_z_distance": "0.17",
"support_interface_speed": "50",
"support_threshold_angle": "35",
"support_top_z_distance": "0.17",
"top_shell_layers": "6",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
]
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.15mm SPEED @COREONE0.25 + MMU3",
"inherits": "0.15mm SPEED @CORE One 0.25",
"from": "system",
"setting_id": "mYSeGZQ0MykDNtXP",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.25 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.15mm SPEED @COREONE0.4 + MMU3",
"inherits": "0.15mm SPEED @CORE One 0.4",
"from": "system",
"setting_id": "CdehEFlvnacxhU2H",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.15mm STRUCTURAL @COREONE0.25 + MMU3",
"inherits": "0.15mm STRUCTURAL @CORE One 0.25",
"from": "system",
"setting_id": "sUWaBUUy033BXEzk",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.25 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.15mm STRUCTURAL @COREONE0.4 + MMU3",
"inherits": "0.15mm STRUCTURAL @CORE One 0.4",
"from": "system",
"setting_id": "kM9rtB6iLqcDNZZU",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.15mm STRUCTURAL @COREONE0.6 + MMU3",
"inherits": "0.15mm STRUCTURAL @CORE One 0.6",
"from": "system",
"setting_id": "PTOVGYLNah28dKRr",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.6 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.16mm SPEED @COREONE0.3 + MMU3",
"inherits": "0.16mm SPEED @CORE One 0.3",
"from": "system",
"setting_id": "ByXT7JeCV0SWiSnt",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.3 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.16mm STRUCTURAL @COREONE0.3 + MMU3",
"inherits": "0.16mm STRUCTURAL @CORE One 0.3",
"from": "system",
"setting_id": "3XaKemYMM9AMLAIE",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.3 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,66 @@
{
"type": "process",
"name": "0.20mm BALANCED @COREONE0.4 + MMU3",
"inherits": "0.20mm Standard @MK4",
"from": "system",
"setting_id": "ZhSjwXMEOWyeWIDd",
"instantiation": "true",
"bridge_acceleration": "1500",
"brim_type": "no_brim",
"default_acceleration": "3000",
"elefant_foot_compensation": "0.2",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"initial_layer_acceleration": "500",
"initial_layer_infill_speed": "100",
"initial_layer_line_width": "0.5",
"inner_wall_line_width": "0.45",
"internal_solid_infill_line_width": "0.45",
"line_width": "0.45",
"outer_wall_line_width": "0.45",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"raft_first_layer_expansion": "3",
"resolution": "0",
"seam_gap": "15%",
"sparse_infill_line_width": "0.45",
"sparse_infill_pattern": "grid",
"support_base_pattern_spacing": "2",
"support_bottom_interface_spacing": "0.2",
"support_interface_bottom_layers": "0",
"support_interface_spacing": "0.2",
"support_interface_top_layers": "3",
"support_line_width": "0.4",
"support_speed": "120",
"top_surface_acceleration": "2000",
"top_surface_line_width": "0.42",
"travel_acceleration": "7000",
"travel_speed": "350",
"wall_loops": "2",
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"bridge_speed": "50",
"inner_wall_acceleration": "3000",
"inner_wall_speed": "150",
"internal_solid_infill_acceleration": "6000",
"internal_solid_infill_speed": "150",
"outer_wall_acceleration": "2500",
"overhang_2_4_speed": "25",
"overhang_3_4_speed": "50",
"overhang_4_4_speed": "80%",
"small_perimeter_speed": "170",
"sparse_infill_acceleration": "5000",
"sparse_infill_speed": "150",
"support_interface_speed": "60",
"support_style": "snug",
"support_threshold_angle": "35",
"top_shell_layers": "5",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
]
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.20mm SOLUBLE FULL @COREONE0.4 + MMU3",
"inherits": "0.20mm SOLUBLE FULL @CORE One 0.4",
"from": "system",
"setting_id": "F4GvezeeqYGgETx5",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.20mm SOLUBLE INTERFACE @COREONE0.4 + MMU3",
"inherits": "0.20mm SOLUBLE INTERFACE @CORE One 0.4",
"from": "system",
"setting_id": "hrh6ZS8cMrp6Fput",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.20mm SPEED @COREONE0.3 + MMU3",
"inherits": "0.20mm SPEED @CORE One 0.3",
"from": "system",
"setting_id": "a8MnMQB4PuzlCBkv",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.3 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.20mm SPEED @COREONE0.4 + MMU3",
"inherits": "0.20mm SPEED @CORE One 0.4",
"from": "system",
"setting_id": "gFegVTUTnp12IurN",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.20mm SPEED @COREONE0.6 + MMU3",
"inherits": "0.20mm SPEED @CORE One 0.6",
"from": "system",
"setting_id": "b5DuLDBbPOrc3QUB",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.6 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.20mm STRUCTURAL @COREONE0.3 + MMU3",
"inherits": "0.20mm STRUCTURAL @CORE One 0.3",
"from": "system",
"setting_id": "3GXAe0t8hNMloSsA",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.3 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.20mm STRUCTURAL @COREONE0.4 + MMU3",
"inherits": "0.20mm STRUCTURAL @CORE One 0.4",
"from": "system",
"setting_id": "elSJkPZlFi4sWveY",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.20mm STRUCTURAL @COREONE0.6 + MMU3",
"inherits": "0.20mm STRUCTURAL @CORE One 0.6",
"from": "system",
"setting_id": "uvQ25wBWKEFdqMVl",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.6 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,68 @@
{
"type": "process",
"name": "0.25mm BALANCED @COREONE0.4 + MMU3",
"inherits": "0.20mm Standard @MK4",
"from": "system",
"setting_id": "cEccdq6KND9xa5HS",
"instantiation": "true",
"bridge_acceleration": "1500",
"brim_type": "no_brim",
"default_acceleration": "3000",
"elefant_foot_compensation": "0.2",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"initial_layer_acceleration": "500",
"initial_layer_infill_speed": "100",
"initial_layer_line_width": "0.5",
"inner_wall_line_width": "0.45",
"internal_solid_infill_line_width": "0.45",
"line_width": "0.45",
"outer_wall_line_width": "0.45",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"raft_first_layer_expansion": "3",
"resolution": "0",
"seam_gap": "15%",
"sparse_infill_line_width": "0.45",
"sparse_infill_pattern": "grid",
"support_base_pattern_spacing": "2",
"support_bottom_interface_spacing": "0.2",
"support_interface_bottom_layers": "0",
"support_interface_spacing": "0.2",
"support_interface_top_layers": "3",
"support_line_width": "0.4",
"support_speed": "120",
"top_surface_acceleration": "2000",
"top_surface_line_width": "0.42",
"travel_acceleration": "7000",
"travel_speed": "350",
"wall_loops": "2",
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"bridge_speed": "50",
"inner_wall_acceleration": "3000",
"inner_wall_speed": "150",
"internal_solid_infill_acceleration": "5000",
"internal_solid_infill_speed": "140",
"layer_height": "0.25",
"outer_wall_acceleration": "2500",
"overhang_2_4_speed": "15",
"overhang_3_4_speed": "25",
"overhang_4_4_speed": "70%",
"small_perimeter_speed": "150",
"sparse_infill_acceleration": "5000",
"sparse_infill_speed": "150",
"support_base_pattern": "rectilinear",
"support_bottom_z_distance": "0.25",
"support_style": "snug",
"support_threshold_angle": "35",
"support_top_z_distance": "0.25",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
]
}
@@ -0,0 +1,65 @@
{
"type": "process",
"name": "0.25mm SPEED @COREONE0.4 + MMU3",
"inherits": "0.20mm Standard @MK4",
"from": "system",
"setting_id": "oVLlJtwPINArAb0Y",
"instantiation": "true",
"bridge_acceleration": "1500",
"brim_type": "no_brim",
"default_acceleration": "3000",
"elefant_foot_compensation": "0.2",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"initial_layer_acceleration": "500",
"initial_layer_infill_speed": "100",
"initial_layer_line_width": "0.5",
"inner_wall_line_width": "0.45",
"internal_solid_infill_line_width": "0.45",
"line_width": "0.45",
"outer_wall_line_width": "0.45",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"raft_first_layer_expansion": "3",
"resolution": "0",
"seam_gap": "15%",
"sparse_infill_line_width": "0.45",
"sparse_infill_pattern": "grid",
"support_base_pattern_spacing": "2",
"support_bottom_interface_spacing": "0.2",
"support_interface_bottom_layers": "0",
"support_interface_spacing": "0.2",
"support_interface_top_layers": "3",
"support_line_width": "0.4",
"support_speed": "120",
"top_surface_acceleration": "2000",
"top_surface_line_width": "0.42",
"travel_acceleration": "7000",
"travel_speed": "350",
"wall_loops": "2",
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"bridge_speed": "50",
"inner_wall_acceleration": "6000",
"internal_solid_infill_acceleration": "5000",
"layer_height": "0.25",
"overhang_2_4_speed": "15",
"overhang_3_4_speed": "25",
"overhang_4_4_speed": "70%",
"small_perimeter_speed": "170",
"sparse_infill_acceleration": "7000",
"support_base_pattern": "rectilinear",
"support_bottom_z_distance": "0.25",
"support_interface_speed": "60",
"support_style": "snug",
"support_threshold_angle": "35",
"support_top_z_distance": "0.25",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
]
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.25mm SPEED @COREONE0.6 + MMU3",
"inherits": "0.25mm SPEED @CORE One 0.6",
"from": "system",
"setting_id": "CRAV58WCDIn2bZdK",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.6 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,72 @@
{
"type": "process",
"name": "0.25mm STRUCTURAL @COREONE0.4 + MMU3",
"inherits": "0.20mm Standard @MK4",
"from": "system",
"setting_id": "lBGry26X4a9IihAD",
"instantiation": "true",
"bridge_acceleration": "1500",
"brim_type": "no_brim",
"default_acceleration": "3000",
"elefant_foot_compensation": "0.2",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"initial_layer_acceleration": "500",
"initial_layer_infill_speed": "100",
"initial_layer_line_width": "0.5",
"inner_wall_line_width": "0.45",
"internal_solid_infill_line_width": "0.45",
"line_width": "0.45",
"outer_wall_line_width": "0.45",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"raft_first_layer_expansion": "3",
"resolution": "0",
"seam_gap": "15%",
"sparse_infill_line_width": "0.45",
"sparse_infill_pattern": "grid",
"support_base_pattern_spacing": "2",
"support_bottom_interface_spacing": "0.2",
"support_interface_bottom_layers": "0",
"support_interface_spacing": "0.2",
"support_interface_top_layers": "3",
"support_line_width": "0.4",
"support_speed": "120",
"top_surface_acceleration": "2000",
"top_surface_line_width": "0.42",
"travel_acceleration": "7000",
"travel_speed": "350",
"wall_loops": "2",
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"bridge_speed": "50",
"gap_infill_speed": "60",
"inner_wall_acceleration": "2500",
"inner_wall_speed": "70",
"internal_solid_infill_acceleration": "4000",
"internal_solid_infill_speed": "140",
"layer_height": "0.25",
"outer_wall_acceleration": "1500",
"outer_wall_speed": "50",
"overhang_1_4_speed": "50%",
"overhang_2_4_speed": "15",
"overhang_3_4_speed": "45",
"overhang_4_4_speed": "90%",
"small_perimeter_speed": "50",
"sparse_infill_acceleration": "6000",
"sparse_infill_speed": "120",
"support_base_pattern": "rectilinear",
"support_bottom_z_distance": "0.25",
"support_style": "snug",
"support_threshold_angle": "40",
"support_top_z_distance": "0.25",
"top_surface_speed": "80",
"compatible_printers": [
"Prusa CORE One MMU3 0.4 nozzle"
]
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.25mm STRUCTURAL @COREONE0.6 + MMU3",
"inherits": "0.25mm STRUCTURAL @CORE One 0.6",
"from": "system",
"setting_id": "95m4AA4YRwcBt63r",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.6 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.32mm SPEED @COREONE0.6 + MMU3",
"inherits": "0.32mm SPEED @CORE One 0.6",
"from": "system",
"setting_id": "nqrmLvULVOKW9bSm",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.6 nozzle"
],
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%",
"compatible_printers_condition": ""
}
@@ -0,0 +1,23 @@
{
"type": "process",
"name": "0.32mm STRUCTURAL @COREONE0.6 + MMU3",
"inherits": "0.32mm STRUCTURAL @CORE One 0.6",
"from": "system",
"setting_id": "rYhCYIq1vvY40IYf",
"instantiation": "true",
"compatible_printers": [
"Prusa CORE One MMU3 0.6 nozzle"
],
"compatible_printers_condition": "",
"filename_format": "{input_filename_base}_{layer_height}mm_{filament_type[0]}-{filament_type[1]}-{filament_type[2]}-{filament_type[3]}-{filament_type[4]}_COREONE_MMU3_{print_time}.gcode",
"prime_tower_brim_width": "2",
"print_extruder_id": [
"1"
],
"print_extruder_variant": [
"Direct Drive Standard"
],
"wipe_tower_cone_angle": "25",
"wipe_tower_extra_flow": "250%",
"wipe_tower_extra_spacing": "110%"
}
+53 -29
View File
@@ -7,18 +7,38 @@
uniform sampler2D color_texture;
uniform sampler2D depth_texture;
uniform sampler2D normal_texture;
uniform vec2 inv_tex_size;
uniform float z_near;
uniform float z_far;
uniform bool is_outline;
// The pass has no normal target to read, so the surface normal is reconstructed from the depth
// buffer. inv_projection_matrix unprojects a pixel back into view space and up_view is world +Z
// expressed in view space, which is what tells a top surface from a wall.
uniform mat4 inv_projection_matrix;
uniform vec3 up_view;
varying vec2 tex_coord;
float linearize_depth(float depth)
// Position of the given pixel in view space. Valid under both an orthographic and a perspective
// camera, unlike the depth linearization it replaces.
vec3 view_pos(vec2 uv)
{
float z = depth * 2.0 - 1.0;
return (2.0 * z_near * z_far) / (z_far + z_near - z * (z_far - z_near));
vec2 c = clamp(uv, vec2(0.0), vec2(1.0));
float d = texture2D(depth_texture, c).r;
vec4 ndc = vec4(c * 2.0 - 1.0, d * 2.0 - 1.0, 1.0);
vec4 view = inv_projection_matrix * ndc;
return view.xyz / view.w;
}
// Surface normal at the given pixel, from the forward differences of the reconstructed view
// position. It rings by a pixel across a depth discontinuity, which is acceptable here: the
// normal only weights the occlusion, nothing is shaded with it.
vec3 view_normal(vec2 uv, vec3 p)
{
vec3 px = view_pos(uv + vec2(inv_tex_size.x, 0.0));
vec3 py = view_pos(uv + vec2(0.0, inv_tex_size.y));
vec3 n = cross(px - p, py - p);
float len = length(n);
return (len > 1e-8) ? n / len : vec3(0.0, 0.0, 1.0);
}
void main()
@@ -28,16 +48,21 @@ void main()
return;
}
vec3 base = texture2D(color_texture, tex_coord).rgb;
float depth_center = linearize_depth(texture2D(depth_texture, tex_coord).r);
// Sample normal at current fragment (range: -1 to 1)
vec3 normal_center = texture2D(normal_texture, tex_coord).rgb * 2.0 - 1.0;
// Nothing was drawn here: occluding the background would only darken the gradient, and its
// reconstructed normal is degenerate anyway.
if (texture2D(depth_texture, tex_coord).r >= 0.9999) {
gl_FragColor = vec4(base, 1.0);
return;
}
vec3 center_pos = view_pos(tex_coord);
float depth_center = -center_pos.z;
vec3 normal_center = view_normal(tex_coord, center_pos);
// Calculate how much the surface faces upward
// up_factor = 1.0 for surfaces pointing straight up (0,0,1)
// up_factor = 0.0 for surfaces pointing down or sideways
float up_factor = max(0.0, normal_center.z); // Assuming Z is up axis
// Alternative: if Y is up, use normal_center.y
// up_factor = 1.0 for surfaces pointing straight up, 0.0 for walls and downward faces
float up_factor = clamp(dot(normal_center, up_view), 0.0, 1.0);
// Adaptive sampling radius
float radius = mix(2.0, 4.0, depth_center / z_far);
@@ -52,39 +77,38 @@ void main()
offsets[6] = vec2( 0.0, -1.0);
offsets[7] = vec2( 0.707,-0.707);
// Occlusion is a slope, not a depth difference: how far a neighbour rises out of the
// centre's tangent plane over how far away it is. Unlike a raw difference, that sine is
// free of camera distance and zoom, so a crease reads the same from any view.
const float SLOPE_MIN = 0.08; // ~5 degrees, above the depth-buffer noise of a flat surface
const float SLOPE_MAX = 0.60; // ~37 degrees, a full crease
const float SAMPLE_COUNT = 8.0;
float occlusion = 0.0;
int valid_samples = 0;
for (int i = 0; i < 8; ++i) {
vec2 uv = tex_coord + offsets[i] * inv_tex_size * radius;
uv = clamp(uv, vec2(0.001), vec2(0.999));
float sample_depth = linearize_depth(texture2D(depth_texture, uv).r);
float depth_diff = max(0.0, depth_center - sample_depth);
float threshold = 0.015 * (0.5 + depth_center / z_far);
float contribution = smoothstep(0.001, threshold, depth_diff);
vec3 delta = view_pos(uv) - center_pos;
float dist = length(delta);
float rise = (dist > 1e-6) ? dot(delta, normal_center) / dist : 0.0;
float contribution = smoothstep(SLOPE_MIN, SLOPE_MAX, rise);
float diagonal_weight = 1.0 - abs(offsets[i].x * offsets[i].y) * 0.5;
occlusion += contribution * diagonal_weight;
valid_samples++;
}
if (valid_samples > 0)
occlusion /= float(valid_samples);
occlusion /= SAMPLE_COUNT;
// flatter/top-like surfaces get less darkening
float ao_intensity = 0.55;
float ambient_occlusion = 1.0 - occlusion * ao_intensity;
// Different min values for top vs bottom surfaces
// Different min values for top vs bottom surfaces. The boost that used to follow lifted a
// top surface back to within 2% of unoccluded once up_factor became a real normal rather
// than a colour, which is where the AO went; the floors alone shape the effect now.
float ao_min = mix(0.45, 0.70, up_factor); // Bottom: 0.45, Top: 0.70
ambient_occlusion = clamp(ambient_occlusion, ao_min, 1.0);
// Boost brightness on top surfaces (optional)
float brightness_boost = 1.0 + up_factor * 0.15; // 15% extra brightness on top
ambient_occlusion = pow(ambient_occlusion, 2.2) * brightness_boost;
ambient_occlusion = clamp(ambient_occlusion, 0.45, 1.05);
gl_FragColor = vec4(base * ambient_occlusion, 1.0);
}
}
+71 -59
View File
@@ -1,24 +1,45 @@
#version 140
/**
* SSAO Shader - GLSL 140 version with sharp depth threshold
* SSAO Shader - GLSL 140 version with a slope-based occlusion test
* Only darkens valleys/concave areas, ignores smooth variations
*/
uniform sampler2D color_texture;
uniform sampler2D depth_texture;
uniform sampler2D normal_texture;
uniform float z_near;
uniform vec2 inv_tex_size;
uniform float z_far;
uniform bool is_outline;
// The pass has no normal target to read, so the surface normal is reconstructed from the depth
// buffer. inv_projection_matrix unprojects a pixel back into view space and up_view is world +Z
// expressed in view space, which is what tells a top surface from a wall.
uniform mat4 inv_projection_matrix;
uniform vec3 up_view;
in vec2 tex_coord;
out vec4 frag_color;
float linearize_depth(float depth)
// Position of the given pixel in view space. Valid under both an orthographic and a perspective
// camera, unlike the depth linearization it replaces.
vec3 view_pos(ivec2 pixel)
{
float z = depth * 2.0 - 1.0;
return (2.0 * z_near * z_far) / (z_far + z_near - z * (z_far - z_near));
ivec2 p = clamp(pixel, ivec2(0), textureSize(depth_texture, 0) - 1);
float d = texelFetch(depth_texture, p, 0).r;
vec4 ndc = vec4((vec2(p) + 0.5) * inv_tex_size * 2.0 - 1.0, d * 2.0 - 1.0, 1.0);
vec4 view = inv_projection_matrix * ndc;
return view.xyz / view.w;
}
// Surface normal at the given pixel, from the forward differences of the reconstructed view
// position. It rings by a pixel across a depth discontinuity, which is acceptable here: the
// normal only weights the occlusion, nothing is shaded with it.
vec3 view_normal(ivec2 pixel, vec3 p)
{
vec3 px = view_pos(pixel + ivec2(1, 0));
vec3 py = view_pos(pixel + ivec2(0, 1));
vec3 n = cross(px - p, py - p);
float len = length(n);
return (len > 1e-8) ? n / len : vec3(0.0, 0.0, 1.0);
}
void main()
@@ -28,81 +49,72 @@ void main()
return;
}
ivec2 pixel = ivec2(gl_FragCoord.xy);
float center_depth = linearize_depth(texelFetch(depth_texture, pixel, 0).r);
// Sample normal buffer (stored as RGB in 0-1 range, convert to -1 to 1)
vec3 normal_center = texelFetch(normal_texture, pixel, 0).rgb * 2.0 - 1.0;
normal_center = normalize(normal_center);
vec3 color = texture(color_texture, tex_coord).rgb;
// Nothing was drawn here: occluding the background would only darken the gradient, and its
// reconstructed normal is degenerate anyway.
if (texelFetch(depth_texture, pixel, 0).r >= 0.9999) {
frag_color = vec4(color, 1.0);
return;
}
vec3 center_pos = view_pos(pixel);
float center_depth = -center_pos.z;
vec3 normal_center = view_normal(pixel, center_pos);
// Calculate upward-facing factor (Z-up coordinate system)
float up_factor = clamp(normal_center.z * 1.5, 0.0, 1.0);
float up_factor = clamp(dot(normal_center, up_view), 0.0, 1.0);
// Adaptive radius in pixel space
int radius = int(mix(2.0, 4.0, center_depth / z_far));
// Optimized sampling pattern
const ivec2 offsets[12] = ivec2[](
const int SAMPLE_COUNT = 12;
const ivec2 offsets[SAMPLE_COUNT] = ivec2[](
ivec2(1, 0), ivec2(-1, 0), ivec2(0, 1), ivec2(0, -1),
ivec2(1, 1), ivec2(-1, 1), ivec2(1, -1), ivec2(-1, -1),
ivec2(2, 0), ivec2(-2, 0), ivec2(0, 2), ivec2(0, -2)
);
float occlusion = 0.0;
int valid_samples = 0;
// Occlusion is a slope, not a depth difference: the sine of the angle a neighbour subtends
// above the centre's tangent plane. A raw difference depends on camera distance and zoom,
// so no fixed thresholds suit both a 0.2 mm layer step and a 5 mm overhang.
const float SLOPE_MIN = 0.08; // ~5 degrees, above the depth-buffer noise of a flat surface
const float SLOPE_MAX = 0.60; // ~37 degrees, a full crease
for (int i = 0; i < 12; i++) {
float occlusion = 0.0;
for (int i = 0; i < SAMPLE_COUNT; i++) {
// No edge rejection: view_pos clamps, giving a near-zero delta and no occlusion.
// Rejecting one side only would bias the denominator against the other.
ivec2 sample_pixel = pixel + offsets[i] * radius;
if (sample_pixel.x < 0 || sample_pixel.y < 0)
continue;
float sample_depth = linearize_depth(texelFetch(depth_texture, sample_pixel, 0).r);
// Sample normal at neighbor
vec3 normal_sample = texelFetch(normal_texture, sample_pixel, 0).rgb * 2.0 - 1.0;
// Depth difference (positive if neighbor is closer to camera)
float depth_diff = center_depth - sample_depth;
// Sharp depth threshold ===
// Minimum depth difference to consider occlusion (ignores small variations)
float threshold_min = 0.008; // Higher = only deep valleys get darkened
float threshold_max = 0.04; // Transition range for full occlusion
vec3 delta = view_pos(sample_pixel) - center_pos;
float dist = length(delta);
// How far the neighbour rises towards the viewer out of the centre's tangent plane. A
// flat surface gives ~0 whatever its orientation, so this also subsumes the separate
// planar test the normals were compared for.
float rise = (dist > 1e-6) ? dot(delta, normal_center) / dist : 0.0;
float contribution = 0.0;
if (depth_diff > threshold_min) {
if (rise > SLOPE_MIN) {
// Abrupt mapping with power curve
contribution = (depth_diff - threshold_min) / (threshold_max - threshold_min);
contribution = (rise - SLOPE_MIN) / (SLOPE_MAX - SLOPE_MIN);
contribution = clamp(contribution, 0.0, 1.0);
contribution = pow(contribution, 2.0); // Steeper curve for sharper transition
}
// Reduce occlusion on planar surfaces (similar normals)
float normal_similarity = dot(normal_center, normal_sample);
float planar_factor = smoothstep(0.75, 0.95, normal_similarity);
contribution *= (1.0 - planar_factor * 0.6);
occlusion += contribution;
valid_samples++;
}
if (valid_samples > 0) {
// Calculate ambient occlusion factor with higher base intensity
float ao_factor = 1.0 - (occlusion / float(valid_samples)) * 0.6;
// Keep bright areas clean (higher minimum for upward-facing surfaces)
float ao_min = mix(0.55, 0.85, up_factor);
ao_factor = clamp(ao_factor, ao_min, 1.0);
// Slight brightness boost for upward-facing surfaces
float brightness_boost = 1.0 + up_factor * 0.15;
ao_factor = ao_factor * brightness_boost;
occlusion = ao_factor;
} else {
occlusion = 1.0;
}
// Calculate ambient occlusion factor with higher base intensity
float ao_factor = 1.0 - (occlusion / float(SAMPLE_COUNT)) * 0.6;
// Keep bright areas clean (higher minimum for upward-facing surfaces). The old 0.85 floor
// and 1.15 boost were set when up_factor came from the colour buffer and read ~0; with a
// real normal they capped a top surface at 2% darkening, which hid the AO entirely.
float ao_min = mix(0.45, 0.70, up_factor);
occlusion = clamp(ao_factor, ao_min, 1.0);
vec3 color = texture(color_texture, tex_coord).rgb;
frag_color = vec4(color * occlusion, 1.0);
}
}
+13 -2
View File
@@ -28,6 +28,7 @@
#include <csignal>
#include <atomic>
#include <new>
#include <optional>
#if defined(__linux__) || defined(__LINUX__)
#include <condition_variable>
@@ -1614,6 +1615,10 @@ int CLI::run(int argc, char **argv)
ConfigOptionBool* allow_rotations_option = m_config.option<ConfigOptionBool>("allow_rotations");
if (allow_rotations_option)
allow_rotations = allow_rotations_option->value;
// Only an explicit --align-to-y-axis overrides the printer-structure default.
std::optional<bool> align_to_y_axis;
if (m_given_option_keys.count("align_to_y_axis") > 0)
align_to_y_axis = m_config.opt_bool("align_to_y_axis");
ConfigOptionBool* skip_modified_gcodes_option = m_config.option<ConfigOptionBool>("skip_modified_gcodes");
if (skip_modified_gcodes_option)
@@ -5298,7 +5303,9 @@ int CLI::run(int argc, char **argv)
arrange_cfg.bed_shrink_x = BED_SHRINK_SEQ_PRINT;
arrange_cfg.bed_shrink_y = BED_SHRINK_SEQ_PRINT;
}
if (auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure")) {
if (align_to_y_axis.has_value()) {
arrange_cfg.align_to_y_axis = *align_to_y_axis;
} else if (auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure")) {
arrange_cfg.align_to_y_axis = (printer_structure_opt->value == PrinterStructure::psI3);
}
@@ -5748,7 +5755,9 @@ int CLI::run(int argc, char **argv)
arrange_cfg.bed_shrink_x = BED_SHRINK_SEQ_PRINT;
arrange_cfg.bed_shrink_y = BED_SHRINK_SEQ_PRINT;
}
if (auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure")) {
if (align_to_y_axis.has_value()) {
arrange_cfg.align_to_y_axis = *align_to_y_axis;
} else if (auto printer_structure_opt = m_print_config.option<ConfigOptionEnum<PrinterStructure>>("printer_structure")) {
arrange_cfg.align_to_y_axis = (printer_structure_opt->value == PrinterStructure::psI3);
}
@@ -7943,6 +7952,8 @@ bool CLI::setup(int argc, char **argv)
for (std::string &input_file : m_input_files)
input_file = resolve_cli_input_path(input_file);
m_given_option_keys.insert(opt_order.begin(), opt_order.end());
// Parse actions and transform options.
for (auto const &opt_key : opt_order) {
if (cli_actions_config_def.has(opt_key))
+4
View File
@@ -1,6 +1,8 @@
#ifndef SLIC3R_HPP
#define SLIC3R_HPP
#include <set>
#include "libslic3r/Config.hpp"
#include "libslic3r/Model.hpp"
@@ -113,6 +115,8 @@ private:
std::vector<std::string> m_input_files;
std::vector<std::string> m_actions;
std::vector<std::string> m_transforms;
// Options the user typed; setup() fills the CLI's own options with defaults afterwards.
std::set<std::string> m_given_option_keys;
std::vector<Model> m_models;
bool setup(int argc, char **argv);
+9
View File
@@ -224,6 +224,12 @@ void AppConfig::set_defaults()
set("preview_dim_previous_layers_brightness", std::to_string(std::max(0, std::min(brightness, 99))));
}
// ORCA: view type the G-code preview opens with. "auto" keeps the automatic choice (Filament for
// multi material prints, Line Type for single material ones), "last" restores the view type the user
// picked last, any other value is a fixed view type name, see GCodeViewer::view_type_to_config_name().
if (get("preview_default_view_type").empty())
set("preview_default_view_type", "auto");
if (get("filaments_area_preferred_count").empty())
set("filaments_area_preferred_count", "10");
@@ -303,6 +309,9 @@ void AppConfig::set_defaults()
if (get(SETTING_OPENGL_REALISTIC_PHONG).empty())
set_bool(SETTING_OPENGL_REALISTIC_PHONG, true);
if (get(SETTING_OPENGL_REALISTIC_PREVIEW).empty())
set_bool(SETTING_OPENGL_REALISTIC_PREVIEW, false);
if (get(SETTING_OPENGL_SHADING_MODEL).empty())
set(SETTING_OPENGL_SHADING_MODEL, "gouraud");
+1
View File
@@ -42,6 +42,7 @@ using namespace nlohmann;
#define SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS "opengl_phong_basic_plate_shadows"
#define SETTING_OPENGL_PHONG_SSAO "opengl_phong_ssao"
#define SETTING_OPENGL_PHONG_SMOOTH_NORMALS "opengl_phong_smooth_normals"
#define SETTING_OPENGL_REALISTIC_PREVIEW "opengl_realistic_preview"
#define SETTING_PLUGIN_PAGES_VISIBLE_COUNT "plugin_pages_visible_count"
#define PLUGIN_PAGES_VISIBLE_COUNT_MIN 1
+51 -5
View File
@@ -8,6 +8,7 @@
#include "I18N.hpp"
#include "GCode.hpp"
#include "Exception.hpp"
#include "LifecycleEvents.hpp"
#include "ExtrusionEntity.hpp"
#include "EdgeGrid.hpp"
#include "Geometry/ConvexHull.hpp"
@@ -2476,6 +2477,15 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
m_writer.set_is_bbl_machine(print->is_BBL_printer());
print->set_started(psGCodeExport);
{
LifecycleEventContext ctx;
ctx.name = std::to_string(print->model().id().id);
ctx.code = LifecycleEvtCode::Ok;
ctx.msg = path;
ctx.cancellation_check = [print]() { return print->canceled(); };
fire_lifecycle_event(LifecycleEvent::GCodeExportStarted, ctx);
}
// check if any custom gcode contains keywords used by the gcode processor to
// produce time estimation and gcode toolpaths
std::vector<std::pair<std::string, std::string>> validation_res = DoExport::validate_custom_gcode(*print);
@@ -2511,12 +2521,23 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
m_processor.set_print(print);
GCodeOutputStream file(boost::nowide::fopen(path_tmp.c_str(), "wb"), m_processor);
if (! file.is_open()) {
BOOST_LOG_TRIVIAL(error) << std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n" << std::endl;
std::string err_msg = std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n";
BOOST_LOG_TRIVIAL(error) << err_msg << std::endl;
if (!fs::exists(folder)) {
//fs::create_directory(folder);
BOOST_LOG_TRIVIAL(error) << "the parent path " + folder.string() +" is not there!!!" << std::endl;
std::string add_err_msg = "the parent path " + folder.string() +" is not there!!!";
BOOST_LOG_TRIVIAL(error) << add_err_msg << std::endl;
err_msg += add_err_msg;
}
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
{
LifecycleEventContext ctx;
ctx.name = std::to_string(print->model().id().id);
ctx.code = LifecycleEvtCode::Error;
ctx.msg = std::string(path) + "\n" + err_msg;
ctx.cancellation_check = [print]() { return print->canceled(); };
fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx);
}
throw Slic3r::RuntimeError(err_msg);
}
try {
@@ -2527,11 +2548,19 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
boost::nowide::remove(path_tmp.c_str());
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed\nIs the disk full?\n");
}
} catch (std::exception & /* ex */) {
} catch (std::exception &ex) {
// Rethrow on any exception. std::runtime_exception and CanceledException are expected to be thrown.
// Close and remove the file.
file.close();
boost::nowide::remove(path_tmp.c_str());
{
LifecycleEventContext ctx;
ctx.name = std::to_string(print->model().id().id);
ctx.code = LifecycleEvtCode::Error;
ctx.msg = std::string(path) + "\n" + ex.what();
ctx.cancellation_check = [print]() { return print->canceled(); };
fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx);
}
throw;
}
file.close();
@@ -2637,6 +2666,14 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
std::error_code ret = rename_file(path_tmp, path);
if (ret) {
{
LifecycleEventContext ctx;
ctx.name = std::to_string(print->model().id().id);
ctx.code = LifecycleEvtCode::Error;
ctx.msg = std::string(path) + "\nFailed to rename the output G-code file: " + ret.message();
ctx.cancellation_check = [print]() { return print->canceled(); };
fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx);
}
throw Slic3r::RuntimeError(
std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' + "error code " + ret.message() + '\n' +
"Is " + path_tmp + " locked?" + '\n');
@@ -2647,7 +2684,16 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
BOOST_LOG_TRIVIAL(info) << "Exporting G-code finished" << log_memory_info();
print->set_done(psGCodeExport);
{
LifecycleEventContext ctx;
ctx.name = std::to_string(print->model().id().id);
ctx.code = LifecycleEvtCode::Ok;
ctx.msg = path;
ctx.cancellation_check = [print]() { return print->canceled(); };
fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx);
}
// Orca: label_object_enabled reflects whether objects are labeled in the g-code (EXCLUDE_OBJECT /
// M486), which is driven by exclude_object for every printer
if(result != nullptr)
+249
View File
@@ -0,0 +1,249 @@
#pragma once
// LifecycleEvents.hpp
// --------------------
// Application lifecycle events (project, slicing, plate editing, preset, printer connection, and
// job activity) that other subsystems -- chiefly the plugin layer above libslic3r -- may want to
// observe. Lives in libslic3r rather than the plugin layer because some events fire from inside
// the slicing engine itself; see fire_lifecycle_event() below.
#include <functional>
#include <condition_variable>
#include <cstddef>
#include <mutex>
#include <string>
#include <utility>
namespace Slic3r
{
enum class LifecycleEvent {
// Project (3mf)
NewProject,
ProjectOpened,
ProjectBeforeSave,
ProjectAfterSave,
ProjectClosed,
ProjectDirtyChanged,
// Slicing pipeline
SliceStarted,
SliceGeometryFinished,
GCodeExportStarted,
GCodeExportFinished,
SlicingJobComplete,
// Plate/model editing
ObjectAdded,
ObjectDeleted,
ObjectTransformed,
ObjectChanged,
ObjectRenamed,
PlateCreated,
PlateDeleted,
PlateSelected,
PlateRenamed,
// Preset
PresetSelected,
PresetSaved,
// Printer/device
PrintStateChanged,
DeviceOnline,
DeviceOffline,
DeviceDiscovered,
DeviceSelected,
UploadStarted,
UploadFinished,
// Print/send jobs
PrintJobStarted,
PrintJobFinished,
SendJobStarted,
SendJobFinished,
};
// Scoped so callers must qualify (LifecycleEvtCode::Error, not ERROR) -- ERROR/OK collide with
// Windows macros (wingdi.h) as unqualified names.
enum class LifecycleEvtCode { Ok, Error, Warn };
struct LifecycleEventContext
{
// The primary subject identifier for the event. This is event-specific (for example, a
// project/output path, preset name, device id, or object name), must not contain status or
// prose, and may be empty when the event has no single subject.
std::string name;
// Outcome of the operation represented by the event. For state-change and start events,
// Ok means that the event occurred; it does not imply that a future operation succeeded.
LifecycleEvtCode code = LifecycleEvtCode::Ok;
// Optional human-readable detail or diagnostic text. It is not a stable parsing contract;
// machine-readable data should be represented by a dedicated field or event instead.
std::string msg;
// Stable subject/object identifier, when the source model provides one.
std::string id;
// Previous value for rename and other before/after events.
std::string previous_name;
// Device identifier for printer and job events.
std::string device_id;
// Job identifier when the originating queue/task provides one.
std::string job_id;
// Source subsystem or operation detail, suitable for filtering but not guaranteed to be
// exhaustive across versions.
std::string source;
// Plate, object, or volume index when the source uses an index rather than a stable id.
int index = -1;
// Aggregate project dirty state for ProjectDirtyChanged.
bool dirty = false;
// Optional host-side cancellation probe. Background slicing and G-code export events set
// this to the originating Print's cancellation state so dispatch can stop before calling
// the next capability. It is intentionally not exposed through the Python payload API.
std::function<bool()> cancellation_check;
};
inline std::string lifecycle_event_to_string(LifecycleEvent event)
{
switch (event) {
case LifecycleEvent::NewProject: return "NewProject";
case LifecycleEvent::ProjectOpened: return "ProjectOpened";
case LifecycleEvent::ProjectBeforeSave: return "ProjectBeforeSave";
case LifecycleEvent::ProjectAfterSave: return "ProjectAfterSave";
case LifecycleEvent::ProjectClosed: return "ProjectClosed";
case LifecycleEvent::ProjectDirtyChanged: return "ProjectDirtyChanged";
case LifecycleEvent::SliceStarted: return "SliceStarted";
case LifecycleEvent::SliceGeometryFinished: return "SliceGeometryFinished";
case LifecycleEvent::GCodeExportStarted: return "GCodeExportStarted";
case LifecycleEvent::GCodeExportFinished: return "GCodeExportFinished";
case LifecycleEvent::SlicingJobComplete: return "SlicingJobComplete";
case LifecycleEvent::ObjectAdded: return "ObjectAdded";
case LifecycleEvent::ObjectDeleted: return "ObjectDeleted";
case LifecycleEvent::ObjectTransformed: return "ObjectTransformed";
case LifecycleEvent::ObjectChanged: return "ObjectChanged";
case LifecycleEvent::ObjectRenamed: return "ObjectRenamed";
case LifecycleEvent::PlateCreated: return "PlateCreated";
case LifecycleEvent::PlateDeleted: return "PlateDeleted";
case LifecycleEvent::PlateSelected: return "PlateSelected";
case LifecycleEvent::PlateRenamed: return "PlateRenamed";
case LifecycleEvent::PresetSelected: return "PresetSelected";
case LifecycleEvent::PresetSaved: return "PresetSaved";
case LifecycleEvent::PrintStateChanged: return "PrintStateChanged";
case LifecycleEvent::DeviceOnline: return "DeviceOnline";
case LifecycleEvent::DeviceOffline: return "DeviceOffline";
case LifecycleEvent::DeviceDiscovered: return "DeviceDiscovered";
case LifecycleEvent::DeviceSelected: return "DeviceSelected";
case LifecycleEvent::UploadStarted: return "UploadStarted";
case LifecycleEvent::UploadFinished: return "UploadFinished";
case LifecycleEvent::PrintJobStarted: return "PrintJobStarted";
case LifecycleEvent::PrintJobFinished: return "PrintJobFinished";
case LifecycleEvent::SendJobStarted: return "SendJobStarted";
case LifecycleEvent::SendJobFinished: return "SendJobFinished";
default: return "Unknown";
}
}
inline std::string lifecycle_evt_code_to_string(LifecycleEvtCode code)
{
switch (code) {
case LifecycleEvtCode::Ok: return "Ok";
case LifecycleEvtCode::Error: return "Error";
case LifecycleEvtCode::Warn: return "Warn";
default: return "Unknown";
}
}
// Global cross-layer seam (mirrors ConfigBase::set_resolve_capability_fn): any libslic3r code can
// fire a lifecycle event without depending on the plugin layer above it, which installs the
// dispatcher here at startup. Not tied to Print/GCode specifically, since nothing here should
// require callers to hold a Print& just to report an event.
using LifecycleHookFn = std::function<void(LifecycleEvent, const LifecycleEventContext&)>;
namespace detail {
struct LifecycleHookState
{
std::mutex mutex;
std::condition_variable cv;
LifecycleHookFn fn;
std::size_t active_dispatches = 0;
bool accepting = false;
};
inline LifecycleHookState& lifecycle_hook_state()
{
static LifecycleHookState state;
return state;
}
class LifecycleDispatchGuard
{
public:
explicit LifecycleDispatchGuard(LifecycleHookState& state) : m_state(state) {}
~LifecycleDispatchGuard()
{
std::lock_guard<std::mutex> lock(m_state.mutex);
--m_state.active_dispatches;
if (m_state.active_dispatches == 0)
m_state.cv.notify_all();
}
LifecycleDispatchGuard(const LifecycleDispatchGuard&) = delete;
LifecycleDispatchGuard& operator=(const LifecycleDispatchGuard&) = delete;
private:
LifecycleHookState& m_state;
};
} // namespace detail
// Installing a hook starts accepting dispatches. Passing an empty function stops accepting
// new dispatches, detaches the hook, and waits for callbacks already in progress to finish.
// This is used during plugin shutdown so plugin code cannot be unloaded while a lifecycle
// callback is still executing. The empty-function path must not be called from inside the
// lifecycle callback itself.
inline void set_lifecycle_hook_fn(LifecycleHookFn fn)
{
detail::LifecycleHookState& state = detail::lifecycle_hook_state();
if (fn) {
std::lock_guard<std::mutex> lock(state.mutex);
state.fn = std::move(fn);
state.accepting = true;
return;
}
std::unique_lock<std::mutex> lock(state.mutex);
state.accepting = false;
state.fn = nullptr;
state.cv.wait(lock, [&state] { return state.active_dispatches == 0; });
}
inline void fire_lifecycle_event(LifecycleEvent event, const LifecycleEventContext& ctx)
{
detail::LifecycleHookState& state = detail::lifecycle_hook_state();
LifecycleHookFn fn;
{
std::lock_guard<std::mutex> lock(state.mutex);
if (!state.accepting || !state.fn)
return;
fn = state.fn;
++state.active_dispatches;
}
detail::LifecycleDispatchGuard guard(state);
fn(event, ctx);
}
}
+10
View File
@@ -47,6 +47,7 @@
#include <boost/log/trivial.hpp>
#include "libslic3r.h"
#include "LifecycleEvents.hpp"
#include "Utils.hpp"
#include "Time.hpp"
#include "PlaceholderParser.hpp"
@@ -2972,6 +2973,7 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
// 1) Find the preset with a new_name or create a new one,
// initialize it with the edited config.
auto it = this->find_preset_internal(new_name);
const bool preset_existed = (it != m_presets.end() && it->name == new_name);
if (it != m_presets.end() && it->name == new_name) {
// Preset with the same name found.
Preset &preset = *it;
@@ -3079,6 +3081,14 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
this->get_selected_preset().save(&(parent_preset->config));
else
this->get_selected_preset().save(nullptr);
{
LifecycleEventContext ctx;
ctx.name = new_name;
ctx.msg = preset_existed ? "overwrite" : "new";
ctx.code = LifecycleEvtCode::Ok;
fire_lifecycle_event(LifecycleEvent::PresetSaved, ctx);
}
}
// A detached standalone preset for the Full Publish receiver: create a user preset holding
+44 -1
View File
@@ -14,6 +14,7 @@
#include "Flow.hpp"
#include "Geometry/ConvexHull.hpp"
#include "I18N.hpp"
#include "LifecycleEvents.hpp"
#include "ShortestPath.hpp"
#include "Thread.hpp"
#include "Time.hpp"
@@ -2694,6 +2695,14 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
if (m_objects.empty())
return;
{
LifecycleEventContext ctx;
ctx.name = std::to_string(m_model.id().id);
ctx.code = LifecycleEvtCode::Ok;
ctx.cancellation_check = [this]() { return canceled(); };
fire_lifecycle_event(LifecycleEvent::SliceStarted, ctx);
}
for (PrintObject *obj : m_objects)
obj->clear_shared_object();
@@ -3312,6 +3321,14 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
}
BOOST_LOG_TRIVIAL(info) << "Slicing process finished." << log_memory_info();
{
LifecycleEventContext ctx;
ctx.name = std::to_string(m_model.id().id);
ctx.code = LifecycleEvtCode::Ok;
ctx.cancellation_check = [this]() { return canceled(); };
fire_lifecycle_event(LifecycleEvent::SliceGeometryFinished, ctx);
}
}
// G-code export process, running at a background thread.
@@ -4911,6 +4928,15 @@ void Print::set_gcode_file_invalidated()
//BBS: add gcode file preload logic
void Print::export_gcode_from_previous_file(const std::string& file, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb)
{
{
LifecycleEventContext ctx;
ctx.name = std::to_string(m_model.id().id);
ctx.code = LifecycleEvtCode::Ok;
ctx.msg = file;
ctx.cancellation_check = [this]() { return canceled(); };
fire_lifecycle_event(LifecycleEvent::GCodeExportStarted, ctx);
}
try {
GCodeProcessor processor;
GCodeProcessor::s_IsBBLPrinter = is_BBL_printer();
@@ -4930,13 +4956,30 @@ void Print::export_gcode_from_previous_file(const std::string& file, GCodeProces
*result = std::move(processor.extract_result());
result->filament_change_sequence = filament_seq_loaded;
result->nozzle_change_sequence = nozzle_seq_loaded;
} catch (std::exception & /* ex */) {
} catch (std::exception &ex) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": found errors when process gcode file %1%") %file.c_str();
{
LifecycleEventContext ctx;
ctx.name = std::to_string(m_model.id().id);
ctx.code = LifecycleEvtCode::Error;
ctx.msg = file + "\n" + ex.what();
ctx.cancellation_check = [this]() { return canceled(); };
fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx);
}
throw Slic3r::RuntimeError(
std::string("Failed to process the G-code file ") + file + " from previous 3mf\n");
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": process the G-code file %1% successfully")%file.c_str();
{
LifecycleEventContext ctx;
ctx.name = std::to_string(m_model.id().id);
ctx.code = LifecycleEvtCode::Ok;
ctx.msg = file;
ctx.cancellation_check = [this]() { return canceled(); };
fire_lifecycle_event(LifecycleEvent::GCodeExportFinished, ctx);
}
}
std::tuple<float, float> Print::object_skirt_offset(double margin_height) const
+6
View File
@@ -12347,6 +12347,12 @@ CLIMiscConfigDef::CLIMiscConfigDef()
def->tooltip = L("If enabled, Arrange will allow rotation when placing objects.");
def->set_default_value(new ConfigOptionBool(true));
def = this->add("align_to_y_axis", coBool);
def->label = L("Align to Y axis when arranging");
def->tooltip = L("If enabled, Arrange will turn each object so its long side runs along the Y axis before placing it. "
"When not given, it is on for i3 printers and off for the others, as in the GUI.");
def->set_default_value(new ConfigOptionBool(false));
def = this->add("avoid_extrusion_cali_region", coBool);
def->label = L("Avoid extrusion calibrate region when arranging");
def->tooltip = L("If enabled, Arrange will avoid extrusion calibrate region when placing objects.");
+16
View File
@@ -60,6 +60,22 @@ public:
// using the given camera matrices.
//
void render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
//
// ORCA: realistic view. Render the toolpaths as seen from the light, to fill the caller's
// shadow map. Depth only - the caller masks colour writes and owns the framebuffer.
//
void render_shadow_casters(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& light_position);
//
// ORCA: realistic view. The shadow map the toolpaths sample, in the given texture unit.
// intensity == 0, the default, turns the lookup off and restores the plain shading.
//
void set_shadow_map(int texture_unit, const Mat4x4& light_view_projection, float intensity, float texel_size);
//
// ORCA: tone applied to the shaded toolpaths, to pay back the light the lighting term,
// the shadow and the SSAO pass each take off. 1.0/1.0, the default, is a no-op; the
// caller decides which of the two it varies with the realistic view setting.
//
void set_tone(float exposure, float saturation);
//
// ************************************************************************
+20 -4
View File
@@ -15,7 +15,12 @@ namespace libvgcode {
//| 2--0-------5--7 |
//| \ | | / |
//| 3-------4 |
static constexpr const std::array<uint8_t, 24> VERTEX_DATA = {
// The eight corners the vertex shader knows how to place. Each is sent once and
// referenced by INDEX_DATA below, so the post-transform cache can reuse it across
// the triangles that share it: the shader runs 8 times per segment instead of 24.
static constexpr const std::array<uint8_t, 8> VERTEX_DATA = { 0, 1, 2, 3, 4, 5, 6, 7 };
static constexpr const std::array<uint8_t, 24> INDEX_DATA = {
0, 1, 2, // front spike
0, 2, 3, // front spike
0, 3, 4, // right/bottom body
@@ -31,7 +36,7 @@ void SegmentTemplate::init()
if (m_vao_id != 0)
return;
m_size_in_bytes_gpu += VERTEX_DATA.size() * sizeof(uint8_t);
m_size_in_bytes_gpu += (VERTEX_DATA.size() + INDEX_DATA.size()) * sizeof(uint8_t);
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
@@ -51,12 +56,22 @@ void SegmentTemplate::init()
glsafe(glVertexAttribIPointer(0, 1, GL_UNSIGNED_BYTE, 0, (const void*)0));
#endif // ENABLE_OPENGL_ES
// The element buffer binding is part of the vao state, so it is left bound here
// and restored together with the vao.
glsafe(glGenBuffers(1, &m_ibo_id));
glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id));
glsafe(glBufferData(GL_ELEMENT_ARRAY_BUFFER, INDEX_DATA.size() * sizeof(uint8_t), INDEX_DATA.data(), GL_STATIC_DRAW));
glsafe(glBindBuffer(GL_ARRAY_BUFFER, curr_array_buffer));
glsafe(glBindVertexArray(curr_vertex_array));
}
void SegmentTemplate::shutdown()
{
if (m_ibo_id != 0) {
glsafe(glDeleteBuffers(1, &m_ibo_id));
m_ibo_id = 0;
}
if (m_vbo_id != 0) {
glsafe(glDeleteBuffers(1, &m_vbo_id));
m_vbo_id = 0;
@@ -71,14 +86,15 @@ void SegmentTemplate::shutdown()
void SegmentTemplate::render(size_t count)
{
if (m_vao_id == 0 || m_vbo_id == 0 || count == 0)
if (m_vao_id == 0 || m_vbo_id == 0 || m_ibo_id == 0 || count == 0)
return;
int curr_vertex_array;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
glsafe(glBindVertexArray(m_vao_id));
glsafe(glDrawArraysInstanced(GL_TRIANGLES, 0, static_cast<GLsizei>(VERTEX_DATA.size()), static_cast<GLsizei>(count)));
glsafe(glDrawElementsInstanced(GL_TRIANGLES, static_cast<GLsizei>(INDEX_DATA.size()), GL_UNSIGNED_BYTE,
nullptr, static_cast<GLsizei>(count)));
glsafe(glBindVertexArray(curr_vertex_array));
}
+1
View File
@@ -40,6 +40,7 @@ private:
//
unsigned int m_vao_id{ 0 };
unsigned int m_vbo_id{ 0 };
unsigned int m_ibo_id{ 0 };
//
// Size of the data sent to gpu, in bytes.
//
+62 -6
View File
@@ -16,7 +16,8 @@ static const char* Segments_Vertex_Shader =
"#define FIX_TWISTING\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
// ORCA: the specular was 0.6 * 0.125, too faint to give the filament any sheen.
"const float light_top_specular = 0.6 * 0.25;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.2;\n"
@@ -30,8 +31,19 @@ static const char* Segments_Vertex_Shader =
"uniform samplerBuffer height_width_angle_tex;\n"
"uniform samplerBuffer color_tex;\n"
"uniform usamplerBuffer segment_index_tex;\n"
// ORCA: 0 during the shadow caster pass - the bias below shifts eye_position but not
// world_position, so the caster would write a depth the receiver never looks up.
"uniform float bias_scale;\n"
"in int vertex_id;\n"
"out vec3 color;\n"
"// ORCA: realistic view - the light the shadow map is able to block, kept apart from the\n"
"// ambient and emissive terms in color, which a shadow does not occlude. Their sum is the\n"
"// single lighting term this replaces, so shading is unchanged while shadows are off.\n"
"out vec3 color_direct;\n"
"// ORCA: realistic view - the fragment shader looks the fragment up in the shadow map, which\n"
"// needs its world position and, for the depth bias, its eye space normal.\n"
"out vec3 world_position;\n"
"out vec3 shadow_normal;\n"
"vec3 decode_color(float color) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
@@ -40,11 +52,11 @@ static const char* Segments_Vertex_Shader =
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
"}\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
"float direct_lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
" return top_diffuse + front_diffuse + top_specular;\n"
"}\n"
"void main() {\n"
" int id_a = int(texelFetch(segment_index_tex, gl_InstanceID).r);\n"
@@ -135,19 +147,63 @@ static const char* Segments_Vertex_Shader =
" }\n"
" vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;\n"
" // ORCA: Apply bias to z-position to avoid z-fighting\n"
" eye_position.z += bias;\n"
" eye_position.z += bias * bias_scale;\n"
" vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;\n"
" vec3 color_base = decode_color(texelFetch(color_tex, id).r);\n"
" color = color_base * lighting(eye_position, eye_normal);\n"
" color = color_base * (ambient + emission);\n"
" color_direct = color_base * direct_lighting(eye_position, eye_normal);\n"
" world_position = pos;\n"
" shadow_normal = eye_normal;\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Segments_Fragment_Shader =
"#version 150\n"
"// ORCA: realistic view - object-on-object and self shadows, read from the same depth map the\n"
"// rest of the 3D scene samples. shadow_intensity == 0, the default, short-circuits the lookup,\n"
"// so the toolpaths shade exactly as before whenever realistic view is off.\n"
"const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"uniform sampler2D shadow_map;\n"
"uniform mat4 shadow_light_vp;\n"
"uniform float shadow_intensity;\n"
"uniform float shadow_map_texel;\n"
// ORCA: the lighting term peaks near 0.9 and every later multiplier - the shadow, then the SSAO
// post pass - only takes more light away, so the print reads dimmer and duller than the legend
// colours. These pay that back. Both are 1.0 for an untouched image; what the caller actually
// passes in each mode is decided in GLCanvas3D::_render_gcode, not here.
"uniform float exposure;\n"
"uniform float saturation;\n"
"const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);\n"
"in vec3 color;\n"
"in vec3 color_direct;\n"
"in vec3 world_position;\n"
"in vec3 shadow_normal;\n"
"out vec4 fragment_color;\n"
"float shadow_shade() {\n"
" if (shadow_intensity <= 0.0)\n"
" return 1.0;\n"
" vec4 lp = shadow_light_vp * vec4(world_position, 1.0);\n"
" vec3 proj = lp.xyz / lp.w;\n"
" proj = proj * 0.5 + 0.5;\n"
" if (proj.z > 1.0)\n"
" return 1.0;\n"
" // Slope-scaled bias, as in gouraud.fs. An extrusion is only a handful of shadow-map texels\n"
" // wide, so grazing faces need the larger bias to keep self-shadow acne off the top surfaces.\n"
" float NdotL = dot(normalize(shadow_normal), SHADOW_LIGHT_DIR);\n"
" float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));\n"
" float sum = 0.0;\n"
" for (int x = -2; x <= 2; ++x) {\n"
" for (int y = -2; y <= 2; ++y) {\n"
" float closest = texture(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;\n"
" sum += (proj.z - bias > closest) ? 1.0 : 0.0;\n"
" }\n"
" }\n"
" return 1.0 - shadow_intensity * (sum / 25.0);\n"
"}\n"
"void main() {\n"
" fragment_color = vec4(color, 1.0);\n"
" vec3 c = (color + color_direct * shadow_shade()) * exposure;\n"
" c = mix(vec3(dot(c, LUMA)), c, saturation);\n"
" fragment_color = vec4(clamp(c, 0.0, 1.0), 1.0);\n"
"}\n";
static const char* Options_Vertex_Shader =
+61 -5
View File
@@ -17,7 +17,8 @@ static const char* Segments_Vertex_Shader_ES =
"#define FIX_TWISTING\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"const float light_top_diffuse = 0.6 * 0.8;\n"
"const float light_top_specular = 0.6 * 0.125;\n"
// ORCA: the specular was 0.6 * 0.125, too faint to give the filament any sheen.
"const float light_top_specular = 0.6 * 0.25;\n"
"const float light_top_shininess = 20.0;\n"
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
"const float light_front_diffuse = 0.6 * 0.3;\n"
@@ -33,6 +34,14 @@ static const char* Segments_Vertex_Shader_ES =
"uniform usampler2D segment_index_tex;\n"
"in float vertex_id_float;\n"
"out vec3 color;\n"
"// ORCA: realistic view - the light the shadow map is able to block, kept apart from the\n"
"// ambient and emissive terms in color, which a shadow does not occlude. Their sum is the\n"
"// single lighting term this replaces, so shading is unchanged while shadows are off.\n"
"out vec3 color_direct;\n"
"// ORCA: realistic view - the fragment shader looks the fragment up in the shadow map, which\n"
"// needs its world position and, for the depth bias, its eye space normal.\n"
"out vec3 world_position;\n"
"out vec3 shadow_normal;\n"
"vec3 decode_color(float color) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
@@ -41,11 +50,11 @@ static const char* Segments_Vertex_Shader_ES =
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
"}\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
"float direct_lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
" return top_diffuse + front_diffuse + top_specular;\n"
"}\n"
"ivec2 tex_coord(sampler2D sampler, int id) {\n"
" ivec2 tex_size = textureSize(sampler, 0);\n"
@@ -143,17 +152,64 @@ static const char* Segments_Vertex_Shader_ES =
" vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;\n"
" vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;\n"
" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r);\n"
" color = color_base * lighting(eye_position, eye_normal);\n"
" color = color_base * (ambient + emission);\n"
" color_direct = color_base * direct_lighting(eye_position, eye_normal);\n"
" world_position = pos;\n"
" shadow_normal = eye_normal;\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
static const char* Segments_Fragment_Shader_ES =
"#version 300 es\n"
"precision highp float;\n"
"// ORCA: sampler2D defaults to lowp in an ES fragment shader, far too coarse to compare\n"
"// shadow map depths against.\n"
"precision highp sampler2D;\n"
"// ORCA: realistic view - object-on-object and self shadows, read from the same depth map the\n"
"// rest of the 3D scene samples. shadow_intensity == 0, the default, short-circuits the lookup,\n"
"// so the toolpaths shade exactly as before whenever realistic view is off.\n"
"const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"uniform sampler2D shadow_map;\n"
"uniform mat4 shadow_light_vp;\n"
"uniform float shadow_intensity;\n"
"uniform float shadow_map_texel;\n"
// ORCA: the lighting term peaks near 0.9 and every later multiplier - the shadow, then the SSAO
// post pass - only takes more light away, so the print reads dimmer and duller than the legend
// colours. These pay that back. Both are 1.0 for an untouched image; what the caller actually
// passes in each mode is decided in GLCanvas3D::_render_gcode, not here.
"uniform float exposure;\n"
"uniform float saturation;\n"
"const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);\n"
"in vec3 color;\n"
"in vec3 color_direct;\n"
"in vec3 world_position;\n"
"in vec3 shadow_normal;\n"
"out vec4 fragment_color;\n"
"float shadow_shade() {\n"
" if (shadow_intensity <= 0.0)\n"
" return 1.0;\n"
" vec4 lp = shadow_light_vp * vec4(world_position, 1.0);\n"
" vec3 proj = lp.xyz / lp.w;\n"
" proj = proj * 0.5 + 0.5;\n"
" if (proj.z > 1.0)\n"
" return 1.0;\n"
" // Slope-scaled bias, as in gouraud.fs. An extrusion is only a handful of shadow-map texels\n"
" // wide, so grazing faces need the larger bias to keep self-shadow acne off the top surfaces.\n"
" float NdotL = dot(normalize(shadow_normal), SHADOW_LIGHT_DIR);\n"
" float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));\n"
" float sum = 0.0;\n"
" for (int x = -2; x <= 2; ++x) {\n"
" for (int y = -2; y <= 2; ++y) {\n"
" float closest = texture(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;\n"
" sum += (proj.z - bias > closest) ? 1.0 : 0.0;\n"
" }\n"
" }\n"
" return 1.0 - shadow_intensity * (sum / 25.0);\n"
"}\n"
"void main() {\n"
" fragment_color = vec4(color, 1.0);\n"
" vec3 c = (color + color_direct * shadow_shade()) * exposure;\n"
" c = mix(vec3(dot(c, LUMA)), c, saturation);\n"
" fragment_color = vec4(clamp(c, 0.0, 1.0), 1.0);\n"
"}\n";
static const char* Options_Vertex_Shader_ES =
+15
View File
@@ -42,6 +42,21 @@ void Viewer::render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix)
m_impl->render(view_matrix, projection_matrix);
}
void Viewer::render_shadow_casters(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& light_position)
{
m_impl->render_shadow_casters(view_matrix, projection_matrix, light_position);
}
void Viewer::set_shadow_map(int texture_unit, const Mat4x4& light_view_projection, float intensity, float texel_size)
{
m_impl->set_shadow_map(texture_unit, light_view_projection, intensity, texel_size);
}
void Viewer::set_tone(float exposure, float saturation)
{
m_impl->set_tone(exposure, saturation);
}
EViewType Viewer::get_view_type() const
{
return m_impl->get_view_type();
+109 -4
View File
@@ -763,6 +763,14 @@ void ViewerImpl::init(const std::string& opengl_context_version)
m_uni_segments_height_width_angle_tex_id = glGetUniformLocation(m_segments_shader_id, "height_width_angle_tex");
m_uni_segments_colors_tex_id = glGetUniformLocation(m_segments_shader_id, "color_tex");
m_uni_segments_segment_index_tex_id = glGetUniformLocation(m_segments_shader_id, "segment_index_tex");
// ORCA: realistic view
m_uni_segments_shadow_map_id = glGetUniformLocation(m_segments_shader_id, "shadow_map");
m_uni_segments_shadow_light_vp_id = glGetUniformLocation(m_segments_shader_id, "shadow_light_vp");
m_uni_segments_shadow_intensity_id = glGetUniformLocation(m_segments_shader_id, "shadow_intensity");
m_uni_segments_shadow_map_texel_id = glGetUniformLocation(m_segments_shader_id, "shadow_map_texel");
m_uni_segments_exposure_id = glGetUniformLocation(m_segments_shader_id, "exposure");
m_uni_segments_saturation_id = glGetUniformLocation(m_segments_shader_id, "saturation");
m_uni_segments_bias_scale_id = glGetUniformLocation(m_segments_shader_id, "bias_scale");
glcheck();
assert(m_uni_segments_view_matrix_id != -1 &&
m_uni_segments_projection_matrix_id != -1 &&
@@ -875,6 +883,12 @@ void ViewerImpl::reset()
m_travels_time = { 0.0f, 0.0f };
m_vertices.clear();
m_vertices_colors.clear();
// swap rather than clear: these are sized by the print, and a reset means the memory
// should go back, not sit reserved until the next load
for (std::vector<float>& times : m_layer_start_times)
std::vector<float>().swap(times);
std::vector<uint32_t>().swap(m_layer_first_vertex);
std::vector<float>().swap(m_colors_scratch);
m_valid_lines_bitset.clear();
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
m_cog_marker.reset();
@@ -1048,6 +1062,37 @@ void ViewerImpl::load(GCodeInputData&& gcode_data)
v.layer_duration = m_layers.get_layer_time(m_settings.time_mode, static_cast<size_t>(v.layer_id));
}
// Index of the first vertex of each layer, walked back to front so that a layer with no
// vertex of its own inherits the next layer's index and the array stays non-decreasing.
if (!m_layers.empty()) {
const uint32_t vertices_count = static_cast<uint32_t>(m_vertices.size());
m_layer_first_vertex.assign(m_layers.count(), vertices_count);
for (uint32_t i = vertices_count; i > 0; --i) {
const uint32_t layer_id = m_vertices[i - 1].layer_id;
if (layer_id < m_layer_first_vertex.size())
m_layer_first_vertex[layer_id] = i - 1;
}
for (size_t i = m_layer_first_vertex.size() - 1; i > 0; --i)
m_layer_first_vertex[i - 1] = std::min(m_layer_first_vertex[i - 1], m_layer_first_vertex[i]);
// the running time at each layer's first vertex, summed in vertex order so that
// get_estimated_time_at() matches a full accumulation exactly
std::array<float, TIME_MODES_COUNT> running{};
for (std::vector<float>& times : m_layer_start_times)
times.assign(m_layer_first_vertex.size(), 0.0f);
size_t layer = 0;
for (size_t i = 0; i <= m_vertices.size(); ++i) {
for (; layer < m_layer_first_vertex.size() && m_layer_first_vertex[layer] == i; ++layer) {
for (size_t j = 0; j < TIME_MODES_COUNT; ++j)
m_layer_start_times[j][layer] = running[j];
}
if (i < m_vertices.size()) {
for (size_t j = 0; j < TIME_MODES_COUNT; ++j)
running[j] += m_vertices[i].times[j];
}
}
}
if (!m_layers.empty())
m_layers.set_view_range(0, static_cast<uint32_t>(m_layers.count()) - 1);
@@ -1261,7 +1306,10 @@ void ViewerImpl::update_colors_texture()
// Based on current settings and slider position, we might want to render some
// vertices as dark grey (or darkened, see above). Use either that or the normal color (from the cache).
std::vector<float> colors(m_vertices_colors.size());
// Reused across calls: this runs on every slider tick, and the allocation alone is
// 4 bytes per vertex of the whole print each time.
std::vector<float>& colors = m_colors_scratch;
colors.resize(m_vertices_colors.size());
assert(colors.size() == m_vertices.size() && m_vertices_colors.size() == m_vertices.size());
for (size_t i=0; i<m_vertices.size(); ++i) {
const PathVertex& v = m_vertices[i];
@@ -1321,7 +1369,7 @@ void ViewerImpl::update_colors()
m_settings.update_colors = false;
}
void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix)
void ViewerImpl::apply_pending_updates()
{
if (m_settings.update_view_full_range)
update_view_full_range();
@@ -1331,6 +1379,11 @@ void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matr
if (m_settings.update_colors)
update_colors();
}
void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix)
{
apply_pending_updates();
const Mat4x4 inv_view_matrix = inverse(view_matrix);
const Vec3 camera_position = { inv_view_matrix[12], inv_view_matrix[13], inv_view_matrix[14] };
@@ -1345,6 +1398,30 @@ void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matr
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
}
void ViewerImpl::render_shadow_casters(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& light_position)
{
apply_pending_updates();
// Only the extrusions and travels cast: the option markers are indicators, not material.
m_rendering_shadow_casters = true;
render_segments(view_matrix, projection_matrix, light_position);
m_rendering_shadow_casters = false;
}
void ViewerImpl::set_shadow_map(int texture_unit, const Mat4x4& light_view_projection, float intensity, float texel_size)
{
m_shadow_map_texture_unit = texture_unit;
m_shadow_light_vp = light_view_projection;
m_shadow_intensity = intensity;
m_shadow_map_texel = texel_size;
}
void ViewerImpl::set_tone(float exposure, float saturation)
{
m_exposure = exposure;
m_saturation = saturation;
}
void ViewerImpl::set_view_type(EViewType type)
{
m_settings.view_type = type;
@@ -1516,8 +1593,19 @@ void ViewerImpl::set_view_visible_range(Interval::value_type min, Interval::valu
float ViewerImpl::get_estimated_time_at(size_t id) const
{
return std::accumulate(m_vertices.begin(), m_vertices.begin() + id + 1, 0.0f,
[this](float a, const PathVertex& v) { return a + v.times[static_cast<size_t>(m_settings.time_mode)]; });
const size_t mode = static_cast<size_t>(m_settings.time_mode);
if (mode >= TIME_MODES_COUNT || id >= m_vertices.size())
return 0.0f;
size_t first = 0;
float time = 0.0f;
const size_t layer = static_cast<size_t>(m_vertices[id].layer_id);
if (layer < m_layer_first_vertex.size() && m_layer_first_vertex[layer] <= id) {
first = m_layer_first_vertex[layer];
time = m_layer_start_times[mode][layer];
}
for (size_t i = first; i <= id; ++i)
time += m_vertices[i].times[mode];
return time;
}
Color ViewerImpl::get_vertex_color(const PathVertex& v) const
@@ -1722,6 +1810,10 @@ size_t ViewerImpl::get_used_cpu_memory() const
ret += sizeof(m_extrusion_roles_colors);
ret += sizeof(m_options_colors);
ret += STDVEC_MEMSIZE(m_vertices, PathVertex);
for (const std::vector<float>& times : m_layer_start_times)
ret += STDVEC_MEMSIZE(times, float);
ret += STDVEC_MEMSIZE(m_layer_first_vertex, uint32_t);
ret += STDVEC_MEMSIZE(m_colors_scratch, float);
ret += m_valid_lines_bitset.size_in_bytes_cpu();
ret += m_height_range.size_in_bytes_cpu();
ret += m_width_range.size_in_bytes_cpu();
@@ -1787,7 +1879,11 @@ void ViewerImpl::update_view_full_range()
const bool travels_visible = m_settings.options_visibility[size_t(EOptionType::Travels)];
const bool wipes_visible = m_settings.options_visibility[size_t(EOptionType::Wipes)];
// every vertex before m_layer_first_vertex[layers_range[0]] has a smaller layer_id, so the loop
// below would skip all of them anyway
auto first_it = m_vertices.begin();
if (layers_range[0] < m_layer_first_vertex.size())
first_it += m_layer_first_vertex[layers_range[0]];
while (first_it != m_vertices.end() &&
(first_it->layer_id < layers_range[0] || !is_visible(*first_it, m_settings))) {
++first_it;
@@ -1994,6 +2090,15 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
glsafe(glUniformMatrix4fv(m_uni_segments_view_matrix_id, 1, GL_FALSE, view_matrix.data()));
glsafe(glUniformMatrix4fv(m_uni_segments_projection_matrix_id, 1, GL_FALSE, projection_matrix.data()));
glsafe(glUniform3fv(m_uni_segments_camera_position_id, 1, camera_position.data()));
// ORCA: realistic view. The depth pass writes the map it would otherwise read, so it shades
// with the lookup off.
glsafe(glUniform1i(m_uni_segments_shadow_map_id, m_shadow_map_texture_unit));
glsafe(glUniformMatrix4fv(m_uni_segments_shadow_light_vp_id, 1, GL_FALSE, m_shadow_light_vp.data()));
glsafe(glUniform1f(m_uni_segments_shadow_intensity_id, m_rendering_shadow_casters ? 0.0f : m_shadow_intensity));
glsafe(glUniform1f(m_uni_segments_shadow_map_texel_id, m_shadow_map_texel));
glsafe(glUniform1f(m_uni_segments_exposure_id, m_exposure));
glsafe(glUniform1f(m_uni_segments_saturation_id, m_saturation));
glsafe(glUniform1f(m_uni_segments_bias_scale_id, m_rendering_shadow_casters ? 0.0f : 1.0f));
glsafe(glDisable(GL_CULL_FACE));
+60
View File
@@ -71,6 +71,24 @@ public:
// Render the toolpaths
//
void render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
//
// ORCA: realistic view. Render the toolpaths as seen from the light, to fill the caller's
// shadow map. Only depth matters here, so the caller masks colour writes; light_position
// takes the place of the camera when the segment boxes are expanded, which gives their
// silhouette as the light sees it.
//
void render_shadow_casters(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& light_position);
//
// ORCA: realistic view. The shadow map the toolpaths sample, in the given texture unit.
// intensity == 0, the default, turns the lookup off and restores the plain shading.
//
void set_shadow_map(int texture_unit, const Mat4x4& light_view_projection, float intensity, float texel_size);
//
// ORCA: tone applied to the shaded toolpaths, to pay back the light the lighting term,
// the shadow and the SSAO pass each take off. 1.0/1.0, the default, is a no-op; the
// caller decides which of the two it varies with the realistic view setting.
//
void set_tone(float exposure, float saturation);
EViewType get_view_type() const { return m_settings.view_type; }
void set_view_type(EViewType type);
@@ -234,6 +252,20 @@ private:
//
std::array<float, TIME_MODES_COUNT> m_total_time{ 0.0f, 0.0f };
//
// Running sum of the vertex estimated times at each layer's first vertex, for each time mode,
// so that get_estimated_time_at() only accumulates the vertices of one layer.
//
std::array<std::vector<float>, TIME_MODES_COUNT> m_layer_start_times;
//
// For each layer L, the index of the first vertex whose layer_id is >= L (m_vertices.size()
// if there is none). Derived from the vertices, so it stays exact whatever order they arrive in.
//
std::vector<uint32_t> m_layer_first_vertex;
//
// Scratch buffer for update_colors_texture(), kept alive across slider steps
//
std::vector<float> m_colors_scratch;
//
// Detected travel moves times
//
std::array<float, TIME_MODES_COUNT> m_travels_time{ 0.0f, 0.0f };
@@ -330,6 +362,13 @@ private:
int m_uni_segments_height_width_angle_tex_id{ -1 };
int m_uni_segments_colors_tex_id{ -1 };
int m_uni_segments_segment_index_tex_id{ -1 };
int m_uni_segments_shadow_map_id{ -1 };
int m_uni_segments_shadow_light_vp_id{ -1 };
int m_uni_segments_shadow_intensity_id{ -1 };
int m_uni_segments_shadow_map_texel_id{ -1 };
int m_uni_segments_exposure_id{ -1 };
int m_uni_segments_saturation_id{ -1 };
int m_uni_segments_bias_scale_id{ -1 };
//
// Caches for OpenGL uniforms id for options shader
//
@@ -469,6 +508,27 @@ private:
size_t m_enabled_options_tex_size{ 0 };
#endif // ENABLE_OPENGL_ES
//
// ORCA: realistic view. Shadow map state set by set_shadow_map(), consumed by the segments
// shader. m_rendering_shadow_casters forces the intensity to 0 for the depth pass, which
// must not sample the very map it is writing.
//
// Defaults past the four texture units render_segments() binds itself, so the sampler never
// aliases one of the buffer textures before the owner of the map has said where it lives.
int m_shadow_map_texture_unit{ 4 };
Mat4x4 m_shadow_light_vp{ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
float m_shadow_intensity{ 0.0f };
float m_shadow_map_texel{ 0.0f };
bool m_rendering_shadow_casters{ false };
//
// ORCA: realistic view. Tone set by set_tone(), consumed by the segments shader.
// The identity values leave the shading as it is outside realistic view.
//
float m_exposure{ 1.0f };
float m_saturation{ 1.0f };
void apply_pending_updates();
void update_view_full_range();
void update_color_ranges();
void update_heights_widths();
+25 -2
View File
@@ -10,6 +10,7 @@
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "slic3r/Utils/NetworkAgentFactory.hpp"
#include "libslic3r/Time.hpp"
@@ -355,7 +356,10 @@ namespace Slic3r
obj->bind_state = "free";
obj->last_alive = Slic3r::Utils::get_current_time_utc();
obj->m_is_online = true;
// Route through set_online_state() (rather than writing m_is_online directly) so the
// DeviceOnline lifecycle event fires consistently; same effective value/behavior
// here since the object was already online in the common case.
obj->set_online_state(true);
obj->set_dev_name(dev_name);
/* if (!obj->dev_ip.empty()) {
Slic3r::GUI::wxGetApp().app_config->set_str("ip_address", obj->dev_id, obj->dev_ip);
@@ -373,6 +377,10 @@ namespace Slic3r
obj->bind_sec_link = sec_link;
obj->dev_connection_name = connection_name;
obj->bind_ssdp_version = ssdp_version;
// Discovery establishes the initial reachability state. Do not report it as an
// online transition; DeviceDiscovered below is the lifecycle event for a new
// device. Subsequent updates route through set_online_state(), so a known device
// still emits DeviceOnline/DeviceOffline when its reachability actually changes.
obj->m_is_online = true;
//load access code
@@ -389,6 +397,15 @@ namespace Slic3r
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " New Machine, dev_id= " << dev_id
<< ", ip = " << dev_ip <<", printer_name = " << dev_name
<< ", con_type= " << connect_type <<", signal= " << printer_signal << ", bind_state= " << bind_state;
// First discovery of a genuinely new device (not a periodic SSDP/heartbeat update to
// an already-known one, which is handled in the branch above).
{
LifecycleEventContext ctx;
ctx.name = dev_id;
ctx.code = LifecycleEvtCode::Ok;
fire_lifecycle_event(LifecycleEvent::DeviceDiscovered, ctx);
}
}
update_local_machine(*obj);
}
@@ -984,8 +1001,14 @@ namespace Slic3r
}
void DeviceManager::OnSelectedMachineChanged(const std::string& /*pre_dev_id*/,
const std::string& /*new_dev_id*/)
const std::string& new_dev_id)
{
{
LifecycleEventContext ctx;
ctx.name = new_dev_id; // empty string is a valid deselection
ctx.code = LifecycleEvtCode::Ok;
fire_lifecycle_event(LifecycleEvent::DeviceSelected, ctx);
}
if (MachineObject* obj_ = get_selected_machine()) {
GUI::wxGetApp().sidebar().update_sync_status(obj_);
if(m_agent->get_filament_sync_mode() == FilamentSyncMode::subscription)
+42 -21
View File
@@ -5,6 +5,7 @@
#include "libslic3r/Time.hpp"
#include "libslic3r/Thread.hpp"
#include "slic3r/Utils/NetworkAgent.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "slic3r/Utils/NetworkAgentFactory.hpp"
#include "GuiColor.hpp"
@@ -2626,7 +2627,15 @@ void MachineObject::reset()
void MachineObject::set_print_state(std::string status)
{
const bool changed = (print_status != status);
print_status = status;
if (changed) {
LifecycleEventContext ctx;
ctx.name = dev_id;
ctx.code = LifecycleEvtCode::Ok;
ctx.msg = print_status;
fire_lifecycle_event(LifecycleEvent::PrintStateChanged, ctx);
}
}
int MachineObject::connect(bool use_openssl)
@@ -2648,7 +2657,10 @@ int MachineObject::connect(bool use_openssl)
int MachineObject::disconnect()
{
if (m_agent) {
return m_agent->disconnect_printer();
const int result = m_agent->disconnect_printer();
if (result == 0)
set_online_state(false);
return result;
}
return -1;
}
@@ -2678,8 +2690,16 @@ bool MachineObject::is_connecting()
void MachineObject::set_online_state(bool on_off)
{
const bool changed = (m_is_online != on_off);
m_is_online = on_off;
if (!on_off) m_active_state = NotActive;
if (changed) {
LifecycleEventContext ctx;
ctx.name = dev_id;
ctx.code = LifecycleEvtCode::Ok;
ctx.msg = on_off ? "online" : "offline";
fire_lifecycle_event(on_off ? LifecycleEvent::DeviceOnline : LifecycleEvent::DeviceOffline, ctx);
}
}
bool MachineObject::is_info_ready(bool check_version) const
@@ -2806,13 +2826,6 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
parse_msg_count++;
std::chrono::system_clock::time_point clock_start = std::chrono::system_clock::now();
this->set_online_state(true);
std::chrono::system_clock::time_point curr_time = std::chrono::system_clock::now();
auto diff1 = std::chrono::duration_cast<std::chrono::microseconds>(curr_time - last_update_time);
/* update last received time */
last_update_time = std::chrono::system_clock::now();
json j_pre;
bool parse_ok = false;
@@ -2825,8 +2838,29 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
/* post process payload */
sanitizeToUtf8(payload);
BOOST_LOG_TRIVIAL(info) << "parse_json: sanitize to utf8";
try {
j_pre = json::parse(payload);
parse_ok = true;
}
catch (...) {}
}
bool client_disconnected = false;
if (parse_ok && j_pre.is_object() && j_pre.contains("event") && j_pre["event"].is_object() &&
j_pre["event"].contains("event") && j_pre["event"]["event"].is_string()) {
client_disconnected = j_pre["event"]["event"].get<std::string>() == "client.disconnected";
}
// A disconnect notification is a transport message too, but it must not first mark an
// already-offline device as online through the generic message-received path.
set_online_state(!client_disconnected);
std::chrono::system_clock::time_point curr_time = std::chrono::system_clock::now();
auto diff1 = std::chrono::duration_cast<std::chrono::microseconds>(curr_time - last_update_time);
/* update last received time */
last_update_time = std::chrono::system_clock::now();
try {
bool restored_json = false;
json j;
@@ -4597,19 +4631,6 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
}
}
// event info
try {
if (j.contains("event")) {
if (j["event"].contains("event")) {
if (j["event"]["event"].get<std::string>() == "client.disconnected")
set_online_state(false);
else if (j["event"]["event"].get<std::string>() == "client.connected")
set_online_state(true);
}
}
}
catch (...) {}
if (!key_field_only) {
BOOST_LOG_TRIVIAL(trace) << "parse_json m_active_state =" << m_active_state;
parse_state_changed_event();
+1
View File
@@ -897,6 +897,7 @@ public:
bool is_connected();
bool is_connecting();
// Emits DeviceOnline or DeviceOffline only when the reachability state changes.
void set_online_state(bool on_off);
bool is_online() { return m_is_online; }
bool is_info_ready(bool check_version = true) const;
+136 -28
View File
@@ -104,6 +104,31 @@ static std::string get_view_type_string(libvgcode::EViewType view_type)
return "";
}
// ORCA: Stable, locale independent names used to persist a view type in the application config.
// Keep these in sync with the entries of libvgcode::EViewType exposed in the preview combo box.
static const std::vector<std::pair<std::string, libvgcode::EViewType>>& view_type_config_map()
{
static const std::vector<std::pair<std::string, libvgcode::EViewType>> map = {
{ "summary", libvgcode::EViewType::Summary },
{ "feature_type", libvgcode::EViewType::FeatureType },
{ "color_print", libvgcode::EViewType::ColorPrint },
{ "speed", libvgcode::EViewType::Speed },
{ "actual_speed", libvgcode::EViewType::ActualSpeed },
{ "acceleration", libvgcode::EViewType::Acceleration },
{ "jerk", libvgcode::EViewType::Jerk },
{ "height", libvgcode::EViewType::Height },
{ "width", libvgcode::EViewType::Width },
{ "volumetric_flow_rate", libvgcode::EViewType::VolumetricFlowRate },
{ "actual_volumetric_flow_rate", libvgcode::EViewType::ActualVolumetricFlowRate },
{ "layer_time_linear", libvgcode::EViewType::LayerTimeLinear },
{ "layer_time_logarithmic", libvgcode::EViewType::LayerTimeLogarithmic },
{ "fan_speed", libvgcode::EViewType::FanSpeed },
{ "temperature", libvgcode::EViewType::Temperature },
{ "pressure_advance", libvgcode::EViewType::PressureAdvance },
};
return map;
}
// Find an index of a value in a sorted vector, which is in <z-eps, z+eps>.
// Returns -1 if there is no such member.
static int find_close_layer_idx(const std::vector<double> &zs, double &z, double eps)
@@ -1091,9 +1116,7 @@ void GCodeViewer::init(ConfigOptionMode mode, PresetBundle* preset_bundle)
// Default view type at first slice.
// May be overridden in load() once we know how many tools are actually used in the G-code.
m_nozzle_nums = preset_bundle ? preset_bundle->get_printer_extruder_count() : 1;
auto it = std::find(view_type_items.begin(), view_type_items.end(), libvgcode::EViewType::FeatureType);
m_view_type_sel = (it != view_type_items.end()) ? std::distance(view_type_items.begin(), it) : 0;
set_view_type(libvgcode::EViewType::FeatureType);
apply_default_view_type();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": finished");
}
@@ -1114,6 +1137,73 @@ void GCodeViewer::set_scale(float scale)
}
}
// ORCA: Preview default view type preference, see "preview_default_view_type" in the application config.
std::string GCodeViewer::view_type_to_config_name(libvgcode::EViewType type)
{
for (const auto& [name, value] : view_type_config_map()) {
if (value == type)
return name;
}
return std::string();
}
bool GCodeViewer::view_type_from_config_name(const std::string& name, libvgcode::EViewType& type)
{
for (const auto& [config_name, value] : view_type_config_map()) {
if (config_name == name) {
type = value;
return true;
}
}
return false;
}
std::vector<std::pair<std::string, std::string>> GCodeViewer::default_view_type_choices()
{
std::vector<std::pair<std::string, std::string>> choices = {
{ "auto", _u8L("Automatic") },
{ "last", _u8L("Last used") },
};
for (const auto& [name, type] : view_type_config_map())
choices.push_back({ name, get_view_type_string(type) });
return choices;
}
void GCodeViewer::select_view_type(libvgcode::EViewType type)
{
auto it = std::find(view_type_items.begin(), view_type_items.end(), type);
m_view_type_sel = (it != view_type_items.end()) ? static_cast<int>(std::distance(view_type_items.begin(), it)) : 0;
set_view_type(type);
}
// ORCA: Pick the view type the preview opens with, following the "preview_default_view_type" preference:
// a fixed view type, the one the user picked last ("last"), or the automatic choice ("auto", the default)
// which shows Filament for multi material prints and Line Type for single material ones.
// The default is only (re)applied when it actually changes, so a view type picked by hand survives a reslice.
void GCodeViewer::apply_default_view_type()
{
const std::string preference = wxGetApp().app_config->get("preview_default_view_type");
std::string key = preference;
libvgcode::EViewType type = libvgcode::EViewType::FeatureType;
if (preference == "last") {
if (!view_type_from_config_name(wxGetApp().app_config->get("preview_last_view_type"), type))
type = libvgcode::EViewType::FeatureType;
}
else if (!view_type_from_config_name(preference, type)) {
// "auto", or an unknown value written by a newer version
const bool multi_material = m_viewer.get_used_extruders_count() > 1;
type = multi_material ? libvgcode::EViewType::ColorPrint : libvgcode::EViewType::FeatureType;
key = multi_material ? "auto_multi_material" : "auto_single_material";
}
if (m_applied_default_view_type_key == key)
return;
m_applied_default_view_type_key = key;
select_view_type(type);
}
void GCodeViewer::update_by_mode(ConfigOptionMode mode)
{
view_type_items.clear();
@@ -1395,27 +1485,8 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
// load_toolpaths(gcode_result, build_volume, exclude_bounding_box);
// ORCA: Apply smart default view type when extruder count changes.
// Multi-color: ColorPrint (Filament), Single-color: FeatureType (Line Type).
// User selections persist within same extruder count, defaults reapply on count change.
int current_count = m_viewer.get_used_extruders_count();
if (current_count > 1) {
if (m_last_extruder_count_default_applied != 2) {
auto it = std::find(view_type_items.begin(), view_type_items.end(), libvgcode::EViewType::ColorPrint);
if (it != view_type_items.end())
m_view_type_sel = std::distance(view_type_items.begin(), it);
set_view_type(libvgcode::EViewType::ColorPrint);
m_last_extruder_count_default_applied = 2;
}
} else {
if (m_last_extruder_count_default_applied != 1) {
auto it = std::find(view_type_items.begin(), view_type_items.end(), libvgcode::EViewType::FeatureType);
if (it != view_type_items.end())
m_view_type_sel = std::distance(view_type_items.begin(), it);
set_view_type(libvgcode::EViewType::FeatureType);
m_last_extruder_count_default_applied = 1;
}
}
// ORCA: Apply the default view type now that we know how many tools the G-code actually uses.
apply_default_view_type();
// BBS: data for rendering color arrangement recommendation
m_nozzle_nums = print.config().option<ConfigOptionFloats>("nozzle_diameter")->values.size();
@@ -1627,7 +1698,7 @@ void GCodeViewer::render_scene(int canvas_width, int canvas_height)
glsafe(::glEnable(GL_DEPTH_TEST));
render_shells(canvas_width, canvas_height);
if (m_viewer.get_extrusion_roles().empty())
if (m_viewer.get_extrusion_roles_count() == 0)
return;
render_toolpaths();
@@ -1641,6 +1712,29 @@ void GCodeViewer::render_scene(int canvas_width, int canvas_height)
m_sequential_view.render_marker(!m_no_render_path, canvas_width, sequential_view_height(canvas_height), m_viewer.get_view_type());
}
void GCodeViewer::render_shadow_casters(const Transform3d& light_view_matrix, const Transform3d& light_projection_matrix, const Vec3d& light_position)
{
if (!has_data())
return;
m_viewer.render_shadow_casters(
libvgcode::convert(static_cast<Matrix4f>(light_view_matrix.matrix().cast<float>())),
libvgcode::convert(static_cast<Matrix4f>(light_projection_matrix.matrix().cast<float>())),
libvgcode::convert(static_cast<Vec3f>(light_position.cast<float>())));
}
void GCodeViewer::set_shadow_map(int texture_unit, const Transform3d& light_view_projection, float intensity, float texel_size)
{
m_viewer.set_shadow_map(texture_unit,
libvgcode::convert(static_cast<Matrix4f>(light_view_projection.matrix().cast<float>())),
intensity, texel_size);
}
void GCodeViewer::set_tone(float exposure, float saturation)
{
m_viewer.set_tone(exposure, saturation);
}
void GCodeViewer::render_overlay(int canvas_width, int canvas_height, int right_margin)
{
if (m_viewer.get_extrusion_roles().empty())
@@ -3426,6 +3520,12 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
std::vector<std::pair<ColorRGBA, std::pair<double, double>>> ret;
ret.reserve(custom_gcode_per_print_z.size());
// Loop invariant, but built lazily: this lambda runs once per extruder on every frame
// and most prints reach neither colour change below, so fetching it up front would cost
// more than the per-item fetch it replaces.
std::vector<float> zs;
bool zs_built = false;
for (const auto& item : custom_gcode_per_print_z) {
if (extruder_id + 1 != static_cast<unsigned char>(item.extruder))
continue;
@@ -3433,7 +3533,10 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
if (item.type != ColorChange)
continue;
const std::vector<float> zs = m_viewer.get_layers_zs();
if (!zs_built) {
zs = m_viewer.get_layers_zs();
zs_built = true;
}
auto lower_b = std::lower_bound(zs.begin(), zs.end(),
static_cast<float>(item.print_z - epsilon()));
if (lower_b == zs.end())
@@ -3558,6 +3661,10 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
m_view_type_sel = i;
set_view_type(view_type_items[m_view_type_sel]);
reset_visible(view_type_items[m_view_type_sel]);
// ORCA: remember the pick so the "Last used" preview default can restore it
const std::string view_type_name = view_type_to_config_name(view_type_items[m_view_type_sel]);
if (!view_type_name.empty())
wxGetApp().app_config->set("preview_last_view_type", view_type_name);
update_moves_slider();
#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
imgui.set_requires_extra_frame();
@@ -4582,6 +4689,8 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
// ORCA: Get layer Zs as doubles
std::vector<double> layer_zs = get_layers_zs();
// loop invariant, same reason as the layer Zs above
const std::vector<float> layer_times = m_viewer.get_layers_estimated_times();
for (Slic3r::CustomGCode::Item custom_gcode : custom_gcode_per_print_z) {
ImGui::Dummy({window_padding, window_padding});
@@ -4601,7 +4710,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
imgui.text(buf);
ImGui::SameLine(max_len * 1.5);
std::vector<float> layer_times = m_viewer.get_layers_estimated_times();
float custom_gcode_time = 0;
if (layer > 0)
{
@@ -4650,7 +4758,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
std::string print_str = _u8L("Model printing time");
std::string total_str = _u8L("Total time");
float max_len = window_padding + 2 * ImGui::GetStyle().ItemSpacing.x;
if (m_viewer.get_layers_estimated_times().empty())
if (m_viewer.get_layers_count() == 0)
max_len += ImGui::CalcTextSize(total_str.c_str()).x;
else {
if (m_viewer.get_view_type() == libvgcode::EViewType::FeatureType)
+19 -1
View File
@@ -228,7 +228,8 @@ private:
std::vector<libvgcode::EViewType> view_type_items;
std::vector<std::string> view_type_items_str;
int m_view_type_sel = 0;
int m_last_extruder_count_default_applied{0}; // 0=unset, 1=single, 2+=multi
// ORCA: which default view type was last applied, see apply_default_view_type(). Empty until the first one is applied.
std::string m_applied_default_view_type_key;
std::vector<EMoveType> options_items;
bool m_legend_visible{ true };
@@ -279,6 +280,13 @@ public:
void render_scene(int canvas_width, int canvas_height);
// Legend, sliders, the marker's position window and the G-code window, all ImGui.
void render_overlay(int canvas_width, int canvas_height, int right_margin);
// ORCA: realistic view. Depth-only pass drawing the toolpaths as the light sees them, into
// the shadow map the caller has bound, and the map they sample back in render_scene.
void render_shadow_casters(const Transform3d& light_view_matrix, const Transform3d& light_projection_matrix, const Vec3d& light_position);
void set_shadow_map(int texture_unit, const Transform3d& light_view_projection, float intensity, float texel_size);
// ORCA: tone applied to the shaded toolpaths, paying back the light the lighting term,
// the shadow and the SSAO pass each take off. 1.0/1.0 is a no-op.
void set_tone(float exposure, float saturation);
//BBS
// void _render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
// void _render_calibration_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
@@ -324,6 +332,16 @@ public:
void set_view_type(libvgcode::EViewType type) {
m_viewer.set_view_type(type);
}
// ORCA: select a view type in the preview combo box and apply it
void select_view_type(libvgcode::EViewType type);
// ORCA: apply the "preview_default_view_type" preference, see the definition for the supported values
void apply_default_view_type();
// ORCA: stable, locale independent name of a view type, as stored in the application config
static std::string view_type_to_config_name(libvgcode::EViewType type);
static bool view_type_from_config_name(const std::string& name, libvgcode::EViewType& type);
// ORCA: (config value, translated label) pairs for the "preview_default_view_type" preference combo box
static std::vector<std::pair<std::string, std::string>> default_view_type_choices();
void reset_visible(libvgcode::EViewType type) {
if (type == libvgcode::EViewType::FeatureType) {
auto roles = m_viewer.get_extrusion_roles();
+125 -112
View File
@@ -43,6 +43,7 @@
#include "slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include "slic3r/Utils/MacDarkMode.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include <slic3r/GUI/GUI_Utils.hpp>
@@ -2199,8 +2200,8 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size)
// Recorded by PartPlate::render_icons() below, when it runs.
wxGetApp().plater()->get_partplate_list().clear_hover_tooltip();
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
// Invalidate the shadow map each frame; only the View3D path below rebuilds it. This keeps
// the Preview / Assemble canvases from sampling a stale map with an outdated light matrix.
// Invalidate the shadow map each frame; the View3D and Preview paths below rebuild it. This
// keeps the Assemble canvas from sampling a stale map with an outdated light matrix.
m_shadow_map_valid = false;
_render_background();
@@ -2251,6 +2252,8 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size)
_render_selection();
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes);
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, true, hover_id);
// Realistic view: the print casts a shadow onto the plate here as it does in View3D.
_render_shadows(camera.get_view_matrix(), camera.get_projection_matrix());
// BBS: GUI refactor: add canvas size as parameters
_render_gcode(cnv_size.get_width(), cnv_size.get_height());
}
@@ -5026,8 +5029,16 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
if (object_moved)
if (object_moved) {
Slic3r::LifecycleEventContext ctx;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
ctx.msg = "moved";
if (done.size() == 1)
ctx.name = m_model->objects[done.begin()->first]->name;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED));
}
// BBS: support wipe-tower for multi-plates
for (int plate_id = 0; plate_id < wipe_tower_origins.size(); plate_id++) {
@@ -5148,8 +5159,16 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
if (!done.empty())
if (!done.empty()) {
Slic3r::LifecycleEventContext ctx;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
ctx.msg = "rotated";
if (done.size() == 1)
ctx.name = m_model->objects[done.begin()->first]->name;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
}
m_dirty = true;
}
@@ -5240,8 +5259,16 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
//BBS: notify object info update
wxGetApp().plater()->show_object_info();
if (!done.empty())
if (!done.empty()) {
Slic3r::LifecycleEventContext ctx;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
ctx.msg = "scaled";
if (done.size() == 1)
ctx.name = m_model->objects[done.begin()->first]->name;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_SCALED));
}
m_dirty = true;
}
@@ -7644,11 +7671,20 @@ bool GLCanvas3D::_is_fxaa_enabled() const
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_FXAA_ENABLED);
}
bool GLCanvas3D::_is_realistic_view_enabled() const
{
const AppConfig* cfg = wxGetApp().app_config;
if (cfg == nullptr || !cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE))
return false;
// Prepare and Assemble follow the umbrella toggle alone; Preview needs its own opt-in.
return m_canvas_type != ECanvasType::CanvasPreview || cfg->get_bool(SETTING_OPENGL_REALISTIC_PREVIEW);
}
bool GLCanvas3D::_is_ssao_enabled() const
{
if (wxGetApp().app_config == nullptr)
return false;
return wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE) &&
return _is_realistic_view_enabled() &&
wxGetApp().app_config->get_bool(SETTING_OPENGL_PHONG_SSAO);
}
@@ -7803,95 +7839,23 @@ void GLCanvas3D::_render_ssao_pass(unsigned int width, unsigned int height)
const Camera& camera = wxGetApp().plater()->get_camera();
GLint prev_stencil_mask = 0xFF;
glsafe(::glGetIntegerv(GL_STENCIL_WRITEMASK, &prev_stencil_mask));
GLboolean prev_stencil_test = GL_FALSE;
glsafe(::glGetBooleanv(GL_STENCIL_TEST, &prev_stencil_test));
GLboolean prev_depth_mask = GL_TRUE;
glsafe(::glGetBooleanv(GL_DEPTH_WRITEMASK, &prev_depth_mask));
GLint prev_depth_func = GL_LESS;
glsafe(::glGetIntegerv(GL_DEPTH_FUNC, &prev_depth_func));
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glDisable(GL_BLEND));
// Build stencil mask for bed/plate and apply SSAO only outside this mask.
glsafe(::glEnable(GL_STENCIL_TEST));
glsafe(::glStencilMask(0xFF));
glsafe(::glClearStencil(0));
glsafe(::glClear(GL_STENCIL_BUFFER_BIT));
glsafe(::glStencilFunc(GL_ALWAYS, 1, 0xFF));
glsafe(::glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
// Mark only visible plate pixels (do not exclude objects in front of plate).
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glDepthMask(GL_FALSE));
glsafe(::glDepthFunc(GL_LEQUAL));
GLboolean prev_color_mask[4] = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE };
glsafe(::glGetBooleanv(GL_COLOR_WRITEMASK, prev_color_mask));
glsafe(::glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
if (const BuildVolume& build_volume = m_bed.build_volume(); build_volume.valid()) {
GLShaderProgram* flat = wxGetApp().get_shader("flat");
if (flat != nullptr) {
flat->start_using();
flat->set_uniform("projection_matrix", camera.get_projection_matrix());
GLModel plate_mask;
GLModel::Geometry mask;
mask.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 };
if (build_volume.type() == BuildVolume_Type::Rectangle) {
const BoundingBox3Base<Vec3d> bb = build_volume.bounding_volume();
mask.reserve_vertices(4);
mask.reserve_indices(6);
mask.add_vertex(Vec3f((float)bb.min.x(), (float)bb.min.y(), 0.0f));
mask.add_vertex(Vec3f((float)bb.max.x(), (float)bb.min.y(), 0.0f));
mask.add_vertex(Vec3f((float)bb.max.x(), (float)bb.max.y(), 0.0f));
mask.add_vertex(Vec3f((float)bb.min.x(), (float)bb.max.y(), 0.0f));
mask.add_triangle(0, 1, 2);
mask.add_triangle(0, 2, 3);
} else if (build_volume.type() == BuildVolume_Type::Circle) {
const Vec2f c = Vec2f(unscaled<float>(build_volume.circle().center.x()), unscaled<float>(build_volume.circle().center.y()));
const float r = unscaled<float>(build_volume.circle().radius);
const int segments = 64;
mask.reserve_vertices(segments + 1);
mask.reserve_indices(segments * 3);
mask.add_vertex(Vec3f(c.x(), c.y(), 0.0f));
for (int i = 0; i < segments; ++i) {
const float a = (2.0f * float(PI) * float(i)) / float(segments);
mask.add_vertex(Vec3f(c.x() + r * std::cos(a), c.y() + r * std::sin(a), 0.0f));
}
for (int i = 0; i < segments; ++i) {
const unsigned int i1 = 1 + i;
const unsigned int i2 = 1 + ((i + 1) % segments);
mask.add_triangle(0, i1, i2);
}
}
if (mask.vertices_count() > 0 && mask.indices_count() > 0) {
plate_mask.init_from(std::move(mask));
flat->set_uniform("view_model_matrix", camera.get_view_matrix());
plate_mask.render(flat);
}
flat->stop_using();
}
}
glsafe(::glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
glsafe(::glDisable(GL_DEPTH_TEST));
glsafe(::glStencilMask(0x00));
glsafe(::glStencilFunc(GL_NOTEQUAL, 1, 0xFF));
glsafe(::glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
shader->start_using();
shader->set_uniform("view_model_matrix", Transform3d::Identity());
shader->set_uniform("projection_matrix", Transform3d::Identity());
shader->set_uniform("color_texture", 0);
shader->set_uniform("depth_texture", 1);
shader->set_uniform("inv_tex_size", Vec2f(1.0f / static_cast<float>(width), 1.0f / static_cast<float>(height)));
shader->set_uniform("z_near", camera.get_near_z());
shader->set_uniform("z_far", camera.get_far_z());
// The shader reconstructs the surface normal from the depth buffer, there being no normal
// target to read: it unprojects a pixel back into view space, then measures the result
// against world +Z expressed in view space to tell a top surface from a wall.
const Matrix4d inv_projection_matrix = camera.get_projection_matrix().matrix().inverse();
shader->set_uniform("inv_projection_matrix", inv_projection_matrix);
const Vec3d up_view = (camera.get_view_matrix().matrix().block<3, 3>(0, 0) * Vec3d::UnitZ()).normalized();
shader->set_uniform("up_view", up_view);
glsafe(::glActiveTexture(GL_TEXTURE0));
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_color_texture_id));
@@ -7903,13 +7867,6 @@ void GLCanvas3D::_render_ssao_pass(unsigned int width, unsigned int height)
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
shader->stop_using();
if (!prev_stencil_test)
glsafe(::glDisable(GL_STENCIL_TEST));
glsafe(::glStencilMask(prev_stencil_mask));
glsafe(::glColorMask(prev_color_mask[0], prev_color_mask[1], prev_color_mask[2], prev_color_mask[3]));
glsafe(::glDepthMask(prev_depth_mask));
glsafe(::glDepthFunc(prev_depth_func));
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
@@ -8154,15 +8111,19 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform
{
if (wxGetApp().app_config == nullptr)
return;
if (!wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE))
if (!_is_realistic_view_enabled())
return;
if (!wxGetApp().app_config->get_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS))
return;
if (m_volumes.empty())
return;
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader == nullptr)
// The preview canvas holds no volumes of its own for FFF. Once slicing has run its printed
// geometry is the G-code toolpaths, which both cast into the map here and sample it back in
// _render_gcode; before slicing there are only shells, and nothing casts at all. View3D and
// SLA preview use m_volumes. The shells are deliberately never casters: they are a
// translucent ghost of the whole object, so they would drop the solid shadow of a print that
// has not been sliced, and at any layer below the last, one that is not there yet.
const bool toolpath_casters = m_canvas_type == ECanvasType::CanvasPreview && m_gcode_viewer.has_data();
if (!toolpath_casters && m_volumes.empty())
return;
if (OpenGLManager::get_framebuffers_type() == OpenGLManager::EFramebufferType::Arb) {
@@ -8174,10 +8135,30 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform
// Bounding box of the printable objects (the shadow casters).
BoundingBoxf3 obj_bb;
for (const GLVolume* volume : m_volumes.volumes) {
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
continue;
obj_bb.merge(volume->transformed_bounding_box());
if (toolpath_casters) {
// Merged corner by corner: BoundingBoxf3(min, max) marks itself undefined at zero
// Z extent, which a single layer print gives, and the check below would then drop
// every shadow in the frame.
const BoundingBoxf3& paths_bb = m_gcode_viewer.get_paths_bounding_box();
if ((paths_bb.min.array() <= paths_bb.max.array()).all()) {
obj_bb.merge(paths_bb.min);
obj_bb.merge(paths_bb.max);
}
// Only the enabled layers are drawn, so fitting the map to the whole print wastes
// its depth range and makes contact shadows shift as the slider moves. The z = 0
// shadow is enclosed separately below, so the plate shadow is unaffected.
const std::vector<double> layer_zs = m_gcode_viewer.get_layers_zs();
if (!layer_zs.empty()) {
const size_t top = std::min<size_t>(m_gcode_viewer.get_layers_z_range()[1], layer_zs.size() - 1);
obj_bb.max.z() = std::max(obj_bb.min.z(), std::min(obj_bb.max.z(), layer_zs[top]));
}
}
else {
for (const GLVolume* volume : m_volumes.volumes) {
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
continue;
obj_bb.merge(volume->transformed_bounding_box());
}
}
if (!obj_bb.defined)
return; // no objects to cast shadows
@@ -8299,16 +8280,21 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform
glsafe(::glPolygonOffset(4.0f, 4.0f));
glsafe(::glDisable(GL_CULL_FACE));
shader->start_using();
shader->set_uniform("projection_matrix", Transform3d(light_proj));
for (GLVolume* volume : m_volumes.volumes) {
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
continue;
const Transform3d view_model = Transform3d(light_view) * volume->world_matrix();
shader->set_uniform("view_model_matrix", view_model);
volume->model.render(shader);
if (toolpath_casters)
m_gcode_viewer.render_shadow_casters(Transform3d(light_view), Transform3d(light_proj), eye);
// Only this branch draws through "flat"; the toolpaths bring their own program.
else if (GLShaderProgram* shader = wxGetApp().get_shader("flat"); shader != nullptr) {
shader->start_using();
shader->set_uniform("projection_matrix", Transform3d(light_proj));
for (GLVolume* volume : m_volumes.volumes) {
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
continue;
const Transform3d view_model = Transform3d(light_view) * volume->world_matrix();
shader->set_uniform("view_model_matrix", view_model);
volume->model.render(shader);
}
shader->stop_using();
}
shader->stop_using();
// Restore state
glsafe(::glDisable(GL_POLYGON_OFFSET_FILL));
@@ -8517,7 +8503,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
return;
}
const bool realistic_mode = wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE);
const bool realistic_mode = _is_realistic_view_enabled();
const bool realistic_phong = wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_PHONG);
const std::string shader_name = (realistic_mode && realistic_phong) ? "phong" : "gouraud";
GLShaderProgram* shader = wxGetApp().get_shader(shader_name);
@@ -8741,7 +8727,34 @@ void GLCanvas3D::_render_wireframe_overlay()
//BBS: GUI refactor: add canvas size as parameters
void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height)
{
// Realistic view: the toolpaths receive the same depth map they were rendered into by
// _render_shadows, which is what gives them object-on-object and self shadows. Intensity 0
// short-circuits the lookup in the shader, so this is inert whenever the map is missing.
const bool receive_shadows = m_shadow_map_valid && m_shadow_map_texture_id != 0 && m_shadow_map_size != 0;
if (receive_shadows) {
glsafe(::glActiveTexture(GL_TEXTURE4));
glsafe(::glBindTexture(GL_TEXTURE_2D, m_shadow_map_texture_id));
glsafe(::glActiveTexture(GL_TEXTURE0));
m_gcode_viewer.set_shadow_map(4, m_shadow_light_vp, 0.35f, 1.0f / static_cast<float>(m_shadow_map_size));
}
else
m_gcode_viewer.set_shadow_map(4, Transform3d::Identity(), 0.0f, 0.0f);
// The lighting term leaves the print dimmer and duller than the legend colours. Saturation
// pays back the duller half in both modes; brightness only where something takes light off
// again - realistic view with at least one lossy pass on - else the lift would just clip.
const AppConfig* cfg = wxGetApp().app_config;
const bool lossy_passes = cfg != nullptr && _is_realistic_view_enabled() &&
(cfg->get_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS) || cfg->get_bool(SETTING_OPENGL_PHONG_SSAO));
m_gcode_viewer.set_tone(lossy_passes ? 1.1f : 1.0f, 1.15f);
m_gcode_viewer.render_scene(canvas_width, canvas_height);
if (receive_shadows) {
glsafe(::glActiveTexture(GL_TEXTURE4));
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
glsafe(::glActiveTexture(GL_TEXTURE0));
}
}
void GLCanvas3D::_render_gcode_overlay(int canvas_width, int canvas_height)
@@ -9831,7 +9844,7 @@ void GLCanvas3D::_render_canvas_toolbar()
);
create_menu_item( _utf8(L("Realistic View")),
m_canvas_type != ECanvasType::CanvasPreview, // not work on preview
true, // work on all
cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE),
[&cfg]{
cfg->set_bool(SETTING_OPENGL_REALISTIC_MODE, !cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE));
+1
View File
@@ -1324,6 +1324,7 @@ private:
void _picking_pass();
void _rectangular_selection_picking_pass();
bool _is_fxaa_enabled() const;
bool _is_realistic_view_enabled() const;
bool _is_ssao_enabled() const;
int _get_effective_fps_cap() const;
bool _is_fps_overlay_enabled() const;
+8
View File
@@ -2182,6 +2182,8 @@ void GUI_App::init_networking_callbacks()
obj->command_get_access_code();
if (m_agent)
m_agent->install_device_cert(obj->get_dev_id(), obj->is_lan_mode_printer());
obj->set_online_state(true);
}
});
});
@@ -2220,6 +2222,8 @@ void GUI_App::init_networking_callbacks()
obj->command_get_version();
event.SetInt(0);
event.SetString(obj->get_dev_id());
obj->set_online_state(true);
} else if (state == ConnectStatus::ConnectStatusFailed) {
// Orca: only update status if same device id
if (m_device_manager->selected_machine != dev_id) return;
@@ -2235,10 +2239,14 @@ void GUI_App::init_networking_callbacks()
wxGetApp().show_dialog(text);
}
event.SetInt(-1);
obj->set_online_state(false);
} else if (state == ConnectStatus::ConnectStatusLost) {
m_device_manager->set_selected_machine("");
event.SetInt(-1);
BOOST_LOG_TRIVIAL(info) << "set_on_local_connect_fn: state = lost";
obj->set_online_state(false);
} else {
event.SetInt(-1);
BOOST_LOG_TRIVIAL(info) << "set_on_local_connect_fn: state = " << state;
+39 -1
View File
@@ -1,5 +1,6 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/LifecycleEvents.hpp"
#include "GUI_ObjectList.hpp"
#include "GUI_Factories.hpp"
//#include "GUI_ObjectLayers.hpp"
@@ -10,6 +11,7 @@
#include "BitmapComboBox.hpp"
#include "MainFrame.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "OptionsGroup.hpp"
#include "Tab.hpp"
@@ -1159,17 +1161,39 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const
if (m_objects_model->GetItemType(item) & itObject) {
std::string name = m_objects_model->GetName(item).ToUTF8().data();
if (obj->name != name) {
const std::string previous_name = obj->name;
obj->name = name;
// if object has just one volume, rename this volume too
if (obj->volumes.size() == 1)
obj->volumes[0]->name = obj->name;
Slic3r::save_object_mesh(*obj);
LifecycleEventContext ctx;
ctx.name = name;
ctx.previous_name = previous_name;
ctx.id = std::to_string(obj->id().id);
ctx.index = obj_idx;
ctx.source = "object";
fire_lifecycle_event(LifecycleEvent::ObjectRenamed, ctx);
}
return;
}
if (volume_id < 0) return;
obj->volumes[volume_id]->name = m_objects_model->GetName(item).ToUTF8().data();
std::string name = m_objects_model->GetName(item).ToUTF8().data();
if (obj->volumes[volume_id]->name == name)
return;
const std::string previous_name = obj->volumes[volume_id]->name;
obj->volumes[volume_id]->name = name;
LifecycleEventContext ctx;
ctx.name = name;
ctx.previous_name = previous_name;
ctx.id = std::to_string(obj->volumes[volume_id]->id().id);
ctx.index = volume_id;
ctx.source = "volume";
fire_lifecycle_event(LifecycleEvent::ObjectRenamed, ctx);
}
void ObjectList::update_name_in_list(int obj_idx, int vol_idx) const
@@ -3519,7 +3543,14 @@ void ObjectList::delete_all_connectors_for_object(int obj_idx)
obj->delete_connectors();
if (obj->volumes.empty() || !obj->has_solid_mesh()) {
const std::string deleted_obj_name = obj->name;
model.delete_object(idx);
{
Slic3r::LifecycleEventContext ctx;
ctx.name = deleted_obj_name;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectDeleted, ctx);
}
m_objects_model->Delete(m_objects_model->GetItemById(idx));
continue;
}
@@ -4088,6 +4119,13 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed,
const auto item = m_objects_model->AddObject(model_object, warning_bitmap, model_object->is_cut());
Expand(m_objects_model->GetParent(item));
{
Slic3r::LifecycleEventContext ctx;
ctx.name = model_object->name;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectAdded, ctx);
}
if (!do_info_update)
return;
+8
View File
@@ -13,6 +13,7 @@
#include "slic3r/GUI/NotificationManager.hpp"
#include "slic3r/GUI/format.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "libnest2d/common.hpp"
@@ -698,6 +699,13 @@ void ArrangeJob::finalize(bool canceled, std::exception_ptr &eptr) {
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":arrange m_unprintable: name: %4%, bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name;
}
{
Slic3r::LifecycleEventContext ctx;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
ctx.msg = "arranged";
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
}
m_plater->update();
// BBS
//wxGetApp().obj_manipul()->set_dirty();
+8
View File
@@ -6,6 +6,7 @@
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "libnest2d/common.hpp"
#include <numeric>
@@ -347,6 +348,13 @@ void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
m_plater->arrange();
}
m_plater->update();
{
Slic3r::LifecycleEventContext ctx;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
ctx.msg = "arranged";
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
}
}
m_plater->mark_plate_toolbar_image_dirty();
+7
View File
@@ -5,6 +5,7 @@
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/NotificationManager.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "libslic3r/PresetBundle.hpp"
@@ -254,6 +255,12 @@ void OrientJob::finalize(bool canceled, std::exception_ptr &eptr)
mesh.apply();
}
if (!m_selected.empty()) {
Slic3r::LifecycleEventContext ctx;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
ctx.msg = "auto_oriented";
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
}
m_plater->update();
+39 -4
View File
@@ -1,4 +1,5 @@
#include "PrintJob.hpp"
#include "libslic3r/LifecycleEvents.hpp"
#include "libslic3r/MTUtils.hpp"
#include "libslic3r/Model.hpp"
#include "libslic3r/PresetBundle.hpp"
@@ -152,6 +153,18 @@ void PrintJob::process(Ctl &ctl)
int result = -1;
std::string http_body;
const auto mark_lifecycle_started = [this]() {
if (m_lifecycle_started)
return;
LifecycleEventContext start_ctx;
start_ctx.name = m_project_name;
start_ctx.device_id = m_dev_id;
start_ctx.source = "print_job";
fire_lifecycle_event(LifecycleEvent::PrintJobStarted, start_ctx);
m_lifecycle_started = true;
};
int total_plate_num = plate_data.plate_count;
if (!plate_data.is_valid) {
total_plate_num = m_plater->get_partplate_list().get_plate_count();
@@ -173,7 +186,7 @@ void PrintJob::process(Ctl &ctl)
}
}
m_project_name = truncate_string(m_project_name, 100);
const std::string transport_project_name = truncate_string(m_project_name, 100);
int curr_plate_idx = 0;
if (m_print_type == "from_normal") {
@@ -372,11 +385,11 @@ void PrintJob::process(Ctl &ctl)
}
}
if (params.preset_name.empty() && m_print_type == "from_normal") { params.preset_name = wxString::Format("%s_plate_%d", m_project_name, curr_plate_idx).ToStdString(); }
if (params.project_name.empty()) {params.project_name = m_project_name;}
if (params.preset_name.empty() && m_print_type == "from_normal") { params.preset_name = wxString::Format("%s_plate_%d", transport_project_name, curr_plate_idx).ToStdString(); }
if (params.project_name.empty()) {params.project_name = transport_project_name;}
if (m_is_calibration_task) {
params.project_name = m_project_name;
params.project_name = transport_project_name;
params.origin_model_id = "";
}
@@ -543,6 +556,7 @@ void PrintJob::process(Ctl &ctl)
if (m_print_type == "from_sdcard_view") {
BOOST_LOG_TRIVIAL(info) << "print_job: try to send with cloud, model is sdcard view";
ctl.update_status(curr_percent, _u8L("Sending print job through cloud service"));
mark_lifecycle_started();
result = m_agent->start_sdcard_print(params, update_fn, cancel_fn);
} else if (params.connection_type != "lan") {
if (params.dev_ip.empty())
@@ -566,6 +580,7 @@ void PrintJob::process(Ctl &ctl)
BOOST_LOG_TRIVIAL(info) << "print_job: use ftp send print only";
ctl.update_status(curr_percent, _u8L("Sending print job over LAN"));
is_try_lan_mode = true;
mark_lifecycle_started();
result = m_agent->start_local_print_with_record(params, update_fn, cancel_fn, wait_fn);
if (result < 0) {
error_text = wxString::Format(_L("Access code:%s IP address:%s"), params.password, params.dev_ip);
@@ -582,6 +597,7 @@ void PrintJob::process(Ctl &ctl)
// try to send local with record
BOOST_LOG_TRIVIAL(info) << "print_job: try to start local print with record";
ctl.update_status(curr_percent, _u8L("Sending print job over LAN"));
mark_lifecycle_started();
result = m_agent->start_local_print_with_record(params, update_fn, cancel_fn, wait_fn);
if (result == 0) {
params.comments = "";
@@ -597,18 +613,21 @@ void PrintJob::process(Ctl &ctl)
// try to send with cloud
BOOST_LOG_TRIVIAL(warning) << "print_job: try to send with cloud";
ctl.update_status(curr_percent, _u8L("Sending print job through cloud service"));
// Started was already emitted before the local attempt.
result = m_agent->start_print(params, update_fn, cancel_fn, wait_fn);
}
}
else {
BOOST_LOG_TRIVIAL(info) << "print_job: send with cloud";
ctl.update_status(curr_percent, _u8L("Sending print job through cloud service"));
mark_lifecycle_started();
result = m_agent->start_print(params, update_fn, cancel_fn, wait_fn);
}
}
} else {
if (this->could_emmc_print) {
ctl.update_status(curr_percent, _u8L("Sending print job over LAN"));
mark_lifecycle_started();
result = m_agent->start_local_print(params, update_fn, cancel_fn);
} else {
switch(this->sdcard_state) {
@@ -619,6 +638,7 @@ void PrintJob::process(Ctl &ctl)
if(this->has_sdcard) {
// means the storage is abnormal but can be used option is enabled
ctl.update_status(curr_percent, _u8L("Sending print job over LAN, but the Storage in the printer is abnormal and print-issues may be caused by this."));
mark_lifecycle_started();
result = m_agent->start_local_print(params, update_fn, cancel_fn);
break;
}
@@ -629,6 +649,7 @@ void PrintJob::process(Ctl &ctl)
return;
case DevStorage::SdcardState::HAS_SDCARD_NORMAL:
ctl.update_status(curr_percent, _u8L("Sending print job over LAN"));
mark_lifecycle_started();
result = m_agent->start_local_print(params, update_fn, cancel_fn);
break;
default:
@@ -686,6 +707,7 @@ void PrintJob::process(Ctl &ctl)
}
wxQueueEvent(m_plater, evt);
m_job_finished = true;
m_lifecycle_success = true;
}
}
@@ -698,6 +720,19 @@ void PrintJob::finalize(bool canceled, std::exception_ptr &eptr) {
eptr = std::current_exception();
}
if (m_lifecycle_started && !m_lifecycle_finished) {
LifecycleEventContext finish_ctx;
finish_ctx.name = m_project_name;
finish_ctx.device_id = m_dev_id;
finish_ctx.source = "print_job";
finish_ctx.code = canceled ? LifecycleEvtCode::Warn :
(eptr || !m_lifecycle_success ? LifecycleEvtCode::Error : LifecycleEvtCode::Ok);
finish_ctx.msg = canceled ? "cancelled" : (eptr ? "exception" :
(m_lifecycle_success ? "" : "failed"));
fire_lifecycle_event(LifecycleEvent::PrintJobFinished, finish_ctx);
m_lifecycle_finished = true;
}
if (canceled || eptr)
return;
}
+3
View File
@@ -43,6 +43,9 @@ class PrintJob : public Job
std::function<void()> m_success_fun{nullptr};
std::string m_dev_id;
bool m_job_finished{ false };
bool m_lifecycle_started{ false };
bool m_lifecycle_finished{ false };
bool m_lifecycle_success{ false };
int m_print_job_completed_id = 0;
wxString m_completed_evt_data;
std::function<void()> m_enter_ip_address_fun_fail{ nullptr };
+21
View File
@@ -1,4 +1,5 @@
#include "SendJob.hpp"
#include "libslic3r/LifecycleEvents.hpp"
#include "slic3r/GUI/I18N.hpp"
#include "slic3r/Utils/NetworkAgent.hpp"
#include "libslic3r/MTUtils.hpp"
@@ -148,6 +149,13 @@ void SendJob::process(Ctl &ctl)
}
}
LifecycleEventContext start_ctx;
start_ctx.name = m_project_name;
start_ctx.device_id = m_dev_id;
start_ctx.source = "send_job";
fire_lifecycle_event(LifecycleEvent::SendJobStarted, start_ctx);
m_lifecycle_started = true;
int total_plate_num = m_plater->get_partplate_list().get_plate_count();
PartPlate* plate = m_plater->get_partplate_list().get_plate(job_data.plate_idx);
@@ -424,6 +432,19 @@ void SendJob::finalize(bool canceled, std::exception_ptr &eptr)
eptr = std::current_exception();
}
if (m_lifecycle_started && !m_lifecycle_finished) {
LifecycleEventContext finish_ctx;
finish_ctx.name = m_project_name;
finish_ctx.device_id = m_dev_id;
finish_ctx.source = "send_job";
finish_ctx.code = canceled ? LifecycleEvtCode::Warn :
(eptr ? LifecycleEvtCode::Error : (m_job_finished ? LifecycleEvtCode::Ok : LifecycleEvtCode::Error));
finish_ctx.msg = canceled ? "cancelled" : (eptr ? "exception" :
(m_job_finished ? "" : "failed"));
fire_lifecycle_event(LifecycleEvent::SendJobFinished, finish_ctx);
m_lifecycle_finished = true;
}
if (canceled || eptr)
return;
}
+2
View File
@@ -22,6 +22,8 @@ class SendJob : public Job
PrintPrepareData job_data;
std::string m_dev_id;
bool m_job_finished{ false };
bool m_lifecycle_started{ false };
bool m_lifecycle_finished{ false };
int m_print_job_completed_id = 0;
bool m_is_check_mode{false};
bool m_check_and_continue{false};
+34 -1
View File
@@ -29,6 +29,7 @@
#include "libslic3r/Tesselate.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp"
#include "libslic3r/Utils.hpp"
#include "libslic3r/LifecycleEvents.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
@@ -2626,11 +2627,20 @@ void PartPlate::set_plate_name(const std::string& name)
if (boost::equals(m_name, name))
return;
const std::string previous_name = m_name;
m_name = name;
if (m_print != nullptr)
m_print->set_plate_name(name);
invalidate_plate_name_texture();
if (m_plater != nullptr && !m_plater->is_loading_project()) {
LifecycleEventContext ctx;
ctx.name = name;
ctx.previous_name = previous_name;
ctx.index = m_plate_index;
fire_lifecycle_event(LifecycleEvent::PlateRenamed, ctx);
}
}
//get the print's object, result and index
@@ -4741,9 +4751,16 @@ int PartPlateList::create_plate(bool adjust_position)
if (m_plater) {
// In GUI mode
wxGetApp().obj_list()->on_plate_added(plate);
wxGetApp().obj_list()->on_plate_added(plate);
}
if (m_plater != nullptr && m_intialized && !m_plater->is_loading_project()) {
LifecycleEventContext ctx;
ctx.name = plate->get_plate_name();
ctx.index = new_index;
fire_lifecycle_event(LifecycleEvent::PlateCreated, ctx);
}
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":created a new plate %1%") % new_index;
return new_index;
}
@@ -4842,6 +4859,7 @@ int PartPlateList::delete_plate(int index)
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":plate %1%, has an invalid index %2%") % index % plate->get_index();
return -1;
}
const std::string plate_name = plate->get_plate_name();
if (m_plater) {
// In GUI mode
@@ -4924,6 +4942,13 @@ int PartPlateList::delete_plate(int index)
delete plate;
if (m_plater != nullptr && m_intialized && !m_plater->is_loading_project()) {
LifecycleEventContext ctx;
ctx.name = plate_name;
ctx.index = index;
fire_lifecycle_event(LifecycleEvent::PlateDeleted, ctx);
}
// FIX: context of BackgroundSliceProcess and gcode preview need to be updated before ObjectList::reload_all_plates().
#if 0
if (m_plater != nullptr) {
@@ -5032,6 +5057,7 @@ int PartPlateList::select_plate(int index)
if (m_plate_list.empty() || index >= m_plate_list.size()) {
return -1;
}
const int previous_index = m_current_plate;
// BBS: erase unnecessary snapshot
if (get_curr_plate_index() != index && m_intialized) {
@@ -5058,6 +5084,13 @@ int PartPlateList::select_plate(int index)
//wxQueueEvent(m_plater, new SimpleEvent(EVT_GLCANVAS_PLATE_SELECT));
}
if (previous_index != index && m_intialized && m_plater != nullptr && !m_plater->is_loading_project()) {
LifecycleEventContext ctx;
ctx.name = m_plate_list[index]->get_plate_name();
ctx.index = index;
fire_lifecycle_event(LifecycleEvent::PlateSelected, ctx);
}
return 0;
}
+105 -13
View File
@@ -57,6 +57,7 @@
#include <wx/aui/aui.h>
#include "libslic3r/libslic3r.h"
#include "libslic3r/LifecycleEvents.hpp"
#include "libslic3r/Format/STL.hpp"
#include "libslic3r/Format/DRC.hpp"
#include "libslic3r/Format/STEP.hpp"
@@ -10271,7 +10272,14 @@ void Plater::priv::remove(size_t obj_idx)
view3D->enable_layers_editing(false);
m_worker.cancel_all();
std::string obj_name = (obj_idx < model.objects.size()) ? model.objects[obj_idx]->name : std::to_string(obj_idx);
model.delete_object(obj_idx);
{
Slic3r::LifecycleEventContext ctx;
ctx.name = obj_name;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectDeleted, ctx);
}
//BBS: notify partplate the instance removed
partplate_list.notify_instance_removed(obj_idx, -1);
update();
@@ -10304,7 +10312,14 @@ bool Plater::priv::delete_object_from_model(size_t obj_idx, bool refresh_immedia
if (obj->is_cut())
sidebar->obj_list()->invalidate_cut_info_for_object(obj_idx);
std::string obj_name = obj->name;
model.delete_object(obj_idx);
{
Slic3r::LifecycleEventContext ctx;
ctx.name = obj_name;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectDeleted, ctx);
}
//BBS: notify partplate the instance removed
partplate_list.notify_instance_removed(obj_idx, -1);
@@ -10350,10 +10365,22 @@ void Plater::priv::delete_all_objects_from_model()
void Plater::priv::reset(bool apply_presets_change)
{
// TakeSnapshot below and load_current_presets() further down each re-evaluate the
// aggregate dirty flag against a baseline that hasn't been reset yet, so they can toggle
// is_dirty() back and forth several times before it settles; coalesce those into one event.
ProjectDirtyStateManager::NotificationSuppressor dirty_notify_suppressor(dirty_state);
Plater::TakeSnapshot snapshot(q, _u8L("Reset Project"), UndoRedo::SnapshotType::ProjectSeparator);
clear_warnings();
const std::string closed_project_name = into_u8(get_project_filename());
if (!closed_project_name.empty() || !model.objects.empty()) {
Slic3r::LifecycleEventContext ctx;
ctx.name = closed_project_name;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ProjectClosed, ctx);
}
// A new project must not inherit the previous project's published selection (Feature A/B).
m_has_pending_published = false;
m_pending_published_keys.clear();
@@ -12781,11 +12808,15 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
notification_manager->set_slicing_progress_export_possible();
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
const std::string lifecycle_job_name = this->background_process.fff_print() ?
this->background_process.fff_print()->output_filename() : std::string();
this->background_process.reset_export();
// This bool stops showing export finished notification even when process_completed_with_error is false
bool has_error = false;
std::string lifecycle_error_msg;
if (evt.error()) {
auto message = evt.format_error_message();
lifecycle_error_msg = message.first;
if (evt.critical_error()) {
if (q->m_tracking_popup_menu) {
// We don't want to pop-up a message box when tracking a pop-up menu.
@@ -12823,6 +12854,14 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
is_finished = true;
}
{
Slic3r::LifecycleEventContext ctx;
ctx.name = lifecycle_job_name;
ctx.code = evt.cancelled() ? Slic3r::LifecycleEvtCode::Warn : (has_error ? Slic3r::LifecycleEvtCode::Error : Slic3r::LifecycleEvtCode::Ok);
ctx.msg = evt.cancelled() ? "cancelled" : (has_error ? lifecycle_error_msg : std::string());
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::SlicingJobComplete, ctx);
}
//BBS: set the current plater's slice result to valid
if (!this->background_process.empty())
this->background_process.get_current_plate()->update_slice_result_valid_state(evt.success());
@@ -15356,21 +15395,33 @@ int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_
//get_partplate_list().reinit();
//get_partplate_list().update_slice_context_to_current_plate(p->background_process);
//p->preview->update_gcode_result(p->partplate_list.get_current_slice_result());
reset(transfer_preset_changes);
reset_project_dirty_after_save();
reset_project_dirty_initial_presets();
wxGetApp().update_saved_preset_from_current_preset();
update_project_dirty_from_presets();
if (!silent) {
Slic3r::LifecycleEventContext ctx;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::NewProject, ctx);
}
{
// Same rationale as in Plater::priv::reset(): the whole reset + preset-reload +
// baseline-reset sequence below settles into its final dirty state only once it
// completes, so hold notifications until then to avoid firing on transient flips.
ProjectDirtyStateManager::NotificationSuppressor dirty_notify_suppressor(p->dirty_state);
//reset project
p->project.reset();
//set project name
if (project_name.empty())
p->set_project_name(_L("Untitled"));
else
p->set_project_name(project_name);
reset(transfer_preset_changes);
reset_project_dirty_after_save();
reset_project_dirty_initial_presets();
wxGetApp().update_saved_preset_from_current_preset();
update_project_dirty_from_presets();
Plater::TakeSnapshot snapshot(this, "New Project", UndoRedo::SnapshotType::ProjectSeparator);
//reset project
p->project.reset();
//set project name
if (project_name.empty())
p->set_project_name(_L("Untitled"));
else
p->set_project_name(project_name);
Plater::TakeSnapshot snapshot(this, "New Project", UndoRedo::SnapshotType::ProjectSeparator);
}
Model m;
model().load_from(m); // new id avoid same path name
@@ -15488,6 +15539,13 @@ void Plater::load_project(wxString const& filename2,
p->set_project_name(_L("Untitled"));
}
{
Slic3r::LifecycleEventContext ctx;
ctx.name = into_u8(load_restore ? originfile : filename);
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ProjectOpened, ctx);
}
} else {
if (using_exported_file()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " using ecported set project filename: " << filename;
@@ -15559,11 +15617,23 @@ int Plater::save_project(bool saveAs)
if (full_pathnames) {
save_strategy = save_strategy | SaveStrategy::FullPathSources;
}
{
Slic3r::LifecycleEventContext ctx;
ctx.name = into_u8(filename);
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ProjectBeforeSave, ctx);
}
if (export_3mf(into_path(filename), save_strategy) < 0) {
MessageDialog(this, _L("Failed to save the project.\nPlease check whether the folder exists online or if other programs have the project file open."),
_L("Save project"), wxOK | wxICON_WARNING).ShowModal();
return wxID_CANCEL;
}
{
Slic3r::LifecycleEventContext ctx;
ctx.name = into_u8(filename);
ctx.code = Slic3r::LifecycleEvtCode::Ok;
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ProjectAfterSave, ctx);
}
Slic3r::remove_backup(model(), false);
@@ -20896,6 +20966,14 @@ void Plater::changed_object(ModelObject &object){
// Check outside bed
get_current_canvas3D()->requires_check_outside_state();
if (!is_loading_project()) {
LifecycleEventContext ctx;
ctx.name = object.name;
ctx.id = std::to_string(object.id().id);
ctx.source = "geometry";
fire_lifecycle_event(LifecycleEvent::ObjectChanged, ctx);
}
}
void Plater::changed_object(int obj_idx)
@@ -20932,6 +21010,20 @@ void Plater::changed_objects(const std::vector<size_t>& object_idxs)
// update print
this->p->schedule_background_process();
if (!is_loading_project()) {
for (size_t obj_idx : object_idxs) {
if (obj_idx >= p->model.objects.size() || p->model.objects[obj_idx] == nullptr)
continue;
LifecycleEventContext ctx;
ctx.name = p->model.objects[obj_idx]->name;
ctx.id = std::to_string(p->model.objects[obj_idx]->id().id);
ctx.index = static_cast<int>(obj_idx);
ctx.source = "geometry";
fire_lifecycle_event(LifecycleEvent::ObjectChanged, ctx);
}
}
}
void Plater::schedule_background_process(bool schedule/* = true*/)
+26
View File
@@ -1932,6 +1932,15 @@ void PreferencesDialog::create_items()
);
g_sizer->Add(item_realistic_phong);
auto item_realistic_preview = create_item_checkbox(
_L("Enable in Preview"),
_L("Also applies realistic view to the Preview canvas, not just Prepare.\n"
"Preview draws the full toolpath geometry, so shadows and SSAO cost considerably"
" more there than on a plain model."),
SETTING_OPENGL_REALISTIC_PREVIEW
);
g_sizer->Add(item_realistic_preview);
auto item_realistic_ssao = create_item_checkbox(
_L("SSAO ambient occlusion"),
_L("Applies SSAO in realistic view."),
@@ -2019,6 +2028,23 @@ void PreferencesDialog::create_items()
//// GRAPHICS > G-code Preview
g_sizer->Add(create_item_title(_L("G-code Preview")), 1, wxEXPAND);
// ORCA: view type the preview opens with
std::vector<wxString> PreviewViewTypeLabels;
std::vector<std::string> PreviewViewTypeValues;
for (const auto& [value, label] : GCodeViewer::default_view_type_choices()) {
PreviewViewTypeValues.push_back(value);
PreviewViewTypeLabels.push_back(from_u8(label));
}
auto item_preview_view_type = create_item_combobox(
_L("Default view type"),
_L("The color scheme the sliced preview opens with.\n"
"Automatic: Filament for multi material prints, Line Type for single material ones.\n"
"Last used: the view type you selected last.\n"
"Any other value always opens that view type.\n"
"You can still switch the view type in the preview afterwards."),
"preview_default_view_type", PreviewViewTypeLabels, PreviewViewTypeValues);
g_sizer->Add(item_preview_view_type);
auto item_dim_previous_layers = create_item_checkbox(
_L("Dim lower layers"),
_L("When scrubbing the layer slider in the sliced preview, render the layers below the current one darkened so that only the layer being viewed is shown at full brightness."),
+46 -1
View File
@@ -6,6 +6,7 @@
#include "MainFrame.hpp"
#include "I18N.hpp"
#include "Plater.hpp"
#include "libslic3r/LifecycleEvents.hpp"
#include <boost/algorithm/string/predicate.hpp>
@@ -17,13 +18,23 @@ namespace GUI {
void ProjectDirtyStateManager::update_from_undo_redo_stack(bool dirty)
{
const bool was_dirty = is_dirty();
m_plater_dirty = dirty;
notify_dirty_change(was_dirty, "undo_redo");
if (const Plater *plater = wxGetApp().plater(); plater && wxGetApp().initialized())
wxGetApp().mainframe->update_title();
}
void ProjectDirtyStateManager::set_plater_dirty(bool is_dirty)
{
const bool was_dirty = this->is_dirty();
m_plater_dirty = is_dirty;
notify_dirty_change(was_dirty, "plater");
}
void ProjectDirtyStateManager::update_from_presets()
{
const bool was_dirty = is_dirty();
m_presets_dirty = false;
// check switching of the presets only for exist/loaded project, but not for new
GUI_App &app = wxGetApp();
@@ -45,18 +56,53 @@ void ProjectDirtyStateManager::update_from_presets()
}
m_presets_dirty |= app.has_unsaved_preset_changes();
m_project_config_dirty = m_initial_project_config != app.preset_bundle->project_config;
notify_dirty_change(was_dirty, "presets");
app.mainframe->update_title();
}
void ProjectDirtyStateManager::reset_after_save()
{
const bool was_dirty = is_dirty();
this->reset_initial_presets();
m_plater_dirty = false;
m_presets_dirty = false;
m_project_config_dirty = false;
notify_dirty_change(was_dirty, "save");
wxGetApp().mainframe->update_title();
}
void ProjectDirtyStateManager::notify_dirty_change(bool was_dirty, const char *source)
{
if (m_suppress_depth > 0)
return;
const bool dirty = is_dirty();
if (was_dirty == dirty)
return;
LifecycleEventContext ctx;
ctx.code = LifecycleEvtCode::Ok;
ctx.dirty = dirty;
ctx.source = source;
fire_lifecycle_event(LifecycleEvent::ProjectDirtyChanged, ctx);
}
void ProjectDirtyStateManager::begin_suppress_notifications()
{
if (m_suppress_depth == 0)
m_suppress_entry_dirty = is_dirty();
++m_suppress_depth;
}
void ProjectDirtyStateManager::end_suppress_notifications()
{
assert(m_suppress_depth > 0);
if (m_suppress_depth > 0)
--m_suppress_depth;
if (m_suppress_depth == 0)
notify_dirty_change(m_suppress_entry_dirty, "batch");
}
void ProjectDirtyStateManager::reset_initial_presets()
{
m_initial_presets.fill(std::string{});
@@ -168,4 +214,3 @@ void ProjectDirtyStateManager::render_debug_window() const
} // namespace GUI
} // namespace Slic3r
+22 -1
View File
@@ -14,21 +14,42 @@ public:
void reset_after_save();
void reset_initial_presets();
void set_plater_dirty(bool is_dirty) { m_plater_dirty = is_dirty; }
void set_plater_dirty(bool is_dirty);
bool is_dirty() const { return m_plater_dirty || m_project_config_dirty || m_presets_dirty; }
bool is_presets_dirty() const { return m_presets_dirty; }
// RAII guard coalescing dirty-state updates: while any guard is alive, ProjectDirtyChanged
// notifications are held back; when the outermost guard is destroyed, at most one
// notification fires, reflecting only the net change across the whole guarded scope.
class NotificationSuppressor
{
public:
explicit NotificationSuppressor(ProjectDirtyStateManager &owner) : m_owner(owner) { m_owner.begin_suppress_notifications(); }
~NotificationSuppressor() { m_owner.end_suppress_notifications(); }
NotificationSuppressor(const NotificationSuppressor &) = delete;
NotificationSuppressor &operator=(const NotificationSuppressor &) = delete;
private:
ProjectDirtyStateManager &m_owner;
};
#if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
void render_debug_window() const;
#endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
private:
void notify_dirty_change(bool was_dirty, const char *source);
void begin_suppress_notifications();
void end_suppress_notifications();
// Does the Undo / Redo stack indicate the project is dirty?
bool m_plater_dirty { false };
// Do the presets indicate the project is dirty?
bool m_presets_dirty { false };
// Is the project config dirty?
bool m_project_config_dirty { false };
// NotificationSuppressor nesting depth and the dirty state observed when the outermost guard began.
int m_suppress_depth { 0 };
bool m_suppress_entry_dirty { false };
// Keeps track of preset names selected at the time of last project save.
std::array<std::string, Preset::TYPE_COUNT> m_initial_presets;
DynamicPrintConfig m_initial_project_config;
+15
View File
@@ -38,6 +38,7 @@
#include "slic3r/Utils/NetworkAgentFactory.hpp"
#include "slic3r/Utils/PresetUpdater.hpp"
#include "slic3r/plugin/PluginConfig.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "Plater.hpp"
#include "MainFrame.hpp"
#include "format.hpp"
@@ -6964,6 +6965,20 @@ bool Tab::select_preset(
}
load_current_preset();
{
Slic3r::LifecycleEventContext ctx;
ctx.name = preset_name;
ctx.code = Slic3r::LifecycleEvtCode::Ok;
switch (m_type) {
case Preset::TYPE_PRINT: ctx.msg = "print"; break;
case Preset::TYPE_SLA_PRINT: ctx.msg = "sla_print"; break;
case Preset::TYPE_FILAMENT: ctx.msg = "filament"; break;
case Preset::TYPE_SLA_MATERIAL: ctx.msg = "sla_material"; break;
case Preset::TYPE_PRINTER: ctx.msg = "printer"; break;
default: break;
}
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::PresetSelected, ctx);
}
if (delete_third_printer) {
wxGetApp().CallAfter([filament_presets, process_presets]() {
+34 -4
View File
@@ -1,10 +1,13 @@
#include "TaskManager.hpp"
#include "libslic3r/Thread.hpp"
#include "libslic3r/LifecycleEvents.hpp"
#include "nlohmann/json.hpp"
#include "MainFrame.hpp"
#include "GUI_App.hpp"
#include <exception>
using namespace nlohmann;
namespace Slic3r {
@@ -214,17 +217,34 @@ int TaskManager::schedule(TaskStateInfo* task)
boost::thread* new_sending_thread = new boost::thread();
*new_sending_thread = Slic3r::create_thread(
[this, task] {
// Keep both lifecycle callbacks on this per-task worker thread. Plugin observers can
// therefore associate Started and Finished for one task with a single execution context.
LifecycleEventContext start_ctx;
start_ctx.name = task->params().project_name;
start_ctx.device_id = task->params().dev_id;
start_ctx.job_id = std::to_string(task->task_info_id);
start_ctx.source = "task_manager";
fire_lifecycle_event(LifecycleEvent::PrintJobStarted, start_ctx);
int result = -1;
if (!m_agent) {
BOOST_LOG_TRIVIAL(trace) << "task_manager: NetworkAgent is nullptr";
return;
}
assert(m_agent);
else {
assert(m_agent);
try {
// DEBUG FOR TEST
#if 0
int result = start_print_test(task->get_params(), task->update_status_fn, task->cancel_fn, task->wait_fn);
result = start_print_test(task->get_params(), task->update_status_fn, task->cancel_fn, task->wait_fn);
#else
int result = m_agent->start_print(task->get_params(), task->update_status_fn, task->cancel_fn, task->wait_fn);
result = m_agent->start_print(task->get_params(), task->update_status_fn, task->cancel_fn, task->wait_fn);
#endif
} catch (const std::exception& ex) {
BOOST_LOG_TRIVIAL(error) << "task_manager: start_print threw: " << ex.what();
} catch (...) {
BOOST_LOG_TRIVIAL(error) << "task_manager: start_print threw an unknown exception";
}
}
if (result == 0) {
last_sent_timestamp = std::chrono::system_clock::now();
task->set_sent_time(last_sent_timestamp);
@@ -237,6 +257,16 @@ int TaskManager::schedule(TaskStateInfo* task)
task->set_state(TaskState::TS_SEND_CANCELED);
}
}
LifecycleEventContext finish_ctx;
finish_ctx.name = task->params().project_name;
finish_ctx.device_id = task->params().dev_id;
finish_ctx.job_id = std::to_string(task->task_info_id);
finish_ctx.source = "task_manager";
finish_ctx.code = result == 0 ? LifecycleEvtCode::Ok :
(task->is_canceled() ? LifecycleEvtCode::Warn : LifecycleEvtCode::Error);
finish_ctx.msg = result == 0 ? "" : (task->is_canceled() ? "cancelled" : "failed");
fire_lifecycle_event(LifecycleEvent::PrintJobFinished, finish_ctx);
/* remove from sending task list */
m_scedule_mutex.lock();
+18
View File
@@ -24,6 +24,7 @@
#include "CrealityPrint.hpp"
#include "../GUI/PrintHostDialogs.hpp"
#include "../GUI/MainFrame.hpp"
#include "slic3r/plugin/PluginManager.hpp"
#include "Obico.hpp"
#include "Flashforge.hpp"
#include "SimplyPrint.hpp"
@@ -360,12 +361,29 @@ void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job)
{
emit_progress(0); // Indicate the upload is starting
// Captured before upload_data is moved into upload() below.
const std::string upload_filename = the_job.upload_data.source_path.filename().string();
{
LifecycleEventContext ctx;
ctx.name = upload_filename;
ctx.code = LifecycleEvtCode::Ok;
fire_lifecycle_event(LifecycleEvent::UploadStarted, ctx);
}
bool success = the_job.printhost->upload(std::move(the_job.upload_data),
[this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); },
[this](wxString error) { this->error_fn(std::move(error)); },
[this](wxString tag, wxString host) { this->info_fn(std::move(tag), std::move(host)); }
);
{
LifecycleEventContext ctx;
ctx.name = upload_filename;
ctx.code = success ? LifecycleEvtCode::Ok : LifecycleEvtCode::Error;
fire_lifecycle_event(LifecycleEvent::UploadFinished, ctx);
}
if (success) {
emit_progress(100);
if (the_job.switch_to_device_tab) {

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