()
| 5221 | // force exclude mode before seeding. setSelectionMode also clears |
| 5222 | // excludedFaces as a side effect, which is fine — we re-seed below. |
| 5223 | if (selectionMode) setSelectionMode(false); |
| 5224 | |
| 5225 | // Seed exclusion mask, exit any active painting/place/rotate modes. |
| 5226 | excludedFaces = new Set(opts.preExcludedFaces || []); |
| 5227 | precisionExcludedFaces = new Set(); |
| 5228 | exclusionTool = null; |
| 5229 | eraseMode = false; |
| 5230 | isPainting = false; |
| 5231 | if (placeOnFaceActive) togglePlaceOnFace(false); |
| 5232 | if (rotateActive) toggleRotateMode(false); |
| 5233 | rotateAngles = { x: 0, y: 0, z: 0 }; |
| 5234 | rotateXInput.value = '0'; rotateYInput.value = '0'; rotateZInput.value = '0'; |
| 5235 | exclBrushBtn.classList.remove('active'); |
| 5236 | exclBucketBtn.classList.remove('active'); |
| 5237 | exclBrushTypeRow.classList.add('hidden'); |
| 5238 | exclRadiusRow.classList.add('hidden'); |
| 5239 | exclThresholdRow.classList.add('hidden'); |
| 5240 | canvas.style.cursor = ''; |
| 5241 | setHoverPreview(null); |
| 5242 | _lastHoverTriIdx = -1; |
| 5243 | |
| 5244 | // Build adjacency for the new geometry (needed by brush/bucket tools and |
| 5245 | // by the exclusion overlay). |
| 5246 | const adjData = buildAdjacency(geometry); |
| 5247 | triangleAdjacency = adjData.adjacency; |
| 5248 | triangleCentroids = adjData.centroids; |
| 5249 | triangleFaceNormals = adjData.faceNormals; |
| 5250 | updateMeshDiagnostics(adjData, geometry.attributes.position.count / 3); |
| 5251 | |
| 5252 | // Refresh exclusion overlay using the new geometry + new mask. |
| 5253 | if (excludedFaces.size > 0) refreshExclusionOverlay(); |
| 5254 | else setExclusionOverlay(null); |
| 5255 | // A seeded post-bake mask means masking is actively in play (exclude mode |
| 5256 | // was forced above); no seed = back to the neutral default. |
| 5257 | maskModeChosen = excludedFaces.size > 0; |
| 5258 | updateMaskModeButtons(); |
| 5259 | const maskCount = excludedFaces.size; |
| 5260 | exclCount.textContent = maskCount === 0 |
| 5261 | ? t('excl.initExcluded') |
| 5262 | : (maskCount === 1 |
| 5263 | ? (selectionMode ? t('excl.faceSelected', { n: 1 }) : t('excl.faceExcluded', { n: 1 })) |
| 5264 | : (selectionMode ? t('excl.facesSelected', { n: maskCount }) : t('excl.facesExcluded', { n: maskCount }))); |
| 5265 | |
| 5266 | // Update mesh info display. |
| 5267 | triLimitWarning.classList.add('hidden'); |
| 5268 | const triCount = getTriangleCount(geometry); |
| 5269 | const mb = ((geometry.attributes.position.array.byteLength) / 1024 / 1024).toFixed(2); |
| 5270 | const sx = bounds.size.x.toFixed(2); |
| 5271 | const sy = bounds.size.y.toFixed(2); |
| 5272 | const sz = bounds.size.z.toFixed(2); |
no test coverage detected