feat: xorg viewer scale modes, resize fix, arch notes
Scale modes (STRETCH/FIT/FILL/1:1) with CENTER/TOP_LEFT anchor: - UV crop via u_uv_scale/u_uv_offset uniforms in vertex shader - glViewport sub-rect + glClear for FIT and 1:1 modes - xorg_viewer_set_scale() / xorg_viewer_set_anchor() setters - Stub implementations for both Resize fix: glfwSetWindowUserPointer + framebuffer_size_callback calls render() synchronously during resize so image tracks window edge immediately. Forward declaration added to fix implicit decl error. Q/Escape close the window via key_callback. xorg_cli: --scale and --anchor arguments added. architecture.md: - Scale mode table and anchor docs in Frame Viewer Sink section - Render loop design note: frame-driven not timer-driven, resize callback rationale, threading note (GL context ownership, frame queue) - Text overlay section: tier 1 bitmap atlas (Pillow build tool, skyline packing, quad rendering), tier 2 HarfBuzz+FreeType, migration path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ DISCOVERY_OBJ = $(BUILD)/discovery/discovery.o
|
||||
CONFIG_OBJ = $(BUILD)/config/config.o
|
||||
PROTOCOL_OBJ = $(BUILD)/protocol/protocol.o
|
||||
TEST_IMAGE_OBJ = $(BUILD)/test_image/test_image.o
|
||||
XORG_OBJ = $(BUILD)/xorg/xorg.o
|
||||
|
||||
CLI_SRCS = \
|
||||
media_ctrl_cli.c \
|
||||
@@ -20,7 +21,8 @@ CLI_SRCS = \
|
||||
config_cli.c \
|
||||
protocol_cli.c \
|
||||
query_cli.c \
|
||||
test_image_cli.c
|
||||
test_image_cli.c \
|
||||
xorg_cli.c
|
||||
|
||||
CLI_OBJS = $(CLI_SRCS:%.c=$(CLI_BUILD)/%.o)
|
||||
|
||||
@@ -34,7 +36,8 @@ all: \
|
||||
$(CLI_BUILD)/config_cli \
|
||||
$(CLI_BUILD)/protocol_cli \
|
||||
$(CLI_BUILD)/query_cli \
|
||||
$(CLI_BUILD)/test_image_cli
|
||||
$(CLI_BUILD)/test_image_cli \
|
||||
$(CLI_BUILD)/xorg_cli
|
||||
|
||||
# Module objects delegate to their sub-makes.
|
||||
$(COMMON_OBJ): ; $(MAKE) -C $(ROOT)/src/modules/common
|
||||
@@ -46,6 +49,7 @@ $(DISCOVERY_OBJ): ; $(MAKE) -C $(ROOT)/src/modules/discovery
|
||||
$(CONFIG_OBJ): ; $(MAKE) -C $(ROOT)/src/modules/config
|
||||
$(PROTOCOL_OBJ): ; $(MAKE) -C $(ROOT)/src/modules/protocol
|
||||
$(TEST_IMAGE_OBJ): ; $(MAKE) -C $(ROOT)/src/modules/test_image
|
||||
$(XORG_OBJ): ; $(MAKE) -C $(ROOT)/src/modules/xorg
|
||||
|
||||
# Compile each CLI source to its own .o (generates .d alongside).
|
||||
$(CLI_BUILD)/%.o: %.c | $(CLI_BUILD)
|
||||
@@ -76,6 +80,9 @@ $(CLI_BUILD)/query_cli: $(CLI_BUILD)/query_cli.o $(COMMON_OBJ) $(SERIAL_OBJ) $(T
|
||||
$(CLI_BUILD)/test_image_cli: $(CLI_BUILD)/test_image_cli.o $(TEST_IMAGE_OBJ)
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
$(CLI_BUILD)/xorg_cli: $(CLI_BUILD)/xorg_cli.o $(TEST_IMAGE_OBJ) $(XORG_OBJ)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(PKG_LDFLAGS)
|
||||
|
||||
$(CLI_BUILD):
|
||||
mkdir -p $@
|
||||
|
||||
@@ -90,6 +97,7 @@ clean:
|
||||
$(CLI_BUILD)/config_cli \
|
||||
$(CLI_BUILD)/protocol_cli \
|
||||
$(CLI_BUILD)/query_cli \
|
||||
$(CLI_BUILD)/test_image_cli
|
||||
$(CLI_BUILD)/test_image_cli \
|
||||
$(CLI_BUILD)/xorg_cli
|
||||
|
||||
-include $(CLI_OBJS:%.o=%.d)
|
||||
|
||||
125
dev/cli/xorg_cli.c
Normal file
125
dev/cli/xorg_cli.c
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test_image.h"
|
||||
#include "xorg.h"
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: xorg_cli [--pattern bars|ramp|grid]\n"
|
||||
" [--width N] [--height N]\n"
|
||||
" [--format yuv420|bgra]\n"
|
||||
" [--scale stretch|fit|fill|1:1]\n"
|
||||
" [--anchor center|topleft]\n"
|
||||
" [--x N] [--y N]\n"
|
||||
"\n"
|
||||
"Opens a window and renders a test image using the xorg viewer sink.\n"
|
||||
"Q or Escape closes the window.\n"
|
||||
"\n"
|
||||
"defaults: bars 1280x720 yuv420 stretch center at 0,0\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Test_Pattern pattern = TEST_PATTERN_BARS;
|
||||
Test_Fmt fmt = TEST_FMT_YUV420;
|
||||
Xorg_Scale scale = XORG_SCALE_STRETCH;
|
||||
Xorg_Anchor anchor = XORG_ANCHOR_CENTER;
|
||||
int width = 1280;
|
||||
int height = 720;
|
||||
int win_x = 0;
|
||||
int win_y = 0;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--pattern") == 0 && i + 1 < argc) {
|
||||
i++;
|
||||
if (strcmp(argv[i], "bars") == 0) { pattern = TEST_PATTERN_BARS; }
|
||||
else if (strcmp(argv[i], "ramp") == 0) { pattern = TEST_PATTERN_RAMP; }
|
||||
else if (strcmp(argv[i], "grid") == 0) { pattern = TEST_PATTERN_GRID; }
|
||||
else { fprintf(stderr, "unknown pattern: %s\n", argv[i]); usage(); return 1; }
|
||||
} else if (strcmp(argv[i], "--width") == 0 && i + 1 < argc) {
|
||||
width = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "--height") == 0 && i + 1 < argc) {
|
||||
height = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "--x") == 0 && i + 1 < argc) {
|
||||
win_x = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "--y") == 0 && i + 1 < argc) {
|
||||
win_y = atoi(argv[++i]);
|
||||
} else if (strcmp(argv[i], "--scale") == 0 && i + 1 < argc) {
|
||||
i++;
|
||||
if (strcmp(argv[i], "stretch") == 0) { scale = XORG_SCALE_STRETCH; }
|
||||
else if (strcmp(argv[i], "fit") == 0) { scale = XORG_SCALE_FIT; }
|
||||
else if (strcmp(argv[i], "fill") == 0) { scale = XORG_SCALE_FILL; }
|
||||
else if (strcmp(argv[i], "1:1") == 0) { scale = XORG_SCALE_1_1; }
|
||||
else { fprintf(stderr, "unknown scale: %s\n", argv[i]); usage(); return 1; }
|
||||
} else if (strcmp(argv[i], "--anchor") == 0 && i + 1 < argc) {
|
||||
i++;
|
||||
if (strcmp(argv[i], "center") == 0) { anchor = XORG_ANCHOR_CENTER; }
|
||||
else if (strcmp(argv[i], "topleft") == 0) { anchor = XORG_ANCHOR_TOP_LEFT; }
|
||||
else { fprintf(stderr, "unknown anchor: %s\n", argv[i]); usage(); return 1; }
|
||||
} else if (strcmp(argv[i], "--format") == 0 && i + 1 < argc) {
|
||||
i++;
|
||||
if (strcmp(argv[i], "yuv420") == 0) { fmt = TEST_FMT_YUV420; }
|
||||
else if (strcmp(argv[i], "bgra") == 0) { fmt = TEST_FMT_BGRA; }
|
||||
else { fprintf(stderr, "unknown format: %s\n", argv[i]); usage(); return 1; }
|
||||
} else {
|
||||
usage(); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!xorg_available()) {
|
||||
fprintf(stderr, "xorg_cli: built without HAVE_GLFW — viewer not available\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (width < 2 || height < 2) {
|
||||
fprintf(stderr, "xorg_cli: width and height must be >= 2\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Test_Frame *f = test_image_alloc(width, height, fmt);
|
||||
if (!f) {
|
||||
fprintf(stderr, "xorg_cli: allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
test_image_generate(f, pattern);
|
||||
|
||||
const char *pat_name = pattern == TEST_PATTERN_BARS ? "bars"
|
||||
: pattern == TEST_PATTERN_RAMP ? "ramp"
|
||||
: "grid";
|
||||
const char *fmt_name = fmt == TEST_FMT_YUV420 ? "yuv420" : "bgra";
|
||||
const char *scale_name = scale == XORG_SCALE_STRETCH ? "stretch"
|
||||
: scale == XORG_SCALE_FIT ? "fit"
|
||||
: scale == XORG_SCALE_FILL ? "fill"
|
||||
: "1:1";
|
||||
const char *anchor_name = anchor == XORG_ANCHOR_CENTER ? "center" : "topleft";
|
||||
|
||||
printf("opening %dx%d %s %s scale=%s anchor=%s at (%d,%d)\n",
|
||||
width, height, fmt_name, pat_name, scale_name, anchor_name, win_x, win_y);
|
||||
|
||||
Xorg_Viewer *v = xorg_viewer_open(win_x, win_y, width, height, "xorg_cli");
|
||||
xorg_viewer_set_scale(v, scale);
|
||||
xorg_viewer_set_anchor(v, anchor);
|
||||
if (!v) {
|
||||
fprintf(stderr, "xorg_cli: failed to open viewer window\n");
|
||||
test_image_free(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fmt == TEST_FMT_YUV420) {
|
||||
xorg_viewer_push_yuv420(v,
|
||||
f->plane[0], f->plane[1], f->plane[2],
|
||||
f->width, f->height);
|
||||
} else {
|
||||
xorg_viewer_push_bgra(v, f->plane[0], f->width, f->height);
|
||||
}
|
||||
|
||||
test_image_free(f);
|
||||
|
||||
while (xorg_viewer_poll(v)) { /* wait for window close */ }
|
||||
|
||||
xorg_viewer_close(v);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user