ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
test_pattern.c File Reference

Go to the source code of this file.

Data Structures

struct  test_pattern
 test pattern is intentionally a small, concrete record. Fields such as image, rgba give callers the identity and current value they need. It is normally borrowed from, or owned by, the surrounding subsystem—not independently managed. More...

Macros

#define TEST_PATTERN_GRADIENT_INTERVALS   4096

Functions

asciichat_error_t test_pattern_resize (test_pattern_t *p, int width, int height)
asciichat_error_t test_pattern_create (int width, int height, test_pattern_t **out)
void test_pattern_destroy (test_pattern_t *p)
image_t * test_pattern_image (test_pattern_t *p)
const uint8_t * test_pattern_rgba (test_pattern_t *p)
asciichat_error_t test_pattern_render (test_pattern_t *p, int index, double time_ms, bool cadence)
asciichat_error_t test_pattern_render_at (test_pattern_t *p, int index, double time_ms, bool cadence)

Macro Definition Documentation

◆ TEST_PATTERN_GRADIENT_INTERVALS

#define TEST_PATTERN_GRADIENT_INTERVALS   4096

Definition at line 3 of file video/anim/test_pattern.c.

Referenced by test_pattern_render_at().

Function Documentation

◆ test_pattern_create()

asciichat_error_t test_pattern_create ( int width,
int height,
test_pattern_t ** out )

Independent, reusable RGB renderer. Time is elapsed milliseconds, not frame count.

Definition at line 109 of file video/anim/test_pattern.c.

109 {
110 if (!out)
111 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing test pattern output");
112 *out = NULL;
113 test_pattern_t *p = SAFE_CALLOC(1, sizeof(*p), test_pattern_t *);
115 if (result != ASCIICHAT_OK) {
117 return result;
118 }
119 *out = p;
120 return ASCIICHAT_OK;
121}
#define SET_ERRNO(code,...)
unsigned int height
Definition fft.c:23
unsigned int width
Definition fft.c:23
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
static bool size_t gotel_query_t * out
Definition queries.h:8
void test_pattern_destroy(test_pattern_t *p)
asciichat_error_t test_pattern_resize(test_pattern_t *p, int width, int height)
struct test_pattern test_pattern_t

References ASCIICHAT_OK, ERROR_INVALID_PARAM, height, out, SAFE_CALLOC, SET_ERRNO, test_pattern_destroy(), test_pattern_resize(), and width.

Referenced by TestPatternBinding::TestPatternBinding().

◆ test_pattern_destroy()

void test_pattern_destroy ( test_pattern_t * p)

Definition at line 122 of file video/anim/test_pattern.c.

122 {
123 if (!p)
124 return;
125 if (p->image)
127 SAFE_FREE(p->rgba);
128 SAFE_FREE(p);
129}
#define SAFE_FREE(ptr)
Definition common.h:377
void image_destroy(image_t *image)
Destroy an image allocated with image_new().

References test_pattern::image, image_destroy(), test_pattern::rgba, and SAFE_FREE.

Referenced by media_source_destroy(), test_pattern_create(), and TestPatternBinding::~TestPatternBinding().

◆ test_pattern_image()

image_t * test_pattern_image ( test_pattern_t * p)

Definition at line 130 of file video/anim/test_pattern.c.

130 {
131 return p ? p->image : NULL;
132}

References test_pattern::image.

◆ test_pattern_render()

asciichat_error_t test_pattern_render ( test_pattern_t * p,
int index,
double time_ms,
bool cadence )

Definition at line 149 of file video/anim/test_pattern.c.

149 {
150 animation_sample_t sample;
151 animation_config_t config = {.type = ANIMATION_TEST_PATTERN, .fps = 60, .speed = 1};
152 asciichat_error_t err = animation_sample_at(config, time_ms / 1000.0, &sample);
153 if (err != ASCIICHAT_OK)
154 return err;
156 .test_pattern = {.context = p, .index = index, .cadence = cadence}};
157 return animation_apply(&sample, &target);
158}
static bool size_t index
Definition queries.h:8
For animation config, this is the live record that ties type, fps, speed, hidden_policy together....
asciichat_error_t animation_apply(const animation_sample_t *s, animation_target_t *t)
asciichat_error_t animation_sample_at(animation_config_t config, double seconds, animation_sample_t *out)
@ ANIMATION_TEST_PATTERN
@ ANIMATION_TARGET_TEST_PATTERN

References animation_apply(), animation_sample_at(), ANIMATION_TARGET_TEST_PATTERN, ANIMATION_TEST_PATTERN, ASCIICHAT_OK, and index.

Referenced by TestPatternBinding::render().

◆ test_pattern_render_at()

asciichat_error_t test_pattern_render_at ( test_pattern_t * p,
int index,
double time_ms,
bool cadence )

Definition at line 160 of file video/anim/test_pattern.c.

160 {
161 if (!p || !p->image || index < 0 || index > 1 || !isfinite(time_ms) || time_ms < 0)
162 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid test pattern frame parameters");
163 int w = p->image->w, h = p->image->h;
164 double phase = fmod(time_ms, index ? 4000 : 10000) / (index ? 4000 : 10000);
165 rgb_pixel_t dark = {16, 24, 32}, white = {255, 255, 255};
166 rgb_pixel_t first = hue(phase * 360, 0.5), last = hue(fmod(phase + 0.5, 1) * 360, 0.5);
167 double box = fmin(fmax(32, fmin(w, h) / 4.0), fmin(w, h) / 2.0);
168 double bx = fmod(time_ms / 11, w + box) - box, by = fmod(time_ms / 17, h + box) - box;
169 double stripe = w / 12.0, offset = phase * w;
170 int first_stripe = (int)ceil(-offset / stripe);
171 double radius = fmin(fmax(12, fmin(w, h) / 8.0), fmin(w, h) / 4.0);
172 double cx = w + radius - phase * (w + radius * 2), cy = h / 2.0 + sin(phase * 12.566370614359172) * h / 4.0;
174 for (int i = 0; i < 12; i++)
175 colors[i] = hue(i * 30, 0.55);
176 uint32_t frame = (uint32_t)fmod(floor(time_ms / (1000.0 / 60)), 512);
177 uint32_t code = frame ^ (frame >> 1);
178 const int slots[8] = {6, 4, 2, 0, 1, 3, 5, 7};
179 rgb_pixel_t *pixels = p->image->pixels;
180 if (index == 1) {
181 // The background is constant down each column. Rasterize one row, then copy.
182 for (int x = 0; x < w; x++) {
183 rgb_pixel_t pixel = dark;
184 if (cadence) {
185 int slot = (int)(x / fmax(2, w / 8.0));
186 if (slot < 8)
187 pixel = (code & (1u << slots[slot])) ? white : (rgb_pixel_t){0, 0, 0};
188 } else {
189 int k = (int)floor((x - offset) / stripe) + 1;
190 for (int j = k; j <= k + 1; j++)
191 if (j >= first_stripe && j <= first_stripe + 12)
192 blend(&pixel, colors[(j % 12 + 12) % 12], overlap(x, j * stripe + offset - stripe, j * stripe + offset));
193 }
194 pixels[x] = pixel;
195 }
196 for (int y = 1; y < h; y++)
197 memcpy(pixels + (size_t)y * w, pixels, (size_t)w * sizeof(*pixels));
198 if (cadence)
199 return ASCIICHAT_OK;
200 int top = (int)fmax(0, floor(cy - radius - 1)), bottom = (int)fmin(h, ceil(cy + radius + 1));
201 int left = (int)fmax(0, floor(cx - radius - 1)), right = (int)fmin(w, ceil(cx + radius + 1));
202 for (int y = top; y < bottom; y++)
203 for (int x = left; x < right; x++) {
204 double dx0 = x + 0.5 - cx, dy0 = y + 0.5 - cy, d2 = dx0 * dx0 + dy0 * dy0;
205 if (d2 > (radius + 0.75) * (radius + 0.75))
206 continue;
207 double coverage = 1;
208 if (d2 > (radius - 0.75) * (radius - 0.75)) {
209 int inside = 0;
210 for (int sy = 0; sy < 4; sy++)
211 for (int sx = 0; sx < 4; sx++) {
212 double dx = x + (sx + 0.5) / 4 - cx, dy = y + (sy + 0.5) / 4 - cy;
213 if (dx * dx + dy * dy < radius * radius)
214 inside++;
215 }
216 coverage = inside / 16.0;
217 }
218 blend(&pixels[(size_t)y * w + x], white, coverage);
219 }
220 } else {
221 // A fixed-point ramp avoids three floating-point conversions per source
222 // pixel. 4096 intervals keep rounding within one RGB level of Canvas.
224 for (int i = 0; i <= TEST_PATTERN_GRADIENT_INTERVALS; i++) {
225 double t = i / (double)TEST_PATTERN_GRADIENT_INTERVALS;
226 gradient[i] = (rgb_pixel_t){(uint8_t)(first.r * (1 - t) + last.r * t + 0.5),
227 (uint8_t)(first.g * (1 - t) + last.g * t + 0.5),
228 (uint8_t)(first.b * (1 - t) + last.b * t + 0.5)};
229 }
230 double scale = (double)TEST_PATTERN_GRADIENT_INTERVALS * 65536 / ((double)w * w + (double)h * h);
231 uint32_t step = (uint32_t)(w * scale + 0.5);
232 for (int y = 0; y < h; y++) {
233 uint32_t position = (uint32_t)((0.5 * w + (y + 0.5) * h) * scale + 0.5);
234 for (int x = 0; x < w; x++, position += step)
235 pixels[(size_t)y * w + x] = gradient[position >> 16];
236 }
237 int top = (int)fmax(0, floor(by)), bottom = (int)fmin(h, ceil(by + box));
238 int left = (int)fmax(0, floor(bx)), right = (int)fmin(w, ceil(bx + box));
239 for (int y = top; y < bottom; y++)
240 for (int x = left; x < right; x++)
241 blend(&pixels[(size_t)y * w + x], white, 0.8 * overlap(x, bx, bx + box) * overlap(y, by, by + box));
242 }
243 render_test_label(p->image);
244 return ASCIICHAT_OK;
245}
unsigned char colors[(512 *256 *2) *3]
Definition fft.c:22
unsigned int uint32_t
Definition common.h:62
unsigned char uint8_t
Definition common.h:60
int w
Image width in pixels (must be > 0).
int h
Image height in pixels (must be > 0).
rgb_pixel_t * pixels
Pixel data array (width * height RGB pixels, row-major order).
uint8_t b
Blue color component (0-255).
uint8_t g
Green color component (0-255).
uint8_t r
Red color component (0-255).
#define TEST_PATTERN_GRADIENT_INTERVALS

References ASCIICHAT_OK, rgb_pixel_t::b, colors, ERROR_INVALID_PARAM, rgb_pixel_t::g, image_t::h, test_pattern::image, index, image_t::pixels, rgb_pixel_t::r, SET_ERRNO, TEST_PATTERN_GRADIENT_INTERVALS, and image_t::w.

Referenced by animation_apply().

◆ test_pattern_resize()

asciichat_error_t test_pattern_resize ( test_pattern_t * p,
int width,
int height )

Definition at line 65 of file video/anim/test_pattern.c.

65 {
66 if (!p || width < 1 || height < 1)
67 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid test pattern dimensions");
68 if (p->image && p->image->w == width && p->image->h == height)
69 return ASCIICHAT_OK;
70 image_t *next = image_new(width, height);
71 if (!next)
72 return SET_ERRNO(ERROR_MEMORY, "Test pattern image allocation failed");
73 if (p->image)
75 p->image = next;
76 SAFE_FREE(p->rgba);
77 return ASCIICHAT_OK;
78}
@ ERROR_MEMORY
Definition error_codes.h:51
image_t * image_new(size_t width, size_t height)
Create a new image with standard allocation.
SIMD-friendly storage for one RGB pixel. r, g, and b hold the color channels and padding keeps the la...

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_MEMORY, image_t::h, height, test_pattern::image, image_destroy(), image_new(), test_pattern::rgba, SAFE_FREE, SET_ERRNO, image_t::w, and width.

Referenced by TestPatternBinding::render(), and test_pattern_create().

◆ test_pattern_rgba()

const uint8_t * test_pattern_rgba ( test_pattern_t * pattern)

Reusable RGBA view for browser upload; invalidated by resize/destroy.

Definition at line 134 of file video/anim/test_pattern.c.

134 {
135 if (!p || !p->image)
136 return NULL;
137 size_t count = (size_t)p->image->w * p->image->h;
138 if (!p->rgba)
139 p->rgba = SAFE_MALLOC(count * 4, uint8_t *);
140 for (size_t i = 0; i < count; i++) {
141 p->rgba[i * 4] = p->image->pixels[i].r;
142 p->rgba[i * 4 + 1] = p->image->pixels[i].g;
143 p->rgba[i * 4 + 2] = p->image->pixels[i].b;
144 p->rgba[i * 4 + 3] = 255;
145 }
146 return p->rgba;
147}
#define SAFE_MALLOC(size, cast)
Definition common.h:265

References rgb_pixel_t::b, rgb_pixel_t::g, image_t::h, test_pattern::image, image_t::pixels, rgb_pixel_t::r, test_pattern::rgba, SAFE_MALLOC, and image_t::w.

Referenced by TestPatternBinding::render().