Bump to 0.3.4, load color palette from resources

This commit is contained in:
spicyjpeg 2023-09-14 23:54:59 +02:00
parent 998d2e6349
commit f8a21070f1
No known key found for this signature in database
GPG Key ID: 5CC87404C01DF393
14 changed files with 221 additions and 107 deletions

View File

@ -6,7 +6,7 @@ set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain.cmake")
project(
cart_tool_private
LANGUAGES C CXX ASM
VERSION 0.3.3
VERSION 0.3.4
DESCRIPTION "Konami System 573 security cartridge tool"
)

20
assets/app.palette.json Normal file
View File

@ -0,0 +1,20 @@
{
"default": "#808080",
"shadow": "#000000",
"backdrop": "#b0b0b0",
"accent1": "#f0d050",
"accent2": "#a08830",
"window1": "#505050",
"window2": "#242424",
"window3": "#080808",
"highlight1": "#c8b040",
"highlight2": "#a08830",
"progress1": "#48c010",
"progress2": "#207800",
"box1": "#000000",
"box2": "#282828",
"text1": "#707070",
"text2": "#383838",
"title": "#808080",
"subtitle": "#a07840"
}

View File

@ -44,6 +44,11 @@
"source": "assets/sounds/click.vag",
"compress": null
},
{
"type": "palette",
"name": "assets/app.palette",
"source": "assets/app.palette.json"
},
{
"type": "strings",
"name": "assets/app.strings",

View File

@ -180,10 +180,7 @@ void CartActionsScreen::update(ui::Context &ctx) {
if (ctx.buttons.pressed(ui::BTN_START))
(this->*action.target)(ctx);
if (
(ctx.buttons.held(ui::BTN_LEFT) && ctx.buttons.pressed(ui::BTN_RIGHT)) ||
(ctx.buttons.pressed(ui::BTN_LEFT) && ctx.buttons.held(ui::BTN_RIGHT))
)
if (ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT))
ctx.show(APP->_cartInfoScreen, true, true);
}
@ -204,8 +201,7 @@ void QRCodeScreen::show(ui::Context &ctx, bool goBack) {
void QRCodeScreen::update(ui::Context &ctx) {
if (
ctx.buttons.pressed(ui::BTN_START) ||
(ctx.buttons.held(ui::BTN_LEFT) && ctx.buttons.pressed(ui::BTN_RIGHT)) ||
(ctx.buttons.pressed(ui::BTN_LEFT) && ctx.buttons.held(ui::BTN_RIGHT))
ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)
)
ctx.show(APP->_cartActionsScreen, true, true);
}
@ -235,8 +231,7 @@ void HexdumpScreen::update(ui::Context &ctx) {
if (
ctx.buttons.pressed(ui::BTN_START) ||
(ctx.buttons.held(ui::BTN_LEFT) && ctx.buttons.pressed(ui::BTN_RIGHT)) ||
(ctx.buttons.pressed(ui::BTN_LEFT) && ctx.buttons.held(ui::BTN_RIGHT))
ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)
)
ctx.show(APP->_cartActionsScreen, true, true);
}
@ -273,10 +268,7 @@ void ReflashGameScreen::update(ui::Context &ctx) {
APP->_selectedEntry = APP->_db.get(_activeItem);
ctx.show(APP->_confirmScreen, false, true);
} else if (
(ctx.buttons.held(ui::BTN_LEFT) && ctx.buttons.pressed(ui::BTN_RIGHT)) ||
(ctx.buttons.pressed(ui::BTN_LEFT) && ctx.buttons.held(ui::BTN_RIGHT))
) {
} else if (ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)) {
ctx.show(APP->_cartActionsScreen, true, true);
}
}

View File

@ -213,10 +213,7 @@ void CartInfoScreen::update(ui::Context &ctx) {
else
ctx.show(APP->_unlockKeyScreen, false, true);
}
if (
(ctx.buttons.held(ui::BTN_LEFT) && ctx.buttons.pressed(ui::BTN_RIGHT)) ||
(ctx.buttons.pressed(ui::BTN_LEFT) && ctx.buttons.held(ui::BTN_RIGHT))
)
if (ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT))
ctx.show(APP->_mainMenuScreen, true, true);
}
@ -344,10 +341,7 @@ void UnlockKeyScreen::update(ui::Context &ctx) {
ctx.show(APP->_confirmScreen, false, true);
}
}
if (
(ctx.buttons.held(ui::BTN_LEFT) && ctx.buttons.pressed(ui::BTN_RIGHT)) ||
(ctx.buttons.pressed(ui::BTN_LEFT) && ctx.buttons.held(ui::BTN_RIGHT))
) {
if (ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)) {
ctx.show(APP->_cartInfoScreen, true, true);
}
}

View File

@ -214,8 +214,7 @@ void AboutScreen::update(ui::Context &ctx) {
if (
ctx.buttons.pressed(ui::BTN_START) ||
(ctx.buttons.held(ui::BTN_LEFT) && ctx.buttons.pressed(ui::BTN_RIGHT)) ||
(ctx.buttons.pressed(ui::BTN_LEFT) && ctx.buttons.held(ui::BTN_RIGHT))
ctx.buttons.bothPressed(ui::BTN_LEFT, ui::BTN_RIGHT)
)
ctx.show(APP->_mainMenuScreen, true, true);
}

View File

@ -58,9 +58,9 @@ size_t upload(const RectWH &rect, const void *data, bool wait) {
void Context::_applyResolution(VideoMode mode, int shiftX, int shiftY) const {
GP1HorizontalRes hres;
GP1VerticalRes vres = (height > 256) ? GP1_VRES_512 : GP1_VRES_256;
GP1VerticalRes vres;
int span;
int span, is480;
if (width < 320) {
hres = GP1_HRES_256;
@ -79,10 +79,18 @@ void Context::_applyResolution(VideoMode mode, int shiftX, int shiftY) const {
span = width * 4;
}
int x = shiftX + 0x760, offsetX = span / 2;
int y = shiftY + (mode ? 0xa3 : 0x88), offsetY = height / (vres ? 4 : 2);
if (height <= 256) {
vres = GP1_VRES_256;
is480 = false;
} else {
vres = GP1_VRES_512;
is480 = true;
}
GPU_GP1 = gp1_fbMode(hres, vres, mode, height > 256, GP1_COLOR_16BPP);
int x = shiftX + 0x760, offsetX = span / 2;
int y = shiftY + (mode ? 0xa3 : 0x88), offsetY = height / (2 << is480);
GPU_GP1 = gp1_fbMode(hres, vres, mode, is480, GP1_COLOR_16BPP);
GPU_GP1 = gp1_fbRangeH(x - offsetX, x + offsetX);
GPU_GP1 = gp1_fbRangeV(y - offsetY, y + offsetY);
}
@ -117,8 +125,17 @@ void Context::setResolution(
for (int fb = 1; fb >= 0; fb--) {
auto &clip = _buffers[fb].clip;
clip.x1 = sideBySide ? (_width * fb) : 0;
clip.y1 = sideBySide ? 0 : (_height * fb);
if (_height > 256) {
clip.x1 = 0;
clip.y1 = 0;
} else if (sideBySide) {
clip.x1 = fb ? _width : 0;
clip.y1 = 0;
} else {
clip.x1 = 0;
clip.y1 = fb ? _height : 0;
}
clip.x2 = clip.x1 + _width - 1;
clip.y2 = clip.y1 + _height - 1;
}

View File

@ -121,13 +121,11 @@ _fileInitDone:
goto _resourceInitDone;
}
if (fileProvider.fileExists(resPath)) {
zipFile = fileProvider.openFile(resPath, file::READ);
zipFile = fileProvider.openFile(resPath, file::READ);
if (zipFile) {
if (resourceProvider.init(zipFile))
goto _resourceInitDone;
}
if (zipFile) {
if (resourceProvider.init(zipFile))
goto _resourceInitDone;
}
resourceProvider.init(_resources, _resourcesSize);
@ -135,7 +133,7 @@ _fileInitDone:
_resourceInitDone:
io::clearWatchdog();
gpu::Context gpuCtx(GP1_MODE_NTSC, width, height, height > 256);
gpu::Context gpuCtx(GP1_MODE_NTSC, width, height);
ui::Context uiCtx(gpuCtx);
ui::TiledBackground background;
@ -153,6 +151,9 @@ _resourceInitDone:
!resourceProvider.loadStruct(
uiCtx.font.metrics, "assets/textures/font.metrics"
) ||
!resourceProvider.loadStruct(
uiCtx.colors, "assets/app.palette"
) ||
!resourceProvider.loadData(
strings, "assets/app.strings"
)

View File

@ -240,9 +240,9 @@ typedef enum {
} GP1HorizontalRes;
typedef enum {
GP1_VRES_BITMASK = 1 << 2,
GP1_VRES_256 = 0 << 2,
GP1_VRES_512 = 1 << 2
GP1_VRES_BITMASK = 1,
GP1_VRES_256 = 0,
GP1_VRES_512 = 1
} GP1VerticalRes;
typedef enum {

View File

@ -34,7 +34,7 @@
typedef enum {
DEV0_BASE = 0xbf000000,
EXP1_BASE = 0xbf000000,
CACHE_BASE = 0xbf800000,
CACHE_BASE = 0x1f800000, // Cannot be accessed from KSEG1
IO_BASE = 0xbf801000,
EXP2_BASE = 0xbf802000,
EXP3_BASE = 0xbfa00000,

View File

@ -125,6 +125,15 @@ void ButtonState::update(void) {
}
}
bool ButtonState::bothPressed(Button buttonA, Button buttonB) {
if (pressed(buttonA) && held(buttonB))
return true;
if (held(buttonA) && pressed(buttonB))
return true;
return false;
}
/* UI context */
Context::Context(gpu::Context &gpuCtx, void *screenData)
@ -205,7 +214,7 @@ void TiledBackground::draw(Context &ctx) const {
rect.y = ctx.gpuCtx.height - (8 + gpu::FONT_LINE_HEIGHT);
rect.w = width;
rect.h = gpu::FONT_LINE_HEIGHT;
ctx.font.draw(ctx.gpuCtx, text, rect, COLOR_TEXT2);
ctx.font.draw(ctx.gpuCtx, text, rect, ctx.colors[COLOR_TEXT2]);
}
LogOverlay::LogOverlay(util::Logger &logger)
@ -222,7 +231,7 @@ void LogOverlay::draw(Context &ctx) const {
ctx, 0, offset - ctx.gpuCtx.height, ctx.gpuCtx.width,
ctx.gpuCtx.height
);
ctx.gpuCtx.drawBackdrop(COLOR_BACKDROP, GP0_BLEND_SUBTRACT);
ctx.gpuCtx.drawBackdrop(ctx.colors[COLOR_BACKDROP], GP0_BLEND_SUBTRACT);
int screenHeight = ctx.gpuCtx.height - SCREEN_MARGIN_Y * 2;
int linesShown = screenHeight / gpu::FONT_LINE_HEIGHT;
@ -235,7 +244,9 @@ void LogOverlay::draw(Context &ctx) const {
rect.y2 = SCREEN_MARGIN_Y + gpu::FONT_LINE_HEIGHT;
for (int i = linesShown - 1; i >= 0; i--) {
ctx.font.draw(ctx.gpuCtx, _logger.getLine(i), rect, COLOR_TEXT1);
ctx.font.draw(
ctx.gpuCtx, _logger.getLine(i), rect, ctx.colors[COLOR_TEXT1]
);
rect.y1 = rect.y2;
rect.y2 += gpu::FONT_LINE_HEIGHT;
@ -312,20 +323,20 @@ void ModalScreen::draw(Context &ctx, bool active) const {
// Window
ctx.gpuCtx.drawGradientRectD(
0, 0, _width, windowHeight, COLOR_WINDOW1, COLOR_WINDOW2,
COLOR_WINDOW3
0, 0, _width, windowHeight, ctx.colors[COLOR_WINDOW1],
ctx.colors[COLOR_WINDOW2], ctx.colors[COLOR_WINDOW3]
);
ctx.gpuCtx.drawGradientRectH(
0, 0, _titleBarAnim.getValue(ctx.time), TITLE_BAR_HEIGHT,
COLOR_ACCENT1, COLOR_ACCENT2
ctx.colors[COLOR_ACCENT1], ctx.colors[COLOR_ACCENT2]
);
ctx.gpuCtx.drawRect(
_width, SHADOW_OFFSET, SHADOW_OFFSET, windowHeight, COLOR_SHADOW,
true
_width, SHADOW_OFFSET, SHADOW_OFFSET, windowHeight,
ctx.colors[COLOR_SHADOW], true
);
ctx.gpuCtx.drawRect(
SHADOW_OFFSET, windowHeight, _width - SHADOW_OFFSET, SHADOW_OFFSET,
COLOR_SHADOW, true
ctx.colors[COLOR_SHADOW], true
);
// Text
@ -336,11 +347,11 @@ void ModalScreen::draw(Context &ctx, bool active) const {
rect.x2 = _width - TITLE_BAR_PADDING;
rect.y2 = TITLE_BAR_PADDING + gpu::FONT_LINE_HEIGHT;
//rect.y2 = TITLE_BAR_HEIGHT - TITLE_BAR_PADDING;
ctx.font.draw(ctx.gpuCtx, _title, rect, COLOR_TITLE);
ctx.font.draw(ctx.gpuCtx, _title, rect, ctx.colors[COLOR_TITLE]);
rect.y1 = TITLE_BAR_HEIGHT + MODAL_PADDING;
rect.y2 = _height - MODAL_PADDING;
ctx.font.draw(ctx.gpuCtx, _body, rect, COLOR_TEXT1, true);
ctx.font.draw(ctx.gpuCtx, _body, rect, ctx.colors[COLOR_TEXT1], true);
}
}

View File

@ -11,29 +11,30 @@ namespace ui {
/* Public constants */
enum Color : gpu::Color {
COLOR_DEFAULT = 0x808080,
COLOR_SHADOW = 0x000000,
COLOR_BACKDROP = 0xb0b0b0,
COLOR_ACCENT1 = 0x50d0f0,
COLOR_ACCENT2 = 0x3088a0,
COLOR_WINDOW1 = 0x505050,
COLOR_WINDOW2 = 0x242424,
COLOR_WINDOW3 = 0x080808,
COLOR_HIGHLIGHT1 = 0x40b0c8,
COLOR_HIGHLIGHT2 = 0x3088a0,
COLOR_PROGRESS1 = 0x10c048,
COLOR_PROGRESS2 = 0x007820,
COLOR_BOX1 = 0x000000,
COLOR_BOX2 = 0x282828,
COLOR_TEXT1 = 0x707070,
COLOR_TEXT2 = 0x383838,
COLOR_TITLE = 0x808080,
COLOR_SUBTITLE = 0x4078a0
};
static constexpr int NUM_UI_COLORS = 18;
static constexpr int NUM_UI_SOUNDS = 6;
enum Color {
COLOR_DEFAULT = 0,
COLOR_SHADOW = 1,
COLOR_BACKDROP = 2,
COLOR_ACCENT1 = 3,
COLOR_ACCENT2 = 4,
COLOR_WINDOW1 = 5,
COLOR_WINDOW2 = 6,
COLOR_WINDOW3 = 7,
COLOR_HIGHLIGHT1 = 8,
COLOR_HIGHLIGHT2 = 9,
COLOR_PROGRESS1 = 10,
COLOR_PROGRESS2 = 11,
COLOR_BOX1 = 12,
COLOR_BOX2 = 13,
COLOR_TEXT1 = 14,
COLOR_TEXT2 = 15,
COLOR_TITLE = 16,
COLOR_SUBTITLE = 17
};
enum Sound {
SOUND_STARTUP = 0,
SOUND_ERROR = 1,
@ -127,6 +128,7 @@ public:
ButtonState(void);
void update(void);
bool bothPressed(Button buttonA, Button buttonB);
};
/* UI context */
@ -144,6 +146,7 @@ public:
gpu::Context &gpuCtx;
gpu::Font font;
gpu::Color colors[NUM_UI_COLORS];
spu::Sound sounds[NUM_UI_SOUNDS];
ButtonState buttons;

View File

@ -13,7 +13,7 @@ namespace ui {
void PlaceholderScreen::draw(Context &ctx, bool active) const {
_newLayer(ctx, 0, 0, ctx.gpuCtx.width, ctx.gpuCtx.height);
ctx.gpuCtx.drawRect(
0, 0, ctx.gpuCtx.width, ctx.gpuCtx.height, COLOR_WINDOW2
0, 0, ctx.gpuCtx.width, ctx.gpuCtx.height, ctx.colors[COLOR_WINDOW2]
);
}
@ -51,26 +51,33 @@ void MessageBoxScreen::draw(Context &ctx, bool active) const {
if (_locked) {
ctx.gpuCtx.drawRect(
buttonX, buttonY, rect.w, BUTTON_HEIGHT, COLOR_SHADOW, true
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
ctx.colors[COLOR_SHADOW], true
);
ctx.font.draw(ctx.gpuCtx, _buttons[i], rect, COLOR_TEXT2);
ctx.font.draw(
ctx.gpuCtx, _buttons[i], rect, ctx.colors[COLOR_TEXT2]
);
} else {
if (i == activeButton) {
ctx.gpuCtx.drawRect(
buttonX, buttonY, rect.w, BUTTON_HEIGHT, COLOR_HIGHLIGHT2
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
ctx.colors[COLOR_HIGHLIGHT2]
);
ctx.gpuCtx.drawRect(
buttonX, buttonY, _buttonAnim.getValue(ctx.time), BUTTON_HEIGHT,
COLOR_HIGHLIGHT1
buttonX, buttonY, _buttonAnim.getValue(ctx.time),
BUTTON_HEIGHT, ctx.colors[COLOR_HIGHLIGHT1]
);
} else {
ctx.gpuCtx.drawRect(
buttonX, buttonY, rect.w, BUTTON_HEIGHT, COLOR_WINDOW3
buttonX, buttonY, rect.w, BUTTON_HEIGHT,
ctx.colors[COLOR_WINDOW3]
);
}
ctx.font.draw(ctx.gpuCtx, _buttons[i], rect, COLOR_TITLE);
ctx.font.draw(
ctx.gpuCtx, _buttons[i], rect, ctx.colors[COLOR_TITLE]
);
}
buttonX += rect.w + BUTTON_SPACING;
@ -138,7 +145,7 @@ void HexEntryScreen::draw(Context &ctx, bool active) const {
// Text box
ctx.gpuCtx.drawRect(
MODAL_PADDING, boxY, boxWidth, BUTTON_HEIGHT, COLOR_BOX1
MODAL_PADDING, boxY, boxWidth, BUTTON_HEIGHT, ctx.colors[COLOR_BOX1]
);
char text[128];
@ -154,8 +161,8 @@ void HexEntryScreen::draw(Context &ctx, bool active) const {
if (_activeButton < _buttonIndexOffset)
ctx.gpuCtx.drawGradientRectV(
textOffset + _cursorAnim.getValue(ctx.time),
boxY + BUTTON_HEIGHT / 2, digitWidth, BUTTON_HEIGHT / 2, COLOR_BOX1,
COLOR_HIGHLIGHT1
boxY + BUTTON_HEIGHT / 2, digitWidth, BUTTON_HEIGHT / 2,
ctx.colors[COLOR_BOX1], ctx.colors[COLOR_HIGHLIGHT1]
);
// Text
@ -163,7 +170,7 @@ void HexEntryScreen::draw(Context &ctx, bool active) const {
rect.y1 = boxY + BUTTON_PADDING;
rect.x2 = _width - MODAL_PADDING;
rect.y2 = boxY + BUTTON_PADDING + gpu::FONT_LINE_HEIGHT;
ctx.font.draw(ctx.gpuCtx, text, rect, COLOR_TITLE);
ctx.font.draw(ctx.gpuCtx, text, rect, ctx.colors[COLOR_TITLE]);
// Highlighted digit
if (_activeButton < _buttonIndexOffset) {
@ -171,7 +178,7 @@ void HexEntryScreen::draw(Context &ctx, bool active) const {
text[1] = 0;
rect.x1 = textOffset + _cursorAnim.getTargetValue();
ctx.font.draw(ctx.gpuCtx, text, rect, COLOR_SUBTITLE);
ctx.font.draw(ctx.gpuCtx, text, rect, ctx.colors[COLOR_SUBTITLE]);
}
}
@ -262,11 +269,11 @@ void ProgressScreen::draw(Context &ctx, bool active) const {
_setBlendMode(ctx, GP0_BLEND_SEMITRANS, true);
ctx.gpuCtx.drawRect(
barX, barY, fullBarWidth, PROGRESS_BAR_HEIGHT, COLOR_WINDOW3
barX, barY, fullBarWidth, PROGRESS_BAR_HEIGHT, ctx.colors[COLOR_WINDOW3]
);
ctx.gpuCtx.drawGradientRectH(
barX, barY, _progressBarAnim.getValue(ctx.time), PROGRESS_BAR_HEIGHT,
COLOR_PROGRESS2, COLOR_PROGRESS1
ctx.colors[COLOR_PROGRESS2], ctx.colors[COLOR_PROGRESS1]
);
}
@ -295,11 +302,11 @@ void TextScreen::draw(Context &ctx, bool active) const {
rect.y1 = 0;
rect.x2 = screenWidth;
rect.y2 = gpu::FONT_LINE_HEIGHT;
ctx.font.draw(ctx.gpuCtx, _title, rect, COLOR_TITLE);
ctx.font.draw(ctx.gpuCtx, _title, rect, ctx.colors[COLOR_TITLE]);
rect.y1 = screenHeight - SCREEN_PROMPT_HEIGHT_MIN;
rect.y2 = screenHeight;
ctx.font.draw(ctx.gpuCtx, _prompt, rect, COLOR_TEXT1, true);
ctx.font.draw(ctx.gpuCtx, _prompt, rect, ctx.colors[COLOR_TEXT1], true);
int bodyOffset = gpu::FONT_LINE_HEIGHT + SCREEN_BLOCK_MARGIN;
int bodyHeight = screenHeight -
@ -319,7 +326,7 @@ void TextScreen::draw(Context &ctx, bool active) const {
clip.y1 = 0;
clip.x2 = screenWidth;
clip.y2 = bodyHeight;
ctx.font.draw(ctx.gpuCtx, _body, rect, clip, COLOR_TEXT1, true);
ctx.font.draw(ctx.gpuCtx, _body, rect, clip, ctx.colors[COLOR_TEXT1], true);
}
void TextScreen::update(Context &ctx) {
@ -404,11 +411,11 @@ void ImageScreen::draw(Context &ctx, bool active) const {
rect.y1 = SCREEN_MARGIN_Y;
rect.x2 = ctx.gpuCtx.width - SCREEN_MARGIN_X;
rect.y2 = SCREEN_MARGIN_Y + gpu::FONT_LINE_HEIGHT;
ctx.font.draw(ctx.gpuCtx, _title, rect, COLOR_TITLE);
ctx.font.draw(ctx.gpuCtx, _title, rect, ctx.colors[COLOR_TITLE]);
rect.y1 = ctx.gpuCtx.height - (SCREEN_MARGIN_Y + SCREEN_PROMPT_HEIGHT);
rect.y2 = ctx.gpuCtx.height - SCREEN_MARGIN_Y;
ctx.font.draw(ctx.gpuCtx, _prompt, rect, COLOR_TEXT1, true);
ctx.font.draw(ctx.gpuCtx, _prompt, rect, ctx.colors[COLOR_TEXT1], true);
}
ListScreen::ListScreen(void)
@ -435,21 +442,25 @@ void ListScreen::_drawItems(Context &ctx) const {
if (i == _activeItem) {
ctx.gpuCtx.drawRect(
LIST_BOX_PADDING, itemY, itemWidth, itemHeight,
COLOR_HIGHLIGHT2
ctx.colors[COLOR_HIGHLIGHT2]
);
ctx.gpuCtx.drawRect(
LIST_BOX_PADDING, itemY, _itemAnim.getValue(ctx.time),
itemHeight, COLOR_HIGHLIGHT1
itemHeight, ctx.colors[COLOR_HIGHLIGHT1]
);
rect.y1 = itemY + LIST_ITEM_PADDING + gpu::FONT_LINE_HEIGHT;
rect.y2 = rect.y1 + gpu::FONT_LINE_HEIGHT;
ctx.font.draw(ctx.gpuCtx, _itemPrompt, rect, COLOR_SUBTITLE);
ctx.font.draw(
ctx.gpuCtx, _itemPrompt, rect, ctx.colors[COLOR_SUBTITLE]
);
}
rect.y1 = itemY + LIST_ITEM_PADDING;
rect.y2 = rect.y1 + gpu::FONT_LINE_HEIGHT;
ctx.font.draw(ctx.gpuCtx, _getItemName(ctx, i), rect, COLOR_TITLE);
ctx.font.draw(
ctx.gpuCtx, _getItemName(ctx, i), rect, ctx.colors[COLOR_TITLE]
);
}
itemY += itemHeight;
@ -480,11 +491,11 @@ void ListScreen::draw(Context &ctx, bool active) const {
rect.y1 = 0;
rect.x2 = screenWidth;
rect.y2 = gpu::FONT_LINE_HEIGHT;
ctx.font.draw(ctx.gpuCtx, _title, rect, COLOR_TITLE);
ctx.font.draw(ctx.gpuCtx, _title, rect, ctx.colors[COLOR_TITLE]);
rect.y1 = screenHeight - SCREEN_PROMPT_HEIGHT;
rect.y2 = screenHeight;
ctx.font.draw(ctx.gpuCtx, _prompt, rect, COLOR_TEXT1, true);
ctx.font.draw(ctx.gpuCtx, _prompt, rect, ctx.colors[COLOR_TEXT1], true);
_newLayer(
ctx, SCREEN_MARGIN_X,
@ -494,9 +505,12 @@ void ListScreen::draw(Context &ctx, bool active) const {
_setBlendMode(ctx, GP0_BLEND_SEMITRANS, true);
// List box
ctx.gpuCtx.drawRect(0, 0, screenWidth / 2, listHeight, COLOR_BOX1);
ctx.gpuCtx.drawRect(
0, 0, screenWidth / 2, listHeight, ctx.colors[COLOR_BOX1]
);
ctx.gpuCtx.drawGradientRectH(
screenWidth / 2, 0, screenWidth / 2, listHeight, COLOR_BOX1, COLOR_BOX2
screenWidth / 2, 0, screenWidth / 2, listHeight, ctx.colors[COLOR_BOX1],
ctx.colors[COLOR_BOX2]
);
if (_listLength) {
@ -511,11 +525,15 @@ void ListScreen::draw(Context &ctx, bool active) const {
if (_activeItem) {
iconRect.y = LIST_BOX_PADDING;
ctx.font.draw(ctx.gpuCtx, CH_UP_ARROW, iconRect, COLOR_TEXT1);
ctx.font.draw(
ctx.gpuCtx, CH_UP_ARROW, iconRect, ctx.colors[COLOR_TEXT1]
);
}
if (_activeItem < (_listLength - 1)) {
iconRect.y = listHeight - (gpu::FONT_LINE_HEIGHT + LIST_BOX_PADDING);
ctx.font.draw(ctx.gpuCtx, CH_DOWN_ARROW, iconRect, COLOR_TEXT1);
ctx.font.draw(
ctx.gpuCtx, CH_DOWN_ARROW, iconRect, ctx.colors[COLOR_TEXT1]
);
}
}
}

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__version__ = "0.3.0"
__version__ = "0.3.4"
__author__ = "spicyjpeg"
import json, re
@ -10,7 +10,7 @@ from collections import defaultdict
from itertools import chain
from pathlib import Path
from struct import Struct
from typing import Any, ByteString, Generator, Mapping
from typing import Any, ByteString, Generator, Mapping, Sequence
from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile
import numpy
@ -149,6 +149,50 @@ def generateFontMetrics(
return data
## Color palette generator
PALETTE_COLOR_REGEX: re.Pattern = re.compile(r"^#?([0-9A-Fa-f]{6})$")
PALETTE_COLORS: Sequence[str] = (
"default",
"shadow",
"backdrop",
"accent1",
"accent2",
"window1",
"window2",
"window3",
"highlight1",
"highlight2",
"progress1",
"progress2",
"box1",
"box2",
"text1",
"text2",
"title",
"subtitle"
)
PALETTE_ENTRY_STRUCT: Struct = Struct("< 3s x")
def generateColorPalette(palette: Mapping[str, str]) -> bytearray:
data: bytearray = bytearray()
for entry in PALETTE_COLORS:
color: str | None = palette.get(entry, None)
if color is None:
raise ValueError(f"no entry found for {entry}")
matched: re.Match | None = PALETTE_COLOR_REGEX.match(color)
if matched is None:
raise ValueError(f"invalid color value: {color}")
data.extend(PALETTE_ENTRY_STRUCT.pack(bytes.fromhex(matched.group(1))))
return data
## String table generator
TABLE_ENTRY_STRUCT: Struct = Struct("< I 2H")
@ -353,7 +397,7 @@ def main():
if image.mode != "P":
image = image.quantize(
int(asset["quantize"]), dither = Image.Dither.NONE
int(asset["quantize"]), dither = Image.NONE
)
data: ByteString = generateIndexedTIM(image, ix, iy, cx, cy)
@ -367,6 +411,15 @@ def main():
data: ByteString = generateFontMetrics(metrics)
case "palette":
if "palette" in asset:
palette: dict = asset["palette"]
else:
with open(sourceDir / asset["source"], "rt") as _file:
palette: dict = json.load(_file)
data: ByteString = generateColorPalette(palette)
case "strings":
if "strings" in asset:
strings: dict = asset["strings"]
@ -380,7 +433,8 @@ def main():
raise KeyError(f"unsupported asset type '{_type}'")
gzipLevel: int | None = asset.get("compress", args.compress_level)
disallow: bool = (gzipLevel is None) or args.no_compression
disallow: bool = \
(len(data) < 1024) or (gzipLevel is None) or args.no_compression
_zip.writestr(
asset["name"], data,