87 lines
3.1 KiB
JavaScript
87 lines
3.1 KiB
JavaScript
"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;
|
|
}
|