Skip to content

Commit

Permalink
Update replace tiles events to allow 16px tiles
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismaltby committed Apr 5, 2024
1 parent 06d96fc commit 6d118c1
Show file tree
Hide file tree
Showing 14 changed files with 347 additions and 110 deletions.
30 changes: 15 additions & 15 deletions appData/templates/gbs2/project.gbsproj
Original file line number Diff line number Diff line change
Expand Up @@ -4542,12 +4542,12 @@
"type": "number",
"value": 0
},
"toTileIndex": {
"type": "number",
"value": 3
},
"variable": "L0",
"tilesetId": "4991cc19-85b6-45f9-bef6-39496dc2c62a"
"tilesetId": "4991cc19-85b6-45f9-bef6-39496dc2c62a",
"frames": {
"type": "number",
"value": 4
}
},
"id": "fb3e9a6c-a491-457e-8c93-d0971516643a"
},
Expand All @@ -4560,12 +4560,12 @@
"type": "number",
"value": 4
},
"toTileIndex": {
"type": "number",
"value": 7
},
"variable": "L1",
"tilesetId": "4991cc19-85b6-45f9-bef6-39496dc2c62a"
"tilesetId": "4991cc19-85b6-45f9-bef6-39496dc2c62a",
"frames": {
"type": "number",
"value": 4
}
},
"id": "418dc58d-8057-41e3-ada5-96e620d889f5"
},
Expand All @@ -4578,12 +4578,12 @@
"type": "number",
"value": 0
},
"toTileIndex": {
"type": "number",
"value": 3
},
"variable": "L2",
"tilesetId": "d7042527-d20e-486d-93e6-66b9397df510"
"tilesetId": "d7042527-d20e-486d-93e6-66b9397df510",
"frames": {
"type": "number",
"value": 4
}
},
"id": "77f7c1aa-6c94-4b45-a05a-3914ec07e588"
}
Expand Down
93 changes: 64 additions & 29 deletions src/components/forms/TilesetSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, { FC, useEffect, useState } from "react";
import { useAppSelector } from "store/hooks";
import { tilesetSelectors } from "store/features/entities/entitiesState";
import { Tileset } from "shared/lib/entities/entitiesTypes";
import {
UnitType,
Tileset,
GridUnitType,
} from "shared/lib/entities/entitiesTypes";
import {
Option,
Select,
Expand All @@ -10,12 +14,17 @@ import {
SelectCommonProps,
} from "ui/form/Select";
import { TileCanvas } from "components/world/TileCanvas";
import { UnitsSelectButtonInputOverlay } from "components/forms/UnitsSelectButtonInputOverlay";
import styled from "styled-components";

interface TilesetSelectProps extends SelectCommonProps {
name: string;
value?: string;
tileIndex?: number;
onChange?: (newId: string) => void;
units?: UnitType;
unitsAllowed?: UnitType[];
onChangeUnits?: (newUnits: UnitType) => void;
optional?: boolean;
optionalLabel?: string;
optionalDefaultTilesetId?: string;
Expand All @@ -25,10 +34,17 @@ interface TilesetOption extends Option {
tileset: Tileset;
}

const Wrapper = styled.div`
position: relative;
`;

export const TilesetSelect: FC<TilesetSelectProps> = ({
value,
tileIndex,
onChange,
units,
unitsAllowed,
onChangeUnits,
optional,
optionalLabel,
optionalDefaultTilesetId,
Expand Down Expand Up @@ -105,33 +121,52 @@ export const TilesetSelect: FC<TilesetSelectProps> = ({
};

return (
<Select
value={currentValue}
options={options}
onChange={onSelectChange}
formatOptionLabel={(option: TilesetOption) => {
return (
<OptionLabelWithPreview
preview={
<TileCanvas tilesetId={option.value} tileIndex={tileIndex} />
}
>
{option.label}
</OptionLabelWithPreview>
);
}}
components={{
SingleValue: () => (
<SingleValueWithPreview
preview={
<TileCanvas tilesetId={value || ""} tileIndex={tileIndex} />
}
>
{currentValue?.label}
</SingleValueWithPreview>
),
}}
{...selectProps}
/>
<Wrapper>
<Select
value={currentValue}
options={options}
onChange={onSelectChange}
formatOptionLabel={(option: TilesetOption) => {
return (
<OptionLabelWithPreview
preview={
<TileCanvas
tilesetId={option.value}
tileIndex={tileIndex}
tileSize={units as GridUnitType}
/>
}
>
{option.label}
</OptionLabelWithPreview>
);
}}
components={{
SingleValue: () => (
<SingleValueWithPreview
preview={
<TileCanvas
tilesetId={value || ""}
tileIndex={tileIndex}
tileSize={units as GridUnitType}
/>
}
>
{currentValue?.label}
</SingleValueWithPreview>
),
}}
{...selectProps}
/>
{units && (
<UnitsSelectButtonInputOverlay
parentValue={String(currentValue?.label) ?? ""}
parentValueOffset={24}
value={units}
allowedValues={unitsAllowed}
onChange={onChangeUnits}
/>
)}
</Wrapper>
);
};
4 changes: 4 additions & 0 deletions src/components/forms/UnitsSelectButtonInputOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ export const UnitsSelectButtonInputOverlay = ({
pixels: l10n("FIELD_PIXELS"),
time: l10n("FIELD_SECONDS"),
frames: l10n("FIELD_FRAMES"),
"8px": "8px",
"16px": "16px",
}),
[]
);
Expand All @@ -79,6 +81,8 @@ export const UnitsSelectButtonInputOverlay = ({
pixels: l10n("FIELD_PIXELS_SHORT").toLocaleLowerCase(),
time: l10n("FIELD_SECONDS").toLocaleLowerCase(),
frames: l10n("FIELD_FRAMES").toLocaleLowerCase(),
"8px": "8px",
"16px": "16px",
}),
[]
);
Expand Down
5 changes: 5 additions & 0 deletions src/components/script/ScriptEventFormInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,11 @@ const ScriptEventFormInput = ({
value={String(value)}
onChange={onChangeField}
tileIndex={argValue(args.tileIndex) as number | undefined}
units={
(args[field.unitsField || ""] || field.unitsDefault) as UnitType
}
unitsAllowed={field.unitsAllowed}
onChangeUnits={onChangeUnits}
/>
</OffscreenSkeletonInput>
);
Expand Down
18 changes: 16 additions & 2 deletions src/components/world/SceneEventHelper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,22 @@ export const SceneEventHelper: FC<SceneEventHelperProps> = ({ scene }) => {
argValue(event.args?.[scriptEventDef.helper.y]),
0
);
const tileWidth = scriptEventDef.helper.tileWidth ?? 1;
const tileHeight = scriptEventDef.helper.tileHeight ?? 1;
const tileSize = ensureMaybeString(
argValue(event.args?.[scriptEventDef.helper.tileSize ?? ""]),
""
);
let tileWidth = 1;
let tileHeight = 1;
if (tileSize === "16px") {
tileWidth = 2;
tileHeight = 2;
}
if (scriptEventDef.helper.tileWidth) {
tileWidth = scriptEventDef.helper.tileWidth;
}
if (scriptEventDef.helper.tileHeight) {
tileHeight = scriptEventDef.helper.tileHeight;
}
if (x === undefined && y === undefined) {
return <div />;
}
Expand Down
20 changes: 14 additions & 6 deletions src/components/world/TileCanvas.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import React, { useCallback, useEffect, useState } from "react";
import { useAppSelector } from "store/hooks";
import { DMG_PALETTE } from "consts";
import { DMG_PALETTE, TILE_SIZE } from "consts";
import { tilesetSelectors } from "store/features/entities/entitiesState";
import TilePreviewWorker, { TilePreviewResult } from "./TilePreview.worker";
import { assetURL } from "shared/lib/helpers/assets";
import { GridUnitType } from "shared/lib/entities/entitiesTypes";

interface TileCanvasProps {
tilesetId: string;
tileIndex?: number;
tileSize?: GridUnitType;
}

const worker = new TilePreviewWorker();

export const TileCanvas = ({ tilesetId, tileIndex }: TileCanvasProps) => {
const width = 8;
const height = 8;
export const TileCanvas = ({
tilesetId,
tileIndex,
tileSize,
}: TileCanvasProps) => {
const size = tileSize === "16px" ? 2 : 1;
const width = TILE_SIZE * size;
const height = TILE_SIZE * size;
const [workerId] = useState(Math.random());
const canvasRef = React.useRef<HTMLCanvasElement>(null);
const tileset = useAppSelector(
Expand All @@ -40,7 +47,7 @@ export const TileCanvas = ({ tilesetId, tileIndex }: TileCanvasProps) => {
ctx.drawImage(offscreenCanvas, 0, 0);
}
},
[tileset, workerId]
[height, tileset, width, workerId]
);

useEffect(() => {
Expand All @@ -65,8 +72,9 @@ export const TileCanvas = ({ tilesetId, tileIndex }: TileCanvasProps) => {
src: tilesetURL,
palette: DMG_PALETTE.colors,
tileIndex,
tileSize,
});
}, [canvasRef, tileIndex, tileset, workerId]);
}, [canvasRef, tileIndex, tileSize, tileset, workerId]);

return (
<canvas
Expand Down
37 changes: 17 additions & 20 deletions src/components/world/TilePreview.worker.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TILE_SIZE } from "consts";
import { hex2GBCrgb } from "shared/lib/helpers/color";

// eslint-disable-next-line no-restricted-globals
Expand All @@ -24,18 +25,16 @@ interface CacheRecord {

export interface TilePreviewResult {
id: number;
width: number;
height: number;
canvasImage: ImageBitmap;
}

const cache: Record<string, CacheRecord> = {};
const TILE_SIZE = 8;

workerCtx.onmessage = async (evt) => {
const id = evt.data.id;
const src = evt.data.src;
const tileIndex = evt.data.tileIndex ?? 0;
const tileSize = evt.data.tileSize === "16px" ? TILE_SIZE * 2 : TILE_SIZE;
const palette = evt.data.palette;
const paletteRGB = palette.map(hex2GBCrgb);

Expand All @@ -53,7 +52,7 @@ workerCtx.onmessage = async (evt) => {
const imgblob = await fetch(src).then((r) => r.blob());
img = await createImageBitmap(imgblob);

canvas = new OffscreenCanvas(TILE_SIZE, TILE_SIZE);
canvas = new OffscreenCanvas(tileSize, tileSize);

const tmpCtx = canvas.getContext("2d");
if (!tmpCtx) {
Expand All @@ -68,38 +67,36 @@ workerCtx.onmessage = async (evt) => {
};
}

const width = img.width;
const height = img.height;
const tileWidth = Math.floor(width / TILE_SIZE);
const tileWidth = Math.floor(img.width / tileSize);

const offsetX = TILE_SIZE * (tileIndex % tileWidth);
const offsetY = TILE_SIZE * Math.floor(tileIndex / tileWidth);
const offsetX = tileSize * (tileIndex % tileWidth);
const offsetY = tileSize * Math.floor(tileIndex / tileWidth);

canvas.width = TILE_SIZE;
canvas.height = TILE_SIZE;
canvas.width = tileSize;
canvas.height = tileSize;

ctx.drawImage(
img,
offsetX,
offsetY,
TILE_SIZE,
TILE_SIZE,
tileSize,
tileSize,
0,
0,
TILE_SIZE,
TILE_SIZE
tileSize,
tileSize
);

const imageData = ctx.getImageData(0, 0, TILE_SIZE, TILE_SIZE);
const imageData = ctx.getImageData(0, 0, tileSize, tileSize);
const data = imageData.data;

const p1X = 0;
const p2X = 8;
const p2X = tileSize;
const p1Y = 0;
const p2Y = 8;
const p2Y = tileSize;
for (let pX = p1X; pX < p2X; pX++) {
for (let pY = p1Y; pY < p2Y; pY++) {
const index = (pX + pY * width) * 4;
const index = (pX + pY * tileSize) * 4;
const colorIndex = indexColour(data[index + 1]);
const color = paletteRGB[colorIndex];
data[index] = color.r;
Expand All @@ -112,7 +109,7 @@ workerCtx.onmessage = async (evt) => {
ctx.putImageData(imageData, 0, 0);

const canvasImage = canvas.transferToImageBitmap();
workerCtx.postMessage({ id, width, height, canvasImage }, [canvasImage]);
workerCtx.postMessage({ id, canvasImage }, [canvasImage]);
};

// -----------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,8 @@
"FIELD_TO_TILE_DESC": "The ending tile offset inside tileset",
"FIELD_STATE_VARIABLE": "State Variable",
"FIELD_STATE_VARIABLE_DESC": "A variable to store the current state of this event",
"FIELD_ANIMATION_FRAMES": "Animation Frames",
"FIELD_ANIMATION_FRAMES_DESC": "The number of animation frames to cycle through.",

"// 7": "Asset Viewer ---------------------------------------------",
"ASSET_SEARCH": "Search...",
Expand Down
Loading

0 comments on commit 6d118c1

Please sign in to comment.