flow: lights and normals

This commit is contained in:
cha0s 2024-07-18 04:18:06 -05:00
parent 82fd31802b
commit 2c2bfcbf0c
8 changed files with 96 additions and 26 deletions

View File

@ -10,6 +10,9 @@ const loading = {};
export function useAsset(source) { export function useAsset(source) {
const [assets, setAssets] = useContext(context); const [assets, setAssets] = useContext(context);
useEffect(() => { useEffect(() => {
if (!source) {
return undefined;
}
if (!assets[source]) { if (!assets[source]) {
if (!loading[source]) { if (!loading[source]) {
(loading[source] = Assets.load(source)).then((asset) => { (loading[source] = Assets.load(source)).then((asset) => {
@ -21,5 +24,5 @@ export function useAsset(source) {
} }
} }
}, [assets, setAssets, source]); }, [assets, setAssets, source]);
return assets[source]; return source ? assets[source] : undefined;
} }

View File

@ -1,10 +1,12 @@
import {ExtensionType} from '@pixi/core'; import {ExtensionType} from '@pixi/core';
import {Layer, Stage as LayerStage} from '@pixi/layers'; import {Layer, Stage as LayerStage} from '@pixi/layers';
let AmbientLight, diffuseGroup, normalGroup, lightGroup; import {
if ('undefined' !== typeof window) { AmbientLight,
({AmbientLight, diffuseGroup, normalGroup, lightGroup} = await import('@pixi/lights')); diffuseGroup,
} normalGroup,
lightGroup,
} from './lights.js';
export const ApplicationStageLayers = { export const ApplicationStageLayers = {
type: ExtensionType.Application, type: ExtensionType.Application,
@ -26,6 +28,7 @@ export const ApplicationStageLights = {
stage.addChild(new Layer(diffuseGroup)); stage.addChild(new Layer(diffuseGroup));
stage.addChild(new Layer(normalGroup)); stage.addChild(new Layer(normalGroup));
stage.addChild(new Layer(lightGroup)); stage.addChild(new Layer(lightGroup));
// stage.addChild(new AmbientLight(0x2244ff, 0.1));
stage.addChild(new AmbientLight(0xffffff, 1)); stage.addChild(new AmbientLight(0xffffff, 1));
}, },
}, },

View File

@ -9,6 +9,11 @@ const LightInternal = PixiComponent('Light', {
create({x, y}) { create({x, y}) {
const light = new PointLight(0xffffff, 1); const light = new PointLight(0xffffff, 1);
light.position.set(x, y); light.position.set(x, y);
// light.shader.program.fragmentSrc = light.shader.program.fragmentSrc.replace(
// 'float D = length(lightVector)',
// 'float D = length(lightVector) / 2.0',
// );
// light.falloff = [1, 10, 100]
return light; return light;
}, },
applyProps(light, oldProps, {x, y}) { applyProps(light, oldProps, {x, y}) {

7
app/react-components/pixi/lights.js vendored Normal file
View File

@ -0,0 +1,7 @@
let AmbientLight, diffuseGroup, normalGroup, lightGroup;
if ('undefined' !== typeof window) {
({AmbientLight, diffuseGroup, normalGroup, lightGroup} = await import('@pixi/lights'));
}
export {AmbientLight, diffuseGroup, normalGroup, lightGroup};

View File

@ -1,27 +1,84 @@
import {Sprite as PixiSprite} from '@pixi/react'; import {Sprite as PixiSprite} from '@pixi/react';
import {useEffect, useState} from 'react';
import {useAsset} from '@/context/assets.js'; import {useAsset} from '@/context/assets.js';
export default function Sprite({entity, ...rest}) { import {diffuseGroup, normalGroup} from './lights.js';
const asset = useAsset(entity.Sprite.source);
function textureFromAsset(asset, animation, frame) {
if (!asset) { if (!asset) {
return false; return undefined;
} }
let texture; let texture;
if (asset.data.animations) { if (asset.data.animations) {
texture = asset.animations[entity.Sprite.animation][entity.Sprite.frame]; texture = asset.animations[animation][frame];
} }
else { else {
texture = asset.textures['']; texture = asset.textures[''];
} }
return texture;
}
export default function Sprite({entity, ...rest}) {
const [mounted, setMounted] = useState();
const [normals, setNormals] = useState();
const [normalsMounted, setNormalsMounted] = useState();
const {anchor, animation, frame, scale, source} = entity.Sprite;
const asset = useAsset(source);
const normalsAsset = useAsset(normals);
useEffect(() => {
if (!asset) {
return;
}
const {normals} = asset.data.meta;
if (normals) {
const {pathname} = new URL(
source.split('/').slice(0, -1).concat(normals).join('/'),
'http://example.org',
);
setNormals(pathname);
}
}, [asset, source]);
const texture = textureFromAsset(
asset,
animation,
frame,
);
const normalsTexture = textureFromAsset(
normalsAsset,
animation,
frame,
);
if (mounted) {
mounted.parentGroup = diffuseGroup;
}
if (normalsMounted) {
normalsMounted.parentGroup = normalGroup;
}
return ( return (
<PixiSprite <>
anchor={entity.Sprite.anchor} {texture && (
scale={entity.Sprite.scale} <PixiSprite
texture={texture} anchor={anchor}
x={Math.round(entity.Position.x)} ref={setMounted}
y={Math.round(entity.Position.y)} scale={scale}
{...rest} texture={texture}
/> x={Math.round(entity.Position.x)}
y={Math.round(entity.Position.y)}
{...rest}
/>
)}
{normalsTexture && (
<PixiSprite
anchor={anchor}
ref={setNormalsMounted}
scale={scale}
texture={normalsTexture}
x={Math.round(entity.Position.x)}
y={Math.round(entity.Position.y)}
{...rest}
/>
)}
</>
); );
} }

View File

@ -8,14 +8,10 @@ import {CompositeTilemap} from '@pixi/tilemap';
import {CHUNK_SIZE} from '@/constants.js'; import {CHUNK_SIZE} from '@/constants.js';
import {useAsset} from '@/context/assets.js'; import {useAsset} from '@/context/assets.js';
let diffuseGroup, normalGroup; import {diffuseGroup, normalGroup} from './lights.js';
if ('undefined' !== typeof window) {
({diffuseGroup, normalGroup} = await import('@pixi/lights'));
}
const TileLayerInternal = PixiComponent('TileLayer', { const TileLayerInternal = PixiComponent('TileLayer', {
create: ({group, stage, tileLayer}) => { create: ({group, tileLayer}) => {
const container = new Container(); const container = new Container();
const cy = Math.ceil(tileLayer.area.y / CHUNK_SIZE); const cy = Math.ceil(tileLayer.area.y / CHUNK_SIZE);
const cx = Math.ceil(tileLayer.area.x / CHUNK_SIZE); const cx = Math.ceil(tileLayer.area.x / CHUNK_SIZE);
@ -85,7 +81,7 @@ const TileLayerInternal = PixiComponent('TileLayer', {
}); });
export default function TileLayer(props) { export default function TileLayer(props) {
const {renderer, stage} = useApp(); const {renderer} = useApp();
const {tileLayer} = props; const {tileLayer} = props;
const asset = useAsset(tileLayer.source); const asset = useAsset(tileLayer.source);
const normalsAsset = useAsset([tileLayer.source.slice(0, -'.json'.length), 'normals.json'].join('.')); const normalsAsset = useAsset([tileLayer.source.slice(0, -'.json'.length), 'normals.json'].join('.'));
@ -99,14 +95,12 @@ export default function TileLayer(props) {
asset={asset} asset={asset}
group={diffuseGroup} group={diffuseGroup}
renderer={renderer} renderer={renderer}
stage={stage}
/> />
<TileLayerInternal <TileLayerInternal
{...props} {...props}
asset={normalsAsset} asset={normalsAsset}
group={normalGroup} group={normalGroup}
renderer={renderer} renderer={renderer}
stage={stage}
/> />
</> </>
); );

View File

@ -0,0 +1 @@
{"frames":{"":{"frame":{"x":0,"y":0,"w":110,"h":102},"spriteSourceSize":{"x":0,"y":0,"w":110,"h":102},"sourceSize":{"w":110,"h":102}}},"meta":{"format":"RGBA8888","image":"./shit-shack.normals.png","scale":1,"size":{"w":110,"h":102}}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB