silphius/app/react/components/pixi/tile-layer.jsx

150 lines
4.5 KiB
React
Raw Normal View History

2024-07-17 05:07:50 -05:00
import {RenderTexture} from '@pixi/core';
2024-07-07 17:34:40 -05:00
import {Container} from '@pixi/display';
2024-07-22 03:17:02 -05:00
import {Graphics} from '@pixi/graphics';
2024-07-17 05:07:50 -05:00
import {PixiComponent, useApp} from '@pixi/react';
import {Sprite} from '@pixi/sprite';
2024-06-11 15:06:43 -05:00
import '@pixi/spritesheet'; // NECESSARY!
import {CompositeTilemap} from '@pixi/tilemap';
2024-07-20 04:32:33 -05:00
import {useAsset} from '@/react/context/assets.js';
2024-07-22 03:17:02 -05:00
import {CHUNK_SIZE, RESOLUTION} from '@/util/constants.js';
2024-06-14 12:05:02 -05:00
2024-07-19 01:27:47 -05:00
import {deferredLighting} from './lights.js';
2024-07-17 05:07:50 -05:00
2024-06-11 15:06:43 -05:00
const TileLayerInternal = PixiComponent('TileLayer', {
2024-07-23 17:03:12 -05:00
create: () => {
2024-07-07 17:34:40 -05:00
const container = new Container();
return container;
},
2024-07-11 01:16:10 -05:00
applyProps: (container, {tileLayer: oldTileLayer}, props) => {
2024-07-17 05:07:50 -05:00
const {asset, group, renderer, tileLayer} = props;
2024-06-14 12:05:02 -05:00
const extless = tileLayer.source.slice('/assets/'.length, -'.json'.length);
2024-06-11 15:06:43 -05:00
const {textures} = asset;
2024-06-14 12:05:02 -05:00
if (tileLayer === oldTileLayer) {
2024-06-11 15:06:43 -05:00
return;
}
2024-07-23 17:03:12 -05:00
if (
!oldTileLayer
|| (
oldTileLayer.area.x !== tileLayer.area.x
|| oldTileLayer.area.y !== tileLayer.area.y
|| oldTileLayer.tileSize.x !== tileLayer.tileSize.x
|| oldTileLayer.tileSize.y !== tileLayer.tileSize.y
)
) {
container.removeChildren();
const {area, tileSize} = tileLayer;
const g = new Graphics();
g.beginFill(group === deferredLighting.diffuseGroup ? 0x000000 : 0x7777ff);
// outer frame
g.drawRect(
-RESOLUTION.x / 2,
-RESOLUTION.y / 2,
area.x * tileSize.x + RESOLUTION.x,
RESOLUTION.y / 2,
);
g.drawRect(
-RESOLUTION.x / 2,
-RESOLUTION.y / 2,
RESOLUTION.x / 2,
area.y * tileSize.y + RESOLUTION.y,
);
g.drawRect(
area.x * tileSize.x,
0,
RESOLUTION.x / 2,
area.y * tileSize.y,
);
g.drawRect(
0,
area.y * tileSize.y,
area.x * tileSize.x,
RESOLUTION.y / 2,
);
g.parentGroup = group;
container.addChild(g);
const cy = Math.ceil(area.y / CHUNK_SIZE);
const cx = Math.ceil(area.x / CHUNK_SIZE);
for (let iy = 0; iy < cy; ++iy) {
for (let ix = 0; ix < cx; ++ix) {
const tilemap = new CompositeTilemap();
const renderTexture = RenderTexture.create({
width: tileSize.x * CHUNK_SIZE,
height: tileSize.y * CHUNK_SIZE,
});
const sprite = new Sprite(renderTexture);
sprite.x = tileSize.x * CHUNK_SIZE * ix;
sprite.y = tileSize.y * CHUNK_SIZE * iy;
sprite.parentGroup = group;
sprite.tilemap = tilemap;
container.addChild(sprite);
}
}
}
2024-07-11 01:16:10 -05:00
for (const i in tileLayer.$$chunks) {
if (!oldTileLayer || oldTileLayer.$$chunks[i] !== tileLayer.$$chunks[i]) {
2024-07-22 03:17:02 -05:00
const {texture, tilemap} = container.children[parseInt(i) + 1];
2024-07-11 01:16:10 -05:00
tilemap.clear();
const ax = Math.ceil(tileLayer.area.x / CHUNK_SIZE);
const cy = Math.floor(i / ax);
const cx = i % ax;
for (let y = 0; y < CHUNK_SIZE; ++y) {
for (let x = 0; x < CHUNK_SIZE; ++x) {
const ty = (cy * CHUNK_SIZE) + y;
const tx = (cx * CHUNK_SIZE) + x;
if (
tx < 0
|| ty < 0
|| tx >= tileLayer.area.x
|| ty >= tileLayer.area.y
) {
continue;
}
2024-07-17 05:07:50 -05:00
const parts = [
extless,
2024-07-19 01:27:47 -05:00
...(deferredLighting.normalGroup === group ? ['normals'] : []),
2024-07-17 05:07:50 -05:00
tileLayer.data[ty * tileLayer.area.x + tx],
];
2024-07-11 01:16:10 -05:00
tilemap.tile(
2024-07-17 05:07:50 -05:00
textures[parts.join('/')],
2024-07-11 01:16:10 -05:00
tileLayer.tileSize.x * x,
tileLayer.tileSize.y * y,
2024-07-17 05:07:50 -05:00
{
tileWidth: 16,
tileHeight: 16,
},
2024-07-11 01:16:10 -05:00
);
}
}
2024-07-17 05:07:50 -05:00
renderer.render(tilemap, {renderTexture: texture});
2024-06-11 15:06:43 -05:00
}
}
},
2024-07-11 01:16:10 -05:00
});
2024-06-11 15:06:43 -05:00
export default function TileLayer(props) {
2024-07-18 04:18:06 -05:00
const {renderer} = useApp();
2024-07-11 01:16:10 -05:00
const {tileLayer} = props;
2024-06-14 12:05:02 -05:00
const asset = useAsset(tileLayer.source);
2024-07-17 05:07:50 -05:00
const normalsAsset = useAsset([tileLayer.source.slice(0, -'.json'.length), 'normals.json'].join('.'));
if (!asset || !normalsAsset) {
2024-06-11 15:06:43 -05:00
return false;
}
return (
2024-07-07 17:34:40 -05:00
<>
<TileLayerInternal
{...props}
asset={asset}
2024-07-19 01:27:47 -05:00
group={deferredLighting.diffuseGroup}
2024-07-17 05:07:50 -05:00
renderer={renderer}
/>
<TileLayerInternal
{...props}
asset={normalsAsset}
2024-07-19 01:27:47 -05:00
group={deferredLighting.normalGroup}
2024-07-17 05:07:50 -05:00
renderer={renderer}
2024-07-07 17:34:40 -05:00
/>
</>
2024-06-11 15:06:43 -05:00
);
2024-06-14 12:05:02 -05:00
}