feat(assets): use single texture atlas instead of loading all images individually

This commit is contained in:
2026-01-08 19:55:43 +01:00
parent c6d5911b7d
commit e2d40a4bc1
41 changed files with 488 additions and 377 deletions

View File

@@ -13,29 +13,17 @@ const props = withDefaults(
);
const { onRender } = useScreen();
const app = useAppStore();
const { assets } = useAssets();
const BAR_WIDTH = 256;
const BAR_HEIGHT = 24;
const TITLE_Y = 5;
onRender((ctx) => {
ctx.globalAlpha = props.opacity;
// top bar
ctx.drawImage(
assets.common.barsSheet,
0,
(app.color.row * 4 + app.color.col) * BAR_HEIGHT,
BAR_WIDTH,
BAR_HEIGHT,
0,
-props.yOffset,
BAR_WIDTH,
BAR_HEIGHT,
);
assets.images.common.barsSheet.draw(ctx, 0, -props.yOffset, {
colored: true,
});
if (props.title) {
ctx.fillStyle = "#000000";
@@ -46,17 +34,9 @@ onRender((ctx) => {
ctx.scale(1, -1);
// bottom bar
ctx.drawImage(
assets.common.barsSheet,
0,
(app.color.row * 4 + app.color.col) * BAR_HEIGHT,
BAR_WIDTH,
BAR_HEIGHT,
0,
-192 - props.yOffset,
BAR_WIDTH,
BAR_HEIGHT,
);
assets.images.common.barsSheet.draw(ctx, 0, -192 - props.yOffset, {
colored: true,
});
}, 50);
defineOptions({

View File

@@ -11,11 +11,9 @@ const props = withDefaults(
const { onRender } = useScreen();
const app = useAppStore();
const { assets } = useAssets();
const ANIMATION_SPEED = 15;
const CORNER_SIZE = 11;
let [currentX, currentY, currentWidth, currentHeight] = props.rect;
@@ -48,67 +46,31 @@ onRender((ctx, deltaTime) => {
ctx.globalAlpha = props.opacity;
const spriteY = (app.color.row * 4 + app.color.col) * CORNER_SIZE;
// top-left corner
assets.images.common.selectorCornersSheet.draw(ctx, x, y, { colored: true });
// Top-left corner
ctx.drawImage(
assets.common.selectorCornersSheet,
0,
spriteY,
CORNER_SIZE,
CORNER_SIZE,
x,
y,
CORNER_SIZE,
CORNER_SIZE,
);
// Top-right corner
// top-right corner
ctx.save();
ctx.scale(-1, 1);
ctx.drawImage(
assets.common.selectorCornersSheet,
0,
spriteY,
CORNER_SIZE,
CORNER_SIZE,
-(x + w),
y,
CORNER_SIZE,
CORNER_SIZE,
);
assets.images.common.selectorCornersSheet.draw(ctx, -(x + w), y, {
colored: true,
});
ctx.restore();
// Bottom-left corner
// bottom-left corner
ctx.save();
ctx.scale(1, -1);
ctx.drawImage(
assets.common.selectorCornersSheet,
0,
spriteY,
CORNER_SIZE,
CORNER_SIZE,
x,
-(y + h),
CORNER_SIZE,
CORNER_SIZE,
);
assets.images.common.selectorCornersSheet.draw(ctx, x, -(y + h), {
colored: true,
});
ctx.restore();
// Bottom-right corner
// bottom-right corner
ctx.save();
ctx.scale(-1, -1);
ctx.drawImage(
assets.common.selectorCornersSheet,
0,
spriteY,
CORNER_SIZE,
CORNER_SIZE,
-(x + w),
-(y + h),
CORNER_SIZE,
CORNER_SIZE,
);
assets.images.common.selectorCornersSheet.draw(ctx, -(x + w), -(y + h), {
colored: true,
});
ctx.restore();
}, 40);

View File

@@ -15,9 +15,9 @@ const { onRender, onClick } = useScreen();
const { assets } = useAssets();
const BUTTON_WIDTH = assets.common.button.width;
const BUTTON_HEIGHT = assets.common.button.height;
const LETTER_WIDTH = assets.common.B.width;
const BUTTON_WIDTH = assets.images.common.button.rect.width;
const BUTTON_HEIGHT = assets.images.common.button.rect.height;
const LETTER_WIDTH = assets.images.common.B.rect.width;
const B_BUTTON: Rect = [31, 172, BUTTON_WIDTH, BUTTON_HEIGHT];
const A_BUTTON: Rect = [144, 172, BUTTON_WIDTH, BUTTON_HEIGHT];
@@ -29,23 +29,25 @@ onRender((ctx) => {
ctx.translate(0, props.yOffset);
const drawButton = (
image: HTMLImageElement,
image: {
draw: (ctx: CanvasRenderingContext2D, x: number, y: number) => void;
},
text: string,
x: number,
offset: number,
) => {
ctx.drawImage(assets.common.button, x, 172);
assets.images.common.button.draw(ctx, x, 172);
const { actualBoundingBoxRight: textWidth } = ctx.measureText(text);
const width = LETTER_WIDTH + 4 + textWidth;
const left = Math.ceil(x + BUTTON_WIDTH / 2 - width / 2 - offset / 2);
ctx.drawImage(image, left, 176);
image.draw(ctx, left, 176);
ctx.fillText(text, left + LETTER_WIDTH + 4, 185);
};
drawButton(assets.common.B, props.bLabel, 31, 5);
drawButton(assets.common.A, props.aLabel, 144, 0);
drawButton(assets.images.common.B, props.bLabel, 31, 5);
drawButton(assets.images.common.A, props.aLabel, 144, 0);
}, 60);
onClick((x, y) => {

View File

@@ -6,8 +6,8 @@ const { onRender } = useScreen();
const { assets } = useAssets();
const confirmationModal = useConfirmationModal();
const BG_WIDTH = assets.common.confirmationModal.width;
const BG_HEIGHT = assets.common.confirmationModal.height;
const BG_WIDTH = assets.images.common.confirmationModal.rect.width;
const BG_HEIGHT = assets.images.common.confirmationModal.rect.height;
const BG_X = Math.floor((SCREEN_WIDTH - BG_WIDTH) / 2);
const BG_Y = Math.floor((SCREEN_HEIGHT - BG_HEIGHT) / 2);
@@ -34,7 +34,7 @@ onRender((ctx) => {
ctx.translate(0, confirmationModal.offsetY);
ctx.drawImage(assets.common.confirmationModal, BG_X, BG_Y);
assets.images.common.confirmationModal.draw(ctx, BG_X, BG_Y);
ctx.font = "16px Pokemon DP Pro";
ctx.textBaseline = "top";

View File

@@ -5,12 +5,12 @@ const store = useContactStore();
const { assets } = useAssets();
onRender((ctx) => {
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
assets.images.home.bottomScreen.background.draw(ctx, 0, 0);
ctx.globalAlpha = store.isIntro
? store.intro.stage2Opacity
: store.outro.stage3Opacity;
ctx.drawImage(assets.contact.bottomScreen.background, 0, 0);
assets.images.contact.bottomScreen.background.draw(ctx, 0, 0);
});
defineOptions({

View File

@@ -8,7 +8,7 @@ onRender((ctx) => {
ctx.globalAlpha = store.isIntro
? store.intro.stage3Opacity
: store.outro.stage1Opacity;
ctx.drawImage(assets.contact.bottomScreen.buttons, 31, 32);
assets.images.contact.bottomScreen.buttons.draw(ctx, 31, 32);
});
defineOptions({

View File

@@ -5,12 +5,12 @@ const store = useContactStore();
const { assets } = useAssets();
onRender((ctx) => {
ctx.drawImage(assets.home.topScreen.background, 0, 0);
assets.images.home.topScreen.background.draw(ctx, 0, 0);
ctx.globalAlpha = store.isIntro
? store.intro.stage2Opacity
: store.outro.stage3Opacity;
ctx.drawImage(assets.contact.topScreen.background, 0, 0);
assets.images.contact.topScreen.background.draw(ctx, 0, 0);
});
defineOptions({

View File

@@ -8,12 +8,12 @@ onRender((ctx) => {
ctx.globalAlpha = store.isIntro
? store.intro.stage1Opacity
: store.outro.stage2Opacity;
ctx.drawImage(assets.contact.topScreen.leftBar, 0, 0);
assets.images.contact.topScreen.leftBar.draw(ctx, 0, 0);
ctx.globalAlpha = store.isIntro
? store.intro.stage3Opacity
: store.outro.stage1Opacity;
ctx.drawImage(assets.contact.topScreen.leftBarThings, 0, 0);
assets.images.contact.topScreen.leftBarThings.draw(ctx, 0, 0);
});
defineOptions({

View File

@@ -15,7 +15,7 @@ onRender((ctx) => {
const y = 169 - 24 * index + store.notificationsYOffset;
if (y < -24) break;
ctx.drawImage(assets.contact.bottomScreen.notification, 21, y);
assets.images.contact.bottomScreen.notification.draw(ctx, 21, y);
const content = store.notifications[i]!;
ctx.fillStyle = content.includes("opened") ? "#00fbba" : "#e3f300";
@@ -26,8 +26,8 @@ onRender((ctx) => {
ctx.globalAlpha = store.isIntro
? store.intro.stage1Opacity
: store.outro.stage2Opacity;
ctx.drawImage(
assets.contact.topScreen.title,
assets.images.contact.topScreen.title.draw(
ctx,
21,
store.isIntro
? store.intro.titleY

View File

@@ -4,7 +4,7 @@ const store = useGalleryStore();
const { assets } = useAssets();
onRender((ctx) => {
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
assets.images.home.bottomScreen.background.draw(ctx, 0, 0);
ctx.fillStyle = "#000000";
ctx.globalAlpha = store.isIntro

View File

@@ -14,7 +14,7 @@ onMounted(() => {
});
onRender((ctx) => {
ctx.drawImage(assets.home.topScreen.background, 0, 0);
assets.images.home.topScreen.background.draw(ctx, 0, 0);
ctx.fillStyle = "#000000";
ctx.globalAlpha = store.isIntro

View File

@@ -3,11 +3,12 @@ const { onRender } = useScreen();
const store = useHomeStore();
const app = useAppStore();
const { assets } = useAssets();
onRender((ctx) => {
ctx.globalAlpha = app.booted ? 1 : store.intro.stage1Opacity;
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
assets.images.home.bottomScreen.background.draw(ctx, 0, 0);
});
defineOptions({

View File

@@ -3,14 +3,16 @@ const props = defineProps<{
x: number;
y: number;
opacity: number;
image: HTMLImageElement;
image: {
draw: (ctx: CanvasRenderingContext2D, x: number, y: number) => void;
};
}>();
const { onRender } = useScreen();
onRender((ctx) => {
ctx.globalAlpha = props.opacity;
ctx.drawImage(props.image, props.x, props.y);
props.image.draw(ctx, props.x, props.y);
});
defineOptions({

View File

@@ -128,45 +128,45 @@ onRender((ctx) => {
:x="33"
:y="25 + getButtonOffset('projects')"
:opacity="getOpacity('projects')"
:image="assets.home.bottomScreen.buttons.game"
:image="assets.images.home.bottomScreen.buttons.game"
/>
<Button
:x="32"
:y="72 + getButtonOffset('contact')"
:opacity="getOpacity('contact')"
:image="assets.home.bottomScreen.buttons.contact"
:image="assets.images.home.bottomScreen.buttons.contact"
/>
<Button
:x="128"
:y="72 + getButtonOffset('gallery')"
:opacity="getOpacity('gallery')"
:image="assets.home.bottomScreen.buttons.gallery"
:image="assets.images.home.bottomScreen.buttons.gallery"
/>
<Button
:x="33"
:y="121"
:opacity="getOpacity()"
:image="assets.home.bottomScreen.buttons.gamePak"
:image="assets.images.home.bottomScreen.buttons.gamePak"
/>
<Button
:x="10"
:y="175 + getButtonOffset('theme')"
:opacity="getOpacity('theme')"
:image="assets.home.bottomScreen.buttons.theme"
:image="assets.images.home.bottomScreen.buttons.theme"
/>
<Button
:x="117"
:y="170 + getButtonOffset('settings')"
:opacity="getOpacity('settings')"
:image="assets.home.bottomScreen.buttons.settings"
:image="assets.images.home.bottomScreen.buttons.settings"
/>
<Button
:x="235"
:y="175 + getButtonOffset('alarm')"
:opacity="getOpacity('alarm')"
:image="assets.home.bottomScreen.buttons.alarm"
:image="assets.images.home.bottomScreen.buttons.alarm"
/>
<Selector :rect="selectorPosition" :opacity="getOpacity()" />

View File

@@ -7,7 +7,7 @@ const { assets } = useAssets();
onRender((ctx) => {
ctx.globalAlpha = app.booted ? 1 : store.intro.stage1Opacity;
ctx.drawImage(assets.home.topScreen.background, 0, 0);
assets.images.home.topScreen.background.draw(ctx, 0, 0);
});
defineOptions({

View File

@@ -2,7 +2,6 @@
const { onRender } = useScreen();
// NOTE: calendar background is handled by TopScreenBackground
const app = useAppStore();
const store = useHomeStore();
const { assets } = useAssets();
@@ -14,7 +13,6 @@ onRender((ctx) => {
const CALENDAR_ROWS = 5;
const CALENDAR_LEFT = 128;
const CALENDAR_TOP = 64;
const SELECTOR_SIZE = 13;
ctx.fillStyle = "#343434";
@@ -30,16 +28,16 @@ onRender((ctx) => {
: store.isOutro && store.outro.animateTop
? store.outro.stage1Opacity
: 1;
ctx.drawImage(
assets.home.topScreen.calendar.calendar,
assets.images.home.topScreen.calendar.calendar.draw(
ctx,
CALENDAR_LEFT - 3,
CALENDAR_TOP - 33,
);
const extraRow = CALENDAR_COLS * CALENDAR_ROWS - daysInMonth - firstDay < 0;
if (extraRow) {
ctx.drawImage(
assets.home.topScreen.calendar.lastRow,
assets.images.home.topScreen.calendar.lastRow.draw(
ctx,
CALENDAR_LEFT - 3,
CALENDAR_TOP + 79,
);
@@ -63,16 +61,11 @@ onRender((ctx) => {
const cellTop = CALENDAR_TOP + col * 16;
if (now.getDate() === day) {
ctx.drawImage(
assets.home.topScreen.calendar.daySelectorsSheet,
0,
(app.color.row * 4 + app.color.col) * SELECTOR_SIZE,
SELECTOR_SIZE,
SELECTOR_SIZE,
assets.images.home.topScreen.calendar.daySelectorsSheet.draw(
ctx,
cellLeft + 1,
cellTop + 1,
SELECTOR_SIZE,
SELECTOR_SIZE,
{ colored: true },
);
}

View File

@@ -59,7 +59,7 @@ onRender((ctx) => {
: store.isOutro && store.outro.animateTop
? store.outro.stage1Opacity
: 1;
ctx.drawImage(assets.home.topScreen.clock, 13, 45);
assets.images.home.topScreen.clock.draw(ctx, 13, 45);
ctx.globalAlpha = store.isIntro
? store.intro.stage1Opacity

View File

@@ -1,13 +1,9 @@
<script setup lang="ts">
const { onRender } = useScreen();
const app = useAppStore();
const store = useHomeStore();
const { assets } = useAssets();
const BAR_WIDTH = 256;
const BAR_HEIGHT = 16;
onRender((ctx) => {
const TEXT_Y = 11;
@@ -15,17 +11,9 @@ onRender((ctx) => {
ctx.globalAlpha =
store.isOutro && store.outro.animateTop ? store.outro.stage2Opacity : 1;
ctx.drawImage(
assets.home.topScreen.statusBar.statusBarsSheet,
0,
(app.color.row * 4 + app.color.col) * BAR_HEIGHT,
BAR_WIDTH,
BAR_HEIGHT,
0,
0,
BAR_WIDTH,
BAR_HEIGHT,
);
assets.images.home.topScreen.statusBar.statusBarsSheet.draw(ctx, 0, 0, {
colored: true,
});
ctx.fillStyle = "#ffffff";
ctx.font = "7px NDS7";
@@ -55,9 +43,9 @@ onRender((ctx) => {
fillNumberCell(now.getMonth() + 1, 12, -1);
// icons
ctx.drawImage(assets.home.topScreen.statusBar.gbaDisplay, 210, 2);
ctx.drawImage(assets.home.topScreen.statusBar.startupMode, 226, 2);
ctx.drawImage(assets.home.topScreen.statusBar.battery, 242, 4);
assets.images.home.topScreen.statusBar.gbaDisplay.draw(ctx, 210, 2);
assets.images.home.topScreen.statusBar.startupMode.draw(ctx, 226, 2);
assets.images.home.topScreen.statusBar.battery.draw(ctx, 242, 4);
});
defineOptions({

View File

@@ -27,7 +27,7 @@ const props = defineProps<{
const { assets } = useAssets();
const app = useAppStore();
const model = assets.nitendoDs.model.clone(true);
const model = assets.models.nitendoDs.model.clone(true);
let topScreenTexture: THREE.CanvasTexture | null = null;
let bottomScreenTexture: THREE.CanvasTexture | null = null;

View File

@@ -4,7 +4,7 @@ const { onRender } = useScreen();
const { assets } = useAssets();
onRender((ctx) => {
ctx.drawImage(assets.projects.bottomScreen.background, 0, 0);
assets.images.projects.bottomScreen.background.draw(ctx, 0, 0);
});
defineOptions({
render: () => null,

View File

@@ -11,23 +11,28 @@ const CLICK_RADIUS = 22;
const BUTTONS = {
prev: {
position: [36, 100],
image: assets.projects.bottomScreen.prevPressed,
image: assets.images.projects.bottomScreen.prevPressed,
},
quit: {
position: [88, 156],
image: assets.projects.bottomScreen.quitPressed,
image: assets.images.projects.bottomScreen.quitPressed,
},
link: {
position: [168, 156],
image: assets.projects.bottomScreen.linkPressed,
image: assets.images.projects.bottomScreen.linkPressed,
},
next: {
position: [220, 100],
image: assets.projects.bottomScreen.nextPressed,
image: assets.images.projects.bottomScreen.nextPressed,
},
} as const satisfies Record<
string,
{ position: Point; image: HTMLImageElement }
{
position: Point;
image: {
draw: (ctx: CanvasRenderingContext2D, x: number, y: number) => void;
};
}
>;
type ButtonType = keyof typeof BUTTONS;
@@ -115,15 +120,15 @@ onClick((x, y) => {
onRender((ctx) => {
// Draw disabled buttons
if (store.currentProject === 0) {
ctx.drawImage(
assets.projects.bottomScreen.prevDisabled,
assets.images.projects.bottomScreen.prevDisabled.draw(
ctx,
BUTTONS.prev.position[0] - 14,
BUTTONS.prev.position[1] - 14,
);
}
if (store.currentProject === store.projects.length - 1) {
ctx.drawImage(
assets.projects.bottomScreen.nextDisabled,
assets.images.projects.bottomScreen.nextDisabled.draw(
ctx,
BUTTONS.next.position[0] - 14,
BUTTONS.next.position[1] - 14,
);
@@ -131,24 +136,24 @@ onRender((ctx) => {
if (currentAnimation?.showButton) {
const image = BUTTONS[currentAnimation.type].image;
ctx.drawImage(
image!,
image.draw(
ctx,
currentAnimation.position[0] - 14,
currentAnimation.position[1] - 14,
);
}
if (currentAnimation?.showSmallCircle) {
ctx.drawImage(
assets.projects.bottomScreen.circleSmall,
assets.images.projects.bottomScreen.circleSmall.draw(
ctx,
currentAnimation.position[0] - 28,
currentAnimation.position[1] - 28,
);
}
if (currentAnimation?.showBigCircle) {
ctx.drawImage(
assets.projects.bottomScreen.circleBig,
assets.images.projects.bottomScreen.circleBig.draw(
ctx,
currentAnimation.position[0] - 44,
currentAnimation.position[1] - 44,
);

View File

@@ -124,7 +124,7 @@ onRender((ctx) => {
ctx.strokeRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
// text
ctx.drawImage(assets.projects.bottomScreen.popupTextBackground, 2, 146);
assets.images.projects.bottomScreen.popupTextBackground.draw(ctx, 2, 146);
ctx.font = "16px Pokemon DP Pro";
ctx.textBaseline = "top";
const displayedText = text.value.slice(
@@ -135,10 +135,14 @@ onRender((ctx) => {
// choice box
if (textProgress.value >= 1) {
ctx.drawImage(assets.projects.bottomScreen.popupChoiceBackground, 194, 98);
assets.images.projects.bottomScreen.popupChoiceBackground.draw(
ctx,
194,
98,
);
const y = selectedOption === "yes" ? YES_Y : NO_Y;
ctx.drawImage(assets.projects.bottomScreen.popupSelector, 200, y);
assets.images.projects.bottomScreen.popupSelector.draw(ctx, 200, y);
drawTextWithShadow(
ctx,

View File

@@ -4,7 +4,7 @@ const { onRender } = useScreen();
const { assets } = useAssets();
onRender((ctx) => {
ctx.drawImage(assets.projects.topScreen.background, 0, 0);
assets.images.projects.topScreen.background.draw(ctx, 0, 0);
});
defineOptions({

View File

@@ -56,7 +56,7 @@ const drawTextWithShadow2Lines = (
};
onRender((ctx) => {
ctx.drawImage(assets.projects.topScreen.background, 0, 0);
assets.images.projects.topScreen.background.draw(ctx, 0, 0);
ctx.textBaseline = "hanging";
ctx.font = "16px Pokemon DP Pro";
@@ -80,19 +80,19 @@ onRender((ctx) => {
const offsetFromCurrent = i - store.currentProject;
// TODO: project.id should be typed from useAssets, shouldn't be just a string
const thumbnailImage =
assets.projects.pokemons[
store.projects[i]!.id as keyof typeof assets.projects.pokemons
assets.images.projects.pokemons[
store.projects[i]!.id as keyof typeof assets.images.projects.pokemons
]!;
ctx.drawImage(
thumbnailImage,
thumbnailImage.draw(
ctx,
Math.floor(
thumbnailCenterX +
offsetFromCurrent * thumbnailSpacing -
thumbnailImage.width / 2 +
thumbnailImage.rect.width / 2 +
store.offsetX,
),
Math.floor(thumbnailCenterY - thumbnailImage.height / 2),
Math.floor(thumbnailCenterY - thumbnailImage.rect.height / 2),
);
}

View File

@@ -4,7 +4,7 @@ const { onRender } = useScreen();
const { assets } = useAssets();
onRender((ctx) => {
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
assets.images.home.bottomScreen.background.draw(ctx, 0, 0);
});
defineOptions({

View File

@@ -33,27 +33,27 @@ onRender((ctx) => {
ctx.translate(props.x, props.y);
if (isOpen.value || animation.playing) {
ctx.drawImage(
assets.settings.topScreen.clock.time,
assets.images.settings.topScreen.clock.time.draw(
ctx,
48 - animation.stage2Offset,
-48 + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.clock.date,
assets.images.settings.topScreen.clock.date.draw(
ctx,
0,
-96 + animation.stage2Offset + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.clock.alarm,
assets.images.settings.topScreen.clock.alarm.draw(
ctx,
0,
-48 + animation.stage1Offset,
);
ctx.drawImage(assets.settings.topScreen.clock.clockActive, 0, 0);
assets.images.settings.topScreen.clock.clockActive.draw(ctx, 0, 0);
} else if (isAnyOtherMenuOpen.value) {
ctx.drawImage(assets.settings.topScreen.clock.clockDisabled, 0, 0);
assets.images.settings.topScreen.clock.clockDisabled.draw(ctx, 0, 0);
} else {
ctx.drawImage(assets.settings.topScreen.clock.clock, 0, 0);
assets.images.settings.topScreen.clock.clock.draw(ctx, 0, 0);
}
});

View File

@@ -33,27 +33,27 @@ onRender((ctx) => {
ctx.translate(props.x, props.y);
if (isOpen.value || animation.playing) {
ctx.drawImage(
assets.settings.topScreen.options.language,
assets.images.settings.topScreen.options.language.draw(
ctx,
0,
-48 + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.options.gbaMode,
assets.images.settings.topScreen.options.gbaMode.draw(
ctx,
48 - animation.stage2Offset,
-48 + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.options.startUp,
assets.images.settings.topScreen.options.startUp.draw(
ctx,
0,
-96 + animation.stage2Offset + animation.stage1Offset,
);
ctx.drawImage(assets.settings.topScreen.options.optionsActive, 0, 0);
assets.images.settings.topScreen.options.optionsActive.draw(ctx, 0, 0);
} else if (isAnyOtherMenuOpen.value) {
ctx.drawImage(assets.settings.topScreen.options.optionsDisabled, 0, 0);
assets.images.settings.topScreen.options.optionsDisabled.draw(ctx, 0, 0);
} else {
ctx.drawImage(assets.settings.topScreen.options.options, 0, 0);
assets.images.settings.topScreen.options.options.draw(ctx, 0, 0);
}
});

View File

@@ -27,14 +27,14 @@ const isAnyOtherMenuOpen = computed(() => {
onRender((ctx) => {
if (isAnyOtherMenuOpen.value) {
ctx.drawImage(
assets.settings.topScreen.touchScreen.touchScreenDisabled,
assets.images.settings.topScreen.touchScreen.touchScreenDisabled.draw(
ctx,
props.x,
props.y,
);
} else {
ctx.drawImage(
assets.settings.topScreen.touchScreen.touchScreen,
assets.images.settings.topScreen.touchScreen.touchScreen.draw(
ctx,
props.x,
props.y,
);

View File

@@ -63,7 +63,7 @@ onClick((x, y) => {
});
onRender((ctx, deltaTime) => {
ctx.drawImage(assets.settings.bottomScreen.user.colorPalette, 16, 32);
assets.images.settings.bottomScreen.user.colorPalette.draw(ctx, 16, 32);
// animate
const finalSelectorX = GRID_START_X + selectedCol * (CELL_SIZE + SPACING) - 4;

View File

@@ -33,32 +33,32 @@ onRender((ctx) => {
ctx.translate(props.x, props.y);
if (isOpen.value || animation.playing) {
ctx.drawImage(
assets.settings.topScreen.user.birthday,
assets.images.settings.topScreen.user.birthday.draw(
ctx,
-48 + animation.stage2Offset,
-48 + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.user.userName,
assets.images.settings.topScreen.user.userName.draw(
ctx,
0,
-48 + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.user.message,
assets.images.settings.topScreen.user.message.draw(
ctx,
48 - animation.stage2Offset,
-48 + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.user.color,
assets.images.settings.topScreen.user.color.draw(
ctx,
0,
-96 + animation.stage2Offset + animation.stage1Offset,
);
ctx.drawImage(assets.settings.topScreen.user.userActive, 0, 0);
assets.images.settings.topScreen.user.userActive.draw(ctx, 0, 0);
} else if (isAnyOtherMenuOpen.value) {
ctx.drawImage(assets.settings.topScreen.user.userDisabled, 0, 0);
assets.images.settings.topScreen.user.userDisabled.draw(ctx, 0, 0);
} else {
ctx.drawImage(assets.settings.topScreen.user.user, 0, 0);
assets.images.settings.topScreen.user.user.draw(ctx, 0, 0);
}
});

View File

@@ -49,33 +49,34 @@ const { onRender, onClick } = useScreen();
const Y = 30;
const SQUARE_HEIGHT = 49;
const ARROW_IMAGE_HEIGHT = assets.settings.bottomScreen.numberInputUp.height;
const ARROW_IMAGE_HEIGHT =
assets.images.settings.bottomScreen.numberInputUp.rect.height;
const upImage = computed(() => {
if (props.digits === 2) {
return props.disabled
? assets.settings.bottomScreen.numberInputUpDisabled
: assets.settings.bottomScreen.numberInputUp;
? assets.images.settings.bottomScreen.numberInputUpDisabled
: assets.images.settings.bottomScreen.numberInputUp;
} else {
return props.disabled
? assets.settings.bottomScreen.numberInputUpXlDisabled
: assets.settings.bottomScreen.numberInputUpXl;
? assets.images.settings.bottomScreen.numberInputUpXlDisabled
: assets.images.settings.bottomScreen.numberInputUpXl;
}
});
const downImage = computed(() => {
if (props.digits === 2) {
return props.disabled
? assets.settings.bottomScreen.numberInputDownDisabled
: assets.settings.bottomScreen.numberInputDown;
? assets.images.settings.bottomScreen.numberInputDownDisabled
: assets.images.settings.bottomScreen.numberInputDown;
} else {
return props.disabled
? assets.settings.bottomScreen.numberInputDownXlDisabled
: assets.settings.bottomScreen.numberInputDownXl;
? assets.images.settings.bottomScreen.numberInputDownXlDisabled
: assets.images.settings.bottomScreen.numberInputDownXl;
}
});
const squareWidth = computed(() => upImage.value.width);
const squareWidth = computed(() => upImage.value.rect.width);
const increase = () => {
const newValue = value.value + 1;
@@ -89,7 +90,7 @@ const decrease = () => {
onRender((ctx) => {
// arrow up
ctx.drawImage(upImage.value, props.x, Y);
upImage.value.draw(ctx, props.x, Y);
// outline
ctx.fillStyle = "#515151";
@@ -123,11 +124,7 @@ onRender((ctx) => {
);
// arrow down
ctx.drawImage(
downImage.value,
props.x,
Y + ARROW_IMAGE_HEIGHT + SQUARE_HEIGHT,
);
downImage.value.draw(ctx, props.x, Y + ARROW_IMAGE_HEIGHT + SQUARE_HEIGHT);
// title
ctx.font = "10px NDS10";
@@ -140,7 +137,7 @@ onRender((ctx) => {
// TODO: -10 is needed because fillTextCentered isn't using top baseline
// i will change that in the future (maybe)
Y + ARROW_IMAGE_HEIGHT * 2 + SQUARE_HEIGHT - 6,
downImage.value.width,
downImage.value.rect.width,
);
});
@@ -159,7 +156,10 @@ useKeyDown((key) => {
onClick((x, y) => {
if (props.disabled) return;
if (
rectContains([props.x, Y, upImage.value.width, ARROW_IMAGE_HEIGHT], [x, y])
rectContains(
[props.x, Y, upImage.value.rect.width, ARROW_IMAGE_HEIGHT],
[x, y],
)
) {
increase();
emit("select");
@@ -175,7 +175,7 @@ onClick((x, y) => {
[
props.x,
Y + ARROW_IMAGE_HEIGHT + SQUARE_HEIGHT + 2,
downImage.value.width,
downImage.value.rect.width,
ARROW_IMAGE_HEIGHT,
],
[x, y],

View File

@@ -4,7 +4,7 @@ const { onRender } = useScreen();
const { assets } = useAssets();
onRender((ctx) => {
ctx.drawImage(assets.home.topScreen.background, 0, 0);
assets.images.home.topScreen.background.draw(ctx, 0, 0);
});
defineOptions({

View File

@@ -1,7 +1,6 @@
<script setup lang="ts">
const { onRender } = useScreen();
const app = useAppStore();
const { assets } = useAssets();
onRender((ctx) => {
@@ -14,7 +13,6 @@ onRender((ctx) => {
const CALENDAR_ROWS = 5;
const CALENDAR_LEFT = 128;
const CALENDAR_TOP = 64;
const SELECTOR_SIZE = 13;
ctx.fillStyle = "#343434";
@@ -25,16 +23,16 @@ onRender((ctx) => {
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
ctx.drawImage(
assets.home.topScreen.calendar.calendar,
assets.images.home.topScreen.calendar.calendar.draw(
ctx,
CALENDAR_LEFT - 3,
CALENDAR_TOP - 33,
);
const extraRow = CALENDAR_COLS * CALENDAR_ROWS - daysInMonth - firstDay < 0;
if (extraRow) {
ctx.drawImage(
assets.home.topScreen.calendar.lastRow,
assets.images.home.topScreen.calendar.lastRow.draw(
ctx,
CALENDAR_LEFT - 3,
CALENDAR_TOP + 79,
);
@@ -53,16 +51,11 @@ onRender((ctx) => {
const cellTop = CALENDAR_TOP + col * 16;
if (now.getDate() === day) {
ctx.drawImage(
assets.home.topScreen.calendar.daySelectorsSheet,
0,
(app.color.row * 4 + app.color.col) * SELECTOR_SIZE,
SELECTOR_SIZE,
SELECTOR_SIZE,
assets.images.home.topScreen.calendar.daySelectorsSheet.draw(
ctx,
cellLeft + 1,
cellTop + 1,
SELECTOR_SIZE,
SELECTOR_SIZE,
{ colored: true },
);
}

View File

@@ -55,7 +55,7 @@ function drawLine(
onRender((ctx) => {
ctx.translate(0, -16);
ctx.drawImage(assets.home.topScreen.clock, 13, 45);
assets.images.home.topScreen.clock.draw(ctx, 13, 45);
const now = new Date();

View File

@@ -6,12 +6,12 @@ const { assets } = useAssets();
const renderNotification = (
ctx: CanvasRenderingContext2D,
image: HTMLImageElement,
image: AtlasImage,
title: string,
description: string,
) => {
ctx.drawImage(assets.settings.topScreen.notification, 0, 0);
ctx.drawImage(image, 2, 2);
assets.images.settings.topScreen.notification.draw(ctx, 0, 0);
image.draw(ctx, 2, 2);
ctx.font = "10px NDS10";
ctx.fillStyle = "#282828";
@@ -26,29 +26,29 @@ const renderNotification = (
};
const mainNotification = computed(() => ({
image: assets.settings.topScreen.settings,
image: assets.images.settings.topScreen.settings,
title: $t("settings.title"),
description: $t("settings.description"),
}));
const IMAGES_MAP: Record<string, HTMLImageElement> = {
options: assets.settings.topScreen.options.options,
optionsStartUp: assets.settings.topScreen.options.startUp,
optionsLanguage: assets.settings.topScreen.options.language,
optionsGbaMode: assets.settings.topScreen.options.gbaMode,
const IMAGES_MAP: Record<string, AtlasImage> = {
options: assets.images.settings.topScreen.options.options,
optionsStartUp: assets.images.settings.topScreen.options.startUp,
optionsLanguage: assets.images.settings.topScreen.options.language,
optionsGbaMode: assets.images.settings.topScreen.options.gbaMode,
clock: assets.settings.topScreen.clock.clock,
clockTime: assets.settings.topScreen.clock.time,
clockDate: assets.settings.topScreen.clock.date,
clockAlarm: assets.settings.topScreen.clock.alarm,
clock: assets.images.settings.topScreen.clock.clock,
clockTime: assets.images.settings.topScreen.clock.time,
clockDate: assets.images.settings.topScreen.clock.date,
clockAlarm: assets.images.settings.topScreen.clock.alarm,
user: assets.settings.topScreen.user.user,
userUserName: assets.settings.topScreen.user.userName,
userBirthday: assets.settings.topScreen.user.birthday,
userMessage: assets.settings.topScreen.user.message,
userColor: assets.settings.topScreen.user.color,
user: assets.images.settings.topScreen.user.user,
userUserName: assets.images.settings.topScreen.user.userName,
userBirthday: assets.images.settings.topScreen.user.birthday,
userMessage: assets.images.settings.topScreen.user.message,
userColor: assets.images.settings.topScreen.user.color,
touchScreen: assets.settings.topScreen.touchScreen.touchScreen,
touchScreen: assets.images.settings.topScreen.touchScreen.touchScreen,
};
const menuNotification = computed(() => {

View File

@@ -1,26 +1,14 @@
<script setup lang="ts">
const { onRender } = useScreen();
const app = useAppStore();
const { assets } = useAssets();
const BAR_WIDTH = 256;
const BAR_HEIGHT = 16;
onRender((ctx) => {
const TEXT_Y = 11;
ctx.drawImage(
assets.home.topScreen.statusBar.statusBarsSheet,
0,
(app.color.row * 4 + app.color.col) * BAR_HEIGHT,
BAR_WIDTH,
BAR_HEIGHT,
0,
0,
BAR_WIDTH,
BAR_HEIGHT,
);
assets.images.home.topScreen.statusBar.statusBarsSheet.draw(ctx, 0, 0, {
colored: true,
});
ctx.fillStyle = "#ffffff";
ctx.font = "7px NDS7";
@@ -50,9 +38,9 @@ onRender((ctx) => {
fillNumberCell(now.getMonth() + 1, 12, -1);
// icons
ctx.drawImage(assets.home.topScreen.statusBar.gbaDisplay, 210, 2);
ctx.drawImage(assets.home.topScreen.statusBar.startupMode, 226, 2);
ctx.drawImage(assets.home.topScreen.statusBar.battery, 242, 4);
assets.images.home.topScreen.statusBar.gbaDisplay.draw(ctx, 210, 2);
assets.images.home.topScreen.statusBar.startupMode.draw(ctx, 226, 2);
assets.images.home.topScreen.statusBar.battery.draw(ctx, 242, 4);
});
defineOptions({