mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
fix: screenshot props
This commit is contained in:
1 parent
3861b07aef
commit
b6fd568cc6
2 files changed
+56
-31
No files matched your search
+30
-27
@@ -32,7 +32,6 @@ import { useEquipment } from '../../../../../hooks/useEquipment';
|
|||||||
import { useFullScreen } from '../../../../../hooks/useFullScreen';
|
import { useFullScreen } from '../../../../../hooks/useFullScreen';
|
||||||
import { useFullscreenAvailability } from '../../../../../hooks/useFullscreenAvailability';
|
import { useFullscreenAvailability } from '../../../../../hooks/useFullscreenAvailability';
|
||||||
import { useLocale } from '../../../../../hooks/useLocale';
|
import { useLocale } from '../../../../../hooks/useLocale';
|
||||||
import { App } from '../../../../../stores/app';
|
|
||||||
import { Duel } from '../../../../../stores/duel';
|
import { Duel } from '../../../../../stores/duel';
|
||||||
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
|
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
|
||||||
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
|
import { TankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
|
||||||
@@ -42,6 +41,7 @@ import type { ThicknessRange } from '../../../../Armor/components/StaticArmor';
|
|||||||
import { ModuleButton } from '../../../../ModuleButtons/ModuleButton';
|
import { ModuleButton } from '../../../../ModuleButtons/ModuleButton';
|
||||||
import { SmallTankIcon } from '../../../../SmallTankIcon';
|
import { SmallTankIcon } from '../../../../SmallTankIcon';
|
||||||
import { TankSearch } from '../../../../TankSearch';
|
import { TankSearch } from '../../../../TankSearch';
|
||||||
|
import { screenshotReadyEvent } from '../TankSandbox/components/SceneProps';
|
||||||
import { CustomShellButton } from './components/CustomShellButton';
|
import { CustomShellButton } from './components/CustomShellButton';
|
||||||
import { DynamicArmorSwitcher } from './components/DynamicArmorSwitcher';
|
import { DynamicArmorSwitcher } from './components/DynamicArmorSwitcher';
|
||||||
import { QuickInputs } from './components/QuickInputs';
|
import { QuickInputs } from './components/QuickInputs';
|
||||||
@@ -58,19 +58,10 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
|||||||
);
|
);
|
||||||
const display = TankopediaEphemeral.use((state) => state.display);
|
const display = TankopediaEphemeral.use((state) => state.display);
|
||||||
const isFullScreen = useFullScreen();
|
const isFullScreen = useFullScreen();
|
||||||
const greenPenetration = TankopediaPersistent.use(
|
|
||||||
(state) => state.greenPenetration,
|
|
||||||
);
|
|
||||||
const hideTankModelUnderArmor = TankopediaPersistent.use(
|
|
||||||
(state) => state.hideTankModelUnderArmor,
|
|
||||||
);
|
|
||||||
const advancedHighlighting = TankopediaPersistent.use(
|
const advancedHighlighting = TankopediaPersistent.use(
|
||||||
(state) => state.advancedHighlighting,
|
(state) => state.advancedHighlighting,
|
||||||
);
|
);
|
||||||
const wireframe = TankopediaPersistent.use((state) => state.wireframe);
|
|
||||||
const opaque = TankopediaPersistent.use((state) => state.opaque);
|
|
||||||
const fullScreenAvailable = useFullscreenAvailability(true);
|
const fullScreenAvailable = useFullscreenAvailability(true);
|
||||||
const developerMode = App.use((state) => state.developerMode);
|
|
||||||
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
||||||
const antagonistGun = Duel.use((state) => state.antagonist.gun);
|
const antagonistGun = Duel.use((state) => state.antagonist.gun);
|
||||||
const antagonistShell = Duel.use((state) => state.antagonist.shell);
|
const antagonistShell = Duel.use((state) => state.antagonist.shell);
|
||||||
@@ -461,19 +452,25 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
|||||||
<Popover.Close>
|
<Popover.Close>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!canvas.current) return;
|
screenshotReadyEvent.dispatch(true);
|
||||||
|
|
||||||
const anchor = document.createElement('a');
|
requestAnimationFrame(() => {
|
||||||
|
if (!canvas.current) return;
|
||||||
|
|
||||||
anchor.setAttribute(
|
const anchor = document.createElement('a');
|
||||||
'download',
|
|
||||||
`${protagonistTank.name}.png`,
|
anchor.setAttribute(
|
||||||
);
|
'download',
|
||||||
anchor.setAttribute(
|
`${protagonistTank.name}.png`,
|
||||||
'href',
|
);
|
||||||
canvas.current.toDataURL('image/png'),
|
anchor.setAttribute(
|
||||||
);
|
'href',
|
||||||
anchor.click();
|
canvas.current.toDataURL('image/png'),
|
||||||
|
);
|
||||||
|
anchor.click();
|
||||||
|
|
||||||
|
screenshotReadyEvent.dispatch(false);
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DownloadIcon />
|
<DownloadIcon />
|
||||||
@@ -487,14 +484,20 @@ export function Options({ thicknessRange, canvas, skeleton }: OptionsProps) {
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!canvas.current) return;
|
screenshotReadyEvent.dispatch(true);
|
||||||
|
|
||||||
canvas.current.toBlob((blob) => {
|
requestAnimationFrame(() => {
|
||||||
if (!blob) return;
|
if (!canvas.current) return;
|
||||||
|
|
||||||
navigator.clipboard.write([
|
canvas.current.toBlob((blob) => {
|
||||||
new ClipboardItem({ 'image/png': blob }),
|
if (!blob) return;
|
||||||
]);
|
|
||||||
|
navigator.clipboard.write([
|
||||||
|
new ClipboardItem({ 'image/png': blob }),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
screenshotReadyEvent.dispatch(false);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
+26
-4
@@ -1,11 +1,15 @@
|
|||||||
import { useFrame } from '@react-three/fiber';
|
import { invalidate, useFrame } from '@react-three/fiber';
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
import { useRef } from 'react';
|
import { Quicklime, type QuicklimeEvent } from 'quicklime';
|
||||||
import { MeshStandardMaterial } from 'three';
|
import { useEffect, useRef } from 'react';
|
||||||
|
import { Mesh, MeshStandardMaterial } from 'three';
|
||||||
|
|
||||||
const SIZE = 2 ** 5;
|
const SIZE = 2 ** 5;
|
||||||
|
|
||||||
|
export const screenshotReadyEvent = new Quicklime(false);
|
||||||
|
|
||||||
export function SceneProps() {
|
export function SceneProps() {
|
||||||
|
const mesh = useRef<Mesh>(null!);
|
||||||
const material = useRef<MeshStandardMaterial>(null);
|
const material = useRef<MeshStandardMaterial>(null);
|
||||||
|
|
||||||
useFrame(({ camera }) => {
|
useFrame(({ camera }) => {
|
||||||
@@ -13,8 +17,26 @@ export function SceneProps() {
|
|||||||
material.current.opacity = clamp(0.5 * camera.position.y, 0, 1);
|
material.current.opacity = clamp(0.5 * camera.position.y, 0, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function handleScreenshotReady(event: QuicklimeEvent<boolean>) {
|
||||||
|
mesh.current.visible = !event.data;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
screenshotReadyEvent.on(handleScreenshotReady);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
screenshotReadyEvent.off(handleScreenshotReady);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<mesh rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
|
<mesh
|
||||||
|
rotation={[-Math.PI / 2, 0, 0]}
|
||||||
|
receiveShadow
|
||||||
|
visible={!screenshotReadyEvent.last!}
|
||||||
|
ref={mesh}
|
||||||
|
>
|
||||||
<planeGeometry args={[SIZE, SIZE]} />
|
<planeGeometry args={[SIZE, SIZE]} />
|
||||||
<meshStandardMaterial
|
<meshStandardMaterial
|
||||||
transparent
|
transparent
|
||||||
|
|||||||
Reference in new issue
Block a user