feat: advanced jsxTree

This commit is contained in:
tresabhi committed 2025-04-15 00:11:49 -05:00
1 parent 2bef96475c
commit 0e6aa734cb
10 files changed
+305 -226

No files matched your search

@@ -211,16 +211,25 @@ export function PrimaryArmorSceneComponent({
return (
<>
{jsxTree(
node,
{ mesh: { renderOrder: 0, material: excludeMaterial } },
`${node.uuid}-exclude`,
)}
{jsxTree(
node,
{ mesh: { renderOrder: 1, material } },
`${node.uuid}-include`,
)}
{jsxTree(node, {
mesh(_, props, key) {
return (
<mesh
{...props}
key={key}
renderOrder={0}
material={excludeMaterial}
/>
);
},
})}
{jsxTree(node, {
mesh(_, props, key) {
return (
<mesh {...props} key={key} renderOrder={1} material={material} />
);
},
})}
</>
);
}
@@ -114,33 +114,40 @@ export function SpacedArmorSubExternal({
return (
<>
{jsxTree(
node,
{
mesh: {
renderOrder: 3,
material: new MeshBasicMaterial({
colorWrite: false,
depthTest: true,
depthWrite: true,
...(clip ? { clippingPlanes: [clip] } : {}),
}),
onClick() {},
userData: {
type: ArmorType.External,
thickness,
variant,
} satisfies ArmorUserData,
},
{jsxTree(node, {
mesh(_, props, key) {
return (
<mesh
{...props}
key={key}
renderOrder={3}
material={
new MeshBasicMaterial({
colorWrite: false,
depthTest: true,
depthWrite: true,
...(clip ? { clippingPlanes: [clip] } : {}),
})
}
userData={
{
type: ArmorType.External,
thickness,
variant,
} satisfies ArmorUserData
}
/>
);
},
`${node.uuid}-exclude`,
)}
})}
{jsxTree(
node,
{ mesh: { renderOrder: 4, material } },
`${node.uuid}-include`,
)}
{jsxTree(node, {
mesh(_, props, key) {
return (
<mesh {...props} key={key} renderOrder={4} material={material} />
);
},
})}
</>
);
}
@@ -124,32 +124,38 @@ export function SpacedArmorSubSpaced({
return (
<>
{jsxTree(
node,
{
mesh: {
renderOrder: 2,
material,
onClick() {},
userData: {
type: ArmorType.Spaced,
thickness,
} satisfies ArmorUserData,
},
{jsxTree(node, {
mesh(_, props, key) {
return (
<mesh
{...props}
key={key}
renderOrder={2}
material={material}
onClick={() => {}}
userData={
{
type: ArmorType.Spaced,
thickness,
} satisfies ArmorUserData
}
/>
);
},
`${node.uuid}-exclude`,
)}
})}
{jsxTree(
node,
{
mesh: {
renderOrder: 5,
material: depthWriteMaterial,
},
{jsxTree(node, {
mesh(_, props, key) {
return (
<mesh
{...props}
key={key}
renderOrder={5}
material={depthWriteMaterial}
/>
);
},
`${node.uuid}-include`,
)}
})}
</>
);
}
@@ -372,29 +372,33 @@ export function SpacedArmorSceneComponent({
return (
<>
{props.type === ArmorType.Primary &&
jsxTree(
node,
{
mesh: {
renderOrder: 0,
material: omitMaterial,
userData: {
type: ArmorType.Primary,
thickness,
} satisfies ArmorUserData,
async onClick(event) {
event.stopPropagation();
const shot = (await shoot(
event.point,
event.intersections,
true,
))!;
tankopediaEphemeralStore.setState({ shot });
},
},
jsxTree(node, {
mesh(mesh, props, key) {
return (
<mesh
{...props}
key={key}
renderOrder={0}
material={omitMaterial}
userData={
{
type: ArmorType.Primary,
thickness,
} satisfies ArmorUserData
}
onClick={async (event) => {
event.stopPropagation();
const shot = (await shoot(
event.point,
event.intersections,
true,
))!;
tankopediaEphemeralStore.setState({ shot });
}}
/>
);
},
node.uuid,
)}
})}
{props.type === ArmorType.Spaced && (
<SpacedArmorSubSpaced node={node} thickness={thickness} />
@@ -215,50 +215,61 @@ export function StaticArmorSceneComponent({
return (
<>
{jsxTree(node, {
mesh: {
material: surfaceMaterial,
onPointerDown,
userData: {
type: props.type,
variant: props.type === ArmorType.External ? props.variant : 'gun',
thickness,
} satisfies ArmorUserData,
mesh(_, meshProps, key) {
return (
<mesh
{...meshProps}
key={key}
material={surfaceMaterial}
userData={
{
type: props.type,
variant:
props.type === ArmorType.External ? props.variant : 'gun',
thickness,
} satisfies ArmorUserData
}
onClick={(event) => {
if (discardClippingPlane(event.object, event.point)) return;
onClick(event) {
if (discardClippingPlane(event.object, event.point)) return;
event.stopPropagation();
event.stopPropagation();
const { editStatic } = tankopediaEphemeralStore.getState();
const { editStatic } = tankopediaEphemeralStore.getState();
const bounds = new Box3().setFromObject(event.object);
const point = bounds.min
.clone()
.add(bounds.max)
.divideScalar(2)
.setY(bounds.max.y);
const cameraNormal = camera.position
.clone()
.sub(point)
.normalize();
const surfaceNormal = event
.normal!.clone()
.applyQuaternion(
event.object.getWorldQuaternion(new Quaternion()),
);
const angle = surfaceNormal.angleTo(cameraNormal);
const thicknessAngled =
thickness / Math.sin(Math.PI / 2 - angle);
const bounds = new Box3().setFromObject(event.object);
const point = bounds.min
.clone()
.add(bounds.max)
.divideScalar(2)
.setY(bounds.max.y);
const cameraNormal = camera.position.clone().sub(point).normalize();
const surfaceNormal = event
.normal!.clone()
.applyQuaternion(
event.object.getWorldQuaternion(new Quaternion()),
);
const angle = surfaceNormal.angleTo(cameraNormal);
const thicknessAngled = thickness / Math.sin(Math.PI / 2 - angle);
mutateTankopediaEphemeralStore((draft) => {
draft.highlightArmor = {
type: props.type,
name,
point,
thickness,
thicknessAngled,
angle,
color: `#${color.getHexString()}`,
editingPlate: editStatic,
};
});
},
mutateTankopediaEphemeralStore((draft) => {
draft.highlightArmor = {
type: props.type,
name,
point,
thickness,
thicknessAngled,
angle,
color: `#${color.getHexString()}`,
editingPlate: editStatic,
};
});
}}
/>
);
},
})}