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,15 @@
1
+ import type { GraphicsBackend } from '../../../src/appViewer'
2
+ import type { ThreeJsBackendMethods } from './graphicsBackend'
3
+
4
+ export function getThreeJsRendererMethods (): ThreeJsBackendMethods | undefined {
5
+ const renderer = appViewer.backend
6
+ if (renderer?.id !== 'threejs' || !renderer.backendMethods) return
7
+ return new Proxy(renderer.backendMethods, {
8
+ get (target, prop) {
9
+ return async (...args) => {
10
+ const result = await (target[prop as any] as any)(...args)
11
+ return result
12
+ }
13
+ }
14
+ }) as ThreeJsBackendMethods
15
+ }
@@ -0,0 +1,160 @@
1
+ import * as THREE from 'three'
2
+
3
+ interface ParticleMesh extends THREE.Mesh {
4
+ velocity: THREE.Vector3;
5
+ }
6
+
7
+ interface ParticleConfig {
8
+ fountainHeight: number;
9
+ resetHeight: number;
10
+ xVelocityRange: number;
11
+ zVelocityRange: number;
12
+ particleCount: number;
13
+ particleRadiusRange: { min: number; max: number };
14
+ yVelocityRange: { min: number; max: number };
15
+ }
16
+
17
+ export interface FountainOptions {
18
+ position?: { x: number, y: number, z: number }
19
+ particleConfig?: Partial<ParticleConfig>;
20
+ }
21
+
22
+ export class Fountain {
23
+ private readonly particles: ParticleMesh[] = []
24
+ private readonly config: { particleConfig: ParticleConfig }
25
+ private readonly position: THREE.Vector3
26
+ container: THREE.Object3D | undefined
27
+
28
+ constructor (public sectionId: string, options: FountainOptions = {}) {
29
+ this.position = options.position ? new THREE.Vector3(options.position.x, options.position.y, options.position.z) : new THREE.Vector3(0, 0, 0)
30
+ this.config = this.createConfig(options.particleConfig)
31
+ }
32
+
33
+ private createConfig (
34
+ particleConfigOverride?: Partial<ParticleConfig>
35
+ ): { particleConfig: ParticleConfig } {
36
+ const particleConfig: ParticleConfig = {
37
+ fountainHeight: 10,
38
+ resetHeight: 0,
39
+ xVelocityRange: 0.4,
40
+ zVelocityRange: 0.4,
41
+ particleCount: 400,
42
+ particleRadiusRange: { min: 0.1, max: 0.6 },
43
+ yVelocityRange: { min: 0.1, max: 2 },
44
+ ...particleConfigOverride
45
+ }
46
+
47
+ return { particleConfig }
48
+ }
49
+
50
+
51
+ createParticles (container: THREE.Object3D): void {
52
+ this.container = container
53
+ const colorStart = new THREE.Color(0xff_ff_00)
54
+ const colorEnd = new THREE.Color(0xff_a5_00)
55
+
56
+ for (let i = 0; i < this.config.particleConfig.particleCount; i++) {
57
+ const radius = Math.random() *
58
+ (this.config.particleConfig.particleRadiusRange.max - this.config.particleConfig.particleRadiusRange.min) +
59
+ this.config.particleConfig.particleRadiusRange.min
60
+ const geometry = new THREE.SphereGeometry(radius)
61
+ const material = new THREE.MeshBasicMaterial({
62
+ color: colorStart.clone().lerp(colorEnd, Math.random())
63
+ })
64
+ const mesh = new THREE.Mesh(geometry, material)
65
+ const particle = mesh as unknown as ParticleMesh
66
+
67
+ particle.position.set(
68
+ this.position.x + (Math.random() - 0.5) * this.config.particleConfig.xVelocityRange * 2,
69
+ this.position.y + this.config.particleConfig.fountainHeight,
70
+ this.position.z + (Math.random() - 0.5) * this.config.particleConfig.zVelocityRange * 2
71
+ )
72
+
73
+ particle.velocity = new THREE.Vector3(
74
+ (Math.random() - 0.5) * this.config.particleConfig.xVelocityRange,
75
+ -Math.random() * this.config.particleConfig.yVelocityRange.max,
76
+ (Math.random() - 0.5) * this.config.particleConfig.zVelocityRange
77
+ )
78
+
79
+ this.particles.push(particle)
80
+ this.container.add(particle)
81
+
82
+ // this.container.onBeforeRender = () => {
83
+ // this.render()
84
+ // }
85
+ }
86
+ }
87
+
88
+ render (): void {
89
+ for (const particle of this.particles) {
90
+ particle.velocity.y -= 0.01 + Math.random() * 0.1
91
+ particle.position.add(particle.velocity)
92
+
93
+ if (particle.position.y < this.position.y + this.config.particleConfig.resetHeight) {
94
+ particle.position.set(
95
+ this.position.x + (Math.random() - 0.5) * this.config.particleConfig.xVelocityRange * 2,
96
+ this.position.y + this.config.particleConfig.fountainHeight,
97
+ this.position.z + (Math.random() - 0.5) * this.config.particleConfig.zVelocityRange * 2
98
+ )
99
+ particle.velocity.set(
100
+ (Math.random() - 0.5) * this.config.particleConfig.xVelocityRange,
101
+ -Math.random() * this.config.particleConfig.yVelocityRange.max,
102
+ (Math.random() - 0.5) * this.config.particleConfig.zVelocityRange
103
+ )
104
+ }
105
+ }
106
+ }
107
+
108
+ private updateParticleCount (newCount: number): void {
109
+ if (newCount !== this.config.particleConfig.particleCount) {
110
+ this.config.particleConfig.particleCount = newCount
111
+ const currentCount = this.particles.length
112
+
113
+ if (newCount > currentCount) {
114
+ this.addParticles(newCount - currentCount)
115
+ } else if (newCount < currentCount) {
116
+ this.removeParticles(currentCount - newCount)
117
+ }
118
+ }
119
+ }
120
+
121
+ private addParticles (count: number): void {
122
+ const geometry = new THREE.SphereGeometry(0.1)
123
+ const material = new THREE.MeshBasicMaterial({ color: 0x00_ff_00 })
124
+
125
+ for (let i = 0; i < count; i++) {
126
+ const mesh = new THREE.Mesh(geometry, material)
127
+ const particle = mesh as unknown as ParticleMesh
128
+ particle.position.copy(this.position)
129
+ particle.velocity = new THREE.Vector3(
130
+ Math.random() * this.config.particleConfig.xVelocityRange -
131
+ this.config.particleConfig.xVelocityRange / 2,
132
+ Math.random() * 2,
133
+ Math.random() * this.config.particleConfig.zVelocityRange -
134
+ this.config.particleConfig.zVelocityRange / 2
135
+ )
136
+ this.particles.push(particle)
137
+ this.container!.add(particle)
138
+ }
139
+ }
140
+
141
+ private removeParticles (count: number): void {
142
+ for (let i = 0; i < count; i++) {
143
+ const particle = this.particles.pop()
144
+ if (particle) {
145
+ this.container!.remove(particle)
146
+ }
147
+ }
148
+ }
149
+
150
+ public dispose (): void {
151
+ for (const particle of this.particles) {
152
+ particle.geometry.dispose()
153
+ if (Array.isArray(particle.material)) {
154
+ for (const material of particle.material) material.dispose()
155
+ } else {
156
+ particle.material.dispose()
157
+ }
158
+ }
159
+ }
160
+ }
@@ -0,0 +1,95 @@
1
+ import * as THREE from 'three'
2
+ import { WorldRendererThree } from './worldRendererThree'
3
+ import { SoundSystem } from '@/graphicsBackend/types'
4
+
5
+ export class ThreeJsSound implements SoundSystem {
6
+ audioListener: THREE.AudioListener | undefined
7
+ private readonly activeSounds = new Set<THREE.PositionalAudio>()
8
+ private readonly audioContext: AudioContext | undefined
9
+ private readonly soundVolumes = new Map<THREE.PositionalAudio, number>()
10
+ baseVolume = 1
11
+
12
+ constructor(public worldRenderer: WorldRendererThree) {
13
+ worldRenderer.onWorldSwitched.push(() => {
14
+ this.stopAll()
15
+ })
16
+
17
+ worldRenderer.onReactiveConfigUpdated('volume', (volume) => {
18
+ this.changeVolume(volume)
19
+ })
20
+ }
21
+
22
+ initAudioListener() {
23
+ if (this.audioListener) return
24
+ this.audioListener = new THREE.AudioListener()
25
+ this.worldRenderer.camera.add(this.audioListener)
26
+ }
27
+
28
+ playSound(position: { x: number, y: number, z: number }, path: string, volume = 1, pitch = 1, timeout = 500) {
29
+ this.initAudioListener()
30
+
31
+ const sound = new THREE.PositionalAudio(this.audioListener!)
32
+ this.activeSounds.add(sound)
33
+ this.soundVolumes.set(sound, volume)
34
+
35
+ const audioLoader = new THREE.AudioLoader()
36
+ const start = Date.now()
37
+ void audioLoader.loadAsync(path).then((buffer) => {
38
+ if (Date.now() - start > timeout) {
39
+ console.warn('Ignored playing sound', path, 'due to timeout:', timeout, 'ms <', Date.now() - start, 'ms')
40
+ return
41
+ }
42
+ // play
43
+ sound.setBuffer(buffer)
44
+ sound.setRefDistance(20)
45
+ sound.setVolume(volume * this.baseVolume)
46
+ sound.setPlaybackRate(pitch) // set the pitch
47
+ this.worldRenderer.scene.add(sound)
48
+ // set sound position
49
+ sound.position.set(position.x, position.y, position.z)
50
+ sound.onEnded = () => {
51
+ this.worldRenderer.scene.remove(sound)
52
+ if (sound.source) {
53
+ sound.disconnect()
54
+ }
55
+ this.activeSounds.delete(sound)
56
+ this.soundVolumes.delete(sound)
57
+ audioLoader.manager.itemEnd(path)
58
+ }
59
+ sound.play()
60
+ })
61
+ }
62
+
63
+ stopAll() {
64
+ for (const sound of this.activeSounds) {
65
+ if (!sound) continue
66
+ sound.stop()
67
+ if (sound.source) {
68
+ sound.disconnect()
69
+ }
70
+ this.worldRenderer.scene.remove(sound)
71
+ }
72
+ this.activeSounds.clear()
73
+ this.soundVolumes.clear()
74
+ }
75
+
76
+ changeVolume(volume: number) {
77
+ this.baseVolume = volume
78
+ for (const [sound, individualVolume] of this.soundVolumes) {
79
+ sound.setVolume(individualVolume * this.baseVolume)
80
+ }
81
+ }
82
+
83
+ destroy() {
84
+ this.stopAll()
85
+ // Remove and cleanup audio listener
86
+ if (this.audioListener) {
87
+ this.audioListener.removeFromParent()
88
+ this.audioListener = undefined
89
+ }
90
+ }
91
+
92
+ playTestSound() {
93
+ this.playSound(this.worldRenderer.camera.position, '/sound.mp3')
94
+ }
95
+ }
@@ -0,0 +1,90 @@
1
+ import * as THREE from 'three'
2
+ import { getLoadedImage } from 'mc-assets/dist/utils'
3
+ import { createCanvas, loadImageFromUrl } from '../lib/utils'
4
+
5
+ export const disposeObject = (obj: THREE.Object3D, cleanTextures = false) => {
6
+ // not cleaning texture there as it might be used by other objects, but would be good to also do that
7
+ if (obj instanceof THREE.Mesh) {
8
+ obj.geometry?.dispose?.()
9
+ obj.material?.dispose?.()
10
+ }
11
+ if (obj.children) {
12
+ // eslint-disable-next-line unicorn/no-array-for-each
13
+ obj.children.forEach(child => disposeObject(child, cleanTextures))
14
+ }
15
+ if (cleanTextures) {
16
+ if (obj instanceof THREE.Mesh) {
17
+ obj.material?.map?.dispose?.()
18
+ }
19
+ }
20
+ }
21
+
22
+ let textureCache: Record<string, THREE.Texture> = {}
23
+ let imagesPromises: Record<string, Promise<THREE.Texture>> = {}
24
+
25
+ export const loadThreeJsTextureFromUrlSync = (imageUrl: string) => {
26
+ const texture = new THREE.Texture()
27
+ const promise = loadImageFromUrl(imageUrl).then(bitmap => {
28
+ const canvas = new OffscreenCanvas(bitmap.width, bitmap.height)
29
+ const ctx = canvas.getContext('2d')!
30
+ ctx.drawImage(bitmap, 0, 0)
31
+ texture.source.data = canvas
32
+ texture.needsUpdate = true
33
+ return texture
34
+ })
35
+ return {
36
+ texture,
37
+ promise
38
+ }
39
+
40
+ // MAIN
41
+ // const texture = new THREE.Texture()
42
+ // const promise = getLoadedImage(imageUrl).then(image => {
43
+ // texture.image = image
44
+ // texture.needsUpdate = true
45
+ // return texture
46
+ // })
47
+ // return {
48
+ // texture,
49
+ // promise
50
+ // }
51
+ }
52
+
53
+ export const loadThreeJsTextureFromUrl = async (imageUrl: string) => {
54
+ return loadThreeJsTextureFromUrlSync(imageUrl).texture
55
+
56
+ // MAIN
57
+ // const loaded = new THREE.TextureLoader().loadAsync(imageUrl)
58
+ // return loaded
59
+ }
60
+
61
+ export const loadThreeJsTextureFromBitmap = (image: ImageBitmap) => {
62
+ const canvas = createCanvas(image.width, image.height)
63
+ const ctx = canvas.getContext('2d')!
64
+ ctx.drawImage(image, 0, 0)
65
+ const texture = new THREE.Texture(canvas)
66
+ texture.magFilter = THREE.NearestFilter
67
+ texture.minFilter = THREE.NearestFilter
68
+ return texture
69
+ }
70
+
71
+ export async function loadTexture (texture: string, cb: (texture: THREE.Texture) => void, onLoad?: () => void): Promise<void> {
72
+ const cached = textureCache[texture]
73
+ if (!cached) {
74
+ const { promise, resolve } = Promise.withResolvers<THREE.Texture>()
75
+ const t = loadThreeJsTextureFromUrlSync(texture)
76
+ textureCache[texture] = t.texture
77
+ void t.promise.then(resolve)
78
+ imagesPromises[texture] = promise
79
+ }
80
+
81
+ cb(textureCache[texture])
82
+ void imagesPromises[texture].then(() => {
83
+ onLoad?.()
84
+ })
85
+ }
86
+
87
+ export const clearTextureCache = () => {
88
+ textureCache = {}
89
+ imagesPromises = {}
90
+ }