diff --git a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx index 60ce34687..17bbdfae3 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/TankSandbox.tsx @@ -21,6 +21,8 @@ import { SceneProps } from '../SceneProps'; import { ModelLoader } from './components/ModelLoader'; import { Options } from './components/Options'; import { TankArmor } from './components/TankArmor'; +import { ExternalModuleMask } from './components/TankArmor/components/ExternalModuleMask'; +import { SpacedArmorDepth } from './components/TankArmor/components/SpacedArmorDepth'; import { TankModel } from './components/TankModel'; export function TankSandbox() { @@ -173,6 +175,8 @@ export function TankSandbox() { + + ) : ( diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/ExternalModuleMask.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/ExternalModuleMask.tsx index a490f7890..fe109f16d 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/ExternalModuleMask.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/ExternalModuleMask.tsx @@ -15,6 +15,10 @@ import { useModelDefinitions } from '../../../../../../../../../hooks/useModelDe import { useDuel } from '../../../../../../../../../stores/duel'; import { useTankopediaTemporary } from '../../../../../../../../../stores/tankopedia'; +interface ExternalModuleMaskProps { + ornamental?: boolean; +} + /** * When rendered, generates a mask and thickness buffer for external modules. * - R: 1 means external module @@ -22,15 +26,120 @@ import { useTankopediaTemporary } from '../../../../../../../../../stores/tankop * - B: no data * - A: 1 means is armor; 0 is background */ -export const ExternalModuleMask = memo(() => { - const protagonist = useDuel((state) => state.protagonist!); - const wrapper = useRef(null); - const modelDefinitions = useModelDefinitions(); - const turretContainer = useRef(null); - const gunContainer = useRef(null); - const initialTankopediaState = useTankopediaTemporary.getState(); +export const ExternalModuleMask = memo( + ({ ornamental = false }) => { + const protagonist = useDuel((state) => state.protagonist!); + const wrapper = useRef(null); + const modelDefinitions = useModelDefinitions(); + const turretContainer = useRef(null); + const gunContainer = useRef(null); + const initialTankopediaState = useTankopediaTemporary.getState(); - useEffect(() => { + useEffect(() => { + const hullOrigin = new Vector3( + tankModelDefinition.hullOrigin[0], + tankModelDefinition.hullOrigin[1], + -tankModelDefinition.hullOrigin[2], + ).applyAxisAngle(I_HAT, Math.PI / 2); + const turretOrigin = new Vector3( + tankModelDefinition.turretOrigin[0], + tankModelDefinition.turretOrigin[1], + -tankModelDefinition.turretOrigin[2], + ).applyAxisAngle(I_HAT, Math.PI / 2); + const gunOrigin = new Vector3( + turretModelDefinition.gunOrigin[0], + turretModelDefinition.gunOrigin[1], + -turretModelDefinition.gunOrigin[2], + ).applyAxisAngle(I_HAT, Math.PI / 2); + const turretPosition = new Vector3(); + const turretRotation = new Euler(); + const gunPosition = new Vector3(); + const gunRotation = new Euler(); + + function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { + gunPosition + .set(0, 0, 0) + .sub(hullOrigin) + .sub(turretOrigin) + .sub(gunOrigin) + .applyAxisAngle(I_HAT, pitch) + .add(gunOrigin) + .add(turretOrigin) + .add(hullOrigin); + gunRotation.set(pitch, 0, 0); + gunContainer.current?.position.copy(gunPosition); + gunContainer.current?.rotation.copy(gunRotation); + + if (yaw === undefined) return; + + turretPosition + .set(0, 0, 0) + .sub(turretOrigin) + .sub(hullOrigin) + .applyAxisAngle(new Vector3(0, 0, 1), yaw); + turretRotation.set(0, 0, yaw); + + if (tankModelDefinition.turretRotation) { + const initialPitch = -degToRad( + tankModelDefinition.turretRotation.pitch, + ); + const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw); + const initialRoll = -degToRad( + tankModelDefinition.turretRotation.roll, + ); + + turretPosition + .applyAxisAngle(I_HAT, initialPitch) + .applyAxisAngle(J_HAT, initialRoll) + .applyAxisAngle(K_HAT, initialYaw); + turretRotation.x += initialPitch; + turretRotation.y += initialRoll; + turretRotation.z += initialYaw; + } + + turretPosition.add(turretOrigin).add(hullOrigin); + turretContainer.current?.position.copy(turretPosition); + turretContainer.current?.rotation.copy(turretRotation); + } + + handleModelTransform(useTankopediaTemporary.getState().model.pose); + modelTransformEvent.on(handleModelTransform); + + return () => { + modelTransformEvent.off(handleModelTransform); + }; + }); + + useEffect(() => { + const unsubscribe = useTankopediaTemporary.subscribe( + (state) => state.mode, + (mode) => { + if (wrapper.current) wrapper.current.visible = mode === 'armor'; + }, + ); + + return unsubscribe; + }); + + const armorGltf = useArmor(protagonist.tank.id); + const { gltf: modelGltf } = useModel(protagonist.tank.id); + + const armorNodes = Object.values(armorGltf.nodes); + const modelNodes = Object.values(modelGltf.nodes); + const tankModelDefinition = modelDefinitions[protagonist.tank.id]; + const turretModelDefinition = + tankModelDefinition.turrets[protagonist.turret.id]; + const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; + const maxThickness = Math.max( + tankModelDefinition.trackThickness, + gunModelDefinition.barrelThickness, + ...armorNodes + .map((node) => { + const armorId = nameToArmorId(node.name); + return resolveArmor(tankModelDefinition.armor, armorId).thickness; + }) + .filter(Boolean), + ); const hullOrigin = new Vector3( tankModelDefinition.hullOrigin[0], tankModelDefinition.hullOrigin[1], @@ -46,223 +155,127 @@ export const ExternalModuleMask = memo(() => { turretModelDefinition.gunOrigin[1], -turretModelDefinition.gunOrigin[2], ).applyAxisAngle(I_HAT, Math.PI / 2); - const turretPosition = new Vector3(); - const turretRotation = new Euler(); - const gunPosition = new Vector3(); - const gunRotation = new Euler(); - function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { - gunPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .sub(gunOrigin) - .applyAxisAngle(I_HAT, pitch) - .add(gunOrigin) - .add(turretOrigin) - .add(hullOrigin); - gunRotation.set(pitch, 0, 0); - gunContainer.current?.position.copy(gunPosition); - gunContainer.current?.rotation.copy(gunRotation); + return ( + + + {armorNodes.map((node) => { + const isHull = node.name.startsWith('hull_'); + const isVisible = isHull; + const armorId = nameToArmorId(node.name); + const { thickness, spaced } = resolveArmor( + tankModelDefinition.armor, + armorId, + ); - if (yaw === undefined) return; + if (!isVisible || thickness === undefined || spaced) return null; - turretPosition - .set(0, 0, 0) - .sub(turretOrigin) - .sub(hullOrigin) - .applyAxisAngle(new Vector3(0, 0, 1), yaw); - turretRotation.set(0, 0, yaw); + return ( + + ); + })} + - if (tankModelDefinition.turretRotation) { - const initialPitch = -degToRad( - tankModelDefinition.turretRotation.pitch, - ); - const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw); - const initialRoll = -degToRad(tankModelDefinition.turretRotation.roll); + {modelNodes.map((node) => { + const isWheel = node.name.startsWith('chassis_wheel_'); + const isTrack = node.name.startsWith('chassis_track_'); + const isVisible = isWheel || isTrack; - turretPosition - .applyAxisAngle(I_HAT, initialPitch) - .applyAxisAngle(J_HAT, initialRoll) - .applyAxisAngle(K_HAT, initialYaw); - turretRotation.x += initialPitch; - turretRotation.y += initialRoll; - turretRotation.z += initialYaw; - } - - turretPosition.add(turretOrigin).add(hullOrigin); - turretContainer.current?.position.copy(turretPosition); - turretContainer.current?.rotation.copy(turretRotation); - } - - handleModelTransform(useTankopediaTemporary.getState().model.pose); - modelTransformEvent.on(handleModelTransform); - - return () => { - modelTransformEvent.off(handleModelTransform); - }; - }); - - useEffect(() => { - const unsubscribe = useTankopediaTemporary.subscribe( - (state) => state.mode, - (mode) => { - if (wrapper.current) wrapper.current.visible = mode === 'armor'; - }, - ); - - return unsubscribe; - }); - - const armorGltf = useArmor(protagonist.tank.id); - const { gltf: modelGltf } = useModel(protagonist.tank.id); - - const armorNodes = Object.values(armorGltf.nodes); - const modelNodes = Object.values(modelGltf.nodes); - const tankModelDefinition = modelDefinitions[protagonist.tank.id]; - const turretModelDefinition = - tankModelDefinition.turrets[protagonist.turret.id]; - const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; - const maxThickness = Math.max( - tankModelDefinition.trackThickness, - gunModelDefinition.barrelThickness, - ...armorNodes - .map((node) => { - const armorId = nameToArmorId(node.name); - return resolveArmor(tankModelDefinition.armor, armorId).thickness; - }) - .filter(Boolean), - ); - const hullOrigin = new Vector3( - tankModelDefinition.hullOrigin[0], - tankModelDefinition.hullOrigin[1], - -tankModelDefinition.hullOrigin[2], - ).applyAxisAngle(I_HAT, Math.PI / 2); - const turretOrigin = new Vector3( - tankModelDefinition.turretOrigin[0], - tankModelDefinition.turretOrigin[1], - -tankModelDefinition.turretOrigin[2], - ).applyAxisAngle(I_HAT, Math.PI / 2); - const gunOrigin = new Vector3( - turretModelDefinition.gunOrigin[0], - turretModelDefinition.gunOrigin[1], - -turretModelDefinition.gunOrigin[2], - ).applyAxisAngle(I_HAT, Math.PI / 2); - - return ( - - - {armorNodes.map((node) => { - const isHull = node.name.startsWith('hull_'); - const isVisible = isHull; - const armorId = nameToArmorId(node.name); - const { thickness, spaced } = resolveArmor( - tankModelDefinition.armor, - armorId, - ); - - if (!isVisible || thickness === undefined || spaced) return null; + if (!isVisible) return null; return ( ); })} - - {modelNodes.map((node) => { - const isWheel = node.name.startsWith('chassis_wheel_'); - const isTrack = node.name.startsWith('chassis_track_'); - const isVisible = isWheel || isTrack; + + + {armorNodes.map((node) => { + const isCurrentTurret = node.name.startsWith( + `turret_${turretModelDefinition.model.toString().padStart(2, '0')}`, + ); + const isVisible = isCurrentTurret; + const armorId = nameToArmorId(node.name); + const { thickness, spaced } = resolveArmor( + turretModelDefinition.armor, + armorId, + ); - if (!isVisible) return null; + if (!isVisible || thickness === undefined || spaced) return null; - return ( - - ); - })} + return ( + + ); + })} + - - - {armorNodes.map((node) => { - const isCurrentTurret = node.name.startsWith( - `turret_${turretModelDefinition.model.toString().padStart(2, '0')}`, - ); - const isVisible = isCurrentTurret; - const armorId = nameToArmorId(node.name); - const { thickness, spaced } = resolveArmor( - turretModelDefinition.armor, - armorId, - ); + + {armorNodes.map((node) => { + const isCurrentGun = node.name.startsWith( + `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`, + ); + const isVisible = isCurrentGun; + const armorId = nameToArmorId(node.name); + const { thickness, spaced } = resolveArmor( + gunModelDefinition.armor, + armorId, + ); - if (!isVisible || thickness === undefined || spaced) return null; + if (!isVisible || thickness === undefined || spaced) return null; - return ( - - ); - })} - + return ( + + ); + })} - - {armorNodes.map((node) => { - const isCurrentGun = node.name.startsWith( - `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`, - ); - const isVisible = isCurrentGun; - const armorId = nameToArmorId(node.name); - const { thickness, spaced } = resolveArmor( - gunModelDefinition.armor, - armorId, - ); + {modelNodes.map((node) => { + const isCurrentGun = + node.name === + `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`; + const isVisible = isCurrentGun; - if (!isVisible || thickness === undefined || spaced) return null; + if (!isVisible) return null; - return ( - - ); - })} - - {modelNodes.map((node) => { - const isCurrentGun = - node.name === - `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`; - const isVisible = isCurrentGun; - - if (!isVisible) return null; - - return ( - - ); - })} + return ( + + ); + })} + - - ); -}); + ); + }, +); diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/SpacedArmorDepth.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/SpacedArmorDepth.tsx index d074452a0..12a06171b 100644 --- a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/SpacedArmorDepth.tsx +++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor/components/SpacedArmorDepth.tsx @@ -15,6 +15,10 @@ import { useModelDefinitions } from '../../../../../../../../../hooks/useModelDe import { useDuel } from '../../../../../../../../../stores/duel'; import { useTankopediaTemporary } from '../../../../../../../../../stores/tankopedia'; +interface SpacedArmorDepthProps { + ornamental?: boolean; +} + /** * When rendered, this component provides the depth buffer for the armor which * when compared to the depth of the core armor will give you the distance @@ -26,17 +30,122 @@ import { useTankopediaTemporary } from '../../../../../../../../../stores/tankop * - B: no data * - A: 1 means is armor; 0 is background */ -export const SpacedArmorDepth = memo(() => { - const protagonist = useDuel((state) => state.protagonist!); - const wrapper = useRef(null); - const modelDefinitions = useModelDefinitions(); - const turretContainer = useRef(null); - const gunContainer = useRef(null); - const initialTankopediaState = useTankopediaTemporary.getState(); +export const SpacedArmorDepth = memo( + ({ ornamental = false }) => { + const protagonist = useDuel((state) => state.protagonist!); + const wrapper = useRef(null); + const modelDefinitions = useModelDefinitions(); + const turretContainer = useRef(null); + const gunContainer = useRef(null); + const initialTankopediaState = useTankopediaTemporary.getState(); - useEffect(() => { - if (!modelDefinitions) return; + useEffect(() => { + if (!modelDefinitions) return; + const hullOrigin = new Vector3( + tankModelDefinition.hullOrigin[0], + tankModelDefinition.hullOrigin[1], + -tankModelDefinition.hullOrigin[2], + ).applyAxisAngle(I_HAT, Math.PI / 2); + const turretOrigin = new Vector3( + tankModelDefinition.turretOrigin[0], + tankModelDefinition.turretOrigin[1], + -tankModelDefinition.turretOrigin[2], + ).applyAxisAngle(I_HAT, Math.PI / 2); + const gunOrigin = new Vector3( + turretModelDefinition.gunOrigin[0], + turretModelDefinition.gunOrigin[1], + -turretModelDefinition.gunOrigin[2], + ).applyAxisAngle(I_HAT, Math.PI / 2); + const turretPosition = new Vector3(); + const turretRotation = new Euler(); + const gunPosition = new Vector3(); + const gunRotation = new Euler(); + + function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { + gunPosition + .set(0, 0, 0) + .sub(hullOrigin) + .sub(turretOrigin) + .sub(gunOrigin) + .applyAxisAngle(I_HAT, pitch) + .add(gunOrigin) + .add(turretOrigin) + .add(hullOrigin); + gunRotation.set(pitch, 0, 0); + gunContainer.current?.position.copy(gunPosition); + gunContainer.current?.rotation.copy(gunRotation); + + if (yaw === undefined) return; + + turretPosition + .set(0, 0, 0) + .sub(hullOrigin) + .sub(turretOrigin) + .applyAxisAngle(new Vector3(0, 0, 1), yaw); + turretRotation.set(0, 0, yaw); + + if (tankModelDefinition.turretRotation) { + const initialPitch = -degToRad( + tankModelDefinition.turretRotation.pitch, + ); + const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw); + const initialRoll = -degToRad( + tankModelDefinition.turretRotation.roll, + ); + + turretPosition + .applyAxisAngle(I_HAT, initialPitch) + .applyAxisAngle(J_HAT, initialRoll) + .applyAxisAngle(K_HAT, initialYaw); + turretRotation.x += initialPitch; + turretRotation.y += initialRoll; + turretRotation.z += initialYaw; + } + + turretPosition.add(turretOrigin).add(hullOrigin); + turretContainer.current?.position.copy(turretPosition); + turretContainer.current?.rotation.copy(turretRotation); + } + + handleModelTransform(useTankopediaTemporary.getState().model.pose); + modelTransformEvent.on(handleModelTransform); + + return () => { + modelTransformEvent.off(handleModelTransform); + }; + }); + + useEffect(() => { + const unsubscribe = useTankopediaTemporary.subscribe( + (state) => state.mode, + (mode) => { + if (wrapper.current) wrapper.current.visible = mode === 'armor'; + }, + ); + + return unsubscribe; + }); + + const armorGltf = useArmor(protagonist.tank.id); + const { gltf: modelGltf } = useModel(protagonist.tank.id); + + const armorNodes = Object.values(armorGltf.nodes); + const modelNodes = Object.values(modelGltf.nodes); + const tankModelDefinition = modelDefinitions[protagonist.tank.id]; + const turretModelDefinition = + tankModelDefinition.turrets[protagonist.turret.id]; + const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; + const maxThickness = Math.max( + tankModelDefinition.trackThickness, + gunModelDefinition.barrelThickness, + ...armorNodes + .map((node) => { + const armorId = nameToArmorId(node.name); + return resolveArmor(tankModelDefinition.armor, armorId).thickness; + }) + .filter(Boolean), + ); const hullOrigin = new Vector3( tankModelDefinition.hullOrigin[0], tankModelDefinition.hullOrigin[1], @@ -52,165 +161,20 @@ export const SpacedArmorDepth = memo(() => { turretModelDefinition.gunOrigin[1], -turretModelDefinition.gunOrigin[2], ).applyAxisAngle(I_HAT, Math.PI / 2); - const turretPosition = new Vector3(); - const turretRotation = new Euler(); - const gunPosition = new Vector3(); - const gunRotation = new Euler(); - function handleModelTransform({ yaw, pitch }: ModelTransformEventData) { - gunPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .sub(gunOrigin) - .applyAxisAngle(I_HAT, pitch) - .add(gunOrigin) - .add(turretOrigin) - .add(hullOrigin); - gunRotation.set(pitch, 0, 0); - gunContainer.current?.position.copy(gunPosition); - gunContainer.current?.rotation.copy(gunRotation); - - if (yaw === undefined) return; - - turretPosition - .set(0, 0, 0) - .sub(hullOrigin) - .sub(turretOrigin) - .applyAxisAngle(new Vector3(0, 0, 1), yaw); - turretRotation.set(0, 0, yaw); - - if (tankModelDefinition.turretRotation) { - const initialPitch = -degToRad( - tankModelDefinition.turretRotation.pitch, - ); - const initialYaw = -degToRad(tankModelDefinition.turretRotation.yaw); - const initialRoll = -degToRad(tankModelDefinition.turretRotation.roll); - - turretPosition - .applyAxisAngle(I_HAT, initialPitch) - .applyAxisAngle(J_HAT, initialRoll) - .applyAxisAngle(K_HAT, initialYaw); - turretRotation.x += initialPitch; - turretRotation.y += initialRoll; - turretRotation.z += initialYaw; - } - - turretPosition.add(turretOrigin).add(hullOrigin); - turretContainer.current?.position.copy(turretPosition); - turretContainer.current?.rotation.copy(turretRotation); - } - - handleModelTransform(useTankopediaTemporary.getState().model.pose); - modelTransformEvent.on(handleModelTransform); - - return () => { - modelTransformEvent.off(handleModelTransform); - }; - }); - - useEffect(() => { - const unsubscribe = useTankopediaTemporary.subscribe( - (state) => state.mode, - (mode) => { - if (wrapper.current) wrapper.current.visible = mode === 'armor'; - }, - ); - - return unsubscribe; - }); - - const armorGltf = useArmor(protagonist.tank.id); - const { gltf: modelGltf } = useModel(protagonist.tank.id); - - const armorNodes = Object.values(armorGltf.nodes); - const modelNodes = Object.values(modelGltf.nodes); - const tankModelDefinition = modelDefinitions[protagonist.tank.id]; - const turretModelDefinition = - tankModelDefinition.turrets[protagonist.turret.id]; - const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id]; - const maxThickness = Math.max( - tankModelDefinition.trackThickness, - gunModelDefinition.barrelThickness, - ...armorNodes - .map((node) => { - const armorId = nameToArmorId(node.name); - return resolveArmor(tankModelDefinition.armor, armorId).thickness; - }) - .filter(Boolean), - ); - const hullOrigin = new Vector3( - tankModelDefinition.hullOrigin[0], - tankModelDefinition.hullOrigin[1], - -tankModelDefinition.hullOrigin[2], - ).applyAxisAngle(I_HAT, Math.PI / 2); - const turretOrigin = new Vector3( - tankModelDefinition.turretOrigin[0], - tankModelDefinition.turretOrigin[1], - -tankModelDefinition.turretOrigin[2], - ).applyAxisAngle(I_HAT, Math.PI / 2); - const gunOrigin = new Vector3( - turretModelDefinition.gunOrigin[0], - turretModelDefinition.gunOrigin[1], - -turretModelDefinition.gunOrigin[2], - ).applyAxisAngle(I_HAT, Math.PI / 2); - - return ( - - - {armorNodes.map((node) => { - const isHull = node.name.startsWith('hull_'); - const isVisible = isHull; - const armorId = nameToArmorId(node.name); - const { spaced, thickness } = resolveArmor( - tankModelDefinition.armor, - armorId, - ); - - if (!isVisible || thickness === undefined) return null; - - return ( - - ); - })} - - {modelNodes.map((node) => { - const isWheel = node.name.startsWith('chassis_wheel_'); - const isTrack = node.name.startsWith('chassis_track_'); - const isVisible = isWheel || isTrack; - - if (!isVisible) return null; - - return ( - - ); - })} - - + return ( + {armorNodes.map((node) => { - const isCurrentTurret = node.name.startsWith( - `turret_${turretModelDefinition.model.toString().padStart(2, '0')}`, - ); - const isVisible = isCurrentTurret; + const isHull = node.name.startsWith('hull_'); + const isVisible = isHull; const armorId = nameToArmorId(node.name); const { spaced, thickness } = resolveArmor( - turretModelDefinition.armor, + tankModelDefinition.armor, armorId, ); @@ -218,27 +182,44 @@ export const SpacedArmorDepth = memo(() => { return ( ); })} - + {modelNodes.map((node) => { + const isWheel = node.name.startsWith('chassis_wheel_'); + const isTrack = node.name.startsWith('chassis_track_'); + const isVisible = isWheel || isTrack; + + if (!isVisible) return null; + + return ( + + ); + })} + + {armorNodes.map((node) => { - const isCurrentGun = node.name.startsWith( - `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`, + const isCurrentTurret = node.name.startsWith( + `turret_${turretModelDefinition.model.toString().padStart(2, '0')}`, ); - const isVisible = isCurrentGun; + const isVisible = isCurrentTurret; const armorId = nameToArmorId(node.name); const { spaced, thickness } = resolveArmor( - gunModelDefinition.armor, + turretModelDefinition.armor, armorId, ); @@ -246,36 +227,68 @@ export const SpacedArmorDepth = memo(() => { return ( ); })} + + + {armorNodes.map((node) => { + const isCurrentGun = node.name.startsWith( + `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`, + ); + const isVisible = isCurrentGun; + const armorId = nameToArmorId(node.name); + const { spaced, thickness } = resolveArmor( + gunModelDefinition.armor, + armorId, + ); - {modelNodes.map((node) => { - const isCurrentGun = - node.name === - `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`; - const isVisible = isCurrentGun; + if (!isVisible || thickness === undefined) return null; - if (!isVisible) return null; + return ( + + ); + })} + - return ( - - ); - })} + {modelNodes.map((node) => { + const isCurrentGun = + node.name === + `gun_${gunModelDefinition.model.toString().padStart(2, '0')}`; + const isVisible = isCurrentGun; + + if (!isVisible) return null; + + return ( + + ); + })} + - - ); -}); + ); + }, +); diff --git a/src/components/ArmorMesh/components/Armor/index.tsx b/src/components/ArmorMesh/components/Armor/index.tsx index 17d433d49..ab7e0a246 100644 --- a/src/components/ArmorMesh/components/Armor/index.tsx +++ b/src/components/ArmorMesh/components/Armor/index.tsx @@ -6,7 +6,10 @@ import { canSplash } from '../../../../core/blitz/canSplash'; import { isExplosive } from '../../../../core/blitz/isExplosive'; import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration'; import { useDuel } from '../../../../stores/duel'; -import { useTankopediaPersistent } from '../../../../stores/tankopedia'; +import { + useTankopediaPersistent, + useTankopediaTemporary, +} from '../../../../stores/tankopedia'; import { externalModuleMaskRenderTarget } from '../ExternalModuleMask'; import { spacedArmorDepthRenderTarget } from '../SpacedArmorDepth'; import fragmentShader from './shaders/fragment.glsl'; @@ -17,6 +20,11 @@ interface ArmorMeshProps extends MeshProps { maxThickness: number; } +export type ArmorMeshUserData = { + type: 'coreArmor' | 'spacedArmor' | 'externalModule'; + thickness: number; +}; + export function ArmorMesh({ thickness, maxThickness, @@ -109,7 +117,26 @@ export function ArmorMesh({ - + { + if (useTankopediaTemporary.getState().mode !== 'armor') return; + + event.intersections + .filter(({ object }) => Boolean(object.userData.type)) + .map(({ object }) => { + const data = object.userData as ArmorMeshUserData; + console.log(data.type, data.thickness); + }); + }} + > - {props.exclude && ( + {(props.exclude || ornamental) && ( )} {!props.exclude && ( - + {} : undefined} + userData={ + { + type: 'externalModule', + thickness: props.thickness, + } satisfies ArmorMeshUserData + } + > )} diff --git a/src/components/ArmorMesh/components/SpacedArmorDepth/index.tsx b/src/components/ArmorMesh/components/SpacedArmorDepth/index.tsx index 9ed611384..a28da6a13 100644 --- a/src/components/ArmorMesh/components/SpacedArmorDepth/index.tsx +++ b/src/components/ArmorMesh/components/SpacedArmorDepth/index.tsx @@ -1,12 +1,14 @@ import { MeshProps } from '@react-three/fiber'; import { WebGLRenderTarget } from 'three'; +import { ArmorMeshUserData } from '../Armor'; import fragmentShader from './shaders/fragment.glsl'; import vertexShader from './shaders/vertex.glsl'; export const spacedArmorDepthRenderTarget = new WebGLRenderTarget(); -type ArmorMeshSpacedArmorDepthProps = MeshProps & - ( +type ArmorMeshSpacedArmorDepthProps = MeshProps & { + ornamental?: boolean; +} & ( | { include?: false; isExternalModule: boolean; @@ -18,27 +20,44 @@ type ArmorMeshSpacedArmorDepthProps = MeshProps & } ); -export function ArmorMeshSpacedArmorDepth( - props: ArmorMeshSpacedArmorDepthProps, -) { +export function ArmorMeshSpacedArmorDepth({ + ornamental = false, + ...props +}: ArmorMeshSpacedArmorDepthProps) { return ( <> - {!props.include && ( + {!props.include && !ornamental && ( )} {props.include && ( - - + {} : undefined} + userData={ + { + type: 'spacedArmor', + thickness: props.thickness, + } satisfies ArmorMeshUserData + } + > + {!ornamental && ( + + )} + + {ornamental && ( + + )} )}