Skip to content

Commit

Permalink
Add ability to auto color backgrounds as well as previewing as monoch…
Browse files Browse the repository at this point in the history
…rome for mixed color mode games
  • Loading branch information
chrismaltby committed Apr 23, 2024
1 parent 8de9b9f commit 5bde484
Show file tree
Hide file tree
Showing 56 changed files with 1,570 additions and 219 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add ability to set common tilesets between scenes, the common tiles will always be loaded in a consistent order between scenes sharing the same common tileset
- Add ability to set Fade Speed as "Instant" when switching scenes, combine this with use of common tilesets in both scenes to enable seamless scene switching
- Add ability to use variables, advanced values and expressions for coordinates in Change Scene event
- Add ability to "Preview as Monochrome" when using mixed color mode by toggling button at bottom left of World view
- Add ability to provide color PNGs for backgrounds and extract palettes automatically by either clicking "Auto Color" button in brush toolbar or using dropdown on Scene sidebar next to "Background Palettes" label
- Add ability to override tile data for auto colored backgrounds by providing a matching *.mono.png in your assets/backgrounds folder containing a monochrome version of the background. When provided this file will be used for tiles data and the regular image will be used to extract the color palettes (useful for mixed color mode games when auto palettes isn't creating tile data as you'd like automatically)

### Changed

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@vercel/webpack-asset-relocator-loader": "1.7.3",
"about-window": "^1.15.2",
"chokidar": "^3.5.1",
"chroma-js": "^2.4.2",
"classnames": "^2.2.5",
"commander": "^6.2.0",
"copy-webpack-plugin": "^9.0.0",
Expand Down Expand Up @@ -129,6 +130,7 @@
"@reforged/maker-appimage": "^4.0.2",
"@testing-library/jest-dom": "^5.11.5",
"@testing-library/react": "^11.1.0",
"@types/chroma-js": "^2.4.4",
"@types/electron-devtools-installer": "^2.2.0",
"@types/electron-settings": "^3.1.1",
"@types/fs-extra": "^9.0.8",
Expand Down
27 changes: 19 additions & 8 deletions src/components/backgrounds/BackgroundViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ColorizedImage from "components/world/ColorizedImage";
import { DMG_PALETTE, TILE_SIZE } from "consts";
import { Palette } from "shared/lib/entities/entitiesTypes";
import { assetURL } from "shared/lib/helpers/assets";
import AutoColorizedImage from "components/world/AutoColorizedImage";

interface MetaspriteEditorProps {
backgroundId: string;
Expand Down Expand Up @@ -79,7 +80,9 @@ const BackgroundViewer = ({ backgroundId }: MetaspriteEditorProps) => {
const defaultPaletteIds = useAppSelector(
(state) => state.project.present.settings.defaultBackgroundPaletteIds
);

const gbcEnabled = useAppSelector(
(state) => state.project.present.settings.colorMode !== "mono"
);
const [palettes, setPalettes] = useState<Palette[]>(emptyPalettes);

useEffect(() => {
Expand Down Expand Up @@ -112,13 +115,21 @@ const BackgroundViewer = ({ backgroundId }: MetaspriteEditorProps) => {
transform: `translate3d(0px, 0px, 0px) scale(${zoom})`,
}}
>
<ColorizedImage
width={background.width * TILE_SIZE}
height={background.height * TILE_SIZE}
src={assetURL("backgrounds", background)}
tiles={background.tileColors}
palettes={palettes}
/>
{gbcEnabled && background.autoColor ? (
<AutoColorizedImage
width={background.width * TILE_SIZE}
height={background.height * TILE_SIZE}
src={assetURL("backgrounds", background)}
/>
) : (
<ColorizedImage
width={background.width * TILE_SIZE}
height={background.height * TILE_SIZE}
src={assetURL("backgrounds", background)}
tiles={background.tileColors}
palettes={palettes}
/>
)}
</ImageScale>
</ImageContainer>
</ContentWrapper>
Expand Down
13 changes: 0 additions & 13 deletions src/components/editors/ActorEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import { Checkbox } from "ui/form/Checkbox";
import { LockIcon, LockOpenIcon, PinIcon } from "ui/icons/Icons";
import { CheckboxField } from "ui/form/CheckboxField";
import DirectionPicker from "components/forms/DirectionPicker";
import { DMG_PALETTE } from "consts";
import { SpriteSheetSelectButton } from "components/forms/SpriteSheetSelectButton";
import { WorldEditor } from "./WorldEditor";
import ScriptEditorDropdownButton from "components/script/ScriptEditorDropdownButton";
Expand Down Expand Up @@ -131,13 +130,6 @@ export const ActorEditor: FC<ActorEditorProps> = ({
const scene = useAppSelector((state) =>
sceneSelectors.selectById(state, sceneId)
);
const defaultSpritePaletteId = useAppSelector(
(state) =>
state.project.present.settings.defaultSpritePaletteId || DMG_PALETTE.id
);
const colorsEnabled = useAppSelector(
(state) => state.project.present.settings.colorMode !== "mono"
);
const lockScriptEditor = useAppSelector(
(state) => state.editor.lockScriptEditor
);
Expand Down Expand Up @@ -482,11 +474,6 @@ export const ActorEditor: FC<ActorEditorProps> = ({
value={actor.spriteSheetId}
direction={actor.direction}
frame={0}
paletteId={
colorsEnabled
? actor.paletteId || defaultSpritePaletteId
: undefined
}
onChange={onChangeSpriteSheetId}
includeInfo
/>
Expand Down
135 changes: 99 additions & 36 deletions src/components/editors/SceneEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { castEventToInt } from "renderer/lib/helpers/castEventValue";
import { WorldEditor } from "./WorldEditor";
import ScriptEditorDropdownButton from "components/script/ScriptEditorDropdownButton";
import BackgroundWarnings from "components/world/BackgroundWarnings";
import { sceneSelectors } from "store/features/entities/entitiesState";
import {
backgroundSelectors,
sceneSelectors,
} from "store/features/entities/entitiesState";
import editorActions from "store/features/editor/editorActions";
import clipboardActions from "store/features/clipboard/clipboardActions";
import entitiesActions from "store/features/entities/entitiesActions";
Expand All @@ -24,8 +27,11 @@ import {
SceneParallaxLayer,
ScriptEventNormalized,
} from "shared/lib/entities/entitiesTypes";
import { MenuDivider, MenuItem } from "ui/menu/Menu";
import { DropdownButton } from "ui/buttons/DropdownButton";
import { MenuDivider, MenuItem, MenuItemIcon } from "ui/menu/Menu";
import {
DropdownButton,
InlineDropdownWrapper,
} from "ui/buttons/DropdownButton";
import { NoteField } from "ui/form/NoteField";
import { SceneTypeSelect } from "components/forms/SceneTypeSelect";
import { BackgroundSelectButton } from "components/forms/BackgroundSelectButton";
Expand All @@ -42,6 +48,8 @@ import {
LockOpenIcon,
ParallaxIcon,
JigsawIcon,
BlankIcon,
CheckIcon,
} from "ui/icons/Icons";
import ParallaxSelect, {
defaultValues as parallaxDefaultValues,
Expand Down Expand Up @@ -131,6 +139,9 @@ export const SceneEditor = ({ id, multiColumn }: SceneEditorProps) => {
const sceneIndex = useAppSelector((state) =>
sceneSelectors.selectIds(state).indexOf(id)
);
const background = useAppSelector((state) =>
backgroundSelectors.selectById(state, scene?.backgroundId ?? "")
);
const clipboardFormat = useAppSelector(
(state) => state.clipboard.data?.format
);
Expand Down Expand Up @@ -350,6 +361,19 @@ export const SceneEditor = ({ id, multiColumn }: SceneEditorProps) => {
dispatch(editorActions.setLockScriptEditor(!lockScriptEditor));
};

const onChangeAutoColor = useCallback(
(value: boolean) => {
scene?.backgroundId &&
dispatch(
entitiesActions.editBackgroundAutoColor({
backgroundId: scene.backgroundId,
autoColor: value,
})
);
},
[dispatch, scene?.backgroundId]
);

const onToggleParallaxSettings = () => {
dispatch(
entitiesActions.editScene({
Expand Down Expand Up @@ -606,33 +630,33 @@ export const SceneEditor = ({ id, multiColumn }: SceneEditorProps) => {
includeInfo
/>
<div style={{ display: "flex", flexDirection: "column" }}>
{showParallaxButton && (
{showCommonTilesetButton && (
<Button
style={{
padding: "5px 0",
minWidth: 28,
marginLeft: 10,
marginBottom: 5,
marginLeft: 4,
marginBottom: 4,
}}
variant={scene?.parallax ? "primary" : "transparent"}
onClick={onToggleParallaxSettings}
title={l10n("FIELD_PARALLAX")}
variant={commonTilesetOpen ? "primary" : "transparent"}
onClick={onToggleCommonTileset}
title={l10n("FIELD_COMMON_TILESET")}
>
<ParallaxIcon />
<JigsawIcon />
</Button>
)}
{showCommonTilesetButton && (
{showParallaxButton && (
<Button
style={{
padding: "5px 0",
minWidth: 28,
marginLeft: 10,
marginLeft: 4,
}}
variant={commonTilesetOpen ? "primary" : "transparent"}
onClick={onToggleCommonTileset}
title={l10n("FIELD_COMMON_TILESET")}
variant={scene?.parallax ? "primary" : "transparent"}
onClick={onToggleParallaxSettings}
title={l10n("FIELD_PARALLAX")}
>
<JigsawIcon />
<ParallaxIcon />
</Button>
)}
</div>
Expand Down Expand Up @@ -690,26 +714,66 @@ export const SceneEditor = ({ id, multiColumn }: SceneEditorProps) => {
<FormRow>
<FormField
name="playerSpriteSheetId"
label={l10n("FIELD_SCENE_BACKGROUND_PALETTES")}
label={
<>
{l10n("FIELD_SCENE_BACKGROUND_PALETTES")}
<InlineDropdownWrapper>
<DropdownButton
size="small"
variant="transparent"
showArrow={false}
label={l10n(
background?.autoColor
? "FIELD_AUTOMATIC"
: "FIELD_MANUAL"
)}
>
<MenuItem onClick={() => onChangeAutoColor(true)}>
<MenuItemIcon>
{background?.autoColor ? (
<CheckIcon />
) : (
<BlankIcon />
)}
</MenuItemIcon>
{l10n("FIELD_AUTOMATIC")}
</MenuItem>
<MenuItem onClick={() => onChangeAutoColor(false)}>
<MenuItemIcon>
{!background?.autoColor ? (
<CheckIcon />
) : (
<BlankIcon />
)}
</MenuItemIcon>
{l10n("FIELD_MANUAL")}
</MenuItem>
</DropdownButton>
</InlineDropdownWrapper>
</>
}
>
<PaletteButtons>
{[0, 1, 2, 3, 4, 5, 6, 7].map((index) => (
<PaletteSelectButton
key={index}
name={`scenePalette${index}`}
value={
(scene.paletteIds && scene.paletteIds[index]) || ""
}
onChange={onEditPaletteId(index)}
slotNumber={index + 1}
optional
optionalDefaultPaletteId={
defaultBackgroundPaletteIds[index] || ""
}
optionalLabel={l10n("FIELD_GLOBAL_DEFAULT")}
/>
))}
</PaletteButtons>
{!background?.autoColor && (
<PaletteButtons>
{[0, 1, 2, 3, 4, 5, 6, 7].map((index) => (
<PaletteSelectButton
key={index}
name={`scenePalette${index}`}
value={
(scene.paletteIds && scene.paletteIds[index]) ||
""
}
onChange={onEditPaletteId(index)}
slotNumber={index + 1}
optional
optionalDefaultPaletteId={
defaultBackgroundPaletteIds[index] || ""
}
optionalLabel={l10n("FIELD_GLOBAL_DEFAULT")}
/>
))}
</PaletteButtons>
)}
</FormField>
</FormRow>

Expand Down Expand Up @@ -756,7 +820,6 @@ export const SceneEditor = ({ id, multiColumn }: SceneEditorProps) => {
name="playerSpriteSheetId"
value={scene.playerSpriteSheetId}
direction={isStartingScene ? startDirection : "down"}
paletteId={undefined}
onChange={onChangePlayerSpriteSheetId}
includeInfo
optional
Expand Down
7 changes: 6 additions & 1 deletion src/components/forms/BackgroundSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { Background } from "shared/lib/entities/entitiesTypes";
import styled from "styled-components";
import { assetURLStyleProp } from "shared/lib/helpers/assets";
import { isMonoOverride } from "shared/lib/assets/backgrounds";

interface BackgroundSelectProps extends SelectCommonProps {
name: string;
Expand Down Expand Up @@ -52,7 +53,11 @@ export const BackgroundSelect: FC<BackgroundSelectProps> = ({
memo.push({
label: plugin,
options: backgrounds
.filter((s) => (plugin ? s.plugin === plugin : !s.plugin))
.filter(
(s) =>
!isMonoOverride(s.filename) &&
(plugin ? s.plugin === plugin : !s.plugin)
)
.map((background) => {
return {
label: background.name,
Expand Down
34 changes: 33 additions & 1 deletion src/components/forms/BackgroundSelectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { BackgroundSelect } from "./BackgroundSelect";
import { assetURLStyleProp } from "shared/lib/helpers/assets";
import { useAppDispatch, useAppSelector } from "store/hooks";
import { MAX_BACKGROUND_TILES, MAX_BACKGROUND_TILES_CGB } from "consts";
import { monoOverrideForFilename } from "shared/lib/assets/backgrounds";

interface BackgroundSelectProps {
name: string;
Expand Down Expand Up @@ -139,6 +140,20 @@ const NoValue = styled.div`
width: 24px;
`;

export const Pill = styled.span`
color: ${(props) => props.theme.colors.button.text};
background: ${(props) => props.theme.colors.list.activeBackground};
border: 0px;
border-radius: 16px;
padding: 3px 2px;
margin-left: 3px;
font-size: ${(props) => props.theme.typography.fontSize};
:active {
background: ${(props) => props.theme.colors.list.selectedBackground};
}
`;

export const BackgroundSelectButton: FC<BackgroundSelectProps> = ({
name,
value,
Expand All @@ -160,6 +175,9 @@ export const BackgroundSelectButton: FC<BackgroundSelectProps> = ({
const isCGBOnly = useAppSelector(
(state) => state.project.present.settings.colorMode === "color"
);
const isColor = useAppSelector(
(state) => state.project.present.settings.colorMode !== "mono"
);
const dispatch = useAppDispatch();

useEffect(() => {
Expand Down Expand Up @@ -262,7 +280,21 @@ export const BackgroundSelectButton: FC<BackgroundSelectProps> = ({
)}
{includeInfo && (
<SpriteInfo>
<SpriteInfoTitle>{background?.name}</SpriteInfoTitle>
<SpriteInfoTitle>
{background?.name}
{isColor && background?.autoColor && background.monoOverrideId && (
<Pill
title={l10n("FIELD_MONO_OVERRIDE_DESC", {
filename: background.filename,
tilesFilename: monoOverrideForFilename(
background.filename
),
})}
>
+
</Pill>
)}
</SpriteInfoTitle>

<SpriteInfoRow>
<SpriteInfoField>{l10n("FIELD_SIZE")}:</SpriteInfoField>
Expand Down
Loading

0 comments on commit 5bde484

Please sign in to comment.