@layoutit/polycss-react 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2638,6 +2638,7 @@ function PolySceneInner({
2638
2638
  rotY: _rotY,
2639
2639
  zoom: _zoom,
2640
2640
  directionalLight,
2641
+ pointLights,
2641
2642
  ambientLight,
2642
2643
  textureLighting = "baked",
2643
2644
  textureQuality,
@@ -2695,17 +2696,19 @@ function PolySceneInner({
2695
2696
  const sceneBbox = centerInputPolygons ? centerSceneBbox : renderSceneBbox;
2696
2697
  const directionalForAtlas = textureLighting === "dynamic" ? void 0 : directionalLight;
2697
2698
  const ambientForAtlas = textureLighting === "dynamic" ? void 0 : ambientLight;
2699
+ const pointLightsForAtlas = textureLighting === "dynamic" ? void 0 : pointLights;
2698
2700
  const polyContext = useMemo6(() => {
2699
2701
  const tileSize = 50;
2700
2702
  return {
2701
2703
  tileSize,
2702
2704
  layerElevation: tileSize,
2703
2705
  directionalLight: directionalForAtlas,
2706
+ pointLights: pointLightsForAtlas,
2704
2707
  ambientLight: ambientForAtlas,
2705
2708
  textureLighting,
2706
2709
  seamBleed
2707
2710
  };
2708
- }, [directionalForAtlas, ambientForAtlas, textureLighting, seamBleed]);
2711
+ }, [directionalForAtlas, pointLightsForAtlas, ambientForAtlas, textureLighting, seamBleed]);
2709
2712
  const autoCenterOffset = useMemo6(() => {
2710
2713
  if (!autoCenter) return [0, 0, 0];
2711
2714
  return [
@@ -2891,6 +2894,7 @@ function PolySceneInner({
2891
2894
  () => ({
2892
2895
  textureLighting,
2893
2896
  directionalLight,
2897
+ pointLights,
2894
2898
  ambientLight,
2895
2899
  strategies,
2896
2900
  seamBleed,
@@ -2907,7 +2911,7 @@ function PolySceneInner({
2907
2911
  groundCssZ,
2908
2912
  sceneEl
2909
2913
  }),
2910
- [textureLighting, directionalLight, ambientLight, strategies, seamBleed, textureLeafSizing, textureImageRendering, textureBackend, textureProjection, shadow, registerShadowCaster, registerShadowReceiver, shadowCastersVersion, hasShadowReceiver, groundCssZ, sceneEl]
2914
+ [textureLighting, directionalLight, pointLights, ambientLight, strategies, seamBleed, textureLeafSizing, textureImageRendering, textureBackend, textureProjection, shadow, registerShadowCaster, registerShadowReceiver, shadowCastersVersion, hasShadowReceiver, groundCssZ, sceneEl]
2911
2915
  );
2912
2916
  return /* @__PURE__ */ jsx8(PolySceneContext.Provider, { value: sceneCtxValue, children: /* @__PURE__ */ jsxs(
2913
2917
  "div",
@@ -2943,9 +2947,10 @@ import {
2943
2947
  } from "react";
2944
2948
  import {
2945
2949
  BASE_TILE as BASE_TILE3,
2950
+ buildParametricCasterOverride,
2946
2951
  buildPolyMeshTransform,
2947
2952
  buildSharedEdgeMap,
2948
- computeReceiverShadowFaces,
2953
+ computeMergedReceiverShadows,
2949
2954
  computeSceneBbox,
2950
2955
  DEFAULT_SEAM_BLEED as DEFAULT_SEAM_BLEED2,
2951
2956
  ensureCcw2D,
@@ -2958,7 +2963,8 @@ import {
2958
2963
  prepareReceiverFacePlanes,
2959
2964
  projectCssVertexToGround,
2960
2965
  resolvePolyTextureLeafGeometry as resolvePolyTextureLeafGeometry2,
2961
- worldDirectionToCss as worldDirectionToCss2
2966
+ worldDirectionToCss as worldDirectionToCss2,
2967
+ worldPositionToCss
2962
2968
  } from "@layoutit/polycss-core";
2963
2969
 
2964
2970
  // src/scene/useMesh.ts
@@ -3835,6 +3841,7 @@ var PolyMesh = forwardRef(function PolyMesh2({
3835
3841
  onFrameReady,
3836
3842
  castShadow,
3837
3843
  receiveShadow,
3844
+ shadowDefinition,
3838
3845
  merge = true,
3839
3846
  children,
3840
3847
  fallback,
@@ -4103,6 +4110,18 @@ var PolyMesh = forwardRef(function PolyMesh2({
4103
4110
  direction: inverseRotateVec3(cssLight.direction, rot)
4104
4111
  };
4105
4112
  }, [effectiveDirectional, bakedRotation]);
4113
+ const bakedPointLights = useMemo7(() => {
4114
+ const pls = sceneCtx?.pointLights;
4115
+ if (!pls || pls.length === 0) return void 0;
4116
+ const pos = position ?? [0, 0, 0];
4117
+ const rot = bakedRotation ?? [0, 0, 0];
4118
+ const hasRot = rot[0] !== 0 || rot[1] !== 0 || rot[2] !== 0;
4119
+ return pls.map((pl) => {
4120
+ const rel = [pl.position[0] - pos[0], pl.position[1] - pos[1], pl.position[2] - pos[2]];
4121
+ const local = hasRot ? inverseRotateVec3(rel, rot) : rel;
4122
+ return { ...pl, position: local };
4123
+ });
4124
+ }, [sceneCtx?.pointLights, position, bakedRotation]);
4106
4125
  const lightOccludedPolyIndices = void 0;
4107
4126
  const atlasPlans = useMemo7(
4108
4127
  () => {
@@ -4121,6 +4140,7 @@ var PolyMesh = forwardRef(function PolyMesh2({
4121
4140
  i,
4122
4141
  {
4123
4142
  directionalLight: bakedDirectional,
4143
+ pointLights: bakedPointLights,
4124
4144
  ambientLight: effectiveAmbient,
4125
4145
  seamBleed: seamBleedEdges?.has(i) ? effectiveSeamBleed : void 0,
4126
4146
  seamEdges: seamBleedEdges?.get(i),
@@ -4130,7 +4150,7 @@ var PolyMesh = forwardRef(function PolyMesh2({
4130
4150
  basisHints[i]
4131
4151
  ));
4132
4152
  },
4133
- [renderPolygon, directVoxelEnabled, polygons, bakedDirectional, effectiveAmbient, effectiveSeamBleed, lightOccludedPolyIndices]
4153
+ [renderPolygon, directVoxelEnabled, polygons, bakedDirectional, bakedPointLights, effectiveAmbient, effectiveSeamBleed, lightOccludedPolyIndices]
4134
4154
  );
4135
4155
  const textureAtlas = useTextureAtlas(
4136
4156
  atlasPlans,
@@ -4176,23 +4196,32 @@ var PolyMesh = forwardRef(function PolyMesh2({
4176
4196
  }
4177
4197
  return s;
4178
4198
  }, [atlasPlans, polygons]);
4199
+ const shadowCasterRegisteredRef = useRef6(false);
4200
+ const lastShadowPolyCountRef = useRef6(-1);
4179
4201
  useEffect5(() => {
4180
- if (!sceneRegisterShadowCaster) return;
4181
- if (castShadow) {
4182
- sceneRegisterShadowCaster(meshIdRef.current, {
4183
- polygons,
4184
- position: position ?? [0, 0, 0],
4185
- scale,
4186
- rotation,
4187
- renderedPolygonIndices
4188
- });
4189
- } else {
4190
- sceneRegisterShadowCaster(meshIdRef.current, null);
4191
- }
4202
+ if (!sceneRegisterShadowCaster || !castShadow) return;
4192
4203
  return () => {
4193
4204
  sceneRegisterShadowCaster(meshIdRef.current, null);
4205
+ shadowCasterRegisteredRef.current = false;
4206
+ lastShadowPolyCountRef.current = -1;
4194
4207
  };
4195
- }, [sceneRegisterShadowCaster, castShadow, polygons, position, scale, rotation, renderedPolygonIndices]);
4208
+ }, [sceneRegisterShadowCaster, castShadow]);
4209
+ useEffect5(() => {
4210
+ if (!sceneRegisterShadowCaster || !castShadow) return;
4211
+ const followAnimation = sceneCtx?.shadow?.followAnimation ?? false;
4212
+ const topologyChanged = polygons.length !== lastShadowPolyCountRef.current;
4213
+ if (shadowCasterRegisteredRef.current && !followAnimation && !topologyChanged) return;
4214
+ lastShadowPolyCountRef.current = polygons.length;
4215
+ shadowCasterRegisteredRef.current = true;
4216
+ sceneRegisterShadowCaster(meshIdRef.current, {
4217
+ polygons,
4218
+ position: position ?? [0, 0, 0],
4219
+ scale,
4220
+ rotation,
4221
+ renderedPolygonIndices,
4222
+ shadowDefinition
4223
+ });
4224
+ }, [sceneRegisterShadowCaster, castShadow, polygons, position, scale, rotation, renderedPolygonIndices, shadowDefinition, sceneCtx?.shadow]);
4196
4225
  const sceneRegisterShadowReceiver = sceneCtx?.registerShadowReceiver;
4197
4226
  useEffect5(() => {
4198
4227
  if (!sceneRegisterShadowReceiver) return;
@@ -4318,6 +4347,16 @@ var PolyMesh = forwardRef(function PolyMesh2({
4318
4347
  if (!shadowCasters || shadowCasters.size === 0) return null;
4319
4348
  const userLightDir = sceneDirectionalLight?.direction ?? [0.4, -0.7, 0.59];
4320
4349
  const lightDir = worldDirectionToCss2(userLightDir);
4350
+ const dynamicShading = effectiveTextureLighting === "dynamic";
4351
+ const scenePoints = dynamicShading ? [] : sceneCtx?.pointLights ?? [];
4352
+ const allPointLightsCss = scenePoints.map((pl) => ({
4353
+ position: worldPositionToCss(pl.position),
4354
+ color: pl.color,
4355
+ intensity: pl.intensity
4356
+ }));
4357
+ const shadowPointIndices = scenePoints.map((pl, i) => pl.castShadow ? i : -1).filter((i) => i >= 0);
4358
+ const runDirectionalShadow = !!sceneDirectionalLight?.direction && (sceneDirectionalLight.intensity ?? 1) > 0;
4359
+ const hasShadowPoints = shadowPointIndices.length > 0;
4321
4360
  const shadowLift = sceneShadow?.lift ?? 1e-3;
4322
4361
  const planes = prepareReceiverFacePlanes(
4323
4362
  polygons,
@@ -4330,18 +4369,17 @@ var PolyMesh = forwardRef(function PolyMesh2({
4330
4369
  if (planes.length === 0) return null;
4331
4370
  const casterInputs = [];
4332
4371
  for (const [casterId, data] of shadowCasters) {
4333
- const rendered = data.renderedPolygonIndices;
4334
4372
  const items = prepareCasterPolyItems(
4335
4373
  data.polygons,
4336
4374
  data.position,
4337
4375
  data.scale,
4338
- rendered ? (idx) => rendered.has(idx) : () => true,
4376
+ () => true,
4339
4377
  data.rotation ?? null
4340
4378
  );
4341
4379
  const isSelf = data.polygons === polygons;
4342
4380
  const selfMap = isSelf ? selfShadowEdgeMap : void 0;
4343
4381
  let edgeOwners;
4344
- if (!isSelf && data.polygons.length >= 40) {
4382
+ if (!isSelf && (data.polygons.length >= 40 || hasShadowPoints)) {
4345
4383
  const dposArr = data.position;
4346
4384
  const drot = data.rotation ?? null;
4347
4385
  const dsKey = JSON.stringify(data.scale ?? null);
@@ -4354,12 +4392,29 @@ var PolyMesh = forwardRef(function PolyMesh2({
4354
4392
  }
4355
4393
  edgeOwners = cachedOwners;
4356
4394
  }
4395
+ let overrideSilhouette;
4396
+ let overridePointSilhouettes;
4397
+ if (sceneShadow?.parametric) {
4398
+ const def = data.shadowDefinition ?? sceneShadow.definition ?? 16;
4399
+ const result = buildParametricCasterOverride({
4400
+ polysWorldVerts: items.map((it) => it.wv),
4401
+ lightDir,
4402
+ definition: def,
4403
+ isSelf,
4404
+ style: sceneShadow.style,
4405
+ pointLights: shadowPointIndices.map((i) => ({ position: allPointLightsCss[i].position, index: i }))
4406
+ });
4407
+ overrideSilhouette = result.overrideSilhouette;
4408
+ overridePointSilhouettes = result.overridePointSilhouettes;
4409
+ }
4357
4410
  casterInputs.push({
4358
4411
  id: casterId,
4359
4412
  items,
4360
4413
  selfShadowEdgeMap: selfMap,
4361
4414
  edgeOwners,
4362
- casterPolygonCount: data.polygons.length
4415
+ casterPolygonCount: data.polygons.length,
4416
+ overrideSilhouette,
4417
+ overridePointSilhouettes
4363
4418
  });
4364
4419
  }
4365
4420
  const cameraState = cameraCtx?.store.getState().cameraState;
@@ -4368,27 +4423,31 @@ var PolyMesh = forwardRef(function PolyMesh2({
4368
4423
  rotY: cameraState?.rotY ?? 45,
4369
4424
  meshRotation: rotation
4370
4425
  };
4371
- const specs = computeReceiverShadowFaces({
4426
+ const faces = computeMergedReceiverShadows({
4372
4427
  receiverPlanes: planes,
4373
4428
  receiverPolygons: polygons,
4374
4429
  receiverHasTexture: polygons.some((p) => p.texture !== void 0),
4375
4430
  casters: casterInputs,
4376
4431
  lightDir,
4432
+ runDirectional: runDirectionalShadow,
4433
+ pointPasses: shadowPointIndices.map((i) => ({ lightPos: allPointLightsCss[i].position, index: i })),
4434
+ allPointLights: allPointLightsCss,
4377
4435
  cameraRot,
4378
4436
  ambientLight: sceneCtx?.ambientLight,
4379
4437
  directionalLight: sceneDirectionalLight,
4380
4438
  shadow: { color: sceneShadow?.color, opacity: sceneShadow?.opacity ?? 0.25, maxExtend: sceneShadow?.maxExtend }
4381
4439
  });
4382
- return /* @__PURE__ */ jsx9(Fragment, { children: specs.map((spec) => /* @__PURE__ */ jsx9(
4440
+ if (faces.length === 0) return null;
4441
+ return /* @__PURE__ */ jsx9(Fragment, { children: faces.map((fc) => /* @__PURE__ */ jsxs2(
4383
4442
  "svg",
4384
4443
  {
4385
4444
  className: "polycss-shadow polycss-shadow-svg polycss-shadow-receiver",
4386
4445
  "data-poly-shadow-type": "receiver",
4387
- "data-poly-shadow-receiver-face": spec.faceIndex,
4388
- "data-poly-shadow-receiver-polys": JSON.stringify(spec.memberPolyIndices),
4389
- width: spec.width,
4390
- height: spec.height,
4391
- viewBox: `0 0 ${spec.width} ${spec.height}`,
4446
+ "data-poly-shadow-receiver-face": fc.faceIndex,
4447
+ "data-poly-shadow-receiver-polys": JSON.stringify(fc.memberPolyIndices),
4448
+ width: fc.width,
4449
+ height: fc.height,
4450
+ viewBox: `0 0 ${fc.width} ${fc.height}`,
4392
4451
  style: {
4393
4452
  position: "absolute",
4394
4453
  top: 0,
@@ -4398,25 +4457,27 @@ var PolyMesh = forwardRef(function PolyMesh2({
4398
4457
  transformOrigin: "0 0",
4399
4458
  pointerEvents: "none",
4400
4459
  willChange: "transform",
4401
- transform: spec.matrixCss
4460
+ opacity: fc.svgOpacity,
4461
+ transform: fc.matrixCss
4402
4462
  },
4403
- children: spec.paths.map((p, i) => /* @__PURE__ */ jsx9(
4404
- "path",
4405
- {
4406
- d: p.d,
4407
- fill: spec.fill,
4408
- stroke: spec.fill,
4409
- strokeWidth: "3",
4410
- strokeLinejoin: "round",
4411
- opacity: spec.opacity.toFixed(4),
4412
- "data-poly-shadow-caster-polys": JSON.stringify(p.casterPolygonIndices)
4413
- },
4414
- i
4415
- ))
4463
+ children: [
4464
+ fc.baseFill && fc.baseD ? /* @__PURE__ */ jsx9("path", { d: fc.baseD, fill: fc.baseFill, fillRule: "nonzero" }) : null,
4465
+ fc.layers.map((layer, i) => /* @__PURE__ */ jsx9(
4466
+ "path",
4467
+ {
4468
+ d: layer.d,
4469
+ fill: layer.fill,
4470
+ fillRule: "nonzero",
4471
+ opacity: layer.opacity !== 1 ? layer.opacity.toFixed(4) : void 0,
4472
+ style: layer.multiply ? { mixBlendMode: "multiply" } : void 0
4473
+ },
4474
+ i
4475
+ ))
4476
+ ]
4416
4477
  },
4417
- `receiver-${spec.faceIndex}`
4478
+ `receiver-${fc.faceIndex}`
4418
4479
  )) });
4419
- }, [receiveShadow, shadowCasters, shadowCastersVersion, polygons, position, scale, rotation, sceneDirectionalLight, sceneShadow, sceneCtx?.ambientLight, cameraCtx?.store, cameraTick, selfShadowEdgeMap]);
4480
+ }, [receiveShadow, shadowCasters, shadowCastersVersion, polygons, position, scale, rotation, sceneDirectionalLight, sceneCtx?.pointLights, effectiveTextureLighting, sceneShadow, sceneCtx?.ambientLight, cameraCtx?.store, cameraTick, selfShadowEdgeMap]);
4420
4481
  const portalSceneEl = sceneCtx?.sceneEl ?? null;
4421
4482
  const portaledReceiverShadowSvgs = portalSceneEl && receiverShadowSvgs ? createPortal(receiverShadowSvgs, portalSceneEl) : null;
4422
4483
  setPolygonsImplRef.current = (nextPolygons) => {
@@ -7819,7 +7880,7 @@ import {
7819
7880
  worldDirectionalLightToPolyCss,
7820
7881
  worldDistanceToCss,
7821
7882
  worldDistanceToPolyCss,
7822
- worldPositionToCss,
7883
+ worldPositionToCss as worldPositionToCss2,
7823
7884
  worldPositionToPolyCss,
7824
7885
  BASE_TILE as BASE_TILE7,
7825
7886
  DEFAULT_CAMERA_STATE as DEFAULT_CAMERA_STATE2,
@@ -7968,6 +8029,6 @@ export {
7968
8029
  worldDirectionalLightToPolyCss,
7969
8030
  worldDistanceToCss,
7970
8031
  worldDistanceToPolyCss,
7971
- worldPositionToCss,
8032
+ worldPositionToCss2 as worldPositionToCss,
7972
8033
  worldPositionToPolyCss
7973
8034
  };