@forgeax/engine-preview 0.1.31 → 0.1.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -628,7 +628,12 @@ function inspectMaterialSubject(input) {
628
628
  }
629
629
  );
630
630
  }
631
- const first = passes[0];
631
+ const first = passes.find((pass) => {
632
+ if (!isRecord4(pass)) return false;
633
+ const tags = isRecord4(pass.renderState) && isRecord4(pass.renderState.tags) ? pass.renderState.tags : void 0;
634
+ const mode = tags?.LightMode ?? pass.name;
635
+ return !/shadow|depth/i.test(String(mode));
636
+ }) ?? passes[0];
632
637
  if (!isRecord4(first) || typeof first.name !== "string" || !isRecord4(first.program)) {
633
638
  return subjectFailure(
634
639
  "resource-preview-subject-invalid",
@@ -1105,17 +1110,40 @@ function requiredNumber(asset, field) {
1105
1110
  const value = asset[field];
1106
1111
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1107
1112
  }
1113
+ function authoredMipCount(asset, shapeDimensions) {
1114
+ const mips = isRecord6(asset.mips) ? asset.mips : void 0;
1115
+ if (mips?.kind === "packed") {
1116
+ const levels2 = requiredNumber(mips, "levelCount");
1117
+ return levels2 !== void 0 && Number.isInteger(levels2) && levels2 > 0 ? levels2 : void 0;
1118
+ }
1119
+ if (mips?.kind !== "generate") return mips?.kind === "none" ? 1 : void 0;
1120
+ const [width, height] = shapeDimensions ?? [void 0, void 0];
1121
+ if (width === void 0 || height === void 0) return void 0;
1122
+ const shape = isRecord6(asset.shape) ? asset.shape : void 0;
1123
+ const extent = shape !== void 0 && isRecord6(shape.extent) ? shape.extent : void 0;
1124
+ const depth = shape?.viewDimension === "3d" && extent !== void 0 ? requiredNumber(extent, "depth") ?? 1 : 1;
1125
+ let largest = Math.max(width, height, depth);
1126
+ let levels = 1;
1127
+ while (largest > 1) {
1128
+ largest = Math.max(1, Math.floor(largest / 2));
1129
+ levels += 1;
1130
+ }
1131
+ return levels;
1132
+ }
1108
1133
  function isTexturePayloadClass(value) {
1109
1134
  return value === "black" || value === "transparent" || value === "single-channel" || value === "color";
1110
1135
  }
1111
1136
  function classifyPayload(data, format) {
1112
1137
  const bytes = data instanceof Uint8Array || data instanceof Uint8ClampedArray ? [...data] : Array.isArray(data) && data.every((value) => typeof value === "number") ? data : void 0;
1113
1138
  if (bytes === void 0 || bytes.length === 0) return void 0;
1114
- const channels = format?.startsWith("r") && !format.startsWith("rg") ? 1 : 4;
1139
+ const normalizedFormat = format?.toLowerCase() ?? "";
1140
+ const singleChannel = normalizedFormat.startsWith("r") && !normalizedFormat.startsWith("rg");
1115
1141
  if (bytes.every((value) => value === 0)) return "black";
1116
- if (channels === 1) return "single-channel";
1117
- const alpha = bytes.filter((_, index) => (index + 1) % channels === 0);
1118
- if (alpha.length > 0 && alpha.every((value) => value === 0)) return "transparent";
1142
+ if (singleChannel) return "single-channel";
1143
+ if (normalizedFormat.startsWith("rgba") || normalizedFormat.startsWith("bgra")) {
1144
+ const alpha = bytes.filter((_, index) => (index + 1) % 4 === 0);
1145
+ if (alpha.length > 0 && alpha.every((value) => value === 0)) return "transparent";
1146
+ }
1119
1147
  return "color";
1120
1148
  }
1121
1149
  function observationString(observation, field) {
@@ -1151,9 +1179,21 @@ function inspectTextureSubject(input) {
1151
1179
  const format = readString("format");
1152
1180
  const colorSpace = readString("colorSpace");
1153
1181
  const filter = readString("filter");
1182
+ const shape = isRecord6(asset.shape) ? asset.shape : void 0;
1183
+ const extent = shape !== void 0 && isRecord6(shape.extent) ? shape.extent : void 0;
1184
+ const shapeDimensions = extent !== void 0 ? [requiredNumber(extent, "width"), requiredNumber(extent, "height")] : void 0;
1154
1185
  const dimensionsValue = asset.dimensions;
1155
- const dimensions = Array.isArray(dimensionsValue) ? dimensionsValue : [requiredNumber(asset, "width"), requiredNumber(asset, "height")];
1156
- const mipCount = requiredNumber(asset, "mipCount") ?? requiredNumber(asset, "mipLevelCount") ?? 1;
1186
+ const dimensions = Array.isArray(dimensionsValue) ? dimensionsValue : shapeDimensions?.[0] !== void 0 && shapeDimensions[1] !== void 0 ? shapeDimensions : [requiredNumber(asset, "width"), requiredNumber(asset, "height")];
1187
+ const authoredMips = isRecord6(asset.mips) ? asset.mips : void 0;
1188
+ const packedLevelCount = authoredMips?.kind === "packed" ? requiredNumber(authoredMips, "levelCount") : void 0;
1189
+ if (authoredMips?.kind === "packed" && (packedLevelCount === void 0 || !Number.isInteger(packedLevelCount) || packedLevelCount <= 0)) {
1190
+ return subjectFailure("resource-preview-subject-invalid", "TextureAsset packed mip metadata", {
1191
+ phase: "subject",
1192
+ guid: input.guid,
1193
+ field: "mips.levelCount"
1194
+ });
1195
+ }
1196
+ const mipCount = authoredMipCount(asset, shapeDimensions) ?? requiredNumber(asset, "mipCount") ?? requiredNumber(asset, "mipLevelCount") ?? requiredNumber(ownerFacts ?? {}, "mipCount") ?? requiredNumber(ownerFacts ?? {}, "mipLevelCount") ?? 1;
1157
1197
  const payloadClass = readString("payloadClass") ?? classifyPayload(asset.data, format) ?? void 0;
1158
1198
  if (subjectDigest === void 0 || boundDigest === void 0 || uvDigest === void 0 || bindingDigest === void 0 || format === void 0 || colorSpace === void 0 || filter === void 0 || dimensions.length !== 2 || dimensions.some(
1159
1199
  (value) => typeof value !== "number" || !Number.isInteger(value) || value <= 0
@@ -1230,6 +1270,13 @@ async function executeTexturePreview(args, input) {
1230
1270
  { phase: "renderer-observation", runId: input.runId }
1231
1271
  );
1232
1272
  }
1273
+ if (observation.rendererTextureResident !== true) {
1274
+ return subjectFailure(
1275
+ "resource-preview-oracle-failed",
1276
+ "the Renderer to report a resident texture binding for the preview draw",
1277
+ { phase: "renderer-texture-binding", runId: input.runId }
1278
+ );
1279
+ }
1233
1280
  const observed = {
1234
1281
  subjectDigest: observationString(observation, "subjectDigest") ?? "",
1235
1282
  boundDigest: observationString(observation, "boundDigest") ?? "",