"use strict"; // Shared item rendering helpers. Field rendering stays in item_render_runtime.js. function segmentPathCacheKey(item, segments, extra = "") { const version = Number(item?._mechanicalShapeVersion || 0) || 0; const len = Array.isArray(segments) ? segments.length : 0; let h = len * 2654435761; if (Array.isArray(segments)) { const step = Math.max(1, Math.floor(len / 24)); for (let i = 0; i < len; i += step) { const seg = segments[i]; if (!Array.isArray(seg)) continue; for (let j = 0; j < 4; j += 1) { h ^= Math.round((Number(seg[j]) || 0) * 10) & 0xffff; h = Math.imul(h, 16777619); } } } return `${item?.type || ""}|${version}|${len}|${h >>> 0}|${extra}`; } function getSegmentPath(item, segments, extra = "") { if (typeof Path2D === "undefined" || !Array.isArray(segments)) return null; const key = segmentPathCacheKey(item, segments, extra); const cache = item._segmentRenderPathCache || (item._segmentRenderPathCache = Object.create(null)); if (cache.key === key && cache.path) return cache.path; const path = new Path2D(); for (const seg of segments) { if (!Array.isArray(seg) || seg.length < 4) continue; path.moveTo(Number(seg[0]) || 0, Number(seg[1]) || 0); path.lineTo(Number(seg[2]) || 0, Number(seg[3]) || 0); } cache.key = key; cache.path = path; return path; } function strokeSegments(ctx, item, segments, extra = "") { const path = getSegmentPath(item, segments, extra); if (path) { ctx.stroke(path); return; } ctx.beginPath(); for (const seg of segments || []) { if (!Array.isArray(seg) || seg.length < 4) continue; ctx.moveTo(Number(seg[0]) || 0, Number(seg[1]) || 0); ctx.lineTo(Number(seg[2]) || 0, Number(seg[3]) || 0); } ctx.stroke(); } function mechanicalRenderTier() { return window.TarinaiPerf.renderQualityTier(); } function itemShadowQualityTier() { return window.TarinaiPerf?.shadowQualityTier?.() || "high"; } function itemShadowsEnabled() { return itemShadowQualityTier() !== "off"; } function drawRopeParticlePath(ctx, particles, ox, oy) { if (!Array.isArray(particles) || particles.length < 2) return false; const tier = mechanicalRenderTier(); const stride = tier === "low" && particles.length > 10 ? 2 : 1; ctx.moveTo((Number(particles[0].x) || 0) - ox, (Number(particles[0].y) || 0) - oy); for (let i = stride; i < particles.length - 1; i += stride) { ctx.lineTo((Number(particles[i].x) || 0) - ox, (Number(particles[i].y) || 0) - oy); } const last = particles[particles.length - 1]; ctx.lineTo((Number(last.x) || 0) - ox, (Number(last.y) || 0) - oy); return true; } function drawRopeRuntimePath(ctx, particles, item, pb, ax, ay, bx, by) { if (particles && drawRopeParticlePath(ctx, particles, item.x, item.y)) return true; const midX = Number(pb?.linkScalar?.(item, "midX", NaN)); const midY = Number(pb?.linkScalar?.(item, "midY", NaN)); const mx = Number.isFinite(midX) ? midX - item.x : (ax + bx) * 0.5; const my = Number.isFinite(midY) ? midY - item.y : (ay + by) * 0.5; ctx.moveTo(ax, ay); ctx.quadraticCurveTo(mx, my, bx, by); return true; }