minecraft-renderer 0.1.0

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 (187) hide show
  1. package/README.md +297 -0
  2. package/dist/index.html +83 -0
  3. package/dist/static/image/arrow.6f27b59f.png +0 -0
  4. package/dist/static/image/blocksAtlasLatest.7850afa3.png +0 -0
  5. package/dist/static/image/blocksAtlasLegacy.5c76823d.png +0 -0
  6. package/dist/static/image/itemsAtlasLatest.36036f95.png +0 -0
  7. package/dist/static/image/itemsAtlasLegacy.dcb1b58d.png +0 -0
  8. package/dist/static/image/tipped_arrow.6f27b59f.png +0 -0
  9. package/dist/static/js/365.f05233ab.js +8462 -0
  10. package/dist/static/js/365.f05233ab.js.LICENSE.txt +52 -0
  11. package/dist/static/js/async/738.efa27644.js +1 -0
  12. package/dist/static/js/index.092ec5be.js +56 -0
  13. package/dist/static/js/lib-polyfill.98986ac5.js +1 -0
  14. package/dist/static/js/lib-react.5c9129e0.js +2 -0
  15. package/dist/static/js/lib-react.5c9129e0.js.LICENSE.txt +39 -0
  16. package/package.json +104 -0
  17. package/src/assets/destroy_stage_0.png +0 -0
  18. package/src/assets/destroy_stage_1.png +0 -0
  19. package/src/assets/destroy_stage_2.png +0 -0
  20. package/src/assets/destroy_stage_3.png +0 -0
  21. package/src/assets/destroy_stage_4.png +0 -0
  22. package/src/assets/destroy_stage_5.png +0 -0
  23. package/src/assets/destroy_stage_6.png +0 -0
  24. package/src/assets/destroy_stage_7.png +0 -0
  25. package/src/assets/destroy_stage_8.png +0 -0
  26. package/src/assets/destroy_stage_9.png +0 -0
  27. package/src/examples/README.md +146 -0
  28. package/src/examples/appViewerExample.ts +205 -0
  29. package/src/examples/initialMenuStart.ts +161 -0
  30. package/src/graphicsBackend/appViewer.ts +297 -0
  31. package/src/graphicsBackend/config.ts +119 -0
  32. package/src/graphicsBackend/index.ts +10 -0
  33. package/src/graphicsBackend/playerState.ts +61 -0
  34. package/src/graphicsBackend/types.ts +143 -0
  35. package/src/index.ts +97 -0
  36. package/src/lib/DebugGui.ts +190 -0
  37. package/src/lib/animationController.ts +85 -0
  38. package/src/lib/buildSharedConfig.mjs +1 -0
  39. package/src/lib/cameraBobbing.ts +94 -0
  40. package/src/lib/canvas2DOverlay.example.ts +361 -0
  41. package/src/lib/canvas2DOverlay.quickstart.ts +242 -0
  42. package/src/lib/canvas2DOverlay.ts +381 -0
  43. package/src/lib/cleanupDecorator.ts +29 -0
  44. package/src/lib/createPlayerObject.ts +55 -0
  45. package/src/lib/frameTimingCollector.ts +164 -0
  46. package/src/lib/guiRenderer.ts +283 -0
  47. package/src/lib/items.ts +140 -0
  48. package/src/lib/mesherlogReader.ts +131 -0
  49. package/src/lib/moreBlockDataGenerated.json +714 -0
  50. package/src/lib/preflatMap.json +1741 -0
  51. package/src/lib/simpleUtils.ts +40 -0
  52. package/src/lib/smoothSwitcher.ts +168 -0
  53. package/src/lib/spiral.ts +29 -0
  54. package/src/lib/ui/newStats.ts +120 -0
  55. package/src/lib/utils/proxy.ts +23 -0
  56. package/src/lib/utils/skins.ts +63 -0
  57. package/src/lib/utils.ts +76 -0
  58. package/src/lib/workerProxy.ts +342 -0
  59. package/src/lib/worldrendererCommon.ts +1088 -0
  60. package/src/mesher/mesher.ts +253 -0
  61. package/src/mesher/models.ts +769 -0
  62. package/src/mesher/modelsGeometryCommon.ts +142 -0
  63. package/src/mesher/shared.ts +80 -0
  64. package/src/mesher/standaloneRenderer.ts +270 -0
  65. package/src/mesher/test/a.ts +3 -0
  66. package/src/mesher/test/mesherTester.ts +76 -0
  67. package/src/mesher/test/playground.ts +19 -0
  68. package/src/mesher/test/test-perf.ts +74 -0
  69. package/src/mesher/test/tests.test.ts +56 -0
  70. package/src/mesher/world.ts +294 -0
  71. package/src/mesher/worldConstants.ts +1 -0
  72. package/src/modules/index.ts +11 -0
  73. package/src/modules/starfield.ts +313 -0
  74. package/src/modules/types.ts +110 -0
  75. package/src/playerState/playerState.ts +78 -0
  76. package/src/playerState/types.ts +36 -0
  77. package/src/playground/allEntitiesDebug.ts +170 -0
  78. package/src/playground/baseScene.ts +587 -0
  79. package/src/playground/mobileControls.tsx +268 -0
  80. package/src/playground/playground.html +83 -0
  81. package/src/playground/playground.ts +11 -0
  82. package/src/playground/playgroundUi.tsx +140 -0
  83. package/src/playground/reactUtils.ts +71 -0
  84. package/src/playground/scenes/allEntities.ts +13 -0
  85. package/src/playground/scenes/entities.ts +37 -0
  86. package/src/playground/scenes/floorRandom.ts +33 -0
  87. package/src/playground/scenes/frequentUpdates.ts +148 -0
  88. package/src/playground/scenes/geometryExport.ts +142 -0
  89. package/src/playground/scenes/index.ts +12 -0
  90. package/src/playground/scenes/lightingStarfield.ts +40 -0
  91. package/src/playground/scenes/main.ts +313 -0
  92. package/src/playground/scenes/railsCobweb.ts +14 -0
  93. package/src/playground/scenes/rotationIssue.ts +7 -0
  94. package/src/playground/scenes/slabsOptimization.ts +16 -0
  95. package/src/playground/scenes/transparencyIssue.ts +11 -0
  96. package/src/playground/shared.ts +79 -0
  97. package/src/resourcesManager/index.ts +5 -0
  98. package/src/resourcesManager/resourcesManager.ts +314 -0
  99. package/src/shims/minecraftData.ts +41 -0
  100. package/src/sign-renderer/index.html +21 -0
  101. package/src/sign-renderer/index.ts +216 -0
  102. package/src/sign-renderer/noop.js +1 -0
  103. package/src/sign-renderer/playground.ts +38 -0
  104. package/src/sign-renderer/tests.test.ts +69 -0
  105. package/src/sign-renderer/vite.config.ts +10 -0
  106. package/src/three/appShared.ts +75 -0
  107. package/src/three/bannerRenderer.ts +275 -0
  108. package/src/three/cameraShake.ts +120 -0
  109. package/src/three/cinimaticScript.ts +350 -0
  110. package/src/three/documentRenderer.ts +491 -0
  111. package/src/three/entities.ts +1580 -0
  112. package/src/three/entity/EntityMesh.ts +707 -0
  113. package/src/three/entity/animations.js +171 -0
  114. package/src/three/entity/armorModels.json +204 -0
  115. package/src/three/entity/armorModels.ts +36 -0
  116. package/src/three/entity/entities.json +6230 -0
  117. package/src/three/entity/exportedModels.js +38 -0
  118. package/src/three/entity/externalTextures.json +1 -0
  119. package/src/three/entity/models/allay.obj +325 -0
  120. package/src/three/entity/models/arrow.obj +60 -0
  121. package/src/three/entity/models/axolotl.obj +509 -0
  122. package/src/three/entity/models/blaze.obj +601 -0
  123. package/src/three/entity/models/boat.obj +417 -0
  124. package/src/three/entity/models/camel.obj +1061 -0
  125. package/src/three/entity/models/cat.obj +509 -0
  126. package/src/three/entity/models/chicken.obj +371 -0
  127. package/src/three/entity/models/cod.obj +371 -0
  128. package/src/three/entity/models/creeper.obj +279 -0
  129. package/src/three/entity/models/dolphin.obj +371 -0
  130. package/src/three/entity/models/ender_dragon.obj +2993 -0
  131. package/src/three/entity/models/enderman.obj +325 -0
  132. package/src/three/entity/models/endermite.obj +187 -0
  133. package/src/three/entity/models/fox.obj +463 -0
  134. package/src/three/entity/models/frog.obj +739 -0
  135. package/src/three/entity/models/ghast.obj +463 -0
  136. package/src/three/entity/models/goat.obj +601 -0
  137. package/src/three/entity/models/guardian.obj +1015 -0
  138. package/src/three/entity/models/horse.obj +1061 -0
  139. package/src/three/entity/models/llama.obj +509 -0
  140. package/src/three/entity/models/minecart.obj +233 -0
  141. package/src/three/entity/models/parrot.obj +509 -0
  142. package/src/three/entity/models/piglin.obj +739 -0
  143. package/src/three/entity/models/pillager.obj +371 -0
  144. package/src/three/entity/models/rabbit.obj +555 -0
  145. package/src/three/entity/models/sheep.obj +555 -0
  146. package/src/three/entity/models/shulker.obj +141 -0
  147. package/src/three/entity/models/sniffer.obj +693 -0
  148. package/src/three/entity/models/spider.obj +509 -0
  149. package/src/three/entity/models/tadpole.obj +95 -0
  150. package/src/three/entity/models/turtle.obj +371 -0
  151. package/src/three/entity/models/vex.obj +325 -0
  152. package/src/three/entity/models/villager.obj +509 -0
  153. package/src/three/entity/models/warden.obj +463 -0
  154. package/src/three/entity/models/witch.obj +647 -0
  155. package/src/three/entity/models/wolf.obj +509 -0
  156. package/src/three/entity/models/zombie_villager.obj +463 -0
  157. package/src/three/entity/objModels.js +1 -0
  158. package/src/three/fireworks.ts +661 -0
  159. package/src/three/fireworksRenderer.ts +434 -0
  160. package/src/three/globals.d.ts +7 -0
  161. package/src/three/graphicsBackend.ts +274 -0
  162. package/src/three/graphicsBackendOffThread.ts +107 -0
  163. package/src/three/hand.ts +89 -0
  164. package/src/three/holdingBlock.ts +926 -0
  165. package/src/three/index.ts +20 -0
  166. package/src/three/itemMesh.ts +427 -0
  167. package/src/three/modules.d.ts +14 -0
  168. package/src/three/panorama.ts +308 -0
  169. package/src/three/panoramaShared.ts +1 -0
  170. package/src/three/renderSlot.ts +82 -0
  171. package/src/three/skyboxRenderer.ts +406 -0
  172. package/src/three/starField.ts +13 -0
  173. package/src/three/threeJsMedia.ts +731 -0
  174. package/src/three/threeJsMethods.ts +15 -0
  175. package/src/three/threeJsParticles.ts +160 -0
  176. package/src/three/threeJsSound.ts +95 -0
  177. package/src/three/threeJsUtils.ts +90 -0
  178. package/src/three/waypointSprite.ts +435 -0
  179. package/src/three/waypoints.ts +163 -0
  180. package/src/three/world/cursorBlock.ts +172 -0
  181. package/src/three/world/vr.ts +257 -0
  182. package/src/three/worldGeometryExport.ts +259 -0
  183. package/src/three/worldGeometryHandler.ts +279 -0
  184. package/src/three/worldRendererThree.ts +1381 -0
  185. package/src/worldView/index.ts +6 -0
  186. package/src/worldView/types.ts +66 -0
  187. package/src/worldView/worldView.ts +424 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Three.js Graphics Backend
3
+ *
4
+ * This module provides the Three.js WebGL implementation for the Minecraft renderer.
5
+ */
6
+
7
+ // Main backend
8
+ export { default as createGraphicsBackend, createGraphicsBackendBase } from './graphicsBackend'
9
+
10
+ // Core components
11
+ export { DocumentRenderer, addCanvasForWorker, isWebWorker } from './documentRenderer'
12
+ export type { ThreeRendererMainData } from './documentRenderer'
13
+
14
+ // World geometry
15
+ export { WorldGeometryHandler, estimateGeometryMemoryUsage, disposeObject } from './worldGeometryHandler'
16
+ export type { WorldGeometryHandlerOptions, SectionObject } from './worldGeometryHandler'
17
+
18
+ // Visual effects
19
+ export { StarField } from './starField'
20
+ export type { StarFieldOptions } from './starField'
@@ -0,0 +1,427 @@
1
+ import * as THREE from 'three'
2
+
3
+ export interface Create3DItemMeshOptions {
4
+ depth: number
5
+ pixelSize?: number
6
+ }
7
+
8
+ export interface Create3DItemMeshResult {
9
+ geometry: THREE.BufferGeometry
10
+ totalVertices: number
11
+ totalTriangles: number
12
+ }
13
+
14
+ /**
15
+ * Creates a 3D item geometry with front/back faces and connecting edges
16
+ * from a canvas containing the item texture
17
+ */
18
+ export function create3DItemMesh (
19
+ canvas: HTMLCanvasElement,
20
+ options: Create3DItemMeshOptions
21
+ ): Create3DItemMeshResult {
22
+ const { depth, pixelSize } = options
23
+
24
+ // Validate canvas dimensions
25
+ if (canvas.width <= 0 || canvas.height <= 0) {
26
+ throw new Error(`Invalid canvas dimensions: ${canvas.width}x${canvas.height}`)
27
+ }
28
+
29
+ const ctx = canvas.getContext('2d')!
30
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
31
+ const { data } = imageData
32
+
33
+ const w = canvas.width
34
+ const h = canvas.height
35
+ const halfDepth = depth / 2
36
+ const actualPixelSize = pixelSize ?? (1 / Math.max(w, h))
37
+
38
+ // Find opaque pixels
39
+ const isOpaque = (x: number, y: number) => {
40
+ if (x < 0 || y < 0 || x >= w || y >= h) return false
41
+ const i = (y * w + x) * 4
42
+ return data[i + 3] > 128 // alpha > 128
43
+ }
44
+
45
+ const vertices: number[] = []
46
+ const indices: number[] = []
47
+ const uvs: number[] = []
48
+ const normals: number[] = []
49
+
50
+ let vertexIndex = 0
51
+
52
+ // Helper to add a vertex
53
+ const addVertex = (x: number, y: number, z: number, u: number, v: number, nx: number, ny: number, nz: number) => {
54
+ vertices.push(x, y, z)
55
+ uvs.push(u, v)
56
+ normals.push(nx, ny, nz)
57
+ return vertexIndex++
58
+ }
59
+
60
+ // Helper to add a quad (two triangles)
61
+ const addQuad = (v0: number, v1: number, v2: number, v3: number) => {
62
+ indices.push(v0, v1, v2, v0, v2, v3)
63
+ }
64
+
65
+ // Convert pixel coordinates to world coordinates
66
+ const pixelToWorld = (px: number, py: number) => {
67
+ const x = (px / w - 0.5) * actualPixelSize * w
68
+ const y = -(py / h - 0.5) * actualPixelSize * h
69
+ return { x, y }
70
+ }
71
+
72
+ // Create a grid of vertices for front and back faces
73
+ const frontVertices: Array<Array<number | null>> = Array.from({ length: h + 1 }, () => Array.from({ length: w + 1 }, () => null))
74
+ const backVertices: Array<Array<number | null>> = Array.from({ length: h + 1 }, () => Array.from({ length: w + 1 }, () => null))
75
+
76
+ // Create vertices at pixel corners
77
+ for (let py = 0; py <= h; py++) {
78
+ for (let px = 0; px <= w; px++) {
79
+ const { x, y } = pixelToWorld(px - 0.5, py - 0.5)
80
+
81
+ // UV coordinates should map to the texture space of the extracted tile
82
+ const u = px / w
83
+ const v = py / h
84
+
85
+ // Check if this vertex is needed for any face or edge
86
+ let needVertex = false
87
+
88
+ // Check all 4 adjacent pixels to see if any are opaque
89
+ const adjacentPixels = [
90
+ [px - 1, py - 1], // top-left pixel
91
+ [px, py - 1], // top-right pixel
92
+ [px - 1, py], // bottom-left pixel
93
+ [px, py] // bottom-right pixel
94
+ ]
95
+
96
+ for (const [adjX, adjY] of adjacentPixels) {
97
+ if (isOpaque(adjX, adjY)) {
98
+ needVertex = true
99
+ break
100
+ }
101
+ }
102
+
103
+ if (needVertex) {
104
+ frontVertices[py][px] = addVertex(x, y, halfDepth, u, v, 0, 0, 1)
105
+ backVertices[py][px] = addVertex(x, y, -halfDepth, u, v, 0, 0, -1)
106
+ }
107
+ }
108
+ }
109
+
110
+ // Create front and back faces
111
+ for (let py = 0; py < h; py++) {
112
+ for (let px = 0; px < w; px++) {
113
+ if (!isOpaque(px, py)) continue
114
+
115
+ const v00 = frontVertices[py][px]
116
+ const v10 = frontVertices[py][px + 1]
117
+ const v11 = frontVertices[py + 1][px + 1]
118
+ const v01 = frontVertices[py + 1][px]
119
+
120
+ const b00 = backVertices[py][px]
121
+ const b10 = backVertices[py][px + 1]
122
+ const b11 = backVertices[py + 1][px + 1]
123
+ const b01 = backVertices[py + 1][px]
124
+
125
+ if (v00 !== null && v10 !== null && v11 !== null && v01 !== null) {
126
+ // Front face
127
+ addQuad(v00, v10, v11, v01)
128
+ }
129
+
130
+ if (b00 !== null && b10 !== null && b11 !== null && b01 !== null) {
131
+ // Back face (reversed winding)
132
+ addQuad(b10, b00, b01, b11)
133
+ }
134
+ }
135
+ }
136
+
137
+ // Create edge faces for each side of the pixel with proper UVs
138
+ for (let py = 0; py < h; py++) {
139
+ for (let px = 0; px < w; px++) {
140
+ if (!isOpaque(px, py)) continue
141
+
142
+ const pixelU = (px + 0.5) / w // Center of current pixel
143
+ const pixelV = (py + 0.5) / h
144
+
145
+ // Left edge (x = px)
146
+ if (!isOpaque(px - 1, py)) {
147
+ const f0 = frontVertices[py][px]
148
+ const f1 = frontVertices[py + 1][px]
149
+ const b0 = backVertices[py][px]
150
+ const b1 = backVertices[py + 1][px]
151
+
152
+ if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) {
153
+ // Create new vertices for edge with current pixel's UV
154
+ const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, -1, 0, 0)
155
+ const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, -1, 0, 0)
156
+ const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, -1, 0, 0)
157
+ const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, -1, 0, 0)
158
+ addQuad(ef0, ef1, eb1, eb0)
159
+ }
160
+ }
161
+
162
+ // Right edge (x = px + 1)
163
+ if (!isOpaque(px + 1, py)) {
164
+ const f0 = frontVertices[py + 1][px + 1]
165
+ const f1 = frontVertices[py][px + 1]
166
+ const b0 = backVertices[py + 1][px + 1]
167
+ const b1 = backVertices[py][px + 1]
168
+
169
+ if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) {
170
+ const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 1, 0, 0)
171
+ const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 1, 0, 0)
172
+ const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 1, 0, 0)
173
+ const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 1, 0, 0)
174
+ addQuad(ef0, ef1, eb1, eb0)
175
+ }
176
+ }
177
+
178
+ // Top edge (y = py)
179
+ if (!isOpaque(px, py - 1)) {
180
+ const f0 = frontVertices[py][px]
181
+ const f1 = frontVertices[py][px + 1]
182
+ const b0 = backVertices[py][px]
183
+ const b1 = backVertices[py][px + 1]
184
+
185
+ if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) {
186
+ const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 0, -1, 0)
187
+ const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 0, -1, 0)
188
+ const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 0, -1, 0)
189
+ const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 0, -1, 0)
190
+ addQuad(ef0, ef1, eb1, eb0)
191
+ }
192
+ }
193
+
194
+ // Bottom edge (y = py + 1)
195
+ if (!isOpaque(px, py + 1)) {
196
+ const f0 = frontVertices[py + 1][px + 1]
197
+ const f1 = frontVertices[py + 1][px]
198
+ const b0 = backVertices[py + 1][px + 1]
199
+ const b1 = backVertices[py + 1][px]
200
+
201
+ if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) {
202
+ const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 0, 1, 0)
203
+ const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 0, 1, 0)
204
+ const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 0, 1, 0)
205
+ const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 0, 1, 0)
206
+ addQuad(ef0, ef1, eb1, eb0)
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+ const geometry = new THREE.BufferGeometry()
213
+ geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3))
214
+ geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2))
215
+ geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3))
216
+ geometry.setIndex(indices)
217
+
218
+ // Compute normals properly
219
+ geometry.computeVertexNormals()
220
+
221
+ return {
222
+ geometry,
223
+ totalVertices: vertexIndex,
224
+ totalTriangles: indices.length / 3
225
+ }
226
+ }
227
+
228
+ export interface ItemTextureInfo {
229
+ u: number
230
+ v: number
231
+ sizeX: number
232
+ sizeY: number
233
+ }
234
+
235
+ export interface ItemMeshResult {
236
+ mesh: THREE.Object3D
237
+ itemsTexture?: THREE.Texture
238
+ itemsTextureFlipped?: THREE.Texture
239
+ cleanup?: () => void
240
+ }
241
+
242
+ /**
243
+ * Extracts item texture region to a canvas
244
+ */
245
+ export function extractItemTextureToCanvas (
246
+ sourceTexture: THREE.Texture,
247
+ textureInfo: ItemTextureInfo
248
+ ): HTMLCanvasElement {
249
+ const { u, v, sizeX, sizeY } = textureInfo
250
+
251
+ // Calculate canvas size - fix the calculation
252
+ const canvasWidth = Math.max(1, Math.floor(sizeX * sourceTexture.image.width))
253
+ const canvasHeight = Math.max(1, Math.floor(sizeY * sourceTexture.image.height))
254
+
255
+ const canvas = document.createElement('canvas')
256
+ canvas.width = canvasWidth
257
+ canvas.height = canvasHeight
258
+
259
+ const ctx = canvas.getContext('2d')!
260
+ ctx.imageSmoothingEnabled = false
261
+
262
+ // Draw the item texture region to canvas
263
+ ctx.drawImage(
264
+ sourceTexture.image,
265
+ u * sourceTexture.image.width,
266
+ v * sourceTexture.image.height,
267
+ sizeX * sourceTexture.image.width,
268
+ sizeY * sourceTexture.image.height,
269
+ 0,
270
+ 0,
271
+ canvas.width,
272
+ canvas.height
273
+ )
274
+
275
+ return canvas
276
+ }
277
+
278
+ /**
279
+ * Creates either a 2D or 3D item mesh based on parameters
280
+ */
281
+ export function createItemMesh (
282
+ sourceTexture: THREE.Texture,
283
+ textureInfo: ItemTextureInfo,
284
+ options: {
285
+ faceCamera?: boolean
286
+ use3D?: boolean
287
+ depth?: number
288
+ } = {}
289
+ ): ItemMeshResult {
290
+ const { faceCamera = false, use3D = true, depth = 0.04 } = options
291
+ const { u, v, sizeX, sizeY } = textureInfo
292
+
293
+ if (faceCamera) {
294
+ // Create sprite for camera-facing items
295
+ const itemsTexture = sourceTexture.clone()
296
+ itemsTexture.flipY = true
297
+ itemsTexture.offset.set(u, 1 - v - sizeY)
298
+ itemsTexture.repeat.set(sizeX, sizeY)
299
+ itemsTexture.needsUpdate = true
300
+ itemsTexture.magFilter = THREE.NearestFilter
301
+ itemsTexture.minFilter = THREE.NearestFilter
302
+
303
+ const spriteMat = new THREE.SpriteMaterial({
304
+ map: itemsTexture,
305
+ transparent: true,
306
+ alphaTest: 0.1,
307
+ })
308
+ const mesh = new THREE.Sprite(spriteMat)
309
+
310
+ return {
311
+ mesh,
312
+ itemsTexture,
313
+ cleanup () {
314
+ itemsTexture.dispose()
315
+ }
316
+ }
317
+ }
318
+
319
+ if (use3D) {
320
+ // Try to create 3D mesh
321
+ try {
322
+ const canvas = extractItemTextureToCanvas(sourceTexture, textureInfo)
323
+ const { geometry } = create3DItemMesh(canvas, { depth })
324
+
325
+ // Create texture from canvas for the 3D mesh
326
+ const itemsTexture = new THREE.CanvasTexture(canvas)
327
+ itemsTexture.magFilter = THREE.NearestFilter
328
+ itemsTexture.minFilter = THREE.NearestFilter
329
+ itemsTexture.wrapS = itemsTexture.wrapT = THREE.ClampToEdgeWrapping
330
+ itemsTexture.flipY = false
331
+ itemsTexture.needsUpdate = true
332
+
333
+ const material = new THREE.MeshStandardMaterial({
334
+ map: itemsTexture,
335
+ side: THREE.DoubleSide,
336
+ transparent: true,
337
+ alphaTest: 0.1,
338
+ })
339
+
340
+ const mesh = new THREE.Mesh(geometry, material)
341
+
342
+ return {
343
+ mesh,
344
+ itemsTexture,
345
+ cleanup () {
346
+ itemsTexture.dispose()
347
+ geometry.dispose()
348
+ if (material.map) material.map.dispose()
349
+ material.dispose()
350
+ }
351
+ }
352
+ } catch (error) {
353
+ console.warn('Failed to create 3D item mesh, falling back to 2D:', error)
354
+ // Fall through to 2D rendering
355
+ }
356
+ }
357
+
358
+ // Fallback to 2D flat rendering
359
+ const itemsTexture = sourceTexture.clone()
360
+ itemsTexture.flipY = true
361
+ itemsTexture.offset.set(u, 1 - v - sizeY)
362
+ itemsTexture.repeat.set(sizeX, sizeY)
363
+ itemsTexture.needsUpdate = true
364
+ itemsTexture.magFilter = THREE.NearestFilter
365
+ itemsTexture.minFilter = THREE.NearestFilter
366
+
367
+ const itemsTextureFlipped = itemsTexture.clone()
368
+ itemsTextureFlipped.repeat.x *= -1
369
+ itemsTextureFlipped.needsUpdate = true
370
+ itemsTextureFlipped.offset.set(u + sizeX, 1 - v - sizeY)
371
+
372
+ const material = new THREE.MeshStandardMaterial({
373
+ map: itemsTexture,
374
+ transparent: true,
375
+ alphaTest: 0.1,
376
+ })
377
+ const materialFlipped = new THREE.MeshStandardMaterial({
378
+ map: itemsTextureFlipped,
379
+ transparent: true,
380
+ alphaTest: 0.1,
381
+ })
382
+ const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 0), [
383
+ new THREE.MeshBasicMaterial({ color: 0x00_00_00 }), new THREE.MeshBasicMaterial({ color: 0x00_00_00 }),
384
+ new THREE.MeshBasicMaterial({ color: 0x00_00_00 }), new THREE.MeshBasicMaterial({ color: 0x00_00_00 }),
385
+ material, materialFlipped,
386
+ ])
387
+
388
+ return {
389
+ mesh,
390
+ itemsTexture,
391
+ itemsTextureFlipped,
392
+ cleanup () {
393
+ itemsTexture.dispose()
394
+ itemsTextureFlipped.dispose()
395
+ material.dispose()
396
+ materialFlipped.dispose()
397
+ }
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Creates a complete 3D item mesh from a canvas texture
403
+ */
404
+ export function createItemMeshFromCanvas (
405
+ canvas: HTMLCanvasElement,
406
+ options: Create3DItemMeshOptions
407
+ ): THREE.Mesh {
408
+ const { geometry } = create3DItemMesh(canvas, options)
409
+
410
+ // Base color texture for the item
411
+ const colorTexture = new THREE.CanvasTexture(canvas)
412
+ colorTexture.magFilter = THREE.NearestFilter
413
+ colorTexture.minFilter = THREE.NearestFilter
414
+ colorTexture.wrapS = colorTexture.wrapT = THREE.ClampToEdgeWrapping
415
+ colorTexture.flipY = false // Important for canvas textures
416
+ colorTexture.needsUpdate = true
417
+
418
+ // Material - no transparency, no alpha test needed for edges
419
+ const material = new THREE.MeshBasicMaterial({
420
+ map: colorTexture,
421
+ side: THREE.DoubleSide,
422
+ transparent: true,
423
+ alphaTest: 0.1
424
+ })
425
+
426
+ return new THREE.Mesh(geometry, material)
427
+ }
@@ -0,0 +1,14 @@
1
+ declare module '*.png' {
2
+ const content: string
3
+ export default content
4
+ }
5
+
6
+ declare module '*.obj' {
7
+ const content: string
8
+ export default content
9
+ }
10
+
11
+ declare module '*.gltf' {
12
+ const content: string
13
+ export default content
14
+ }