Files
HyperDRM/native/layout.h
T
2026-10-06 22:01:38 +02:00

97 lines
3.8 KiB
C

#ifndef HYPERION_LAYOUT_H
#define HYPERION_LAYOUT_H
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <math.h>
typedef struct {
unsigned char a, b;
unsigned weight;
} LedBlend;
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include "calibration.h"
static double screen_perimeter(double x, double y) {
double distances[] = {y, 1 - x, 1 - y, x}, positions[] = {x, 1 + y, 3 - x, 4 - y};
unsigned edge = 0;
for (unsigned i = 1; i < 4; i++)
if (distances[i] < distances[edge])
edge = i;
return positions[edge] >= 4 ? positions[edge] - 4 : positions[edge];
}
static LedBlend layout_blend(double x, double y) {
const RimPoint *rim = calibration_effective() == CAL_CUSTOM ? calibration.points : g4_rim;
double t = screen_perimeter(x, y);
unsigned n = calibration_effective() == CAL_CUSTOM ? calibration.count
: sizeof(g4_rim) / sizeof(*g4_rim),
right = 0;
while (right < n && rim[right].position <= t)
right++;
right %= n;
unsigned left = (right + n - 1) % n;
double span = rim[right].position - rim[left].position, distance = t - rim[left].position;
if (span <= 0)
span += 4;
if (distance < 0)
distance += 4;
return (LedBlend){rim[left].region, rim[right].region,
(unsigned)(distance / span * 65535 + 0.5)};
}
/* Use the TV's JSON-C library; validate every rectangle before replacing the
* layout. The safety limit is independent of the installed LED count. */
static bool layout_from_json(const char *text, LedBlend **result, unsigned *count) {
void *lib = dlopen("libjson-c.so.5", RTLD_NOW);
if (!lib)
return false;
void *(*parse)(const char *) = dlsym(lib, "json_tokener_parse");
int (*get)(const void *, const char *, void **) = dlsym(lib, "json_object_object_get_ex");
int (*type)(const void *) = dlsym(lib, "json_object_get_type");
size_t (*length)(const void *) = dlsym(lib, "json_object_array_length");
void *(*at)(const void *, size_t) = dlsym(lib, "json_object_array_get_idx");
double (*number)(const void *) = dlsym(lib, "json_object_get_double");
int (*put)(void *) = dlsym(lib, "json_object_put");
if (!parse || !get || !type || !length || !at || !number || !put) {
dlclose(lib);
return false;
}
void *root = parse(text), *info = NULL, *leds = NULL;
bool valid = root && type(root) == 4 && get(root, "info", &info) && type(info) == 4 &&
get(info, "leds", &leds) && type(leds) == 5;
size_t n = valid ? length(leds) : 0;
valid = valid && n > 0 && n <= 16384;
LedBlend *mapping = valid ? calloc(n, sizeof(*mapping)) : NULL;
valid = valid && mapping;
const char *keys[] = {"hmin", "hmax", "vmin", "vmax"};
for (size_t i = 0; valid && i < n; i++) {
void *led = at(leds, i);
double coordinates[4];
valid = led && type(led) == 4;
for (unsigned c = 0; valid && c < 4; c++) {
void *v = NULL;
valid = get(led, keys[c], &v) && (type(v) == 2 || type(v) == 3);
if (valid) {
coordinates[c] = number(v);
valid = isfinite(coordinates[c]) && coordinates[c] >= 0 && coordinates[c] <= 1;
}
}
if (valid)
valid = coordinates[0] <= coordinates[1] && coordinates[2] <= coordinates[3];
if (valid)
mapping[i] = layout_blend((coordinates[0] + coordinates[1]) / 2,
(coordinates[2] + coordinates[3]) / 2);
}
if (root)
put(root);
dlclose(lib);
if (!valid) {
free(mapping);
return false;
}
*result = mapping;
*count = (unsigned)n;
return true;
}
#endif