minerender 2.1.0-beta.6 → 2.1.0-beta.8

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.
Files changed (128) hide show
  1. package/README.md +10 -1
  2. package/dist/browser/esm/Materials.mjs +3 -1
  3. package/dist/browser/esm/Materials.mjs.map +1 -1
  4. package/dist/browser/esm/Ticker.mjs +3 -1
  5. package/dist/browser/esm/Ticker.mjs.map +1 -1
  6. package/dist/browser/esm/UVMapper.mjs +9 -9
  7. package/dist/browser/esm/UVMapper.mjs.map +1 -1
  8. package/dist/browser/esm/armor/Armor.mjs +84 -0
  9. package/dist/browser/esm/armor/Armor.mjs.map +1 -0
  10. package/dist/browser/esm/armor/index.mjs +3 -0
  11. package/dist/browser/esm/armor/index.mjs.map +1 -0
  12. package/dist/browser/esm/assets/AssetDefaults.mjs +8 -0
  13. package/dist/browser/esm/assets/AssetDefaults.mjs.map +1 -0
  14. package/dist/browser/esm/assets/AssetKey.mjs +1 -1
  15. package/dist/browser/esm/assets/AssetKey.mjs.map +1 -1
  16. package/dist/browser/esm/assets/AssetLoader.mjs +5 -5
  17. package/dist/browser/esm/assets/AssetLoader.mjs.map +1 -1
  18. package/dist/browser/esm/assets/Assets.mjs +1 -5
  19. package/dist/browser/esm/assets/Assets.mjs.map +1 -1
  20. package/dist/browser/esm/assets/BlockEntities.mjs +5 -1
  21. package/dist/browser/esm/assets/BlockEntities.mjs.map +1 -1
  22. package/dist/browser/esm/assets/BlockStates.mjs +1 -1
  23. package/dist/browser/esm/assets/BlockStates.mjs.map +1 -1
  24. package/dist/browser/esm/assets/Entities.mjs +40 -12
  25. package/dist/browser/esm/assets/Entities.mjs.map +1 -1
  26. package/dist/browser/esm/assets/MineRenderData.mjs +8 -17
  27. package/dist/browser/esm/assets/MineRenderData.mjs.map +1 -1
  28. package/dist/browser/esm/assets/ModelTextures.mjs +13 -7
  29. package/dist/browser/esm/assets/ModelTextures.mjs.map +1 -1
  30. package/dist/browser/esm/assets/Models.mjs +1 -1
  31. package/dist/browser/esm/assets/Models.mjs.map +1 -1
  32. package/dist/browser/esm/assets/_fonts/Unihex.mjs +5 -3
  33. package/dist/browser/esm/assets/_fonts/Unihex.mjs.map +1 -1
  34. package/dist/browser/esm/assets/_versions/DatasetVersions.mjs +22 -0
  35. package/dist/browser/esm/assets/_versions/DatasetVersions.mjs.map +1 -0
  36. package/dist/browser/esm/assets/index.mjs +1 -0
  37. package/dist/browser/esm/assets/index.mjs.map +1 -1
  38. package/dist/browser/esm/assets/source/HostedAssetSource.mjs +7 -8
  39. package/dist/browser/esm/assets/source/HostedAssetSource.mjs.map +1 -1
  40. package/dist/browser/esm/cache/Caching.mjs +8 -0
  41. package/dist/browser/esm/cache/Caching.mjs.map +1 -1
  42. package/dist/browser/esm/entity/scene/EntityObject.mjs +31 -5
  43. package/dist/browser/esm/entity/scene/EntityObject.mjs.map +1 -1
  44. package/dist/browser/esm/env/browser/BrowserCache.mjs +3 -3
  45. package/dist/browser/esm/env/browser/BrowserCache.mjs.map +1 -1
  46. package/dist/browser/esm/env/browser/BrowserEnv.mjs +11 -4
  47. package/dist/browser/esm/env/browser/BrowserEnv.mjs.map +1 -1
  48. package/dist/browser/esm/image/ImageLoader.mjs +3 -3
  49. package/dist/browser/esm/image/ImageLoader.mjs.map +1 -1
  50. package/dist/browser/esm/index.browser.d.mts +191 -22
  51. package/dist/browser/esm/index.browser.mjs.map +1 -1
  52. package/dist/browser/esm/index.mjs +1 -0
  53. package/dist/browser/esm/index.mjs.map +1 -1
  54. package/dist/browser/esm/inspector/SceneInspector.mjs +3 -3
  55. package/dist/browser/esm/inspector/SceneInspector.mjs.map +1 -1
  56. package/dist/browser/esm/instance/InstanceManager.mjs +4 -4
  57. package/dist/browser/esm/instance/InstanceManager.mjs.map +1 -1
  58. package/dist/browser/esm/model/ItemGlint.mjs +7 -6
  59. package/dist/browser/esm/model/ItemGlint.mjs.map +1 -1
  60. package/dist/browser/esm/model/block/scene/BlockObject.mjs +19 -6
  61. package/dist/browser/esm/model/block/scene/BlockObject.mjs.map +1 -1
  62. package/dist/browser/esm/model/multiblock/StructureParser.mjs +7 -4
  63. package/dist/browser/esm/model/multiblock/StructureParser.mjs.map +1 -1
  64. package/dist/browser/esm/model/scene/ModelObject.mjs +4 -4
  65. package/dist/browser/esm/model/scene/ModelObject.mjs.map +1 -1
  66. package/dist/browser/esm/nbt/NBTHelper.mjs +5 -2
  67. package/dist/browser/esm/nbt/NBTHelper.mjs.map +1 -1
  68. package/dist/browser/esm/renderer/Renderer.mjs +4 -2
  69. package/dist/browser/esm/renderer/Renderer.mjs.map +1 -1
  70. package/dist/browser/esm/renderer/SceneObject.mjs +0 -6
  71. package/dist/browser/esm/renderer/SceneObject.mjs.map +1 -1
  72. package/dist/browser/esm/request/Requests.mjs +3 -3
  73. package/dist/browser/esm/request/Requests.mjs.map +1 -1
  74. package/dist/browser/esm/scene/SceneDocument.mjs +35 -5
  75. package/dist/browser/esm/scene/SceneDocument.mjs.map +1 -1
  76. package/dist/browser/esm/scene/SceneDocumentLoader.mjs +14 -3
  77. package/dist/browser/esm/scene/SceneDocumentLoader.mjs.map +1 -1
  78. package/dist/browser/esm/skin/SkinGeometries.mjs +4 -1
  79. package/dist/browser/esm/skin/SkinGeometries.mjs.map +1 -1
  80. package/dist/browser/esm/skin/SkinPart.mjs +2 -0
  81. package/dist/browser/esm/skin/SkinPart.mjs.map +1 -1
  82. package/dist/browser/esm/skin/SkinTextureCoordinates.mjs +11 -1
  83. package/dist/browser/esm/skin/SkinTextureCoordinates.mjs.map +1 -1
  84. package/dist/browser/esm/skin/SkinTextures.mjs +1 -1
  85. package/dist/browser/esm/skin/SkinTextures.mjs.map +1 -1
  86. package/dist/browser/esm/skin/Skins.mjs +6 -4
  87. package/dist/browser/esm/skin/Skins.mjs.map +1 -1
  88. package/dist/browser/esm/skin/scene/SkinObject.mjs +119 -7
  89. package/dist/browser/esm/skin/scene/SkinObject.mjs.map +1 -1
  90. package/dist/browser/esm/texture/PalettedTextures.mjs +46 -0
  91. package/dist/browser/esm/texture/PalettedTextures.mjs.map +1 -0
  92. package/dist/browser/esm/texture/TextureLoader.mjs +4 -2
  93. package/dist/browser/esm/texture/TextureLoader.mjs.map +1 -1
  94. package/dist/browser/esm/texture/index.mjs +1 -0
  95. package/dist/browser/esm/texture/index.mjs.map +1 -1
  96. package/dist/browser/esm/util/log.mjs +75 -0
  97. package/dist/browser/esm/util/log.mjs.map +1 -1
  98. package/dist/browser/esm/util/performance.mjs.map +1 -1
  99. package/dist/browser/esm/util/util.mjs +0 -2
  100. package/dist/browser/esm/util/util.mjs.map +1 -1
  101. package/dist/browser/esm/world/Chunk.mjs +70 -38
  102. package/dist/browser/esm/world/Chunk.mjs.map +1 -1
  103. package/dist/browser/esm/world/MineRenderWorld.mjs +187 -60
  104. package/dist/browser/esm/world/MineRenderWorld.mjs.map +1 -1
  105. package/dist/browser/esm/world/SectionMesh.mjs +65 -9
  106. package/dist/browser/esm/world/SectionMesh.mjs.map +1 -1
  107. package/dist/browser/esm/world/SectionModels.mjs +21 -15
  108. package/dist/browser/esm/world/SectionModels.mjs.map +1 -1
  109. package/dist/browser/esm/world/SectionWorker.mjs +8 -2
  110. package/dist/browser/esm/world/SectionWorker.mjs.map +1 -1
  111. package/dist/browser/esm/world/WorldStreamer.mjs +129 -34
  112. package/dist/browser/esm/world/WorldStreamer.mjs.map +1 -1
  113. package/dist/browser/esm/world/_culling/BlockCulling.mjs +1 -1
  114. package/dist/browser/esm/world/_culling/BlockCulling.mjs.map +1 -1
  115. package/dist/browser/esm/world/_entities/WorldEntities.mjs +3 -1
  116. package/dist/browser/esm/world/_entities/WorldEntities.mjs.map +1 -1
  117. package/dist/browser/index.d.ts +191 -22
  118. package/dist/browser/index.js +4461 -3648
  119. package/dist/browser/index.js.map +1 -1
  120. package/dist/bundle.js +13482 -12651
  121. package/dist/bundle.js.map +1 -1
  122. package/dist/node/index.d.mts +179 -21
  123. package/dist/node/index.d.ts +179 -21
  124. package/dist/node/index.js +4495 -3666
  125. package/dist/node/index.js.map +1 -1
  126. package/dist/node/index.mjs +4412 -3586
  127. package/dist/node/index.mjs.map +1 -1
  128. package/package.json +2 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MineRender V2
2
2
 
3
- A TypeScript library for interactive Minecraft skins, models, blocks, entities, and worlds.
3
+ A TypeScript library for interactive Minecraft skins, models, blocks, entities, GUIs, and worlds.
4
4
  V2 is in beta. See the [roadmap](https://github.com/InventivetalentDev/MineRender/blob/main/ROADMAP.md) for feature parity and remaining work.
5
5
 
6
6
  Live examples and usage docs: [beta.minerender.org](https://beta.minerender.org/). API reference: [beta-docs.minerender.org](https://beta-docs.minerender.org/).
@@ -29,6 +29,11 @@ an injected WebGL 2 context or the optional native `gl` backend. See
29
29
 
30
30
  Requires Node.js 22.12+ or a browser with WebGL 2, Fetch, `AbortSignal.any()`, and `AbortSignal.timeout()`.
31
31
 
32
+ The library prints only warnings and errors. To see debug output, call
33
+ `Logging.configure({ level: "debug" })`, or set the `minerender:log` localStorage key
34
+ in a browser or the `MINERENDER_LOG` environment variable in Node. See
35
+ [Logging](https://beta-docs.minerender.org/concepts#logging).
36
+
32
37
  ## Resource-pack ZIPs
33
38
 
34
39
  Register a browser `File` or `Blob` before loading models or textures:
@@ -123,3 +128,7 @@ Supported object types are `skin`, `block`, `item`, `model`, `entity`, and `gui`
123
128
  Positions use model units (16 per block); JSON rotations use radians.
124
129
 
125
130
  Callers apply the saved camera settings and select the matching asset version.
131
+
132
+ `encodeSceneDocument` and `decodeSceneDocument` convert a document to and from the compact
133
+ link format used by the editor. To show a scene on another page without bundling the library,
134
+ use the [iframe embed page](https://beta-docs.minerender.org/embeds).
@@ -4,6 +4,8 @@ import { Color, CustomBlending, DoubleSide, OneFactor, OneMinusSrcAlphaFactor, R
4
4
  import { Textures } from "./texture/Textures.mjs";
5
5
  import { TextureLoader } from "./texture/TextureLoader.mjs";
6
6
  import { Caching } from "./cache/Caching.mjs";
7
+ import { logger } from "./util/log.mjs";
8
+ var log = logger("Materials");
7
9
  var Materials = class _Materials {
8
10
  /** Shared checkerboard material, created on first access. */
9
11
  static get MISSING_TEXTURE() {
@@ -274,7 +276,7 @@ var Materials = class _Materials {
274
276
  Object.assign(material.defaultAttributeValues, { shade: [1], uvBounds: [0, 0, 1, 1] });
275
277
  return material;
276
278
  } catch (e) {
277
- console.warn(e);
279
+ log.warn(e);
278
280
  }
279
281
  return this.createBasicCanvasMaterial(canvas, transparent, shade);
280
282
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/Materials.ts"],"sourcesContent":["import { MaterialKey, serializeMaterialKey } from \"./cache/CacheKey\";\nimport { Color, ColorRepresentation, CustomBlending, DoubleSide, OneFactor, OneMinusSrcAlphaFactor, RepeatWrapping, FrontSide, Material, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, MeshStandardMaterial, ShaderChunk, ShaderMaterial } from \"three\";\nimport { Textures } from \"./texture/Textures\";\nimport { TextureLoader } from \"./texture/TextureLoader\";\nimport { Caching } from \"./cache/Caching\";\nimport { AssetKey } from \"./assets/AssetKey\";\nimport type { EntityRenderMode } from \"./entity/EntityModel\";\n\n/** Creates Minecraft model, entity, and GUI materials, with shared caches for image materials. */\nexport class Materials {\n\n /** Shared checkerboard material, created on first access. */\n public static get MISSING_TEXTURE(): Material {\n return Caching.materialCache.get(\"builtin:missing-texture\", () => new MeshBasicMaterial({\n map: Textures.getMissing(),\n alphaTest: 0.5\n }))!;\n }\n\n public static createImage(key: MaterialKey): Material {\n //TODO: type from key\n const transparent = key.transparent || false;\n return new MeshBasicMaterial({\n map: Textures.getImage(key.texture),\n transparent: transparent,\n side: transparent ? DoubleSide : FrontSide,\n alphaTest: 0.5\n });\n //TODO: params\n }\n\n\n public static createBasicCanvasMaterial(canvas: HTMLCanvasElement, transparent: boolean = false, shade: boolean = false): Material {\n if (shade) {\n return new MeshStandardMaterial({\n map: Textures.createCanvasTexture(canvas),\n transparent: transparent,\n side: transparent ? DoubleSide : FrontSide,\n alphaTest: 0.5,\n\n })\n }\n return new MeshBasicMaterial({\n map: Textures.createCanvasTexture(canvas),\n transparent: transparent,\n side: transparent ? DoubleSide : FrontSide,\n alphaTest: 0.5,\n\n })\n }\n\n /** Whether vanilla's render type for the mode culls back faces. */\n public static entityModeCulls(mode: EntityRenderMode = \"cutout\"): boolean {\n return mode === \"cutout_cull\" || mode === \"solid\" || mode === \"eyes\" || mode === \"water_mask\";\n }\n\n /** UV offset per tick of entity age for the scrolling modes, as vanilla's texture matrix applies it. */\n public static entityModeScroll(mode: EntityRenderMode = \"cutout\"): [number, number] | undefined {\n if (mode === \"energy_swirl\") return [0.01, 0.01];\n if (mode === \"breeze_wind\") return [0.02, 0];\n return undefined;\n }\n\n /**\n * Entity material for one of vanilla's render types. Entities are unlit here, so the lit and full-bright modes\n * differ only in blending and depth state. Culling is not a material property: {@link entityModeCulls} decides\n * whether the geometry gets inward faces.\n */\n public static createEntityCanvasMaterial(canvas: HTMLCanvasElement, mode: EntityRenderMode = \"cutout\", tint?: ColorRepresentation): MeshBasicMaterial {\n const material = Materials.createBasicCanvasMaterial(canvas) as MeshBasicMaterial;\n switch (mode) {\n case \"cutout\":\n case \"cutout_cull\":\n break;\n case \"cutout_z_offset\":\n material.polygonOffset = true;\n material.polygonOffsetFactor = -1;\n material.polygonOffsetUnits = -10;\n break;\n case \"solid\":\n material.alphaTest = 0;\n break;\n case \"translucent\":\n case \"breeze_wind\":\n material.transparent = true;\n material.alphaTest = 0.1;\n break;\n case \"translucent_emissive\":\n material.transparent = true;\n material.alphaTest = 0.1;\n material.depthWrite = false;\n break;\n case \"eyes\":\n case \"no_outline\":\n material.transparent = true;\n material.alphaTest = 0;\n material.depthWrite = false;\n break;\n case \"energy_swirl\":\n material.transparent = true;\n material.alphaTest = 0.1;\n material.blending = CustomBlending;\n material.blendSrc = OneFactor;\n material.blendDst = OneFactor;\n // The canvas is premultiplied: a glow pixel needs alpha, or browsers and image exports drop it wherever\n // nothing opaque is behind it. Its brightness serves as coverage, so the glow stays visible outside the body.\n material.blendSrcAlpha = OneFactor;\n material.blendDstAlpha = OneMinusSrcAlphaFactor;\n material.onBeforeCompile = shader => {\n shader.fragmentShader = shader.fragmentShader.replace(\"#include <dithering_fragment>\",\n \"gl_FragColor.a = max(gl_FragColor.r, max(gl_FragColor.g, gl_FragColor.b));\\n#include <dithering_fragment>\");\n };\n material.customProgramCacheKey = () => \"energy_swirl\";\n // Vanilla submits the swirl with half-grey vertex colour.\n material.color.set(0x808080);\n break;\n case \"water_mask\":\n material.alphaTest = 0;\n material.colorWrite = false;\n break;\n }\n if (Materials.entityModeScroll(mode)) {\n material.map!.wrapS = material.map!.wrapT = RepeatWrapping;\n }\n if (tint !== undefined) material.color.multiply(new Color(tint));\n return material;\n }\n\n /** Creates an unlit, transparent GUI material without depth writes or tone mapping. */\n public static createGuiCanvasMaterial(canvas: HTMLCanvasElement): MeshBasicMaterial {\n const material = new MeshBasicMaterial({\n map: Textures.createCanvasTexture(canvas),\n transparent: true,\n depthWrite: false,\n side: DoubleSide,\n toneMapped: false\n });\n material.onBeforeCompile = shader => {\n // Keep MSAA edge pixels inside the layer's cropped texture region.\n for (const [stage, direction] of [[\"vertex\", \"out\"], [\"fragment\", \"in\"]] as const) {\n const chunk = `uv_pars_${stage}` as const;\n shader[`${stage}Shader`] = shader[`${stage}Shader`].replace(`#include <${chunk}>`,\n ShaderChunk[chunk].replace(\"varying vec2 vMapUv;\", `\n #if __VERSION__ >= 300\n centroid ${direction} vec2 vMapUv;\n #else\n varying vec2 vMapUv;\n #endif\n `));\n }\n };\n return material;\n }\n\n public static createShadedCanvasMaterial(canvas: HTMLCanvasElement, transparent: boolean = false, shade:boolean=false, boundUvs: boolean = false):Material {\n //TODO\n // this might help https://github.com/JannisX11/blockbench/blob/1701f764641376414d29100c4f6c7cd74997fad8/js/preview/canvas.js#L62\n\n\n // Based on https://github.com/JannisX11/blockbench/blob/cc73aa8a9c0494fd9fe1cee4d062d060af4db06d/js/texturing/textures.js#L59\n // + support for instanced meshes\n const vertShader =`\n uniform bool SHADE;\n attribute float shade;\n \n // Keep MSAA edge pixels from sampling outside the face's atlas region.\n #if __VERSION__ >= 300\n centroid out vec2 vUv;\n #else\n varying vec2 vUv;\n #endif\n #ifdef BOUND_UVS\n attribute vec4 uvBounds;\n flat out vec4 vUvBounds;\n #endif\n varying vec3 vTint;\n varying float light;\n varying float lift;\n\n float AMBIENT = 0.5;\n float XFAC = -0.15;\n float ZFAC = 0.05;\n\n void main()\n {\n\n if (SHADE && shade > 0.5) {\n\n #ifdef USE_INSTANCING\n vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );\n #else\n vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );\n #endif\n\n float yLight = (1.0+N.y) * 0.5;\n light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;\n\n } else {\n\n light = 1.0;\n\n } \n\n if (color.b > 1.1) {\n lift = 0.1;\n } else {\n lift = 0.0;\n }\n \n vUv = uv;\n #ifdef BOUND_UVS\n vUvBounds = uvBounds;\n #endif\n vTint = color;\n \n vec4 mvPosition = vec4(position, 1.0);\n #ifdef USE_INSTANCING\n mvPosition = instanceMatrix * mvPosition;\n #endif\n mvPosition = modelViewMatrix * mvPosition;\n gl_Position = projectionMatrix * mvPosition;\n \n }\n `\n const fragShader = `\n #ifdef GL_ES\n precision highp float;\n #endif\n\n uniform sampler2D map;\n\n uniform bool SHADE;\n uniform bool EMISSIVE;\n uniform float BRIGHTNESS;\n\n #if __VERSION__ >= 300\n centroid in vec2 vUv;\n #else\n varying vec2 vUv;\n #endif\n #ifdef BOUND_UVS\n flat in vec4 vUvBounds;\n #endif\n varying vec3 vTint;\n varying float light;\n varying float lift;\n\n void main(void)\n {\n #ifdef BOUND_UVS\n // Keep edge samples inside their texture even without centroid interpolation.\n vec2 mapUv = clamp(vUv, vUvBounds.xy, vUvBounds.zw);\n #else\n vec2 mapUv = vUv;\n #endif\n vec4 color = texture2D(map, mapUv);\n color.rgb *= vTint;\n \n if (color.a < 0.01) discard;\n\n if (EMISSIVE == false) {\n\n gl_FragColor = vec4(lift + color.rgb * light * BRIGHTNESS, color.a);\n\n } else {\n\n float light2 = (light * BRIGHTNESS) + (1.0 - light * BRIGHTNESS) * (1.0 - color.a);\n gl_FragColor = vec4(lift + color.rgb * light2, 1.0);\n\n }\n\n #include <tonemapping_fragment>\n #include <colorspace_fragment>\n }\n `\n //TODO: this does add the MC-like shading, but breaks when stuff is instanced (can't updated position)\n // https://medium.com/@pailhead011/instancing-with-three-js-part-2-3be34ae83c57 might help with that\n\n try {\n const material = new ShaderMaterial({\n defines: boundUvs ? { BOUND_UVS: true } : {},\n uniforms: {\n SHADE: { value: true },\n BRIGHTNESS: { value: 1 },\n EMISSIVE:{value:false},\n base: { value: new Color(0xc1c1c1)/*TODO*/ },\n map: {value:Textures.createCanvasTexture(canvas)}\n },\n vertexShader: vertShader,\n fragmentShader: fragShader,\n vertexColors: true,\n transparent: transparent,\n side: transparent ? DoubleSide : FrontSide,\n alphaTest: 0.5,\n });\n Object.assign(material.defaultAttributeValues, { shade: [1], uvBounds: [0, 0, 1, 1] });\n return material;\n } catch (e) {\n console.warn(e)\n }\n\n // fallback\n return this.createBasicCanvasMaterial(canvas, transparent, shade);\n }\n\n /** Returns a shared image material. Use {@link createImage} for a separate material instance. */\n public static getImage(key: MaterialKey): Material {\n const keyStr = serializeMaterialKey(key);\n const map = (Caching.materialCache.peek(keyStr) as MeshBasicMaterial | undefined)?.map;\n if (map && TextureLoader.hasFailed(map)) {\n Caching.materialCache.invalidate(keyStr);\n }\n return Caching.materialCache.get(keyStr, k => {\n return Materials.createImage(key);\n })!;\n }\n\n public static needsUpdate(mat: Material) {\n mat.needsUpdate = true;\n\n if (mat.type === 'ShaderMaterial') {\n let mat1=mat as ShaderMaterial;\n if (\"map\" in mat1.uniforms) {\n mat1.uniforms.map.value.needsUpdate = true;\n }\n }\n if (mat.type === 'MeshBasicMaterial' || mat.type === 'MeshStandardMaterial') {\n let mat1 = mat as (MeshBasicMaterial | MeshStandardMaterial);\n if (mat1.map) {\n mat1.map.needsUpdate = true;\n }\n }\n }\n\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/Materials.ts"],"sourcesContent":["import { MaterialKey, serializeMaterialKey } from \"./cache/CacheKey\";\nimport { Color, ColorRepresentation, CustomBlending, DoubleSide, OneFactor, OneMinusSrcAlphaFactor, RepeatWrapping, FrontSide, Material, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, MeshStandardMaterial, ShaderChunk, ShaderMaterial } from \"three\";\nimport { Textures } from \"./texture/Textures\";\nimport { TextureLoader } from \"./texture/TextureLoader\";\nimport { Caching } from \"./cache/Caching\";\nimport { AssetKey } from \"./assets/AssetKey\";\nimport type { EntityRenderMode } from \"./entity/EntityModel\";\nimport { logger } from \"./util/log\";\n\nconst log = logger(\"Materials\");\n\n/** Creates Minecraft model, entity, and GUI materials, with shared caches for image materials. */\nexport class Materials {\n\n /** Shared checkerboard material, created on first access. */\n public static get MISSING_TEXTURE(): Material {\n return Caching.materialCache.get(\"builtin:missing-texture\", () => new MeshBasicMaterial({\n map: Textures.getMissing(),\n alphaTest: 0.5\n }))!;\n }\n\n public static createImage(key: MaterialKey): Material {\n //TODO: type from key\n const transparent = key.transparent || false;\n return new MeshBasicMaterial({\n map: Textures.getImage(key.texture),\n transparent: transparent,\n side: transparent ? DoubleSide : FrontSide,\n alphaTest: 0.5\n });\n //TODO: params\n }\n\n\n public static createBasicCanvasMaterial(canvas: HTMLCanvasElement, transparent: boolean = false, shade: boolean = false): Material {\n if (shade) {\n return new MeshStandardMaterial({\n map: Textures.createCanvasTexture(canvas),\n transparent: transparent,\n side: transparent ? DoubleSide : FrontSide,\n alphaTest: 0.5,\n\n })\n }\n return new MeshBasicMaterial({\n map: Textures.createCanvasTexture(canvas),\n transparent: transparent,\n side: transparent ? DoubleSide : FrontSide,\n alphaTest: 0.5,\n\n })\n }\n\n /** Whether vanilla's render type for the mode culls back faces. */\n public static entityModeCulls(mode: EntityRenderMode = \"cutout\"): boolean {\n return mode === \"cutout_cull\" || mode === \"solid\" || mode === \"eyes\" || mode === \"water_mask\";\n }\n\n /** UV offset per tick of entity age for the scrolling modes, as vanilla's texture matrix applies it. */\n public static entityModeScroll(mode: EntityRenderMode = \"cutout\"): [number, number] | undefined {\n if (mode === \"energy_swirl\") return [0.01, 0.01];\n if (mode === \"breeze_wind\") return [0.02, 0];\n return undefined;\n }\n\n /**\n * Entity material for one of vanilla's render types. Entities are unlit here, so the lit and full-bright modes\n * differ only in blending and depth state. Culling is not a material property: {@link entityModeCulls} decides\n * whether the geometry gets inward faces.\n */\n public static createEntityCanvasMaterial(canvas: HTMLCanvasElement, mode: EntityRenderMode = \"cutout\", tint?: ColorRepresentation): MeshBasicMaterial {\n const material = Materials.createBasicCanvasMaterial(canvas) as MeshBasicMaterial;\n switch (mode) {\n case \"cutout\":\n case \"cutout_cull\":\n break;\n case \"cutout_z_offset\":\n material.polygonOffset = true;\n material.polygonOffsetFactor = -1;\n material.polygonOffsetUnits = -10;\n break;\n case \"solid\":\n material.alphaTest = 0;\n break;\n case \"translucent\":\n case \"breeze_wind\":\n material.transparent = true;\n material.alphaTest = 0.1;\n break;\n case \"translucent_emissive\":\n material.transparent = true;\n material.alphaTest = 0.1;\n material.depthWrite = false;\n break;\n case \"eyes\":\n case \"no_outline\":\n material.transparent = true;\n material.alphaTest = 0;\n material.depthWrite = false;\n break;\n case \"energy_swirl\":\n material.transparent = true;\n material.alphaTest = 0.1;\n material.blending = CustomBlending;\n material.blendSrc = OneFactor;\n material.blendDst = OneFactor;\n // The canvas is premultiplied: a glow pixel needs alpha, or browsers and image exports drop it wherever\n // nothing opaque is behind it. Its brightness serves as coverage, so the glow stays visible outside the body.\n material.blendSrcAlpha = OneFactor;\n material.blendDstAlpha = OneMinusSrcAlphaFactor;\n material.onBeforeCompile = shader => {\n shader.fragmentShader = shader.fragmentShader.replace(\"#include <dithering_fragment>\",\n \"gl_FragColor.a = max(gl_FragColor.r, max(gl_FragColor.g, gl_FragColor.b));\\n#include <dithering_fragment>\");\n };\n material.customProgramCacheKey = () => \"energy_swirl\";\n // Vanilla submits the swirl with half-grey vertex colour.\n material.color.set(0x808080);\n break;\n case \"water_mask\":\n material.alphaTest = 0;\n material.colorWrite = false;\n break;\n }\n if (Materials.entityModeScroll(mode)) {\n material.map!.wrapS = material.map!.wrapT = RepeatWrapping;\n }\n if (tint !== undefined) material.color.multiply(new Color(tint));\n return material;\n }\n\n /** Creates an unlit, transparent GUI material without depth writes or tone mapping. */\n public static createGuiCanvasMaterial(canvas: HTMLCanvasElement): MeshBasicMaterial {\n const material = new MeshBasicMaterial({\n map: Textures.createCanvasTexture(canvas),\n transparent: true,\n depthWrite: false,\n side: DoubleSide,\n toneMapped: false\n });\n material.onBeforeCompile = shader => {\n // Keep MSAA edge pixels inside the layer's cropped texture region.\n for (const [stage, direction] of [[\"vertex\", \"out\"], [\"fragment\", \"in\"]] as const) {\n const chunk = `uv_pars_${stage}` as const;\n shader[`${stage}Shader`] = shader[`${stage}Shader`].replace(`#include <${chunk}>`,\n ShaderChunk[chunk].replace(\"varying vec2 vMapUv;\", `\n #if __VERSION__ >= 300\n centroid ${direction} vec2 vMapUv;\n #else\n varying vec2 vMapUv;\n #endif\n `));\n }\n };\n return material;\n }\n\n public static createShadedCanvasMaterial(canvas: HTMLCanvasElement, transparent: boolean = false, shade:boolean=false, boundUvs: boolean = false):Material {\n //TODO\n // this might help https://github.com/JannisX11/blockbench/blob/1701f764641376414d29100c4f6c7cd74997fad8/js/preview/canvas.js#L62\n\n\n // Based on https://github.com/JannisX11/blockbench/blob/cc73aa8a9c0494fd9fe1cee4d062d060af4db06d/js/texturing/textures.js#L59\n // + support for instanced meshes\n const vertShader =`\n uniform bool SHADE;\n attribute float shade;\n \n // Keep MSAA edge pixels from sampling outside the face's atlas region.\n #if __VERSION__ >= 300\n centroid out vec2 vUv;\n #else\n varying vec2 vUv;\n #endif\n #ifdef BOUND_UVS\n attribute vec4 uvBounds;\n flat out vec4 vUvBounds;\n #endif\n varying vec3 vTint;\n varying float light;\n varying float lift;\n\n float AMBIENT = 0.5;\n float XFAC = -0.15;\n float ZFAC = 0.05;\n\n void main()\n {\n\n if (SHADE && shade > 0.5) {\n\n #ifdef USE_INSTANCING\n vec3 N = vec3( modelMatrix * instanceMatrix * vec4(normal, 0.0) );\n #else\n vec3 N = vec3( modelMatrix * vec4(normal, 0.0) );\n #endif\n\n float yLight = (1.0+N.y) * 0.5;\n light = yLight * (1.0-AMBIENT) + N.x*N.x * XFAC + N.z*N.z * ZFAC + AMBIENT;\n\n } else {\n\n light = 1.0;\n\n } \n\n if (color.b > 1.1) {\n lift = 0.1;\n } else {\n lift = 0.0;\n }\n \n vUv = uv;\n #ifdef BOUND_UVS\n vUvBounds = uvBounds;\n #endif\n vTint = color;\n \n vec4 mvPosition = vec4(position, 1.0);\n #ifdef USE_INSTANCING\n mvPosition = instanceMatrix * mvPosition;\n #endif\n mvPosition = modelViewMatrix * mvPosition;\n gl_Position = projectionMatrix * mvPosition;\n \n }\n `\n const fragShader = `\n #ifdef GL_ES\n precision highp float;\n #endif\n\n uniform sampler2D map;\n\n uniform bool SHADE;\n uniform bool EMISSIVE;\n uniform float BRIGHTNESS;\n\n #if __VERSION__ >= 300\n centroid in vec2 vUv;\n #else\n varying vec2 vUv;\n #endif\n #ifdef BOUND_UVS\n flat in vec4 vUvBounds;\n #endif\n varying vec3 vTint;\n varying float light;\n varying float lift;\n\n void main(void)\n {\n #ifdef BOUND_UVS\n // Keep edge samples inside their texture even without centroid interpolation.\n vec2 mapUv = clamp(vUv, vUvBounds.xy, vUvBounds.zw);\n #else\n vec2 mapUv = vUv;\n #endif\n vec4 color = texture2D(map, mapUv);\n color.rgb *= vTint;\n \n if (color.a < 0.01) discard;\n\n if (EMISSIVE == false) {\n\n gl_FragColor = vec4(lift + color.rgb * light * BRIGHTNESS, color.a);\n\n } else {\n\n float light2 = (light * BRIGHTNESS) + (1.0 - light * BRIGHTNESS) * (1.0 - color.a);\n gl_FragColor = vec4(lift + color.rgb * light2, 1.0);\n\n }\n\n #include <tonemapping_fragment>\n #include <colorspace_fragment>\n }\n `\n //TODO: this does add the MC-like shading, but breaks when stuff is instanced (can't updated position)\n // https://medium.com/@pailhead011/instancing-with-three-js-part-2-3be34ae83c57 might help with that\n\n try {\n const material = new ShaderMaterial({\n defines: boundUvs ? { BOUND_UVS: true } : {},\n uniforms: {\n SHADE: { value: true },\n BRIGHTNESS: { value: 1 },\n EMISSIVE:{value:false},\n base: { value: new Color(0xc1c1c1)/*TODO*/ },\n map: {value:Textures.createCanvasTexture(canvas)}\n },\n vertexShader: vertShader,\n fragmentShader: fragShader,\n vertexColors: true,\n transparent: transparent,\n side: transparent ? DoubleSide : FrontSide,\n alphaTest: 0.5,\n });\n Object.assign(material.defaultAttributeValues, { shade: [1], uvBounds: [0, 0, 1, 1] });\n return material;\n } catch (e) {\n log.warn(e)\n }\n\n // fallback\n return this.createBasicCanvasMaterial(canvas, transparent, shade);\n }\n\n /** Returns a shared image material. Use {@link createImage} for a separate material instance. */\n public static getImage(key: MaterialKey): Material {\n const keyStr = serializeMaterialKey(key);\n const map = (Caching.materialCache.peek(keyStr) as MeshBasicMaterial | undefined)?.map;\n if (map && TextureLoader.hasFailed(map)) {\n Caching.materialCache.invalidate(keyStr);\n }\n return Caching.materialCache.get(keyStr, k => {\n return Materials.createImage(key);\n })!;\n }\n\n public static needsUpdate(mat: Material) {\n mat.needsUpdate = true;\n\n if (mat.type === 'ShaderMaterial') {\n let mat1=mat as ShaderMaterial;\n if (\"map\" in mat1.uniforms) {\n mat1.uniforms.map.value.needsUpdate = true;\n }\n }\n if (mat.type === 'MeshBasicMaterial' || mat.type === 'MeshStandardMaterial') {\n let mat1 = mat as (MeshBasicMaterial | MeshStandardMaterial);\n if (mat1.map) {\n mat1.map.needsUpdate = true;\n }\n }\n }\n\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,6 @@
1
1
  // src/Ticker.ts
2
+ import { logger } from "./util/log.mjs";
3
+ var log = logger("Ticker");
2
4
  var _Ticker = class _Ticker {
3
5
  static schedule(fn, ms) {
4
6
  const handle = setInterval(fn, ms);
@@ -16,7 +18,7 @@ var _Ticker = class _Ticker {
16
18
  try {
17
19
  t();
18
20
  } catch (e) {
19
- console.warn(e);
21
+ log.warn(e);
20
22
  }
21
23
  });
22
24
  _Ticker.oneSecondTicks++;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/Ticker.ts"],"sourcesContent":["/** A synchronous callback registered with {@link Ticker.add}. */\nexport interface TickerFunction {\n (): void;\n}\n\ntype IntervalHandle = ReturnType<typeof setInterval>;\n\n/**\n * Shared 20-per-second tick loop, used for things like animated texture frames.\n *\n * The timers are started lazily by {@link Ticker.add} and unref'd where the platform supports it -\n * importing MineRender must never on its own keep a Node process alive.\n */\nexport class Ticker {\n\n public static readonly TPS = 20;\n\n private static counter: number = 0;\n private static readonly _tickers: Map<number, TickerFunction> = new Map<number, TickerFunction>();\n\n private static interval: IntervalHandle | undefined;\n private static oneSecondTicksTracker: IntervalHandle | undefined;\n private static fiveSecondTicksTracker: IntervalHandle | undefined;\n\n private static oneSecondTps = 0;\n private static oneSecondTicks = 0;\n\n private static fiveSecondTps = 0;\n private static fiveSecondTicks = 0;\n\n private static schedule(fn: () => void, ms: number): IntervalHandle {\n const handle = setInterval(fn, ms);\n // Node's Timeout keeps the event loop alive unless unref'd; browsers return a plain number\n const unref = (handle as { unref?: () => void }).unref;\n if (typeof unref === \"function\") {\n unref.call(handle);\n }\n return handle;\n }\n\n /** Starts or resumes the shared tick loop. Repeated calls have no effect. */\n public static start(): void {\n if (this.interval) return;\n\n this.interval = this.schedule(() => {\n Ticker._tickers.forEach(t => {\n try {\n t();\n } catch (e) {\n console.warn(e);\n }\n });\n Ticker.oneSecondTicks++;\n Ticker.fiveSecondTicks++;\n }, 1000 / this.TPS);\n\n this.oneSecondTicksTracker = this.schedule(() => {\n Ticker.oneSecondTps = Ticker.oneSecondTicks;\n Ticker.oneSecondTicks = 0;\n }, 1000);\n\n this.fiveSecondTicksTracker = this.schedule(() => {\n Ticker.fiveSecondTps = Ticker.fiveSecondTicks / 5;\n Ticker.fiveSecondTicks = 0;\n }, 1000 * 5);\n }\n\n /** Pauses the loop while retaining callbacks for a later {@link start}. */\n public static stop(): void {\n if (this.interval) clearInterval(this.interval);\n if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);\n if (this.fiveSecondTicksTracker) clearInterval(this.fiveSecondTicksTracker);\n this.interval = undefined;\n this.oneSecondTicksTracker = undefined;\n this.fiveSecondTicksTracker = undefined;\n }\n\n /** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */\n public static add(tick: TickerFunction): number {\n this.start();\n const c = this.counter++;\n this._tickers.set(c, tick);\n return c;\n }\n\n /** Removes a callback by ID and stops the timers when no callbacks remain. */\n public static remove(c?: number) {\n // note: plain `if (c)` used to drop id 0, i.e. the very first registered ticker\n if (typeof c === \"number\") this._tickers.delete(c);\n if (!this._tickers.size) this.stop();\n }\n\n public static get tickers(): Map<number, TickerFunction> {\n return this._tickers;\n }\n\n public static get tpsOneSecond() {\n return this.oneSecondTps;\n }\n\n public static get tpsFiveSeconds() {\n return this.fiveSecondTps;\n }\n\n /** Stops the loop and removes all registered callbacks. */\n public static dispose() {\n this.stop();\n this._tickers.clear();\n }\n\n}\n"],"mappings":";AAaO,IAAM,UAAN,MAAM,QAAO;AAAA,EAiBhB,OAAe,SAAS,IAAgB,IAA4B;AAChE,UAAM,SAAS,YAAY,IAAI,EAAE;AAEjC,UAAM,QAAS,OAAkC;AACjD,QAAI,OAAO,UAAU,YAAY;AAC7B,YAAM,KAAK,MAAM;AAAA,IACrB;AACA,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,OAAc,QAAc;AACxB,QAAI,KAAK,SAAU;AAEnB,SAAK,WAAW,KAAK,SAAS,MAAM;AAChC,cAAO,SAAS,QAAQ,OAAK;AACzB,YAAI;AACA,YAAE;AAAA,QACN,SAAS,GAAG;AACR,kBAAQ,KAAK,CAAC;AAAA,QAClB;AAAA,MACJ,CAAC;AACD,cAAO;AACP,cAAO;AAAA,IACX,GAAG,MAAO,KAAK,GAAG;AAElB,SAAK,wBAAwB,KAAK,SAAS,MAAM;AAC7C,cAAO,eAAe,QAAO;AAC7B,cAAO,iBAAiB;AAAA,IAC5B,GAAG,GAAI;AAEP,SAAK,yBAAyB,KAAK,SAAS,MAAM;AAC9C,cAAO,gBAAgB,QAAO,kBAAkB;AAChD,cAAO,kBAAkB;AAAA,IAC7B,GAAG,MAAO,CAAC;AAAA,EACf;AAAA;AAAA,EAGA,OAAc,OAAa;AACvB,QAAI,KAAK,SAAU,eAAc,KAAK,QAAQ;AAC9C,QAAI,KAAK,sBAAuB,eAAc,KAAK,qBAAqB;AACxE,QAAI,KAAK,uBAAwB,eAAc,KAAK,sBAAsB;AAC1E,SAAK,WAAW;AAChB,SAAK,wBAAwB;AAC7B,SAAK,yBAAyB;AAAA,EAClC;AAAA;AAAA,EAGA,OAAc,IAAI,MAA8B;AAC5C,SAAK,MAAM;AACX,UAAM,IAAI,KAAK;AACf,SAAK,SAAS,IAAI,GAAG,IAAI;AACzB,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,OAAc,OAAO,GAAY;AAE7B,QAAI,OAAO,MAAM,SAAU,MAAK,SAAS,OAAO,CAAC;AACjD,QAAI,CAAC,KAAK,SAAS,KAAM,MAAK,KAAK;AAAA,EACvC;AAAA,EAEA,WAAkB,UAAuC;AACrD,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,WAAkB,eAAe;AAC7B,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,WAAkB,iBAAiB;AAC/B,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA,EAGA,OAAc,UAAU;AACpB,SAAK,KAAK;AACV,SAAK,SAAS,MAAM;AAAA,EACxB;AAEJ;AAjGa,QAEc,MAAM;AAFpB,QAIM,UAAkB;AAJxB,QAKe,WAAwC,oBAAI,IAA4B;AALvF,QAWM,eAAe;AAXrB,QAYM,iBAAiB;AAZvB,QAcM,gBAAgB;AAdtB,QAeM,kBAAkB;AAf9B,IAAM,SAAN;","names":[]}
1
+ {"version":3,"sources":["../../../src/Ticker.ts"],"sourcesContent":["import { logger } from \"./util/log\";\n\nconst log = logger(\"Ticker\");\n\n/** A synchronous callback registered with {@link Ticker.add}. */\nexport interface TickerFunction {\n (): void;\n}\n\ntype IntervalHandle = ReturnType<typeof setInterval>;\n\n/**\n * Shared 20-per-second tick loop, used for things like animated texture frames.\n *\n * The timers are started lazily by {@link Ticker.add} and unref'd where the platform supports it -\n * importing MineRender must never on its own keep a Node process alive.\n */\nexport class Ticker {\n\n public static readonly TPS = 20;\n\n private static counter: number = 0;\n private static readonly _tickers: Map<number, TickerFunction> = new Map<number, TickerFunction>();\n\n private static interval: IntervalHandle | undefined;\n private static oneSecondTicksTracker: IntervalHandle | undefined;\n private static fiveSecondTicksTracker: IntervalHandle | undefined;\n\n private static oneSecondTps = 0;\n private static oneSecondTicks = 0;\n\n private static fiveSecondTps = 0;\n private static fiveSecondTicks = 0;\n\n private static schedule(fn: () => void, ms: number): IntervalHandle {\n const handle = setInterval(fn, ms);\n // Node's Timeout keeps the event loop alive unless unref'd; browsers return a plain number\n const unref = (handle as { unref?: () => void }).unref;\n if (typeof unref === \"function\") {\n unref.call(handle);\n }\n return handle;\n }\n\n /** Starts or resumes the shared tick loop. Repeated calls have no effect. */\n public static start(): void {\n if (this.interval) return;\n\n this.interval = this.schedule(() => {\n Ticker._tickers.forEach(t => {\n try {\n t();\n } catch (e) {\n log.warn(e);\n }\n });\n Ticker.oneSecondTicks++;\n Ticker.fiveSecondTicks++;\n }, 1000 / this.TPS);\n\n this.oneSecondTicksTracker = this.schedule(() => {\n Ticker.oneSecondTps = Ticker.oneSecondTicks;\n Ticker.oneSecondTicks = 0;\n }, 1000);\n\n this.fiveSecondTicksTracker = this.schedule(() => {\n Ticker.fiveSecondTps = Ticker.fiveSecondTicks / 5;\n Ticker.fiveSecondTicks = 0;\n }, 1000 * 5);\n }\n\n /** Pauses the loop while retaining callbacks for a later {@link start}. */\n public static stop(): void {\n if (this.interval) clearInterval(this.interval);\n if (this.oneSecondTicksTracker) clearInterval(this.oneSecondTicksTracker);\n if (this.fiveSecondTicksTracker) clearInterval(this.fiveSecondTicksTracker);\n this.interval = undefined;\n this.oneSecondTicksTracker = undefined;\n this.fiveSecondTicksTracker = undefined;\n }\n\n /** Registers a callback, starts the loop if needed, and returns an ID for {@link remove}. */\n public static add(tick: TickerFunction): number {\n this.start();\n const c = this.counter++;\n this._tickers.set(c, tick);\n return c;\n }\n\n /** Removes a callback by ID and stops the timers when no callbacks remain. */\n public static remove(c?: number) {\n // note: plain `if (c)` used to drop id 0, i.e. the very first registered ticker\n if (typeof c === \"number\") this._tickers.delete(c);\n if (!this._tickers.size) this.stop();\n }\n\n public static get tickers(): Map<number, TickerFunction> {\n return this._tickers;\n }\n\n public static get tpsOneSecond() {\n return this.oneSecondTps;\n }\n\n public static get tpsFiveSeconds() {\n return this.fiveSecondTps;\n }\n\n /** Stops the loop and removes all registered callbacks. */\n public static dispose() {\n this.stop();\n this._tickers.clear();\n }\n\n}\n"],"mappings":";AAAA,SAAS,cAAc;AAEvB,IAAM,MAAM,OAAO,QAAQ;AAepB,IAAM,UAAN,MAAM,QAAO;AAAA,EAiBhB,OAAe,SAAS,IAAgB,IAA4B;AAChE,UAAM,SAAS,YAAY,IAAI,EAAE;AAEjC,UAAM,QAAS,OAAkC;AACjD,QAAI,OAAO,UAAU,YAAY;AAC7B,YAAM,KAAK,MAAM;AAAA,IACrB;AACA,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,OAAc,QAAc;AACxB,QAAI,KAAK,SAAU;AAEnB,SAAK,WAAW,KAAK,SAAS,MAAM;AAChC,cAAO,SAAS,QAAQ,OAAK;AACzB,YAAI;AACA,YAAE;AAAA,QACN,SAAS,GAAG;AACR,cAAI,KAAK,CAAC;AAAA,QACd;AAAA,MACJ,CAAC;AACD,cAAO;AACP,cAAO;AAAA,IACX,GAAG,MAAO,KAAK,GAAG;AAElB,SAAK,wBAAwB,KAAK,SAAS,MAAM;AAC7C,cAAO,eAAe,QAAO;AAC7B,cAAO,iBAAiB;AAAA,IAC5B,GAAG,GAAI;AAEP,SAAK,yBAAyB,KAAK,SAAS,MAAM;AAC9C,cAAO,gBAAgB,QAAO,kBAAkB;AAChD,cAAO,kBAAkB;AAAA,IAC7B,GAAG,MAAO,CAAC;AAAA,EACf;AAAA;AAAA,EAGA,OAAc,OAAa;AACvB,QAAI,KAAK,SAAU,eAAc,KAAK,QAAQ;AAC9C,QAAI,KAAK,sBAAuB,eAAc,KAAK,qBAAqB;AACxE,QAAI,KAAK,uBAAwB,eAAc,KAAK,sBAAsB;AAC1E,SAAK,WAAW;AAChB,SAAK,wBAAwB;AAC7B,SAAK,yBAAyB;AAAA,EAClC;AAAA;AAAA,EAGA,OAAc,IAAI,MAA8B;AAC5C,SAAK,MAAM;AACX,UAAM,IAAI,KAAK;AACf,SAAK,SAAS,IAAI,GAAG,IAAI;AACzB,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,OAAc,OAAO,GAAY;AAE7B,QAAI,OAAO,MAAM,SAAU,MAAK,SAAS,OAAO,CAAC;AACjD,QAAI,CAAC,KAAK,SAAS,KAAM,MAAK,KAAK;AAAA,EACvC;AAAA,EAEA,WAAkB,UAAuC;AACrD,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,WAAkB,eAAe;AAC7B,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,WAAkB,iBAAiB;AAC/B,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA,EAGA,OAAc,UAAU;AACpB,SAAK,KAAK;AACV,SAAK,SAAS,MAAM;AAAA,EACxB;AAEJ;AAjGa,QAEc,MAAM;AAFpB,QAIM,UAAkB;AAJxB,QAKe,WAAwC,oBAAI,IAA4B;AALvF,QAWM,eAAe;AAXrB,QAYM,iBAAiB;AAZvB,QAcM,gBAAgB;AAdtB,QAeM,kBAAkB;AAf9B,IAAM,SAAN;","names":[]}
@@ -9,9 +9,9 @@ import { Caching } from "./cache/Caching.mjs";
9
9
  import { Textures } from "./texture/Textures.mjs";
10
10
  import { AssetKey } from "./assets/AssetKey.mjs";
11
11
  import { ModelGenerator } from "./model/ModelGenerator.mjs";
12
- import { prefix } from "./util/log.mjs";
12
+ import { logger } from "./util/log.mjs";
13
13
  import { DEFAULT_UV, makeUv, makeUvCoords, setFaceUvInArray, setCubeFaceUvInArray, addCubeFaceUvToArray, facesToUvArray } from "./util/_internal/cubeUv.mjs";
14
- var p = prefix("UVMapper");
14
+ var log = logger("UVMapper");
15
15
  var X = 0;
16
16
  var Y = 1;
17
17
  var Z = 2;
@@ -244,7 +244,7 @@ var UVMapper = class {
244
244
  model.elements = originalModel.elements.map((element) => ({ ...element }));
245
245
  }
246
246
  const isItemModel = !("elements" in model);
247
- console.debug(p, "Creating Atlas for", model.key);
247
+ log.debug("Creating Atlas for", model.key);
248
248
  if (model.textures) {
249
249
  const promises = [];
250
250
  const uniqueTextureNames = [];
@@ -258,7 +258,7 @@ var UVMapper = class {
258
258
  const assetKey = AssetKey.parse("textures", textureValue, model.key);
259
259
  promises.push(ModelTextures.get(assetKey).then((asset) => {
260
260
  if (!asset) {
261
- console.warn(p, "Missing texture", assetKey);
261
+ log.warn("Missing texture", assetKey);
262
262
  return;
263
263
  }
264
264
  textureMap[textureKey] = new WrappedImage(asset);
@@ -270,7 +270,7 @@ var UVMapper = class {
270
270
  }
271
271
  await Promise.all(promises);
272
272
  const textureCount = uniqueTextureNames.length;
273
- console.debug(p, "Creating Atlas for", textureCount, "textures");
273
+ log.debug("Creating Atlas for", textureCount, "textures");
274
274
  this.fillMissingTextureKeys(model.textures, textureMap);
275
275
  this.fillMissingTextureKeys(model.textures, metaMap);
276
276
  const sizes = {};
@@ -301,7 +301,7 @@ var UVMapper = class {
301
301
  this.fillMissingTextureKeys(model.textures, sizes);
302
302
  const s = Math.ceil(Math.sqrt(textureCount + 1));
303
303
  const size = Math.ceil(s * maxWidth);
304
- console.debug(p, "Atlas size:", size);
304
+ log.debug("Atlas size:", size);
305
305
  const squaredSize = size * size;
306
306
  const image = new CanvasImage(size, size);
307
307
  const missing = Textures.getMissing().image;
@@ -380,7 +380,7 @@ var UVMapper = class {
380
380
  }
381
381
  this.fillMissingTextureKeys(model.textures, positions);
382
382
  if (isItemModel) {
383
- console.debug(p, "Generating item model for", model);
383
+ log.debug("Generating item model for", model);
384
384
  model.elements = [];
385
385
  for (let layerName of ModelGenerator.ITEM_LAYERS) {
386
386
  const textureImage = textureMap[layerName];
@@ -396,7 +396,7 @@ var UVMapper = class {
396
396
  ), layerName));
397
397
  }
398
398
  }
399
- console.debug(p, "Item model elements", model.elements);
399
+ log.debug("Item model elements", model.elements);
400
400
  }
401
401
  if (!model.elements) {
402
402
  }
@@ -453,7 +453,7 @@ var UVMapper = class {
453
453
  hasTranslucency
454
454
  );
455
455
  } else {
456
- console.warn(p, "Model does not have any textures", model);
456
+ log.warn("Model does not have any textures", model);
457
457
  }
458
458
  return void 0;
459
459
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/UVMapper.ts"],"sourcesContent":["import { BoxGeometry, BufferAttribute, Euler, Float32BufferAttribute, Vector2, Vector3, Vector4 } from \"three\";\nimport { DoubleArray, Model, QuadArray, TextureAsset } from \"./model/Model\";\nimport { ModelElement, ModelFaces } from \"./model/ModelElement\";\nimport { CUBE_FACES, CubeFace } from \"./CubeFace\";\nimport { ModelTextures } from \"./assets/ModelTextures\";\nimport { Assets } from \"./assets/Assets\";\nimport { Maybe, toRadians } from \"./util/util\";\nimport { WrappedImage } from \"./WrappedImage\";\nimport { CanvasImage } from \"./canvas/CanvasImage\";\nimport { TextureAtlas } from \"./texture/TextureAtlas\";\nimport { Caching } from \"./cache/Caching\";\nimport { Textures } from \"./texture/Textures\";\nimport { AnimatorFunction } from \"./AnimatorFunction\";\nimport { MinecraftTextureMeta } from \"./MinecraftTextureMeta\";\nimport { AssetKey } from \"./assets/AssetKey\";\nimport { ModelGenerator } from \"./model/ModelGenerator\";\nimport { prefix } from \"./util/log\";\nimport { DEFAULT_UV, makeUv, makeUvCoords, setFaceUvInArray, setCubeFaceUvInArray, addCubeFaceUvToArray, facesToUvArray } from \"./util/_internal/cubeUv\";\n\nconst p = prefix(\"UVMapper\");\n\nexport { DEFAULT_UV };\nconst X = 0;\nconst Y = 1;\nconst Z = 2;\n\n// Each face's right/down axes in Minecraft's top-origin UV coordinates.\nconst FACE_UV_AXES: Record<CubeFace, [Vector3, Vector3]> = {\n east: [new Vector3(0, 0, -1), new Vector3(0, -1, 0)],\n west: [new Vector3(0, 0, 1), new Vector3(0, -1, 0)],\n up: [new Vector3(1, 0, 0), new Vector3(0, 0, 1)],\n down: [new Vector3(1, 0, 0), new Vector3(0, 0, -1)],\n south: [new Vector3(1, 0, 0), new Vector3(0, -1, 0)],\n north: [new Vector3(-1, 0, 0), new Vector3(0, -1, 0)]\n};\n\n/*\n * - Minecraft Block UVs are from the top-left to bottom-right\n * - three.js UVs are from the bottom-left to top-right\n * - canvas coordinates are from the top-left to bottom-right\n */\n\n// noinspection PointlessArithmeticExpressionJS\n/** Maps Minecraft face coordinates to Three.js UVs and builds per-model texture atlases. */\nexport class UVMapper {\n\n protected static makeUv(uvCoord: number, originalTextureSize: number, actualTextureSize: number): number {\n return makeUv(uvCoord, originalTextureSize, actualTextureSize);\n }\n\n protected static makeUvCoords([originalTextureWidth, originalTextureHeight]: DoubleArray, [actualTextureWidth, actualTextureHeight]: DoubleArray, [x1, y1, x2, y2]: QuadArray): QuadArray {\n return makeUvCoords([originalTextureWidth, originalTextureHeight], [actualTextureWidth, actualTextureHeight], [x1, y1, x2, y2]);\n }\n\n\n public static rotateSingleUv([u, v]: DoubleArray, [px, py]: DoubleArray, radians: number): DoubleArray {\n const sin = Math.sin(radians);\n const cos = Math.cos(radians);\n\n u -= px;\n v -= py;\n\n const uc = u;\n const vc = v;\n\n u = cos * uc - sin * vc;\n v = cos * vc + sin * uc;\n\n u += px;\n v += py;\n\n // return [parseFloat(u.toFixed(8)), parseFloat(v.toFixed(8))];\n return [u, v];\n }\n\n public static addCubeFaceUvToArray(array: number[], faceIndex: number, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray, originalCoords: QuadArray) {\n return addCubeFaceUvToArray(array, faceIndex, originalTextureSize, actualTextureSize, originalCoords);\n }\n\n public static setCubeFaceUvInArray(array: number[], faceIndex: number, [u1, v1, u2, v2]: QuadArray) {\n return setCubeFaceUvInArray(array, faceIndex, [u1, v1, u2, v2]);\n }\n\n public static setFaceUvInArrayV(array: number[], faceIndex: number, uvs: QuadArray<Vector2>) {\n array[((faceIndex + 0) * 2) + 0] = uvs[0].x;\n array[((faceIndex + 0) * 2) + 1] = uvs[0].y;\n\n array[((faceIndex + 1) * 2) + 0] = uvs[1].x;\n array[((faceIndex + 1) * 2) + 1] = uvs[1].y;\n\n array[((faceIndex + 2) * 2) + 0] = uvs[2].x;\n array[((faceIndex + 2) * 2) + 1] = uvs[2].y;\n\n array[((faceIndex + 3) * 2) + 0] = uvs[3].x;\n array[((faceIndex + 3) * 2) + 1] = uvs[3].y;\n }\n\n public static setFaceUvInArray(array: number[], faceIndex: number, uvs: QuadArray<DoubleArray>) {\n return setFaceUvInArray(array, faceIndex, uvs);\n }\n\n public static setCubeFaceUvAttribute(attributes: BufferAttribute, faceIndex: number, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray, originalCoords: QuadArray): void {\n const uv = this.makeUvCoords(originalTextureSize, actualTextureSize, originalCoords);\n this.setCubeFaceUvInAttribute(attributes, faceIndex, uv);\n }\n\n public static setCubeFaceUvInAttribute(attributes: BufferAttribute, faceIndex: number, [u1, v1, u2, v2]: QuadArray) {\n attributes.setXY(faceIndex + 0, u1, v1);\n attributes.setXY(faceIndex + 1, u2, v1);\n attributes.setXY(faceIndex + 2, u1, v2);\n attributes.setXY(faceIndex + 3, u2, v2);\n }\n\n public static setCubeUvs(geometry: BoxGeometry, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray, faces: ModelFaces): void {\n const attributes = geometry.getAttribute(\"uv\") as BufferAttribute;\n for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {\n let faceName = CUBE_FACES[faceIndex];\n let face = faces[faceName];\n if (!face) continue;\n if (!face.uv) {\n face.uv = DEFAULT_UV;\n }\n\n this.setCubeFaceUvAttribute(attributes, faceIndex * 4, originalTextureSize, actualTextureSize, face.uv);\n }\n }\n\n public static facesToUvArray(faces: ModelFaces, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray): number[] {\n return facesToUvArray(faces, originalTextureSize, actualTextureSize);\n }\n\n public static facesToUv(faces: ModelFaces, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray): Float32BufferAttribute {\n return new Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);\n }\n\n /** Bounds texture sampling to texel centres without changing cropped face UVs. */\n public static setAtlasUvBounds(geometry: BoxGeometry, faces: ModelFaces, atlas: TextureAtlas): void {\n const uv = geometry.getAttribute(\"uv\");\n const bounds = new Float32Array(uv.count * 4);\n for (const [faceIndex, faceName] of CUBE_FACES.entries()) {\n const texture = faces[faceName]?.texture?.substring(1);\n const position = texture && atlas.positions[texture];\n const size = texture && atlas.sizes[texture];\n let minU = Infinity, minV = Infinity, maxU = -Infinity, maxV = -Infinity;\n if (position && size) {\n minU = position[0] / atlas.image.width;\n maxU = (position[0] + size[0]) / atlas.image.width;\n minV = 1 - (position[1] + size[1]) / atlas.image.height;\n maxV = 1 - position[1] / atlas.image.height;\n } else {\n for (let corner = 0; corner < 4; corner++) {\n const index = faceIndex * 4 + corner;\n minU = Math.min(minU, uv.getX(index));\n minV = Math.min(minV, uv.getY(index));\n maxU = Math.max(maxU, uv.getX(index));\n maxV = Math.max(maxV, uv.getY(index));\n }\n }\n const insetU = Math.min(0.5 / atlas.image.width, (maxU - minU) / 2);\n const insetV = Math.min(0.5 / atlas.image.height, (maxV - minV) / 2);\n for (let corner = 0; corner < 4; corner++) {\n bounds.set([minU + insetU, minV + insetV, maxU - insetU, maxV - insetV], (faceIndex * 4 + corner) * 4);\n }\n }\n geometry.setAttribute(\"uvBounds\", new Float32BufferAttribute(bounds, 4));\n }\n\n public static lockUvs(geometry: BoxGeometry, faces: ModelFaces, atlas: TextureAtlas, rotation: Euler): void {\n const uv = geometry.getAttribute(\"uv\") as BufferAttribute;\n for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {\n const faceName = CUBE_FACES[faceIndex];\n const texture = faces[faceName]?.texture?.substring(1);\n const position = texture && atlas.positions[texture];\n const size = texture && atlas.sizes[texture];\n if (!position || !size) continue;\n\n const [sourceU, sourceV] = FACE_UV_AXES[faceName];\n const uAxis = sourceU.clone().applyEuler(rotation);\n const vAxis = sourceV.clone().applyEuler(rotation);\n const normal = vAxis.clone().cross(uAxis);\n const targetFace = CUBE_FACES.find(name => {\n const [u, v] = FACE_UV_AXES[name];\n return v.clone().cross(u).dot(normal) > 0.5;\n })!;\n const [targetU, targetV] = FACE_UV_AXES[targetFace];\n const uu = Math.round(targetU.dot(uAxis));\n const uvCross = Math.round(targetU.dot(vAxis));\n const vu = Math.round(targetV.dot(uAxis));\n const vv = Math.round(targetV.dot(vAxis));\n\n // Rotate about the full texture center, not the cropped face or atlas center.\n for (let corner = 0; corner < 4; corner++) {\n const index = faceIndex * 4 + corner;\n const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;\n const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;\n const lockedU = uu * u + uvCross * v + 0.5;\n const lockedV = vu * u + vv * v + 0.5;\n uv.setXY(index,\n (position[0] + lockedU * size[0]) / atlas.image.width,\n 1 - (position[1] + lockedV * size[1]) / atlas.image.height);\n }\n }\n uv.needsUpdate = true;\n }\n\n /** Returns the shared atlas for a keyed, merged model, creating it on first use. */\n public static async getAtlas(model: Model): Promise<Maybe<TextureAtlas>> {\n const keyStr = model.key!.serialize();\n return Caching.modelTextureAtlasCache.get(keyStr, k => {\n return this.createAtlas(model);\n })\n }\n\n public static fillMissingTextureKeys<T>(textures: ModelTextures, target: { [k: string]: T }): { [k: string]: T } {\n for (const key in textures) {\n // Follow references such as \"#all\" -> \"#texture\" to the variable that names a texture.\n let name = key;\n const seen = new Set<string>();\n while (textures[name]?.startsWith(\"#\") && !seen.has(name)) {\n seen.add(name);\n name = textures[name].substr(1);\n }\n if (name !== key) target[key] = target[name];\n }\n return target;\n }\n\n // https://yeleha.co/3qlboGS\n protected static getFallbackUv(element: ModelElement, faceName: CubeFace): QuadArray {\n switch (faceName) {\n case CubeFace.DOWN:\n return [element.from[X], 16 - element.to[Z], element.to[X], 16 - element.from[Z]];\n case CubeFace.UP:\n return [element.from[X], element.from[Z], element.to[X], element.to[Z]];\n case CubeFace.NORTH:\n default:\n return [16 - element.to[X], 16 - element.to[Y], 16 - element.from[X], 16 - element.from[Y]];\n case CubeFace.SOUTH:\n return [element.from[X], 16 - element.to[Y], element.to[X], 16 - element.from[Y]];\n case CubeFace.WEST:\n return [element.from[Z], 16 - element.to[Y], element.to[Z], 16 - element.from[Y]];\n case CubeFace.EAST:\n return [16 - element.to[Z], 16 - element.to[Y], 16 - element.from[Z], 16 - element.from[Y]];\n }\n }\n\n protected static expandAndRotateMcUvs([u1, v1, u2, v2]: QuadArray, rotation: number = 0, actualWidth: number, actualHeight: number): QuadArray<Vector2> {\n // Resize coordinates to actual texture size\n const scaleU = actualWidth / 16;\n const scaleV = actualHeight / 16;\n u1 *= scaleU;\n v1 *= scaleV;\n u2 *= scaleU;\n v2 *= scaleV;\n\n let tl: Vector2 = new Vector2(u1, v1);// top left\n let tr: Vector2 = new Vector2(u2, v1);// top right\n let bl: Vector2 = new Vector2(u1, v2);// bottom left\n let br: Vector2 = new Vector2(u2, v2);// bottom right\n\n switch (rotation) {\n case 0:\n case 360:\n default:\n break;\n case 90:\n tl = new Vector2(u1, v2);\n tr = new Vector2(u1, v1);\n bl = new Vector2(u2, v2);\n br = new Vector2(u2, v1);\n break;\n case 180:\n tl = new Vector2(u2, v2);\n tr = new Vector2(u1, v2);\n bl = new Vector2(u2, v1);\n br = new Vector2(u1, v1);\n break;\n case 270:\n tl = new Vector2(u2, v1);\n tr = new Vector2(u2, v2);\n bl = new Vector2(u1, v1);\n br = new Vector2(u1, v2);\n break;\n }\n\n return [tl, tr, bl, br];\n }\n\n /**\n * Combines model textures and animation metadata into an atlas.\n * Mapped UVs are stored on copies of the model's elements, available through the returned atlas.\n * Returns `undefined` for models without a texture map.\n */\n public static async createAtlas(originalModel: Model): Promise<Maybe<TextureAtlas>> {\n const textureMap: { [key: string]: Maybe<WrappedImage>; } = {};\n const metaMap: { [key: string]: Maybe<MinecraftTextureMeta>; } = {};\n const model = {...originalModel};\n // Merged models share element objects with their cached parents (cube, cube_all, ...), so the\n // baked UVs below must go onto this atlas's own copies, not onto objects other atlases read.\n if (originalModel.elements) {\n model.elements = originalModel.elements.map(element => ({ ...element }));\n }\n const isItemModel = !(\"elements\" in model);\n\n console.debug(p, \"Creating Atlas for\", model.key);\n\n if (model.textures) {\n const promises: Promise<void>[] = [];\n const uniqueTextureNames: string[] = []; // TODO: make these actually unique\n const textureReferences: { [k: string]: string; } = {};\n for (let textureKey in model.textures) {\n let textureValue = model.textures[textureKey];\n if (textureValue.startsWith(\"#\")) {\n textureReferences[textureKey] = textureValue.substr(1);\n } else {\n uniqueTextureNames.push(textureKey);\n const assetKey = AssetKey.parse(\"textures\", textureValue, model.key);\n promises.push(ModelTextures.get(assetKey).then(asset => {\n if (!asset) {\n console.warn(p, \"Missing texture\", assetKey)\n return;\n }\n textureMap[textureKey] = new WrappedImage(asset);\n }));\n promises.push(ModelTextures.getMeta(assetKey).then(meta => {\n metaMap[textureKey] = meta;\n }))\n }\n }\n await Promise.all(promises);\n const textureCount = uniqueTextureNames.length;\n console.debug(p, \"Creating Atlas for\", textureCount, \"textures\");\n // console.log(model.textures)\n\n this.fillMissingTextureKeys(model.textures, textureMap);\n this.fillMissingTextureKeys(model.textures, metaMap);\n\n const sizes: { [texture: string]: DoubleArray; } = {};\n const frames: { [texture: string]: { index: number; time: number }[] } = {};\n\n // Find largest texture dimensions\n let maxWidth = 0;\n for (let textureKey of uniqueTextureNames) {\n let texture = textureMap[textureKey];\n if (!texture) continue;\n const animation = metaMap[textureKey]?.animation;\n let width = texture.width, height = texture.height;\n if (animation) {\n const square = Math.min(width, height);\n width = animation.width ?? (animation.height === undefined ? square : width);\n height = animation.height ?? (animation.width === undefined ? square : height);\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0\n || texture.width % width || texture.height % height) {\n throw new RangeError(`Invalid animation frame dimensions for ${textureKey}`);\n }\n const count = (texture.width / width) * (texture.height / height);\n const time = animation.frametime ?? 1;\n frames[textureKey] = (animation.frames ?? Array.from({ length: count }, (_, index) => index))\n .map(frame => typeof frame === \"number\" ? { index: frame, time } : { index: frame.index, time: frame.time ?? time });\n if (!frames[textureKey].length || frames[textureKey].some(frame => !Number.isInteger(frame.index)\n || frame.index < 0 || frame.index >= count || !Number.isInteger(frame.time) || frame.time < 1)) {\n throw new RangeError(`Invalid animation frames for ${textureKey}`);\n }\n }\n sizes[textureKey] = [width, height];\n maxWidth = Math.max(maxWidth, width, height);\n }\n this.fillMissingTextureKeys(model.textures, sizes);\n\n // console.log(\"sizes\", sizes);\n\n const s = (Math.ceil(Math.sqrt(textureCount + 1))); // +1 for transparency\n const size = Math.ceil(s * maxWidth)\n console.debug(p, \"Atlas size:\", size);\n // console.log(\"size: \" + size);\n const squaredSize = size * size;\n\n const image = new CanvasImage(size, size);\n const missing = Textures.getMissing().image;\n const missingPixels = image.context.createImageData(missing.width, missing.height);\n missingPixels.data.set(missing.data!);\n image.putData(missingPixels, 0, 0);\n // The top-left atlas cell keeps absent model faces transparent.\n image.context.clearRect(0, 0, maxWidth, maxWidth);\n\n const positions: { [texture: string]: DoubleArray; } = {};\n\n let hasTransparency = false;\n let hasTranslucency = false;\n\n let hasAnimation = false;\n const animatorFunctions: { [texture: string]: AnimatorFunction; } = {};\n\n // Draw all textures onto a single image\n let tx = 1; // start one over to leave room for the transparent space\n let ty = 0;\n for (let textureIndex = 0; textureIndex < uniqueTextureNames.length; textureIndex++) {\n let textureKey = uniqueTextureNames[textureIndex];\n let texture = textureMap[textureKey];\n let x = tx * maxWidth;\n let y = ty * maxWidth;\n if (texture) {\n positions[textureKey] = [x, y];\n const [width, height] = sizes[textureKey];\n const sequence = frames[textureKey];\n const getFrameData = (index: number) => {\n const columns = texture!.width / width;\n return texture!.getSectionData((index % columns) * width,\n Math.floor(index / columns) * height, width, height);\n };\n const firstFrame = getFrameData(sequence?.[0].index ?? 0);\n image.putData(firstFrame, x, y);\n\n if (texture.hasTransparency) {\n hasTransparency = true;\n }\n if (texture.hasTranslucency) {\n hasTranslucency = true;\n }\n\n if (sequence && sequence.some(frame => frame.index !== sequence[0].index)) {\n hasAnimation = true;\n let t = 0;\n let f = 0;\n const interpolated = metaMap[textureKey]?.animation?.interpolate\n ? image.context.createImageData(width, height) : undefined;\n let currentFrame = firstFrame;\n let nextFrame = interpolated ? getFrameData(sequence[1].index) : firstFrame;\n\n animatorFunctions[textureKey] = () => {\n if (++t >= sequence[f].time) {\n t = 0;\n const previous = sequence[f].index;\n f = (f + 1) % sequence.length;\n if (interpolated) {\n currentFrame = nextFrame;\n nextFrame = getFrameData(sequence[(f + 1) % sequence.length].index);\n }\n if (sequence[f].index === previous) return false;\n image.putData(interpolated ? currentFrame : getFrameData(sequence[f].index), x, y);\n return true;\n }\n if (!interpolated || sequence[f].index === sequence[(f + 1) % sequence.length].index) return false;\n // Vanilla encodes the atlas shader's interpolation progress in thousandths.\n const progress = Math.floor(Math.fround(Math.fround(t / sequence[f].time) * 1000)) / 1000;\n for (let i = 0; i < interpolated.data.length; i++) {\n interpolated.data[i] = currentFrame.data[i] + (nextFrame.data[i] - currentFrame.data[i]) * progress;\n }\n image.putData(interpolated, x, y);\n return true;\n };\n }\n }\n tx++;\n if (tx >= s) {\n tx = 0;\n ty++;\n }\n }\n this.fillMissingTextureKeys(model.textures, positions);\n\n // console.log(\"positions\", positions);\n\n if (isItemModel) {\n console.debug(p, \"Generating item model for\", model);\n model.elements = [];\n for (let layerName of ModelGenerator.ITEM_LAYERS) {\n const textureImage = textureMap[layerName];\n if (textureImage) {\n // Outline the frame that was drawn into the atlas, not the whole animation strip.\n const [width, height] = sizes[layerName];\n const frame = frames[layerName]?.[0].index ?? 0;\n const columns = textureImage.width / width;\n model.elements.push(...ModelGenerator.generateItemModel(textureImage.getSectionData(\n (frame % columns) * width, Math.floor(frame / columns) * height, width, height), layerName))\n }\n }\n console.debug(p, \"Item model elements\", model.elements)\n }\n\n if (!model.elements) {\n //TODO: default elements\n }\n\n // Adjust UV positions\n if (model.elements) {\n for (let elementIndex = 0; elementIndex < model.elements.length; elementIndex++) {\n let element = model.elements[elementIndex];\n let uv: number[] = [];\n // Set default uvs to missing texture\n for (let i = 0; i < CUBE_FACES.length; i++) {\n this.setCubeFaceUvInArray(uv, i * 4, [0, 0, 8 / size, 8 / size])\n }\n for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {\n let faceName = CUBE_FACES[faceIndex];\n // console.log(faceName)\n let face = element.faces[faceName];\n if (!face) {\n // set uv transparent\n this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size])\n continue;\n }\n // Keep the missing-texture UVs when no texture is referenced.\n if (!face.texture) continue;\n if (!face.uv) {\n face.uv = this.getFallbackUv(element, faceName);\n }\n\n const faceTexture = face.texture.substr(1); // remove #\n const texPosition = positions[faceTexture] || [0, 0];\n const texSize = sizes[faceTexture] || [16, 16];\n\n let texPosV = new Vector2(texPosition[0], texPosition[1]);\n\n const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);\n\n // move to atlas position\n tl.add(texPosV);\n tr.add(texPosV);\n bl.add(texPosV);\n br.add(texPosV);\n\n // divide to 0-1\n tl.divideScalar(size);\n tr.divideScalar(size);\n bl.divideScalar(size);\n br.divideScalar(size);\n\n // flip y coordinates\n tl.y = 1 - tl.y;\n tr.y = 1 - tr.y;\n bl.y = 1 - bl.y;\n br.y = 1 - br.y;\n\n let uvs: QuadArray<Vector2> = [tl, tr, bl, br];\n // console.log(\"uvs\", uvs);\n this.setFaceUvInArrayV(uv, faceIndex * 4, uvs);\n }\n\n element.mappedUv = uv;\n }\n } else {\n //TODO: item model\n }\n\n return new TextureAtlas(\n model,\n image,\n sizes,\n positions,\n hasAnimation,\n animatorFunctions,\n hasTransparency,\n hasTranslucency\n );\n } else {\n console.warn(p, \"Model does not have any textures\", model);\n }\n return undefined;\n }\n\n}\n\n// Based on net.minecraft.client.renderer.block.model.BlockFaceUV\n/** Stores a Minecraft face's UV rectangle and its rotation in degrees. */\nexport class MinecraftFaceUV {\n\n constructor(readonly uv: QuadArray = [0, 0, 16, 16], readonly rotation: number = 0) {\n }\n\n getU(index: number): number {\n const shiftedIndex = this.getShiftedIndex(index);\n return this.uv[shiftedIndex !== 0 && index !== 1 ? 2 : 0];\n }\n\n getV(index: number): number {\n const shiftedIndex = this.getShiftedIndex(index);\n return this.uv[shiftedIndex !== 0 && index !== 3 ? 3 : 1];\n }\n\n protected getShiftedIndex(index: number): number {\n return (index + this.rotation / 90) % 40;\n }\n\n protected getReverseIndex(index: number): number {\n return (index + 4 - this.rotation / 90) % 4;\n }\n\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/UVMapper.ts"],"sourcesContent":["import { BoxGeometry, BufferAttribute, Euler, Float32BufferAttribute, Vector2, Vector3, Vector4 } from \"three\";\nimport { DoubleArray, Model, QuadArray, TextureAsset } from \"./model/Model\";\nimport { ModelElement, ModelFaces } from \"./model/ModelElement\";\nimport { CUBE_FACES, CubeFace } from \"./CubeFace\";\nimport { ModelTextures } from \"./assets/ModelTextures\";\nimport { Assets } from \"./assets/Assets\";\nimport { Maybe, toRadians } from \"./util/util\";\nimport { WrappedImage } from \"./WrappedImage\";\nimport { CanvasImage } from \"./canvas/CanvasImage\";\nimport { TextureAtlas } from \"./texture/TextureAtlas\";\nimport { Caching } from \"./cache/Caching\";\nimport { Textures } from \"./texture/Textures\";\nimport { AnimatorFunction } from \"./AnimatorFunction\";\nimport { MinecraftTextureMeta } from \"./MinecraftTextureMeta\";\nimport { AssetKey } from \"./assets/AssetKey\";\nimport { ModelGenerator } from \"./model/ModelGenerator\";\nimport { logger } from \"./util/log\";\nimport { DEFAULT_UV, makeUv, makeUvCoords, setFaceUvInArray, setCubeFaceUvInArray, addCubeFaceUvToArray, facesToUvArray } from \"./util/_internal/cubeUv\";\n\nconst log = logger(\"UVMapper\");\n\nexport { DEFAULT_UV };\nconst X = 0;\nconst Y = 1;\nconst Z = 2;\n\n// Each face's right/down axes in Minecraft's top-origin UV coordinates.\nconst FACE_UV_AXES: Record<CubeFace, [Vector3, Vector3]> = {\n east: [new Vector3(0, 0, -1), new Vector3(0, -1, 0)],\n west: [new Vector3(0, 0, 1), new Vector3(0, -1, 0)],\n up: [new Vector3(1, 0, 0), new Vector3(0, 0, 1)],\n down: [new Vector3(1, 0, 0), new Vector3(0, 0, -1)],\n south: [new Vector3(1, 0, 0), new Vector3(0, -1, 0)],\n north: [new Vector3(-1, 0, 0), new Vector3(0, -1, 0)]\n};\n\n/*\n * - Minecraft Block UVs are from the top-left to bottom-right\n * - three.js UVs are from the bottom-left to top-right\n * - canvas coordinates are from the top-left to bottom-right\n */\n\n// noinspection PointlessArithmeticExpressionJS\n/** Maps Minecraft face coordinates to Three.js UVs and builds per-model texture atlases. */\nexport class UVMapper {\n\n protected static makeUv(uvCoord: number, originalTextureSize: number, actualTextureSize: number): number {\n return makeUv(uvCoord, originalTextureSize, actualTextureSize);\n }\n\n protected static makeUvCoords([originalTextureWidth, originalTextureHeight]: DoubleArray, [actualTextureWidth, actualTextureHeight]: DoubleArray, [x1, y1, x2, y2]: QuadArray): QuadArray {\n return makeUvCoords([originalTextureWidth, originalTextureHeight], [actualTextureWidth, actualTextureHeight], [x1, y1, x2, y2]);\n }\n\n\n public static rotateSingleUv([u, v]: DoubleArray, [px, py]: DoubleArray, radians: number): DoubleArray {\n const sin = Math.sin(radians);\n const cos = Math.cos(radians);\n\n u -= px;\n v -= py;\n\n const uc = u;\n const vc = v;\n\n u = cos * uc - sin * vc;\n v = cos * vc + sin * uc;\n\n u += px;\n v += py;\n\n // return [parseFloat(u.toFixed(8)), parseFloat(v.toFixed(8))];\n return [u, v];\n }\n\n public static addCubeFaceUvToArray(array: number[], faceIndex: number, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray, originalCoords: QuadArray) {\n return addCubeFaceUvToArray(array, faceIndex, originalTextureSize, actualTextureSize, originalCoords);\n }\n\n public static setCubeFaceUvInArray(array: number[], faceIndex: number, [u1, v1, u2, v2]: QuadArray) {\n return setCubeFaceUvInArray(array, faceIndex, [u1, v1, u2, v2]);\n }\n\n public static setFaceUvInArrayV(array: number[], faceIndex: number, uvs: QuadArray<Vector2>) {\n array[((faceIndex + 0) * 2) + 0] = uvs[0].x;\n array[((faceIndex + 0) * 2) + 1] = uvs[0].y;\n\n array[((faceIndex + 1) * 2) + 0] = uvs[1].x;\n array[((faceIndex + 1) * 2) + 1] = uvs[1].y;\n\n array[((faceIndex + 2) * 2) + 0] = uvs[2].x;\n array[((faceIndex + 2) * 2) + 1] = uvs[2].y;\n\n array[((faceIndex + 3) * 2) + 0] = uvs[3].x;\n array[((faceIndex + 3) * 2) + 1] = uvs[3].y;\n }\n\n public static setFaceUvInArray(array: number[], faceIndex: number, uvs: QuadArray<DoubleArray>) {\n return setFaceUvInArray(array, faceIndex, uvs);\n }\n\n public static setCubeFaceUvAttribute(attributes: BufferAttribute, faceIndex: number, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray, originalCoords: QuadArray): void {\n const uv = this.makeUvCoords(originalTextureSize, actualTextureSize, originalCoords);\n this.setCubeFaceUvInAttribute(attributes, faceIndex, uv);\n }\n\n public static setCubeFaceUvInAttribute(attributes: BufferAttribute, faceIndex: number, [u1, v1, u2, v2]: QuadArray) {\n attributes.setXY(faceIndex + 0, u1, v1);\n attributes.setXY(faceIndex + 1, u2, v1);\n attributes.setXY(faceIndex + 2, u1, v2);\n attributes.setXY(faceIndex + 3, u2, v2);\n }\n\n public static setCubeUvs(geometry: BoxGeometry, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray, faces: ModelFaces): void {\n const attributes = geometry.getAttribute(\"uv\") as BufferAttribute;\n for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {\n let faceName = CUBE_FACES[faceIndex];\n let face = faces[faceName];\n if (!face) continue;\n if (!face.uv) {\n face.uv = DEFAULT_UV;\n }\n\n this.setCubeFaceUvAttribute(attributes, faceIndex * 4, originalTextureSize, actualTextureSize, face.uv);\n }\n }\n\n public static facesToUvArray(faces: ModelFaces, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray): number[] {\n return facesToUvArray(faces, originalTextureSize, actualTextureSize);\n }\n\n public static facesToUv(faces: ModelFaces, originalTextureSize: DoubleArray, actualTextureSize: DoubleArray): Float32BufferAttribute {\n return new Float32BufferAttribute(this.facesToUvArray(faces, originalTextureSize, actualTextureSize), 2);\n }\n\n /** Bounds texture sampling to texel centres without changing cropped face UVs. */\n public static setAtlasUvBounds(geometry: BoxGeometry, faces: ModelFaces, atlas: TextureAtlas): void {\n const uv = geometry.getAttribute(\"uv\");\n const bounds = new Float32Array(uv.count * 4);\n for (const [faceIndex, faceName] of CUBE_FACES.entries()) {\n const texture = faces[faceName]?.texture?.substring(1);\n const position = texture && atlas.positions[texture];\n const size = texture && atlas.sizes[texture];\n let minU = Infinity, minV = Infinity, maxU = -Infinity, maxV = -Infinity;\n if (position && size) {\n minU = position[0] / atlas.image.width;\n maxU = (position[0] + size[0]) / atlas.image.width;\n minV = 1 - (position[1] + size[1]) / atlas.image.height;\n maxV = 1 - position[1] / atlas.image.height;\n } else {\n for (let corner = 0; corner < 4; corner++) {\n const index = faceIndex * 4 + corner;\n minU = Math.min(minU, uv.getX(index));\n minV = Math.min(minV, uv.getY(index));\n maxU = Math.max(maxU, uv.getX(index));\n maxV = Math.max(maxV, uv.getY(index));\n }\n }\n const insetU = Math.min(0.5 / atlas.image.width, (maxU - minU) / 2);\n const insetV = Math.min(0.5 / atlas.image.height, (maxV - minV) / 2);\n for (let corner = 0; corner < 4; corner++) {\n bounds.set([minU + insetU, minV + insetV, maxU - insetU, maxV - insetV], (faceIndex * 4 + corner) * 4);\n }\n }\n geometry.setAttribute(\"uvBounds\", new Float32BufferAttribute(bounds, 4));\n }\n\n public static lockUvs(geometry: BoxGeometry, faces: ModelFaces, atlas: TextureAtlas, rotation: Euler): void {\n const uv = geometry.getAttribute(\"uv\") as BufferAttribute;\n for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {\n const faceName = CUBE_FACES[faceIndex];\n const texture = faces[faceName]?.texture?.substring(1);\n const position = texture && atlas.positions[texture];\n const size = texture && atlas.sizes[texture];\n if (!position || !size) continue;\n\n const [sourceU, sourceV] = FACE_UV_AXES[faceName];\n const uAxis = sourceU.clone().applyEuler(rotation);\n const vAxis = sourceV.clone().applyEuler(rotation);\n const normal = vAxis.clone().cross(uAxis);\n const targetFace = CUBE_FACES.find(name => {\n const [u, v] = FACE_UV_AXES[name];\n return v.clone().cross(u).dot(normal) > 0.5;\n })!;\n const [targetU, targetV] = FACE_UV_AXES[targetFace];\n const uu = Math.round(targetU.dot(uAxis));\n const uvCross = Math.round(targetU.dot(vAxis));\n const vu = Math.round(targetV.dot(uAxis));\n const vv = Math.round(targetV.dot(vAxis));\n\n // Rotate about the full texture center, not the cropped face or atlas center.\n for (let corner = 0; corner < 4; corner++) {\n const index = faceIndex * 4 + corner;\n const u = (uv.getX(index) * atlas.image.width - position[0]) / size[0] - 0.5;\n const v = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] - 0.5;\n const lockedU = uu * u + uvCross * v + 0.5;\n const lockedV = vu * u + vv * v + 0.5;\n uv.setXY(index,\n (position[0] + lockedU * size[0]) / atlas.image.width,\n 1 - (position[1] + lockedV * size[1]) / atlas.image.height);\n }\n }\n uv.needsUpdate = true;\n }\n\n /** Returns the shared atlas for a keyed, merged model, creating it on first use. */\n public static async getAtlas(model: Model): Promise<Maybe<TextureAtlas>> {\n const keyStr = model.key!.serialize();\n return Caching.modelTextureAtlasCache.get(keyStr, k => {\n return this.createAtlas(model);\n })\n }\n\n public static fillMissingTextureKeys<T>(textures: ModelTextures, target: { [k: string]: T }): { [k: string]: T } {\n for (const key in textures) {\n // Follow references such as \"#all\" -> \"#texture\" to the variable that names a texture.\n let name = key;\n const seen = new Set<string>();\n while (textures[name]?.startsWith(\"#\") && !seen.has(name)) {\n seen.add(name);\n name = textures[name].substr(1);\n }\n if (name !== key) target[key] = target[name];\n }\n return target;\n }\n\n // https://yeleha.co/3qlboGS\n protected static getFallbackUv(element: ModelElement, faceName: CubeFace): QuadArray {\n switch (faceName) {\n case CubeFace.DOWN:\n return [element.from[X], 16 - element.to[Z], element.to[X], 16 - element.from[Z]];\n case CubeFace.UP:\n return [element.from[X], element.from[Z], element.to[X], element.to[Z]];\n case CubeFace.NORTH:\n default:\n return [16 - element.to[X], 16 - element.to[Y], 16 - element.from[X], 16 - element.from[Y]];\n case CubeFace.SOUTH:\n return [element.from[X], 16 - element.to[Y], element.to[X], 16 - element.from[Y]];\n case CubeFace.WEST:\n return [element.from[Z], 16 - element.to[Y], element.to[Z], 16 - element.from[Y]];\n case CubeFace.EAST:\n return [16 - element.to[Z], 16 - element.to[Y], 16 - element.from[Z], 16 - element.from[Y]];\n }\n }\n\n protected static expandAndRotateMcUvs([u1, v1, u2, v2]: QuadArray, rotation: number = 0, actualWidth: number, actualHeight: number): QuadArray<Vector2> {\n // Resize coordinates to actual texture size\n const scaleU = actualWidth / 16;\n const scaleV = actualHeight / 16;\n u1 *= scaleU;\n v1 *= scaleV;\n u2 *= scaleU;\n v2 *= scaleV;\n\n let tl: Vector2 = new Vector2(u1, v1);// top left\n let tr: Vector2 = new Vector2(u2, v1);// top right\n let bl: Vector2 = new Vector2(u1, v2);// bottom left\n let br: Vector2 = new Vector2(u2, v2);// bottom right\n\n switch (rotation) {\n case 0:\n case 360:\n default:\n break;\n case 90:\n tl = new Vector2(u1, v2);\n tr = new Vector2(u1, v1);\n bl = new Vector2(u2, v2);\n br = new Vector2(u2, v1);\n break;\n case 180:\n tl = new Vector2(u2, v2);\n tr = new Vector2(u1, v2);\n bl = new Vector2(u2, v1);\n br = new Vector2(u1, v1);\n break;\n case 270:\n tl = new Vector2(u2, v1);\n tr = new Vector2(u2, v2);\n bl = new Vector2(u1, v1);\n br = new Vector2(u1, v2);\n break;\n }\n\n return [tl, tr, bl, br];\n }\n\n /**\n * Combines model textures and animation metadata into an atlas.\n * Mapped UVs are stored on copies of the model's elements, available through the returned atlas.\n * Returns `undefined` for models without a texture map.\n */\n public static async createAtlas(originalModel: Model): Promise<Maybe<TextureAtlas>> {\n const textureMap: { [key: string]: Maybe<WrappedImage>; } = {};\n const metaMap: { [key: string]: Maybe<MinecraftTextureMeta>; } = {};\n const model = {...originalModel};\n // Merged models share element objects with their cached parents (cube, cube_all, ...), so the\n // baked UVs below must go onto this atlas's own copies, not onto objects other atlases read.\n if (originalModel.elements) {\n model.elements = originalModel.elements.map(element => ({ ...element }));\n }\n const isItemModel = !(\"elements\" in model);\n\n log.debug(\"Creating Atlas for\", model.key);\n\n if (model.textures) {\n const promises: Promise<void>[] = [];\n const uniqueTextureNames: string[] = []; // TODO: make these actually unique\n const textureReferences: { [k: string]: string; } = {};\n for (let textureKey in model.textures) {\n let textureValue = model.textures[textureKey];\n if (textureValue.startsWith(\"#\")) {\n textureReferences[textureKey] = textureValue.substr(1);\n } else {\n uniqueTextureNames.push(textureKey);\n const assetKey = AssetKey.parse(\"textures\", textureValue, model.key);\n promises.push(ModelTextures.get(assetKey).then(asset => {\n if (!asset) {\n log.warn(\"Missing texture\", assetKey)\n return;\n }\n textureMap[textureKey] = new WrappedImage(asset);\n }));\n promises.push(ModelTextures.getMeta(assetKey).then(meta => {\n metaMap[textureKey] = meta;\n }))\n }\n }\n await Promise.all(promises);\n const textureCount = uniqueTextureNames.length;\n log.debug(\"Creating Atlas for\", textureCount, \"textures\");\n\n this.fillMissingTextureKeys(model.textures, textureMap);\n this.fillMissingTextureKeys(model.textures, metaMap);\n\n const sizes: { [texture: string]: DoubleArray; } = {};\n const frames: { [texture: string]: { index: number; time: number }[] } = {};\n\n // Find largest texture dimensions\n let maxWidth = 0;\n for (let textureKey of uniqueTextureNames) {\n let texture = textureMap[textureKey];\n if (!texture) continue;\n const animation = metaMap[textureKey]?.animation;\n let width = texture.width, height = texture.height;\n if (animation) {\n const square = Math.min(width, height);\n width = animation.width ?? (animation.height === undefined ? square : width);\n height = animation.height ?? (animation.width === undefined ? square : height);\n if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0\n || texture.width % width || texture.height % height) {\n throw new RangeError(`Invalid animation frame dimensions for ${textureKey}`);\n }\n const count = (texture.width / width) * (texture.height / height);\n const time = animation.frametime ?? 1;\n frames[textureKey] = (animation.frames ?? Array.from({ length: count }, (_, index) => index))\n .map(frame => typeof frame === \"number\" ? { index: frame, time } : { index: frame.index, time: frame.time ?? time });\n if (!frames[textureKey].length || frames[textureKey].some(frame => !Number.isInteger(frame.index)\n || frame.index < 0 || frame.index >= count || !Number.isInteger(frame.time) || frame.time < 1)) {\n throw new RangeError(`Invalid animation frames for ${textureKey}`);\n }\n }\n sizes[textureKey] = [width, height];\n maxWidth = Math.max(maxWidth, width, height);\n }\n this.fillMissingTextureKeys(model.textures, sizes);\n\n\n const s = (Math.ceil(Math.sqrt(textureCount + 1))); // +1 for transparency\n const size = Math.ceil(s * maxWidth)\n log.debug(\"Atlas size:\", size);\n const squaredSize = size * size;\n\n const image = new CanvasImage(size, size);\n const missing = Textures.getMissing().image;\n const missingPixels = image.context.createImageData(missing.width, missing.height);\n missingPixels.data.set(missing.data!);\n image.putData(missingPixels, 0, 0);\n // The top-left atlas cell keeps absent model faces transparent.\n image.context.clearRect(0, 0, maxWidth, maxWidth);\n\n const positions: { [texture: string]: DoubleArray; } = {};\n\n let hasTransparency = false;\n let hasTranslucency = false;\n\n let hasAnimation = false;\n const animatorFunctions: { [texture: string]: AnimatorFunction; } = {};\n\n // Draw all textures onto a single image\n let tx = 1; // start one over to leave room for the transparent space\n let ty = 0;\n for (let textureIndex = 0; textureIndex < uniqueTextureNames.length; textureIndex++) {\n let textureKey = uniqueTextureNames[textureIndex];\n let texture = textureMap[textureKey];\n let x = tx * maxWidth;\n let y = ty * maxWidth;\n if (texture) {\n positions[textureKey] = [x, y];\n const [width, height] = sizes[textureKey];\n const sequence = frames[textureKey];\n const getFrameData = (index: number) => {\n const columns = texture!.width / width;\n return texture!.getSectionData((index % columns) * width,\n Math.floor(index / columns) * height, width, height);\n };\n const firstFrame = getFrameData(sequence?.[0].index ?? 0);\n image.putData(firstFrame, x, y);\n\n if (texture.hasTransparency) {\n hasTransparency = true;\n }\n if (texture.hasTranslucency) {\n hasTranslucency = true;\n }\n\n if (sequence && sequence.some(frame => frame.index !== sequence[0].index)) {\n hasAnimation = true;\n let t = 0;\n let f = 0;\n const interpolated = metaMap[textureKey]?.animation?.interpolate\n ? image.context.createImageData(width, height) : undefined;\n let currentFrame = firstFrame;\n let nextFrame = interpolated ? getFrameData(sequence[1].index) : firstFrame;\n\n animatorFunctions[textureKey] = () => {\n if (++t >= sequence[f].time) {\n t = 0;\n const previous = sequence[f].index;\n f = (f + 1) % sequence.length;\n if (interpolated) {\n currentFrame = nextFrame;\n nextFrame = getFrameData(sequence[(f + 1) % sequence.length].index);\n }\n if (sequence[f].index === previous) return false;\n image.putData(interpolated ? currentFrame : getFrameData(sequence[f].index), x, y);\n return true;\n }\n if (!interpolated || sequence[f].index === sequence[(f + 1) % sequence.length].index) return false;\n // Vanilla encodes the atlas shader's interpolation progress in thousandths.\n const progress = Math.floor(Math.fround(Math.fround(t / sequence[f].time) * 1000)) / 1000;\n for (let i = 0; i < interpolated.data.length; i++) {\n interpolated.data[i] = currentFrame.data[i] + (nextFrame.data[i] - currentFrame.data[i]) * progress;\n }\n image.putData(interpolated, x, y);\n return true;\n };\n }\n }\n tx++;\n if (tx >= s) {\n tx = 0;\n ty++;\n }\n }\n this.fillMissingTextureKeys(model.textures, positions);\n\n\n if (isItemModel) {\n log.debug(\"Generating item model for\", model);\n model.elements = [];\n for (let layerName of ModelGenerator.ITEM_LAYERS) {\n const textureImage = textureMap[layerName];\n if (textureImage) {\n // Outline the frame that was drawn into the atlas, not the whole animation strip.\n const [width, height] = sizes[layerName];\n const frame = frames[layerName]?.[0].index ?? 0;\n const columns = textureImage.width / width;\n model.elements.push(...ModelGenerator.generateItemModel(textureImage.getSectionData(\n (frame % columns) * width, Math.floor(frame / columns) * height, width, height), layerName))\n }\n }\n log.debug(\"Item model elements\", model.elements)\n }\n\n if (!model.elements) {\n //TODO: default elements\n }\n\n // Adjust UV positions\n if (model.elements) {\n for (let elementIndex = 0; elementIndex < model.elements.length; elementIndex++) {\n let element = model.elements[elementIndex];\n let uv: number[] = [];\n // Set default uvs to missing texture\n for (let i = 0; i < CUBE_FACES.length; i++) {\n this.setCubeFaceUvInArray(uv, i * 4, [0, 0, 8 / size, 8 / size])\n }\n for (let faceIndex = 0; faceIndex < CUBE_FACES.length; faceIndex++) {\n let faceName = CUBE_FACES[faceIndex];\n let face = element.faces[faceName];\n if (!face) {\n // set uv transparent\n this.setCubeFaceUvInArray(uv, faceIndex * 4, [0, 1, 8 / size, (size - 8) / size])\n continue;\n }\n // Keep the missing-texture UVs when no texture is referenced.\n if (!face.texture) continue;\n if (!face.uv) {\n face.uv = this.getFallbackUv(element, faceName);\n }\n\n const faceTexture = face.texture.substr(1); // remove #\n const texPosition = positions[faceTexture] || [0, 0];\n const texSize = sizes[faceTexture] || [16, 16];\n\n let texPosV = new Vector2(texPosition[0], texPosition[1]);\n\n const [tl, tr, bl, br] = this.expandAndRotateMcUvs(face.uv, face.rotation, texSize[0], texSize[1]);\n\n // move to atlas position\n tl.add(texPosV);\n tr.add(texPosV);\n bl.add(texPosV);\n br.add(texPosV);\n\n // divide to 0-1\n tl.divideScalar(size);\n tr.divideScalar(size);\n bl.divideScalar(size);\n br.divideScalar(size);\n\n // flip y coordinates\n tl.y = 1 - tl.y;\n tr.y = 1 - tr.y;\n bl.y = 1 - bl.y;\n br.y = 1 - br.y;\n\n let uvs: QuadArray<Vector2> = [tl, tr, bl, br];\n this.setFaceUvInArrayV(uv, faceIndex * 4, uvs);\n }\n\n element.mappedUv = uv;\n }\n } else {\n //TODO: item model\n }\n\n return new TextureAtlas(\n model,\n image,\n sizes,\n positions,\n hasAnimation,\n animatorFunctions,\n hasTransparency,\n hasTranslucency\n );\n } else {\n log.warn(\"Model does not have any textures\", model);\n }\n return undefined;\n }\n\n}\n\n// Based on net.minecraft.client.renderer.block.model.BlockFaceUV\n/** Stores a Minecraft face's UV rectangle and its rotation in degrees. */\nexport class MinecraftFaceUV {\n\n constructor(readonly uv: QuadArray = [0, 0, 16, 16], readonly rotation: number = 0) {\n }\n\n getU(index: number): number {\n const shiftedIndex = this.getShiftedIndex(index);\n return this.uv[shiftedIndex !== 0 && index !== 1 ? 2 : 0];\n }\n\n getV(index: number): number {\n const shiftedIndex = this.getShiftedIndex(index);\n return this.uv[shiftedIndex !== 0 && index !== 3 ? 3 : 1];\n }\n\n protected getShiftedIndex(index: number): number {\n return (index + this.rotation / 90) % 40;\n }\n\n protected getReverseIndex(index: number): number {\n return (index + 4 - this.rotation / 90) % 4;\n }\n\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,84 @@
1
+ // src/armor/Armor.ts
2
+ import { AssetKey, BasicAssetKey, isResourceLocation } from "../assets/AssetKey.mjs";
3
+ import { AssetLoader } from "../assets/AssetLoader.mjs";
4
+ import { Entities } from "../assets/Entities.mjs";
5
+ import { AssetParser } from "../assets/source/parser/AssetParsers.mjs";
6
+ import { Caching } from "../cache/Caching.mjs";
7
+ import { MineRenderError } from "../error/MineRenderError.mjs";
8
+ var ARMOR_TRANSFORM = [
9
+ { rotate: [0, Math.PI, 0] },
10
+ { scale: [-1, -1, 1] },
11
+ { translate: [0, -24, 0] }
12
+ ];
13
+ var Armor = class {
14
+ /** Loads 1.21.4+ armor in SkinObject's frame, or returns undefined when no layer draws. */
15
+ static async getEntity(armor) {
16
+ const model = await Entities.getModelFile(new BasicAssetKey("minecraft", "player"));
17
+ const layers = {};
18
+ const slots = { chest: "chestplate", legs: "leggings", feet: "boots", head: "helmet" };
19
+ for (const slot of Object.keys(slots)) {
20
+ const value = armor[slot];
21
+ if (value === void 0) continue;
22
+ const piece = typeof value === "string" ? { asset: value } : value;
23
+ const name = slots[slot], geometry = model?.layers[name];
24
+ if (!geometry) throw new MineRenderError(`Missing armor geometry ${name}; armor needs Minecraft 1.21.4 or later`);
25
+ const id = this.identifier(piece.asset);
26
+ const key = new AssetKey(id.namespace, id.path, "equipment", void 0, "assets", ".json");
27
+ const equipment = await Caching.equipmentCache.get(key.serialize(), () => AssetLoader.get(key, AssetParser.JSON));
28
+ if (!equipment) throw new MineRenderError(`Missing equipment asset ${piece.asset}; armor takes equipment asset IDs such as minecraft:diamond and needs Minecraft 1.21.4 or later`);
29
+ const layerType = slot === "legs" ? "humanoid_leggings" : "humanoid";
30
+ const equipmentLayers = equipment.layers[layerType];
31
+ if (!equipmentLayers?.length) continue;
32
+ let count = 0;
33
+ const add = (texture, settings) => {
34
+ layers[++count === 1 ? name : `${name}#${count}`] = { key: texture, texture, layer: geometry, ...settings };
35
+ };
36
+ let glint = piece.glint;
37
+ for (const layer of equipmentLayers) {
38
+ let color;
39
+ if (layer.dyeable) {
40
+ const undyed = layer.dyeable.color_when_undyed;
41
+ color = piece.color || (Array.isArray(undyed) ? Math.floor(undyed[0] * 255) << 16 | Math.floor(undyed[1] * 255) << 8 | Math.floor(undyed[2] * 255) : undyed === void 0 ? void 0 : undyed & 16777215);
42
+ if (color === void 0) continue;
43
+ }
44
+ const texture = this.identifier(layer.texture);
45
+ add(
46
+ new AssetKey(texture.namespace, `equipment/${layerType}/${texture.path}`, "textures", "entity", "assets", ".png"),
47
+ { ...color !== void 0 && { color }, ...glint && { glint: true } }
48
+ );
49
+ glint = false;
50
+ }
51
+ if (piece.trim) {
52
+ const patternId = this.identifier(piece.trim.pattern), materialId = this.identifier(piece.trim.material);
53
+ const patternKey = new AssetKey(patternId.namespace, patternId.path, "trim_pattern", void 0, "data", ".json");
54
+ const materialKey = new AssetKey(materialId.namespace, materialId.path, "trim_material", void 0, "data", ".json");
55
+ const pattern = await Caching.trimCache.get(patternKey.serialize(), () => AssetLoader.get(patternKey, AssetParser.JSON));
56
+ if (!pattern) throw new MineRenderError(`Missing trim pattern ${piece.trim.pattern}`);
57
+ const material = await Caching.trimCache.get(materialKey.serialize(), () => AssetLoader.get(materialKey, AssetParser.JSON));
58
+ if (!material) throw new MineRenderError(`Missing trim material ${piece.trim.material}`);
59
+ const patternAsset = this.identifier(pattern.asset_id);
60
+ const suffix = material.override_armor_assets?.[id.toNamespacedString()] ?? material.asset_name;
61
+ add(new AssetKey(patternAsset.namespace, `entity/${layerType}/${patternAsset.path}`, "textures", "trims", "assets", ".png"), {
62
+ palette: {
63
+ key: new AssetKey("minecraft", "color_palettes/trim_palette", "textures", "trims", "assets", ".png"),
64
+ permutation: new AssetKey("minecraft", `color_palettes/${suffix}`, "textures", "trims", "assets", ".png")
65
+ },
66
+ render: pattern.decal ? "cutout_z_offset" : "cutout"
67
+ });
68
+ }
69
+ }
70
+ const first = Object.values(layers)[0];
71
+ return first ? { ...first, id: "minecraft:player", layers, transform: ARMOR_TRANSFORM } : void 0;
72
+ }
73
+ static identifier(value) {
74
+ if (!isResourceLocation(value) || value.split(/[:/]/).some((part) => !part || part === "." || part === "..")) {
75
+ throw new MineRenderError(`Invalid armor identifier ${value}`);
76
+ }
77
+ const [namespace, path] = value.includes(":") ? value.split(":") : ["minecraft", value];
78
+ return new BasicAssetKey(namespace, path);
79
+ }
80
+ };
81
+ export {
82
+ Armor
83
+ };
84
+ //# sourceMappingURL=Armor.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/armor/Armor.ts"],"sourcesContent":["import { AssetKey, BasicAssetKey, isResourceLocation } from \"../assets/AssetKey\";\nimport { AssetLoader } from \"../assets/AssetLoader\";\nimport { Entities } from \"../assets/Entities\";\nimport { AssetParser } from \"../assets/source/parser/AssetParsers\";\nimport { Caching } from \"../cache/Caching\";\nimport type { EntityLayer, EntityModel, EntityTransformOp } from \"../entity/EntityModel\";\nimport { MineRenderError } from \"../error/MineRenderError\";\nimport type { Maybe } from \"../util/util\";\n\nexport type ArmorSlot = \"head\" | \"chest\" | \"legs\" | \"feet\";\n\nexport interface ArmorTrim {\n /** `trim_pattern` registry ID, such as `minecraft:sentry`. */\n pattern: string;\n /** `trim_material` registry ID, such as `minecraft:iron`. */\n material: string;\n}\n\n/** An equipment asset ID, such as `minecraft:diamond`, or the asset with the worn item's state. */\nexport type ArmorPiece = string | {\n asset: string;\n /** `dyed_color` as an RGB integer. */\n color?: number;\n trim?: ArmorTrim;\n /** Draws the enchantment glint, as an enchanted item does. */\n glint?: boolean;\n};\n\nexport type ArmorSet = Partial<Record<ArmorSlot, ArmorPiece>>;\n\nconst ARMOR_TRANSFORM: EntityTransformOp[] = [\n { rotate: [0, Math.PI, 0] }, { scale: [-1, -1, 1] }, { translate: [0, -24, 0] }\n];\n\n/** Resolves humanoid equipment assets into armor draws. */\nexport class Armor {\n /** Loads 1.21.4+ armor in SkinObject's frame, or returns undefined when no layer draws. */\n public static async getEntity(armor: ArmorSet): Promise<Maybe<EntityModel>> {\n const model = await Entities.getModelFile(new BasicAssetKey(\"minecraft\", \"player\"));\n const layers: Record<string, EntityLayer> = {};\n // HumanoidArmorLayer.submit draws the helmet last.\n const slots = { chest: \"chestplate\", legs: \"leggings\", feet: \"boots\", head: \"helmet\" } as const;\n for (const slot of Object.keys(slots) as ArmorSlot[]) {\n const value = armor[slot];\n if (value === undefined) continue;\n const piece = typeof value === \"string\" ? { asset: value } : value;\n const name = slots[slot], geometry = model?.layers[name];\n if (!geometry) throw new MineRenderError(`Missing armor geometry ${name}; armor needs Minecraft 1.21.4 or later`);\n const id = this.identifier(piece.asset);\n const key = new AssetKey(id.namespace, id.path, \"equipment\", undefined, \"assets\", \".json\");\n const equipment = await Caching.equipmentCache.get(key.serialize(), () => AssetLoader.get(key, AssetParser.JSON)) as Maybe<{\n layers: Record<string, { texture: string; dyeable?: { color_when_undyed?: number | [number, number, number] } }[]>;\n }>;\n if (!equipment) throw new MineRenderError(`Missing equipment asset ${piece.asset}; armor takes equipment asset IDs such as minecraft:diamond and needs Minecraft 1.21.4 or later`);\n // HumanoidArmorLayer.usesInnerModel selects the inner texture only for leggings.\n const layerType = slot === \"legs\" ? \"humanoid_leggings\" : \"humanoid\";\n const equipmentLayers = equipment.layers[layerType];\n if (!equipmentLayers?.length) continue;\n let count = 0;\n const add = (texture: AssetKey, settings: Partial<EntityLayer>) => {\n layers[++count === 1 ? name : `${name}#${count}`] = { key: texture, texture, layer: geometry, ...settings };\n };\n let glint = piece.glint;\n for (const layer of equipmentLayers) {\n let color: number | undefined;\n if (layer.dyeable) {\n // EquipmentLayerRenderer.getColorForLayer treats dyed colour 0 as undyed.\n const undyed = layer.dyeable.color_when_undyed;\n color = piece.color || (Array.isArray(undyed)\n ? (Math.floor(undyed[0] * 255) << 16) | (Math.floor(undyed[1] * 255) << 8) | Math.floor(undyed[2] * 255)\n : undyed === undefined ? undefined : undyed & 0xffffff);\n if (color === undefined) continue;\n }\n const texture = this.identifier(layer.texture);\n add(new AssetKey(texture.namespace, `equipment/${layerType}/${texture.path}`, \"textures\", \"entity\", \"assets\", \".png\"),\n { ...(color !== undefined && { color }), ...(glint && { glint: true }) });\n // EquipmentLayerRenderer.renderLayers consumes foil on the first drawn layer.\n glint = false;\n }\n if (piece.trim) {\n const patternId = this.identifier(piece.trim.pattern), materialId = this.identifier(piece.trim.material);\n const patternKey = new AssetKey(patternId.namespace, patternId.path, \"trim_pattern\", undefined, \"data\", \".json\");\n const materialKey = new AssetKey(materialId.namespace, materialId.path, \"trim_material\", undefined, \"data\", \".json\");\n const pattern = await Caching.trimCache.get(patternKey.serialize(), () => AssetLoader.get(patternKey, AssetParser.JSON)) as Maybe<{ asset_id: string; decal?: boolean }>;\n if (!pattern) throw new MineRenderError(`Missing trim pattern ${piece.trim.pattern}`);\n const material = await Caching.trimCache.get(materialKey.serialize(), () => AssetLoader.get(materialKey, AssetParser.JSON)) as Maybe<{ asset_name: string; override_armor_assets?: Record<string, string> }>;\n if (!material) throw new MineRenderError(`Missing trim material ${piece.trim.material}`);\n const patternAsset = this.identifier(pattern.asset_id);\n // MaterialAssetGroup.assetId keys overrides by equipment asset, not by item ID.\n const suffix = material.override_armor_assets?.[id.toNamespacedString()] ?? material.asset_name;\n add(new AssetKey(patternAsset.namespace, `entity/${layerType}/${patternAsset.path}`, \"textures\", \"trims\", \"assets\", \".png\"), {\n palette: {\n key: new AssetKey(\"minecraft\", \"color_palettes/trim_palette\", \"textures\", \"trims\", \"assets\", \".png\"),\n permutation: new AssetKey(\"minecraft\", `color_palettes/${suffix}`, \"textures\", \"trims\", \"assets\", \".png\")\n },\n render: pattern.decal ? \"cutout_z_offset\" : \"cutout\"\n });\n }\n }\n const first = Object.values(layers)[0];\n return first ? { ...first, id: \"minecraft:player\", layers, transform: ARMOR_TRANSFORM } : undefined;\n }\n\n private static identifier(value: string): BasicAssetKey {\n if (!isResourceLocation(value) || value.split(/[:/]/).some(part => !part || part === \".\" || part === \"..\")) {\n throw new MineRenderError(`Invalid armor identifier ${value}`);\n }\n const [namespace, path] = value.includes(\":\") ? value.split(\":\") : [\"minecraft\", value];\n return new BasicAssetKey(namespace, path);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,3 @@
1
+ // src/armor/index.ts
2
+ export * from "./Armor.mjs";
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/armor/index.ts"],"sourcesContent":["// autogenerated\nexport * from './Armor';\n"],"mappings":";AACA,cAAc;","names":[]}
@@ -0,0 +1,8 @@
1
+ // src/assets/AssetDefaults.ts
2
+ var DEFAULT_ROOT = "https://assets.mcasset.cloud/1.21.11";
3
+ var DEFAULT_NAMESPACE = "minecraft";
4
+ export {
5
+ DEFAULT_NAMESPACE,
6
+ DEFAULT_ROOT
7
+ };
8
+ //# sourceMappingURL=AssetDefaults.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/assets/AssetDefaults.ts"],"sourcesContent":["// Kept free of imports: AssetLoader reads DEFAULT_ROOT in a static initializer, and Assets.ts sits in an import\n// cycle with AssetLoader, so code-split bundles could run that initializer before the constant was assigned.\nexport const DEFAULT_ROOT = \"https://assets.mcasset.cloud/1.21.11\";\nexport const DEFAULT_NAMESPACE = \"minecraft\";\n"],"mappings":";AAEO,IAAM,eAAe;AACrB,IAAM,oBAAoB;","names":[]}
@@ -1,5 +1,5 @@
1
1
  // src/assets/AssetKey.ts
2
- import { DEFAULT_NAMESPACE } from "./Assets.mjs";
2
+ import { DEFAULT_NAMESPACE } from "./AssetDefaults.mjs";
3
3
  import { AssetLoader } from "./AssetLoader.mjs";
4
4
  var BasicAssetKey = class {
5
5
  constructor(namespaceOrKey, path) {