From 318a71bd32d1ad3e077d0a2f1ee0bc979a42ecd2 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Sun, 15 Dec 2024 18:13:23 -0600 Subject: [PATCH] feat: advanced mode --- .../PrimaryArmorSceneComponent/index.tsx | 19 ++- .../shaders/fragment.glsl | 20 +++- .../HeroSection/components/Options/index.tsx | 108 +++++++++++------- .../TankSandbox/components/Control.tsx | 1 - .../src/stores/tankopediaPersistent/index.ts | 2 + 5 files changed, 98 insertions(+), 52 deletions(-) diff --git a/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx b/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx index 519646c10..462288558 100644 --- a/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx +++ b/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/index.tsx @@ -49,6 +49,7 @@ export function PrimaryArmorSceneComponent({ damage: { value: null }, explosionRadius: { value: null }, greenPenetration: { value: null }, + advancedHighlighting: { value: null }, opaque: { value: null }, inverseProjectionMatrix: { value: null }, @@ -90,6 +91,9 @@ export function PrimaryArmorSceneComponent({ function handleGreenPenetrationChange(greenPenetration: boolean) { material.uniforms.greenPenetration.value = greenPenetration; } + function handleAdvancedHighlightingChange(advancedHighlighting: boolean) { + material.uniforms.advancedHighlighting.value = advancedHighlighting; + } function handleOpaqueChange(opaque: boolean) { material.uniforms.opaque.value = opaque; } @@ -133,12 +137,13 @@ export function PrimaryArmorSceneComponent({ if (!noInvalidate) invalidate(); } + const initialState = tankopediaPersistentStore.getState(); + handleShellChange(); - handleGreenPenetrationChange( - tankopediaPersistentStore.getState().greenPenetration, - ); - handleOpaqueChange(tankopediaPersistentStore.getState().opaque); - handleWireframeChange(tankopediaPersistentStore.getState().wireframe); + handleGreenPenetrationChange(initialState.greenPenetration); + handleAdvancedHighlightingChange(initialState.advancedHighlighting); + handleOpaqueChange(initialState.opaque); + handleWireframeChange(initialState.wireframe); handleProtagonistEquipmentChange( duelStore.getState().protagonist.equipmentMatrix, ); @@ -156,6 +161,10 @@ export function PrimaryArmorSceneComponent({ (state) => state.greenPenetration, handleGreenPenetrationChange, ), + tankopediaPersistentStore.subscribe( + (state) => state.advancedHighlighting, + handleAdvancedHighlightingChange, + ), tankopediaPersistentStore.subscribe( (state) => state.opaque, handleOpaqueChange, diff --git a/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/shaders/fragment.glsl b/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/shaders/fragment.glsl index 045d49a80..76bc4520f 100644 --- a/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/shaders/fragment.glsl +++ b/packages/website/src/components/Armor/components/PrimaryArmorSceneComponent/shaders/fragment.glsl @@ -12,6 +12,7 @@ uniform bool canSplash; uniform float damage; uniform float explosionRadius; uniform bool greenPenetration; +uniform bool advancedHighlighting; uniform bool opaque; uniform mat4 inverseProjectionMatrix; @@ -27,16 +28,18 @@ float depthToDistance(float depth) { void main() { float penetrationChance = -1.0; float splashChance = -1.0; + bool didRicochet = false; vec2 screenCoordinates = gl_FragCoord.xy / resolution; float angle = acos(dot(vNormal, -vViewPosition) / length(vViewPosition)); vec4 spacedArmorBufferFragment = texture2D(spacedArmorBuffer, screenCoordinates); bool isUnderSpacedArmor = spacedArmorBufferFragment.a != 0.0; - bool threeCalibersRule = caliber > thickness * 3.0 || isUnderSpacedArmor; + if (!threeCalibersRule && angle >= ricochet) { penetrationChance = 0.0; + didRicochet = true; } else { bool twoCalibersRule = caliber > thickness * 2.0 && thickness > 0.0; float finalNormalization = twoCalibersRule ? ((1.4 * normalization * caliber) / (2.0 * thickness)) : normalization; @@ -82,11 +85,22 @@ void main() { float alpha = opaque ? 1.0 : 0.5; vec3 color = vec3(1.0, splashChance * 0.392, 0.0); - if (greenPenetration) { + + if (advancedHighlighting && didRicochet) { + color = vec3(1.0, color.g, 1.0); + } + + if (greenPenetration || advancedHighlighting) { // non-trigonometric red-green mixing: https://www.desmos.com/calculator/ceo1oq7l67 float falling = -pow(penetrationChance, 2.0) + 1.0; float gaining = -pow(penetrationChance - 1.0, 2.0) + 1.0; - gl_FragColor = vec4(falling * color + gaining * vec3(0.0, 1.0, 0.0), alpha); + vec3 penetrationColor = vec3(0.0, 1.0, 0.0); + + if (advancedHighlighting && threeCalibersRule) { + penetrationColor = vec3(0.0, 1.0, 1.0); + } + + gl_FragColor = vec4(falling * color + gaining * penetrationColor, alpha); } else { gl_FragColor = vec4(color, (1.0 - penetrationChance) * alpha); } diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx index 20dad8563..1e4baa024 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx @@ -17,6 +17,7 @@ import { import { Box, Button, + Checkbox, Dialog, DropdownMenu, Flex, @@ -68,6 +69,9 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { const greenPenetration = TankopediaPersistent.use( (state) => state.greenPenetration, ); + const advancedHighlighting = TankopediaPersistent.use( + (state) => state.advancedHighlighting, + ); const wireframe = TankopediaPersistent.use((state) => state.wireframe); const opaque = TankopediaPersistent.use((state) => state.opaque); const fullScreenAvailable = useFullscreenAvailability(); @@ -325,53 +329,71 @@ export function Options({ thicknessRange, canvas }: OptionsProps) { style={{ transform: 'translateX(-50%)' }} > {display === TankopediaDisplay.DynamicArmor && ( - - - Shooter: - - + { + mutateTankopediaPersistent((draft) => { + draft.advancedHighlighting = !draft.advancedHighlighting; + }); + }} > - - - + + + Advanced highlighting + + - - Select tank + + + Shooter: + + + + + - - { - mutateDuel((draft) => { - draft.antagonist.tank = tank; - draft.antagonist.engine = tank.engines.at(-1)!; - draft.antagonist.track = tank.tracks.at(-1)!; - draft.antagonist.turret = tank.turrets.at(-1)!; - draft.antagonist.gun = - draft.antagonist.turret.guns.at(-1)!; - draft.antagonist.shell = - draft.antagonist.gun.gun_type!.value.base.shells[0]; - }); - setAntagonistSelectorOpen(false); - }} - /> - - - - + + Select tank + + + { + mutateDuel((draft) => { + draft.antagonist.tank = tank; + draft.antagonist.engine = tank.engines.at(-1)!; + draft.antagonist.track = tank.tracks.at(-1)!; + draft.antagonist.turret = tank.turrets.at(-1)!; + draft.antagonist.gun = + draft.antagonist.turret.guns.at(-1)!; + draft.antagonist.shell = + draft.antagonist.gun.gun_type!.value.base.shells[0]; + }); + setAntagonistSelectorOpen(false); + }} + /> + + + + + )} - diff --git a/packages/website/src/stores/tankopediaPersistent/index.ts b/packages/website/src/stores/tankopediaPersistent/index.ts index c70dd4607..d8054b75a 100644 --- a/packages/website/src/stores/tankopediaPersistent/index.ts +++ b/packages/website/src/stores/tankopediaPersistent/index.ts @@ -12,6 +12,7 @@ export type TankopediaTestTankDisplay = 'include' | 'exclude' | 'only'; export interface TankopediaPersistentStore { wireframe: boolean; opaque: boolean; + advancedHighlighting: boolean; environment: (typeof ENVIRONMENTS)[number]; showGrid: boolean; greenPenetration: boolean; @@ -33,6 +34,7 @@ export const TankopediaPersistent = createContextualStore(() => subscribeWithSelector(() => ({ wireframe: false, opaque: false, + advancedHighlighting: false, environment: ENVIRONMENTS[0], showGrid: true, greenPenetration: false,