From 683ee491109fc8b6b632154539aabfcf7191b7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauri=20Kentt=C3=A4?= Date: Sat, 28 Mar 2026 21:51:13 +0200 Subject: [PATCH] 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 --- config.txt | 17 +++++----- src/config.c | 93 ++++++++++++++++++++++++++++++++++++---------------- src/config.h | 44 ++++++++++++++++++++----- src/main.c | 44 +++++++++++++++---------- 4 files changed, 135 insertions(+), 63 deletions(-) diff --git a/config.txt b/config.txt index 2e1a2b8..f725a9e 100644 --- a/config.txt +++ b/config.txt @@ -8,12 +8,13 @@ boot=MS # Multiple image lines may be present, in which case one will be picked by random. # The image line may contain the following parts: # Any of the following: -# - "n=(number)", a weight for this image in the randomization process. Default: n=1. -# - "x=(number)" or "x=keep", the x offset from the center. Default: x=0. -# - "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. Default: o=keep. +# - "x=(number) y=(number)" positions the image relative to the screen center. +# - "x=.(decimal) y=.(decimal)" positions the image as a fraction of the resolution. +# - "o=(0|90|180|270|keep)", the screen orientation, degrees anticlockwise. +# - "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: -# - "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. # - "black" to use only a black image. Makes x and y meaningless. # - "path=file.bmp" to read an image file. @@ -21,9 +22,9 @@ boot=MS # Examples: # - image=remove # - 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=50 y=999999 o=keep path=probable.bmp +# - image= n=50 y=999999 path=probable.bmp # The above examples together would produce # - 1/54 chance for the default OS logo # - 1/54 chance for black screen @@ -31,7 +32,7 @@ boot=MS # - 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 # 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. resolution=0x0 diff --git a/src/config.c b/src/config.c index 1bd6084..ac7e59f 100644 --- a/src/config.c +++ b/src/config.c @@ -68,54 +68,89 @@ BOOLEAN ReadConfigFile(struct HackBGRT_config* config, EFI_FILE_HANDLE base_dir, 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; UINT32 random = (((UINT64) Random() & 0xffffffff) * config->image_weight_sum) >> 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) { - config->action = action; - config->image_path = path; - config->orientation = o; - config->image_x = x; - config->image_y = y; + config->image = *image; } } -static int ParseCoordinate(const CHAR16* str, enum HackBGRT_action action) { - if (str && ((L'0' <= str[0] && str[0] <= L'9') || str[0] == L'-')) { - return str[0] == L'-' ? -(int)Atoi(str+1) : (int)Atoi(str); +static void ParseCoordinate(const CHAR16* str, int* out_int, enum HackBGRT_coordinate_mode* out_mode) { + if (!str) { + return; } - if ((str && StrnCmp(str, L"keep", 4) == 0) || action == HackBGRT_KEEP) { - return HackBGRT_coord_keep; + if (StrnCmp(str, L"keep", 4) == 0) { + *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) { - const CHAR16* n = StrStrAfter(line, L"n="); - const CHAR16* x = StrStrAfter(line, L"x="); - const CHAR16* y = StrStrAfter(line, L"y="); - const CHAR16* o = StrStrAfter(line, L"o="); - const CHAR16* f = StrStrAfter(line, L"path="); - enum HackBGRT_action action = HackBGRT_KEEP; - if (f) { - action = HackBGRT_REPLACE; + struct HackBGRT_image_config image = { + .action = HackBGRT_ACTION_KEEP, + .orientation = HackBGRT_ORIENTATION_KEEP, + }; + const CHAR16* tmp; + image.path = StrStrAfter(line, L"path="); + if (image.path) { + 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")) { - action = HackBGRT_REMOVE; + image.action = HackBGRT_ACTION_REMOVE; } else if (StrStr(line, L"black")) { - action = HackBGRT_REPLACE; + image.action = HackBGRT_ACTION_REPLACE; + image.path = 0; } 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 { Log(1, L"Invalid image line: %s\n", line); return; } - int weight = n && (!f || n < f) ? Atoi(n) : 1; - int x_val = ParseCoordinate(x, action); - int y_val = ParseCoordinate(y, action); - int o_val = o ? ParseCoordinate(o, action) : HackBGRT_coord_keep; - SetBMPWithRandom(config, weight, action, x_val, y_val, o_val, f); + ParseCoordinate(StrStrAfter(line, L"x="), &image.x, &image.x_mode); + ParseCoordinate(StrStrAfter(line, L"y="), &image.y, &image.y_mode); + if (StrStrAfter(line, L"o=keep")) { + image.orientation = HackBGRT_ORIENTATION_KEEP; + } 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) { diff --git a/src/config.h b/src/config.h index 90b4705..eda80da 100644 --- a/src/config.h +++ b/src/config.h @@ -6,15 +6,47 @@ * Possible actions to perform on the BGRT. */ 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. * @see struct HackBGRT_config */ -enum HackBGRT_coordinate { - HackBGRT_coord_keep = -1000001 +enum HackBGRT_coordinate_mode { + 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 { int debug, log; - enum HackBGRT_action action; - const CHAR16* image_path; - int image_x; - int image_y; + struct HackBGRT_image_config image; int image_weight_sum; - int orientation; int resolution_x; int resolution_y; int old_resolution_x; diff --git a/src/main.c b/src/main.c index c508d6d..690b246 100644 --- a/src/main.c +++ b/src/main.c @@ -21,7 +21,6 @@ EFI_RUNTIME_SERVICES *RT; */ static struct HackBGRT_config config = { .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)); switch (action) { - case HackBGRT_KEEP: + case HackBGRT_ACTION_KEEP: if (!bgrt) { Log(config.debug, L" -> Returning this one for later use.\n"); bgrt = (ACPI_BGRT*) entry; } break; - case HackBGRT_REMOVE: + case HackBGRT_ACTION_REMOVE: Log(config.debug, L" -> Deleting.\n"); for (int k = j+1; k < entry_arr_length; ++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]); --j; break; - case HackBGRT_REPLACE: + case HackBGRT_ACTION_REPLACE: Log(config.debug, L" -> Replacing.\n"); entry_arr[j] = (UINTN) bgrt; } 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"); xsdt = CreateXsdt(xsdt, entry_arr_length + 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) { // REMOVE: simply delete all BGRT entries. - if (config.action == HackBGRT_REMOVE) { - HandleAcpiTables(config.action, 0); + if (config.image.action == HackBGRT_ACTION_REMOVE) { + HandleAcpiTables(config.image.action, 0); return; } // 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. const int old_valid = bgrt && VerifyAcpiSdtChecksum(bgrt); @@ -324,7 +323,7 @@ void HackBgrt(EFI_FILE_HANDLE base_dir) { // Missing BGRT? if (!bgrt) { // Keep missing = do nothing. - if (config.action == HackBGRT_KEEP) { + if (config.image.action == HackBGRT_ACTION_KEEP) { return; } // Replace missing = allocate new. @@ -351,13 +350,13 @@ void HackBgrt(EFI_FILE_HANDLE base_dir) { // Get the image (either old or new). BMP* new_bmp = old_bmp; - if (config.action == HackBGRT_REPLACE) { - new_bmp = LoadBMP(base_dir, config.image_path); + if (config.image.action == HackBGRT_ACTION_REPLACE) { + new_bmp = LoadBMP(base_dir, config.image.path); } // No image = no need for BGRT. if (!new_bmp) { - HandleAcpiTables(HackBGRT_REMOVE, 0); + HandleAcpiTables(HackBGRT_ACTION_REMOVE, 0); return; } @@ -366,16 +365,23 @@ void HackBgrt(EFI_FILE_HANDLE base_dir) { // Set the image address and orientation. 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; // 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_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_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. const int max_x = new_reso_x - new_bmp->width; 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)); 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, - new_x, new_y, new_reso_x, new_reso_y, new_orientation * 90 ); // Store this BGRT in the ACPI tables. SetAcpiSdtChecksum(bgrt); - HandleAcpiTables(HackBGRT_REPLACE, bgrt); + HandleAcpiTables(HackBGRT_ACTION_REPLACE, bgrt); } /**