From 95018e643b23c46020c41c32b1290e31d76eab46 Mon Sep 17 00:00:00 2001 From: Svornost <11434-svornost@users.noreply.gitgud.io> Date: Thu, 14 Jan 2021 14:34:00 -0800 Subject: [PATCH] Art infrastructure improvements 1. Reduce node iteration 2. Merge common sections of the Revamped and Deepmurk paths in SVGQueue 3. Pre-cache def IDs for replacement, and always replace the original IDs, not modified ones --- js/artInfrastructure.js | 114 ++++++++---------- .../vector_revamp/vectorRevampedArtControl.js | 12 +- 2 files changed, 58 insertions(+), 68 deletions(-) diff --git a/js/artInfrastructure.js b/js/artInfrastructure.js index 4d38db881ab..542d23b1510 100644 --- a/js/artInfrastructure.js +++ b/js/artInfrastructure.js @@ -1,3 +1,5 @@ +/** @typedef {Element & {defIDs?:Array<string>}} CachedElement */ + App.Art.cacheArtData = function() { /** @param {Element} node */ function removeBadNamespaces(node) { @@ -13,9 +15,28 @@ App.Art.cacheArtData = function() { } } + /** @param {CachedElement} node */ + function cacheDefIDs(node) { + for (const child of node.children) { + // Extract all filter IDs + if (child.nodeName === "defs") { + for (const defChild of child.children) { + if (defChild.nodeName === "filter") { + if (!node.defIDs) { + node.defIDs = [defChild.id]; + } else { + node.defIDs.push(defChild.id); + } + } + } + } + } + return node; + } + /** * @param {NodeListOf<Element>} imagePassages - * @returns {Map<string, Element>} + * @returns {Map<string, CachedElement>} */ function makeCache(imagePassages) { const dict = new Map(); @@ -26,7 +47,7 @@ App.Art.cacheArtData = function() { const svgData = atob(ip.innerHTML.replace(/data:image\/svg\+xml;base64,/, '')); div.innerHTML = svgData.trim(); removeBadNamespaces(div.children.item(0)); - dict.set(name, div.children.item(0)); + dict.set(name, cacheDefIDs(div.children.item(0))); } return dict; @@ -40,7 +61,7 @@ App.Art.cacheArtData = function() { App.Art.SvgQueue = class { /** * @param {{trigger:string, action:string, value:string}[]} transformRules - when a 'data-transform' attribute with value "trigger" is seen on an element, perform 'action' with 'value' - * @param {Map<string, Element>} cache + * @param {Map<string, CachedElement>} cache * @param {string} displayClass */ constructor(transformRules, cache, displayClass) { @@ -83,25 +104,32 @@ App.Art.SvgQueue = class { } } - /** Append IDs + /** Turn a single fixed ID into a unique one + * @param {string} id + * @param {number} rndID + */ + _makeUniqueID(id, rndID) { + return `${id}_rndID_${rndID}`; + } + + /** Append unique IDs to clip-path and filter references * @param {Element} node * @param {Array<string>} defIDs * @param {number} rndID */ _replaceIDs(node, defIDs, rndID) { - if (node.hasAttribute('clip-path')) { - let cp = node.getAttribute('clip-path').split(")", 1); - let cpID = cp[0].split("_rndID_", 1); - node.setAttribute('clip-path', `${cpID}_rndID_${rndID})`); - } - if (node.hasAttribute('style')) { - let st = node.getAttribute('style'); - if (st.search("filter") > -1) { + const cp = node.getAttribute('clip-path'); + if (cp) { + let cpID = cp.split(")", 1)[0]; + node.setAttribute('clip-path', this._makeUniqueID(cpID, rndID)); + } + const style = node.getAttribute('style'); + if (defIDs && style) { + if (style.search("filter") > -1) { + let st = style; for (const defID of defIDs) { - // Loop through all filter IDs and append the randum number to it - // Remove if another number is already in the ID - let origID = defID.split("_rndID_", 1); - st = st.split(defID).join(`${origID}_rndID_${rndID}`); + // Loop through all filter IDs and append the unique instance number to it + st = st.split(defID).join(this._makeUniqueID(defID, rndID)); } node.setAttribute('style', st); } @@ -113,8 +141,9 @@ App.Art.SvgQueue = class { /** add an SVG from the cache to the render queue * @param {string} id + * @param {number} [rndID] - optional unique ID which identifies this specific art instance to make internal defs link correctly */ - add(id) { + add(id, rndID) { const res = this._cache.get(id); let clones = []; if (!res) { @@ -123,54 +152,15 @@ App.Art.SvgQueue = class { } for (const srcNode of res.children) { const node = /** @type {Element} */ (srcNode.cloneNode(true)); - this._transform(node); - this._setclip(node); - let transformNodes = node.querySelectorAll('g[data-transform]'); - for (const child of transformNodes) { - this._transform(child); - } - let clipNodes = node.querySelectorAll('g[select_clip]'); - for (const child of clipNodes) { - this._setclip(child); - } - clones.push(node); - } - this._container.push({attrs: res.attributes, nodes: clones}); - } - - /** add an revamped SVG from the cache to the render queue - * @param {string} id - * @param {number} rndID - */ - addRevamped(id, rndID) { - const res = this._cache.get(id); - let defIDs = []; - let clones = []; - if (!res) { - console.error(`Missing art resource: ${id}`); - return; - } - for (const srcNode of res.children) { - // Extract all filter IDs - if (srcNode.nodeName === "defs") { - for (const defChild of srcNode.children) { - if (defChild.nodeName === "filter") { - defIDs.push(defChild.id); + if (rndID) { + if (node.nodeName === "defs") { + for (const defNode of node.children) { + defNode.setAttribute("id", this._makeUniqueID(defNode.id, rndID)); } + } else { + this._replaceIDs(node, res.defIDs, rndID); } } - } - for (const srcNode of res.children) { - if (srcNode.nodeName === "defs") { - for (const defNode of srcNode.children) { - defNode.setAttribute("id", `${defNode.id.split("_rndID_", 1)}_rndID_${rndID}`); - } - } else { - this._replaceIDs(srcNode, defIDs, rndID); - } - } - for (const srcNode of res.children) { - const node = /** @type {Element} */ (srcNode.cloneNode(true)); this._transform(node); this._setclip(node); let transformNodes = node.querySelectorAll('g[data-transform]'); diff --git a/src/art/vector_revamp/vectorRevampedArtControl.js b/src/art/vector_revamp/vectorRevampedArtControl.js index 360a0e73ff8..38dd0ca1d15 100644 --- a/src/art/vector_revamp/vectorRevampedArtControl.js +++ b/src/art/vector_revamp/vectorRevampedArtControl.js @@ -42,11 +42,11 @@ App.Art.revampedVectorArtElement = function(slave, displayClass) { style.innerHTML = styleCSS; res.appendChild(style); } - const randomID = Math.floor(Math.random() * 9007199254740991); + const randomID = Math.floor(Math.random() * 9007199254740991); const revampedVectorArtControl = new RevampedArtControl(displayClass, slave, V.seeVectorArtHighlights, V.showBodyMods, randomID); const layers = revampedVectorArtControl.Layers; // side effects are important, must fetch layers before getting transformRules (FIXME?) const svgQueue = new App.Art.SvgQueue(revampedVectorArtControl.transformRules, App.Data.Art.VectorRevamp, displayClass); - layers.forEach((l) => svgQueue.addRevamped(l,randomID)); + layers.forEach((l) => svgQueue.add(l, randomID)); res.appendChild(svgQueue.output()); return res; @@ -3555,11 +3555,11 @@ class RevampedArtControl { } else if (this.artSlave.boobs <= 1000) { // Medium 800 coorA = [[232.141, 722.456], [232.141, 722.456], [254.074, 686.660], [254.074, 686.660], [0, 0], [0, 0]]; - if (strap == 0) { coorA[0] = [238.961, 733.245]; } - if (strap == 2) { coorA[0] = [228.272, 716.336]; } + if (strap === 0) { coorA[0] = [238.961, 733.245]; } + if (strap === 2) { coorA[0] = [228.272, 716.336]; } coorB = [[355.529, 842.501], [355.529, 842.501], [334.522, 761.607], [334.522, 761.607], [0, 0], [0, 0]]; - if (strap == 0) { coorB[2] = [330.234, 767.086]; } - if (strap == 2) { coorB[2] = [336.955, 758.499]; } + if (strap === 0) { coorB[2] = [330.234, 767.086]; } + if (strap === 2) { coorB[2] = [336.955, 758.499]; } } else if (this.artSlave.boobs <= 2500) { // Medium 1500 } else if (this.artSlave.boobs < 15000) { -- GitLab