Files
pihkaal-me/app/components/NDS.vue
2025-12-13 23:45:50 +01:00

86 lines
2.4 KiB
Vue

<script setup lang="ts">
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { useLoop } from "@tresjs/core";
import * as THREE from "three";
const props = defineProps<{
topScreenCanvas: HTMLCanvasElement | null;
bottomScreenCanvas: HTMLCanvasElement | null;
}>();
const { state: model } = useLoader(
GLTFLoader,
"/models/nintendo-ds/scene.gltf",
);
const scene = computed(() => model.value?.scene);
let topScreenTexture: THREE.CanvasTexture | null = null;
let bottomScreenTexture: THREE.CanvasTexture | null = null;
watch(
() => [props.topScreenCanvas, props.bottomScreenCanvas],
() => {
if (!props.topScreenCanvas || !props.bottomScreenCanvas) return;
topScreenTexture = new THREE.CanvasTexture(props.topScreenCanvas);
topScreenTexture.minFilter = THREE.NearestFilter;
topScreenTexture.magFilter = THREE.NearestFilter;
topScreenTexture.flipY = false;
bottomScreenTexture = new THREE.CanvasTexture(props.bottomScreenCanvas);
bottomScreenTexture.minFilter = THREE.NearestFilter;
bottomScreenTexture.magFilter = THREE.NearestFilter;
bottomScreenTexture.flipY = false;
},
{ immediate: true },
);
watch(scene, () => {
if (!scene.value) return;
scene.value.traverse((child) => {
if (child instanceof THREE.Mesh) {
const material = child.material as THREE.Material;
if (material.name?.includes("screen_up") && topScreenTexture) {
topScreenTexture.repeat.set(1, 1024 / 404);
topScreenTexture.offset.set(0, -4 / 1024);
child.material = new THREE.MeshStandardMaterial({
map: topScreenTexture,
emissive: new THREE.Color(0x222222),
emissiveIntensity: 0.5,
});
} else if (
material.name?.includes("screen_down") &&
bottomScreenTexture
) {
bottomScreenTexture.repeat.set(1, 1024 / 532);
bottomScreenTexture.offset.set(0, -1024 / 532 + 1);
child.material = new THREE.MeshStandardMaterial({
map: bottomScreenTexture,
emissive: new THREE.Color(0x222222),
emissiveIntensity: 0.5,
});
}
}
});
});
const { onRender } = useLoop();
onRender(() => {
if (topScreenTexture) topScreenTexture.needsUpdate = true;
if (bottomScreenTexture) bottomScreenTexture.needsUpdate = true;
});
onUnmounted(() => {
topScreenTexture?.dispose();
bottomScreenTexture?.dispose();
});
</script>
<template>
<primitive v-if="scene" :object="scene" />
</template>