Allow position as a fraction of resolution

UEFI recommends y=.382 (1 - 1 / (golden ratio)), make this the default.
Fractional position starts with a decimal point: x=.5 y=.382
Pixel offset relative to the center is set as before: x=123 y=456
If the coordinates were omitted, old default was: x=0 y=0
This commit is contained in:
Lauri Kenttä
2026-03-30 19:14:31 +03:00
parent d40ce9f6c5
commit 683ee49110
4 changed files with 135 additions and 63 deletions
+9 -8
View File
@@ -8,12 +8,13 @@ boot=MS
# Multiple image lines may be present, in which case one will be picked by random. # Multiple image lines may be present, in which case one will be picked by random.
# The image line may contain the following parts: # The image line may contain the following parts:
# Any of the following: # Any of the following:
# - "n=(number)", a weight for this image in the randomization process. Default: n=1. # - "x=(number) y=(number)" positions the image relative to the screen center.
# - "x=(number)" or "x=keep", the x offset from the center. Default: x=0. # - "x=.(decimal) y=.(decimal)" positions the image as a fraction of the resolution.
# - "y=(number)" or "y=keep", the y offset from the center. Default: y=0. # - "o=(0|90|180|270|keep)", the screen orientation, degrees anticlockwise.
# - "o=(0|90|180|270|keep)", the screen orientation, degrees anticlockwise. Default: o=keep. # - "n=(number)", a weight for this image in the randomization process.
# - Default values: o=keep x=.5 y=.382 n=1
# One of the following: # One of the following:
# - "keep" to keep the firmware logo. Also keeps coordinates by default. # - "keep" to keep the firmware logo (and coordinates, unless specified).
# - "remove" to remove the BGRT. Makes x and y meaningless. # - "remove" to remove the BGRT. Makes x and y meaningless.
# - "black" to use only a black image. Makes x and y meaningless. # - "black" to use only a black image. Makes x and y meaningless.
# - "path=file.bmp" to read an image file. # - "path=file.bmp" to read an image file.
@@ -21,9 +22,9 @@ boot=MS
# Examples: # Examples:
# - image=remove # - image=remove
# - image=black # - image=black
# - image= x=0 y=-200 path=topimage.bmp # - image= x=0 y=.0 path=topimage.bmp
# - image= n=1 o=90 path=sideways.bmp # - image= n=1 o=90 path=sideways.bmp
# - image= n=50 y=999999 o=keep path=probable.bmp # - image= n=50 y=999999 path=probable.bmp
# The above examples together would produce # The above examples together would produce
# - 1/54 chance for the default OS logo # - 1/54 chance for the default OS logo
# - 1/54 chance for black screen # - 1/54 chance for black screen
@@ -31,7 +32,7 @@ boot=MS
# - 1/54 chance for splash.bmp, centered, orientation set to 90 degrees # - 1/54 chance for splash.bmp, centered, orientation set to 90 degrees
# - 50/54 chance for probable.bmp, at the bottom edge, explicitly default orientation # - 50/54 chance for probable.bmp, at the bottom edge, explicitly default orientation
# Default: just one image. # Default: just one image.
image= y=-200 path=splash.bmp image= path=splash.bmp
# Preferred resolution. Use 0x0 for maximum and -1x-1 for original. # Preferred resolution. Use 0x0 for maximum and -1x-1 for original.
resolution=0x0 resolution=0x0
+64 -29
View File
@@ -68,54 +68,89 @@ BOOLEAN ReadConfigFile(struct HackBGRT_config* config, EFI_FILE_HANDLE base_dir,
return TRUE; return TRUE;
} }
static void SetBMPWithRandom(struct HackBGRT_config* config, int weight, enum HackBGRT_action action, int x, int y, int o, const CHAR16* path) { static void SetBMPWithRandom(struct HackBGRT_config* config, const struct HackBGRT_image_config* image, int weight) {
config->image_weight_sum += weight; config->image_weight_sum += weight;
UINT32 random = (((UINT64) Random() & 0xffffffff) * config->image_weight_sum) >> 32; UINT32 random = (((UINT64) Random() & 0xffffffff) * config->image_weight_sum) >> 32;
UINT32 limit = ((UINT64) 0xffffffff * weight) >> 32; UINT32 limit = ((UINT64) 0xffffffff * weight) >> 32;
Log(config->debug, L"%s n=%d, action=%d, x=%d, y=%d, o=%d, path=%s, rand=%x/%x\n", random <= limit ? L"Using" : L"Skipping", weight, action, x, y, o, path, random, limit); Log(
config->debug,
L"image n=%d, action=%d, x=%d (mode %d), y=%d (mode %d), o=%d, path=%s, rand=%x/%x, chosen=%d\n",
weight, image->action, image->x, image->x_mode, image->y, image->y_mode, image->orientation, image->path, random, limit, (random <= limit)
);
if (random <= limit) { if (random <= limit) {
config->action = action; config->image = *image;
config->image_path = path;
config->orientation = o;
config->image_x = x;
config->image_y = y;
} }
} }
static int ParseCoordinate(const CHAR16* str, enum HackBGRT_action action) { static void ParseCoordinate(const CHAR16* str, int* out_int, enum HackBGRT_coordinate_mode* out_mode) {
if (str && ((L'0' <= str[0] && str[0] <= L'9') || str[0] == L'-')) { if (!str) {
return str[0] == L'-' ? -(int)Atoi(str+1) : (int)Atoi(str); return;
} }
if ((str && StrnCmp(str, L"keep", 4) == 0) || action == HackBGRT_KEEP) { if (StrnCmp(str, L"keep", 4) == 0) {
return HackBGRT_coord_keep; *out_int = 0;
*out_mode = HackBGRT_COORDINATE_MODE_KEEP;
return;
}
if (str[0] == L'.' && L'0' <= str[1] && str[1] <= L'9') {
int result = 0, i = 1, length = 0;
for (length = 0; length < HackBGRT_FRACTION_DIGITS; ++length) {
result = 10 * result;
if (L'0' <= str[i] && str[i] <= L'9') {
result += str[i] - L'0';
i += 1;
}
}
*out_mode = HackBGRT_COORDINATE_MODE_FRACTION;
*out_int = result;
return;
}
int neg = str[0] == L'-' ? 1 : 0;
if (L'0' <= str[neg] && str[neg] <= L'9') {
*out_int = Atoi(str + neg) * (neg ? -1 : 1);
*out_mode = HackBGRT_COORDINATE_MODE_CENTERED;
return;
} }
return 0;
} }
static void ReadConfigImage(struct HackBGRT_config* config, const CHAR16* line) { static void ReadConfigImage(struct HackBGRT_config* config, const CHAR16* line) {
const CHAR16* n = StrStrAfter(line, L"n="); struct HackBGRT_image_config image = {
const CHAR16* x = StrStrAfter(line, L"x="); .action = HackBGRT_ACTION_KEEP,
const CHAR16* y = StrStrAfter(line, L"y="); .orientation = HackBGRT_ORIENTATION_KEEP,
const CHAR16* o = StrStrAfter(line, L"o="); };
const CHAR16* f = StrStrAfter(line, L"path="); const CHAR16* tmp;
enum HackBGRT_action action = HackBGRT_KEEP; image.path = StrStrAfter(line, L"path=");
if (f) { if (image.path) {
action = HackBGRT_REPLACE; image.action = HackBGRT_ACTION_REPLACE;
// Default: x centered, y 38.2 % (= 1 - 1 / golden_ratio)
image.x_mode = image.y_mode = HackBGRT_COORDINATE_MODE_FRACTION;
image.x = HackBGRT_FRACTION_HALF;
image.y = HackBGRT_FRACTION_381966011;
} else if (StrStr(line, L"remove")) { } else if (StrStr(line, L"remove")) {
action = HackBGRT_REMOVE; image.action = HackBGRT_ACTION_REMOVE;
} else if (StrStr(line, L"black")) { } else if (StrStr(line, L"black")) {
action = HackBGRT_REPLACE; image.action = HackBGRT_ACTION_REPLACE;
image.path = 0;
} else if (StrStr(line, L"keep")) { } else if (StrStr(line, L"keep")) {
action = HackBGRT_KEEP; image.action = HackBGRT_ACTION_KEEP;
image.x_mode = image.y_mode = HackBGRT_COORDINATE_MODE_KEEP;
} else { } else {
Log(1, L"Invalid image line: %s\n", line); Log(1, L"Invalid image line: %s\n", line);
return; return;
} }
int weight = n && (!f || n < f) ? Atoi(n) : 1; ParseCoordinate(StrStrAfter(line, L"x="), &image.x, &image.x_mode);
int x_val = ParseCoordinate(x, action); ParseCoordinate(StrStrAfter(line, L"y="), &image.y, &image.y_mode);
int y_val = ParseCoordinate(y, action); if (StrStrAfter(line, L"o=keep")) {
int o_val = o ? ParseCoordinate(o, action) : HackBGRT_coord_keep; image.orientation = HackBGRT_ORIENTATION_KEEP;
SetBMPWithRandom(config, weight, action, x_val, y_val, o_val, f); } else if ((tmp = StrStrAfter(line, L"o="))) {
// convert orientation in degrees to number 0-3 (* 90 degrees)
int i = tmp[0] == L'-' ? -(int)Atoi(tmp+1) : (int)Atoi(tmp);
image.orientation = (i / 90) & 3;
}
int weight = 1;
if ((tmp = StrStrAfter(line, L"n="))) {
weight = Atoi(tmp);
}
SetBMPWithRandom(config, &image, weight);
} }
static void ReadConfigResolution(struct HackBGRT_config* config, const CHAR16* line) { static void ReadConfigResolution(struct HackBGRT_config* config, const CHAR16* line) {
+36 -8
View File
@@ -6,15 +6,47 @@
* Possible actions to perform on the BGRT. * Possible actions to perform on the BGRT.
*/ */
enum HackBGRT_action { enum HackBGRT_action {
HackBGRT_KEEP = 0, HackBGRT_REPLACE, HackBGRT_REMOVE HackBGRT_ACTION_KEEP = 0,
HackBGRT_ACTION_REPLACE,
HackBGRT_ACTION_REMOVE
}; };
/** /**
* Special values for the image coordinates. * Special values for the image coordinates.
* @see struct HackBGRT_config * @see struct HackBGRT_config
*/ */
enum HackBGRT_coordinate { enum HackBGRT_coordinate_mode {
HackBGRT_coord_keep = -1000001 HackBGRT_COORDINATE_MODE_KEEP = 0,
HackBGRT_COORDINATE_MODE_CENTERED,
HackBGRT_COORDINATE_MODE_FRACTION,
};
/**
* Constants for the fractional coordinates.
*/
enum HackBGRT_fraction {
HackBGRT_FRACTION_DIGITS = 4,
HackBGRT_FRACTION_ONE = 10000,
HackBGRT_FRACTION_HALF = 5000,
HackBGRT_FRACTION_381966011 = 3820,
};
/**
* Possible values for the orientation.
*/
enum HackBGRT_orientation {
HackBGRT_ORIENTATION_KEEP = -1,
};
/**
* The configuration for one image.
*/
struct HackBGRT_image_config {
enum HackBGRT_action action;
const CHAR16* path;
enum HackBGRT_coordinate_mode x_mode, y_mode;
int x, y;
int orientation;
}; };
/** /**
@@ -22,12 +54,8 @@ enum HackBGRT_coordinate {
*/ */
struct HackBGRT_config { struct HackBGRT_config {
int debug, log; int debug, log;
enum HackBGRT_action action; struct HackBGRT_image_config image;
const CHAR16* image_path;
int image_x;
int image_y;
int image_weight_sum; int image_weight_sum;
int orientation;
int resolution_x; int resolution_x;
int resolution_y; int resolution_y;
int old_resolution_x; int old_resolution_x;
+26 -18
View File
@@ -21,7 +21,6 @@ EFI_RUNTIME_SERVICES *RT;
*/ */
static struct HackBGRT_config config = { static struct HackBGRT_config config = {
.log = 1, .log = 1,
.action = HackBGRT_KEEP,
}; };
/** /**
@@ -163,13 +162,13 @@ static ACPI_BGRT* HandleAcpiTables(enum HackBGRT_action action, ACPI_BGRT* bgrt)
} }
Log(config.debug, L" - ACPI table @%x: %s, revision = %d, OEM ID = %s\n", (UINTN)entry, TmpStr(entry->signature, 4), entry->revision, TmpStr(entry->oem_id, 6)); Log(config.debug, L" - ACPI table @%x: %s, revision = %d, OEM ID = %s\n", (UINTN)entry, TmpStr(entry->signature, 4), entry->revision, TmpStr(entry->oem_id, 6));
switch (action) { switch (action) {
case HackBGRT_KEEP: case HackBGRT_ACTION_KEEP:
if (!bgrt) { if (!bgrt) {
Log(config.debug, L" -> Returning this one for later use.\n"); Log(config.debug, L" -> Returning this one for later use.\n");
bgrt = (ACPI_BGRT*) entry; bgrt = (ACPI_BGRT*) entry;
} }
break; break;
case HackBGRT_REMOVE: case HackBGRT_ACTION_REMOVE:
Log(config.debug, L" -> Deleting.\n"); Log(config.debug, L" -> Deleting.\n");
for (int k = j+1; k < entry_arr_length; ++k) { for (int k = j+1; k < entry_arr_length; ++k) {
entry_arr[k-1] = entry_arr[k]; entry_arr[k-1] = entry_arr[k];
@@ -179,13 +178,13 @@ static ACPI_BGRT* HandleAcpiTables(enum HackBGRT_action action, ACPI_BGRT* bgrt)
xsdt->length -= sizeof(entry_arr[0]); xsdt->length -= sizeof(entry_arr[0]);
--j; --j;
break; break;
case HackBGRT_REPLACE: case HackBGRT_ACTION_REPLACE:
Log(config.debug, L" -> Replacing.\n"); Log(config.debug, L" -> Replacing.\n");
entry_arr[j] = (UINTN) bgrt; entry_arr[j] = (UINTN) bgrt;
} }
bgrt_count += 1; bgrt_count += 1;
} }
if (!bgrt_count && action == HackBGRT_REPLACE && bgrt) { if (!bgrt_count && action == HackBGRT_ACTION_REPLACE && bgrt) {
Log(config.debug, L" - Adding missing BGRT.\n"); Log(config.debug, L" - Adding missing BGRT.\n");
xsdt = CreateXsdt(xsdt, entry_arr_length + 1); xsdt = CreateXsdt(xsdt, entry_arr_length + 1);
entry_arr = (UINT64*)&xsdt[1]; entry_arr = (UINT64*)&xsdt[1];
@@ -303,13 +302,13 @@ static void CropBMP(BMP* bmp, int w, int h) {
*/ */
void HackBgrt(EFI_FILE_HANDLE base_dir) { void HackBgrt(EFI_FILE_HANDLE base_dir) {
// REMOVE: simply delete all BGRT entries. // REMOVE: simply delete all BGRT entries.
if (config.action == HackBGRT_REMOVE) { if (config.image.action == HackBGRT_ACTION_REMOVE) {
HandleAcpiTables(config.action, 0); HandleAcpiTables(config.image.action, 0);
return; return;
} }
// KEEP/REPLACE: first get the old BGRT entry. // KEEP/REPLACE: first get the old BGRT entry.
ACPI_BGRT* bgrt = HandleAcpiTables(HackBGRT_KEEP, 0); ACPI_BGRT* bgrt = HandleAcpiTables(HackBGRT_ACTION_KEEP, 0);
// Get the old BMP and position (relative to screen center), if possible. // Get the old BMP and position (relative to screen center), if possible.
const int old_valid = bgrt && VerifyAcpiSdtChecksum(bgrt); const int old_valid = bgrt && VerifyAcpiSdtChecksum(bgrt);
@@ -324,7 +323,7 @@ void HackBgrt(EFI_FILE_HANDLE base_dir) {
// Missing BGRT? // Missing BGRT?
if (!bgrt) { if (!bgrt) {
// Keep missing = do nothing. // Keep missing = do nothing.
if (config.action == HackBGRT_KEEP) { if (config.image.action == HackBGRT_ACTION_KEEP) {
return; return;
} }
// Replace missing = allocate new. // Replace missing = allocate new.
@@ -351,13 +350,13 @@ void HackBgrt(EFI_FILE_HANDLE base_dir) {
// Get the image (either old or new). // Get the image (either old or new).
BMP* new_bmp = old_bmp; BMP* new_bmp = old_bmp;
if (config.action == HackBGRT_REPLACE) { if (config.image.action == HackBGRT_ACTION_REPLACE) {
new_bmp = LoadBMP(base_dir, config.image_path); new_bmp = LoadBMP(base_dir, config.image.path);
} }
// No image = no need for BGRT. // No image = no need for BGRT.
if (!new_bmp) { if (!new_bmp) {
HandleAcpiTables(HackBGRT_REMOVE, 0); HandleAcpiTables(HackBGRT_ACTION_REMOVE, 0);
return; return;
} }
@@ -366,16 +365,23 @@ void HackBgrt(EFI_FILE_HANDLE base_dir) {
// Set the image address and orientation. // Set the image address and orientation.
bgrt->image_address = (UINTN) new_bmp; bgrt->image_address = (UINTN) new_bmp;
const int new_orientation = config.orientation == HackBGRT_coord_keep ? old_orientation : ((config.orientation / 90) & 3); const int new_orientation = config.image.orientation == HackBGRT_ORIENTATION_KEEP ? old_orientation : config.image.orientation;
bgrt->status = new_orientation << 1; bgrt->status = new_orientation << 1;
// New center coordinates. // New center coordinates.
const int new_x = config.image_x == HackBGRT_coord_keep ? old_x : config.image_x;
const int new_y = config.image_y == HackBGRT_coord_keep ? old_y : config.image_y;
const int new_swap = new_orientation & 1; const int new_swap = new_orientation & 1;
const int new_reso_x = new_swap ? config.resolution_y : config.resolution_x; const int new_reso_x = new_swap ? config.resolution_y : config.resolution_x;
const int new_reso_y = new_swap ? config.resolution_x : config.resolution_y; const int new_reso_y = new_swap ? config.resolution_x : config.resolution_y;
const int new_x =
config.image.x_mode == HackBGRT_COORDINATE_MODE_KEEP ? old_x :
config.image.x_mode == HackBGRT_COORDINATE_MODE_CENTERED ? config.image.x :
(config.image.x - HackBGRT_FRACTION_HALF) * new_reso_x / HackBGRT_FRACTION_ONE;
const int new_y =
config.image.y_mode == HackBGRT_COORDINATE_MODE_KEEP ? old_y :
config.image.y_mode == HackBGRT_COORDINATE_MODE_CENTERED ? config.image.y :
(config.image.y - HackBGRT_FRACTION_HALF) * new_reso_y / HackBGRT_FRACTION_ONE;
// Calculate absolute position. // Calculate absolute position.
const int max_x = new_reso_x - new_bmp->width; const int max_x = new_reso_x - new_bmp->width;
const int max_y = new_reso_y - new_bmp->height; const int max_y = new_reso_y - new_bmp->height;
@@ -383,15 +389,17 @@ void HackBgrt(EFI_FILE_HANDLE base_dir) {
bgrt->image_offset_y = max(0, min(max_y, new_y + (new_reso_y - new_bmp->height) / 2)); bgrt->image_offset_y = max(0, min(max_y, new_y + (new_reso_y - new_bmp->height) / 2));
Log(config.debug, Log(config.debug,
L"BMP at (%d, %d), center (%d, %d), resolution (%d, %d), orientation %d.\n", L"Screen %dx%d, BMP %dx%d, center (%d, %d) = corner (%d, %d), orientation %d.\n",
new_reso_x, new_reso_y,
new_bmp->width, new_bmp->height,
new_x, new_y,
(int) bgrt->image_offset_x, (int) bgrt->image_offset_y, (int) bgrt->image_offset_x, (int) bgrt->image_offset_y,
new_x, new_y, new_reso_x, new_reso_y,
new_orientation * 90 new_orientation * 90
); );
// Store this BGRT in the ACPI tables. // Store this BGRT in the ACPI tables.
SetAcpiSdtChecksum(bgrt); SetAcpiSdtChecksum(bgrt);
HandleAcpiTables(HackBGRT_REPLACE, bgrt); HandleAcpiTables(HackBGRT_ACTION_REPLACE, bgrt);
} }
/** /**