ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
mirror.c File Reference

Go to the source code of this file.

Macros

#define RAIN_UPDATE_INTERVAL_MS   100.0
 

Functions

EMSCRIPTEN_KEEPALIVE int mirror_init_with_args (const char *args_json)
 
EMSCRIPTEN_KEEPALIVE void mirror_cleanup (void)
 
EMSCRIPTEN_KEEPALIVE char * mirror_convert_frame (uint8_t *rgba_data, int src_width, int src_height)
 
EMSCRIPTEN_KEEPALIVE void mirror_submit_audio_samples (const float *samples, int count, int source)
 
EMSCRIPTEN_KEEPALIVE char * mirror_render_audio_visualization (unsigned int width, unsigned int height, int source)
 
EMSCRIPTEN_KEEPALIVE void mirror_free_string (char *ptr)
 
EMSCRIPTEN_KEEPALIVE const unsigned char * get_font_default_ptr (void)
 
EMSCRIPTEN_KEEPALIVE unsigned int get_font_default_size (void)
 

Variables

const unsigned char g_font_default []
 
const size_t g_font_default_size
 
const unsigned char g_font_matrix_resurrected []
 
const size_t g_font_matrix_resurrected_size
 

Macro Definition Documentation

◆ RAIN_UPDATE_INTERVAL_MS

#define RAIN_UPDATE_INTERVAL_MS   100.0

Definition at line 32 of file mirror.c.

Function Documentation

◆ get_font_default_ptr()

EMSCRIPTEN_KEEPALIVE const unsigned char * get_font_default_ptr ( void  )

Get the pointer to the embedded default font data

Returns
Pointer to font data

Definition at line 333 of file mirror.c.

333 {
334 // Auto-select matrix font when --matrix flag is set
335 int matrix_rain_val = GET_OPTION(matrix_rain);
336 log_info("[get_font_default_ptr] CALLED: matrix_rain=%d, g_font_matrix_resurrected=%p, g_font_default=%p",
337 matrix_rain_val, (void *)g_font_matrix_resurrected, (void *)g_font_default);
338 if (matrix_rain_val) {
339 log_info("[get_font_default_ptr] RETURNING matrix font");
341 }
342 log_info("[get_font_default_ptr] RETURNING default font");
343 return g_font_default;
344}
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
const unsigned char g_font_matrix_resurrected[]
const unsigned char g_font_default[]

References g_font_default, g_font_matrix_resurrected, GET_OPTION, and log_info.

◆ get_font_default_size()

EMSCRIPTEN_KEEPALIVE unsigned int get_font_default_size ( void  )

Get the size of the embedded default font

Returns
Font data size in bytes

Definition at line 351 of file mirror.c.

351 {
352 // Auto-select matrix font when --matrix flag is set
353 if (GET_OPTION(matrix_rain)) {
354 return (unsigned int)g_font_matrix_resurrected_size;
355 }
356 return (unsigned int)g_font_default_size;
357}
const size_t g_font_matrix_resurrected_size
const size_t g_font_default_size

References g_font_default_size, g_font_matrix_resurrected_size, and GET_OPTION.

◆ mirror_cleanup()

EMSCRIPTEN_KEEPALIVE void mirror_cleanup ( void  )

Definition at line 85 of file mirror.c.

85 {
86 if (g_digital_rain) {
87 digital_rain_destroy(g_digital_rain);
88 g_digital_rain = NULL;
89 }
90 if (g_last_rain_output) {
91 SAFE_FREE(g_last_rain_output);
92 g_last_rain_output = NULL;
93 }
96}
#define SAFE_FREE(ptr)
Definition common.h:376
void platform_destroy(void)
Cleanup platform-specific subsystems.
void digital_rain_destroy(digital_rain_t *rain)
Destroy digital rain effect context.
void options_state_destroy(void)
Shutdown RCU options system.
Definition rcu.c:461

References digital_rain_destroy(), options_state_destroy(), platform_destroy(), and SAFE_FREE.

◆ mirror_convert_frame()

EMSCRIPTEN_KEEPALIVE char * mirror_convert_frame ( uint8_t *  rgba_data,
int  src_width,
int  src_height 
)

Definition at line 103 of file mirror.c.

103 {
104 if (!rgba_data || src_width <= 0 || src_height <= 0) {
105 return NULL;
106 }
107
108 g_frame_count++;
109 // Derive a time value from frame count using actual target FPS from options
110 int target_fps = (int)GET_OPTION(fps);
111 if (target_fps <= 0) {
112 target_fps = 60; // Default to 60 FPS if not set
113 }
114 float time_seconds = (float)g_frame_count / (float)target_fps;
115
116 // Get current settings from options or terminal detection
117 int dst_width = (int)terminal_get_effective_width();
118 int dst_height = (int)terminal_get_effective_height();
119 color_filter_t filter = (color_filter_t)GET_OPTION(color_filter);
121 if (g_frame_count <= 3 || g_frame_count % 120 == 0) {
122 log_debug("frame=%u color_filter=%d color_mode=%d", g_frame_count, (int)filter, (int)color_mode);
123 }
124 if (color_mode == TERM_COLOR_AUTO) {
125 color_mode = TERM_COLOR_TRUECOLOR; // xterm.js supports truecolor
126 }
127 palette_type_t palette_type = (palette_type_t)GET_OPTION(palette_type);
128 bool preserve_aspect_ratio = true; // Preserve webcam aspect ratio
129 bool stretch = false; // Don't stretch - maintain proportions
130
131 // Build terminal capabilities structure with user's color mode
132 terminal_capabilities_t caps = {0}; // Zero-initialize all fields first
133 caps.color_level = color_mode;
134 caps.capabilities = 0;
135 caps.color_count = (color_mode == TERM_COLOR_NONE) ? 0
136 : (color_mode == TERM_COLOR_16) ? 16
137 : (color_mode == TERM_COLOR_256) ? 256
138 : 16777216;
139 caps.utf8_support = true;
140 caps.detection_reliable = true;
141 caps.render_mode = (render_mode_t)GET_OPTION(render_mode);
143 caps.wants_padding = true;
144 caps.palette_type = palette_type;
145 caps.desired_fps = 60;
146 caps.color_filter = filter;
147
148 // Convert RGBA to RGB (strip alpha channel) and optionally flip horizontally
149 rgb_pixel_t *rgb_pixels = SAFE_MALLOC(src_width * src_height * sizeof(rgb_pixel_t), rgb_pixel_t *);
150 if (!rgb_pixels) {
151 return NULL;
152 }
153
154 bool flip_x = GET_OPTION(flip_x);
155 bool flip_y = GET_OPTION(flip_y);
156 for (int y = 0; y < src_height; y++) {
157 for (int x = 0; x < src_width; x++) {
158 int src_x = flip_x ? (src_width - 1 - x) : x;
159 int src_y = flip_y ? (src_height - 1 - y) : y;
160 int src_idx = (src_y * src_width + src_x) * 4;
161 int dst_idx = y * src_width + x;
162
163 rgb_pixels[dst_idx].r = rgba_data[src_idx + 0];
164 rgb_pixels[dst_idx].g = rgba_data[src_idx + 1];
165 rgb_pixels[dst_idx].b = rgba_data[src_idx + 2];
166 // Alpha (rgba_data[src_idx + 3]) is discarded
167 }
168 }
169
170 // Apply color filter to pixels if needed (except rainbow - handled in ANSI stage)
171 if (filter != COLOR_FILTER_NONE && filter != COLOR_FILTER_RAINBOW) {
172 // color_filter operates on packed RGB24 format
173 uint8_t *rgb24 = (uint8_t *)rgb_pixels;
174 int stride = src_width * 3;
175 apply_color_filter(rgb24, src_width, src_height, stride, filter, time_seconds);
176 }
177
178 // Create image structure
179 image_t img = {.w = src_width, .h = src_height, .pixels = rgb_pixels, .alloc_method = IMAGE_ALLOC_SIMD};
180
181 // Get palette characters based on selected palette type
182 const char *palette_chars;
183 switch (palette_type) {
184 case PALETTE_BLOCKS:
185 palette_chars = PALETTE_CHARS_BLOCKS;
186 break;
187 case PALETTE_DIGITAL:
188 palette_chars = PALETTE_CHARS_DIGITAL;
189 break;
190 case PALETTE_MINIMAL:
191 palette_chars = PALETTE_CHARS_MINIMAL;
192 break;
193 case PALETTE_COOL:
194 palette_chars = PALETTE_CHARS_COOL;
195 break;
196 case PALETTE_CUSTOM:
197 // Custom palette uses user-provided characters from options
198 palette_chars = GET_OPTION(palette_custom);
199 if (!palette_chars || palette_chars[0] == '\0') {
200 palette_chars = PALETTE_CHARS_STANDARD; // Fallback
201 }
202 break;
203 case PALETTE_STANDARD:
204 default:
205 palette_chars = PALETTE_CHARS_STANDARD;
206 break;
207 }
208
209 // Convert to ASCII using capability-aware function
210 char *ascii_output = ascii_convert_with_capabilities(&img, dst_width, dst_height, &caps, preserve_aspect_ratio,
211 stretch, palette_chars);
212
213 // Clean up
214 SAFE_FREE(rgb_pixels);
215
216 if (!ascii_output) {
217 log_error("ascii_convert_with_capabilities returned NULL");
218 return NULL;
219 }
220
221 // Apply rainbow color filter to ANSI output by replacing RGB values
222 // This preserves character selection while applying rainbow colors
223 if (filter == COLOR_FILTER_RAINBOW) {
224 char *rainbow_output = rainbow_replace_ansi_colors(ascii_output, time_seconds);
225 if (rainbow_output) {
226 SAFE_FREE(ascii_output);
227 ascii_output = rainbow_output;
228 }
229 }
230
231 bool matrix_rain = GET_OPTION(matrix_rain);
232 if (matrix_rain) {
233 // Initialize digital rain context if needed or dimensions changed
234 if (!g_digital_rain || g_digital_rain->num_columns != dst_width || g_digital_rain->num_rows != dst_height) {
235 if (g_digital_rain) {
236 digital_rain_destroy(g_digital_rain);
237 }
238 if (g_last_rain_output) {
239 SAFE_FREE(g_last_rain_output);
240 g_last_rain_output = NULL;
241 }
242 g_digital_rain = digital_rain_init(dst_width, dst_height);
243 if (!g_digital_rain) {
244 log_error("Failed to initialize digital rain effect");
245 return ascii_output; // Return without effect on error
246 }
247 g_last_rain_update_time = emscripten_get_now();
248 }
249
250 // Update color from active filter (allows filter changes after initialization)
251 digital_rain_set_color_from_filter(g_digital_rain, filter);
252
253 // Time-based updates: only update effect every RAIN_UPDATE_INTERVAL_MS
254 double current_time = emscripten_get_now();
255 double elapsed_ms = current_time - g_last_rain_update_time;
256
257 if (elapsed_ms >= RAIN_UPDATE_INTERVAL_MS) {
258 // Calculate actual delta time in seconds
259 float delta_time = (float)(elapsed_ms / 1000.0);
260 g_last_rain_update_time = current_time;
261
262 // Apply effect and cache a copy
263 char *rain_output = digital_rain_apply(g_digital_rain, ascii_output, delta_time);
264 if (rain_output) {
265 // Free old cached output
266 if (g_last_rain_output) {
267 SAFE_FREE(g_last_rain_output);
268 }
269 // Cache a copy (we'll return the original rain_output)
270 g_last_rain_output = strdup(rain_output);
271 // Return the rain output (caller will free it)
272 SAFE_FREE(ascii_output);
273 ascii_output = rain_output;
274 }
275 } else if (g_last_rain_output) {
276 // Use cached output
277 SAFE_FREE(ascii_output);
278 ascii_output = strdup(g_last_rain_output);
279 }
280 } else {
281 // Clean up digital rain context if it exists but effect is disabled
282 if (g_digital_rain) {
283 digital_rain_destroy(g_digital_rain);
284 g_digital_rain = NULL;
285 }
286 if (g_last_rain_output) {
287 SAFE_FREE(g_last_rain_output);
288 g_last_rain_output = NULL;
289 }
290 g_last_rain_update_time = 0.0;
291 }
292
293 return ascii_output;
294}
#define SAFE_MALLOC(size, cast)
Definition common.h:264
unsigned char uint8_t
Definition common.h:56
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
#define PALETTE_CHARS_MINIMAL
Minimal ASCII palette character string.
Definition palette.h:188
#define PALETTE_CHARS_DIGITAL
Digital/glitch palette character string.
Definition palette.h:179
palette_type_t
Built-in palette type enumeration.
Definition palette.h:84
#define PALETTE_CHARS_STANDARD
Standard ASCII palette character string.
Definition palette.h:161
#define PALETTE_CHARS_BLOCKS
Unicode block palette character string.
Definition palette.h:170
#define PALETTE_CHARS_COOL
Cool ascending blocks palette character string.
Definition palette.h:197
@ PALETTE_BLOCKS
Unicode block characters: " ░░▒▒▓▓██".
Definition palette.h:90
@ PALETTE_CUSTOM
User-defined via –palette-chars.
Definition palette.h:98
@ PALETTE_COOL
Ascending blocks: " ▁▂▃▄▅▆▇█".
Definition palette.h:96
@ PALETTE_STANDARD
Standard ASCII palette: " ...',;:clodxkO0KXNWM".
Definition palette.h:88
@ PALETTE_DIGITAL
Digital/glitch aesthetic: " -=≡≣▰▱◼".
Definition palette.h:92
@ PALETTE_MINIMAL
Simple ASCII: " .-+*#".
Definition palette.h:94
char * ascii_convert_with_capabilities(image_t *original, const ssize_t width, const ssize_t height, const terminal_capabilities_t *caps, const bool use_aspect_ratio, const bool stretch, const char *palette_chars)
Convert image to ASCII art with terminal capability awareness.
Definition ascii.c:233
char * rainbow_replace_ansi_colors(const char *ansi_string, float time_seconds)
Replace all RGB ANSI codes with rainbow color.
int apply_color_filter(uint8_t *pixels, uint32_t width, uint32_t height, uint32_t stride, color_filter_t filter, float time)
Apply color filter to entire image in-place.
void digital_rain_set_color_from_filter(digital_rain_t *rain, color_filter_t filter)
Set digital rain color from color filter.
char * digital_rain_apply(digital_rain_t *rain, const char *frame, float delta_time)
Apply digital rain effect to ASCII frame.
digital_rain_t * digital_rain_init(int num_columns, int num_rows)
Initialize digital rain effect context.
@ IMAGE_ALLOC_SIMD
Pixels allocated with SAFE_MALLOC_SIMD()
#define RAIN_UPDATE_INTERVAL_MS
Definition mirror.c:32
unsigned short int terminal_get_effective_width(void)
Get effective terminal width with fallback priority.
unsigned short int terminal_get_effective_height(void)
Get effective terminal height with fallback priority.
int num_columns
Number of columns in grid.
int num_rows
Number of rows in grid.
Image structure.
int w
Image width in pixels (must be > 0)
RGB pixel structure.
uint8_t b
Blue color component (0-255)
uint8_t g
Green color component (0-255)
uint8_t r
Red color component (0-255)
Complete terminal capabilities structure.
Definition terminal.h:709
int palette_type
Palette type enum value (palette_type_t)
Definition terminal.h:729
terminal_color_mode_t color_level
Detected color support level (terminal_color_mode_t)
Definition terminal.h:711
uint8_t desired_fps
Client's desired frame rate (1-144 FPS)
Definition terminal.h:733
render_mode_t render_mode
Preferred rendering mode (render_mode_t)
Definition terminal.h:721
bool utf8_support
True if terminal supports UTF-8 encoding.
Definition terminal.h:717
bool wants_padding
Whether client wants frame padding (centering) - false for snapshot/piped modes.
Definition terminal.h:737
uint32_t capabilities
Capability flags bitmask (terminal_capability_flags_t)
Definition terminal.h:713
uint32_t color_count
Maximum number of colors (2, 16, 256, or 16777216)
Definition terminal.h:715
color_filter_t color_filter
Monochromatic color filter enum value (color_filter_t)
Definition terminal.h:735
bool detection_reliable
True if detection is confident (reliable detection)
Definition terminal.h:719
bool wants_background
True if background colors are preferred.
Definition terminal.h:727
color_filter_t
Monochromatic color filter enumeration.
Definition terminal.h:599
@ COLOR_FILTER_NONE
No filtering (default)
Definition terminal.h:601
@ COLOR_FILTER_RAINBOW
Rainbow (cycles through spectrum over 3.5s)
Definition terminal.h:625
render_mode_t
Render mode preferences.
Definition terminal.h:662
@ RENDER_MODE_BACKGROUND
Background colors (block colors)
Definition terminal.h:666
terminal_color_mode_t
Terminal color support levels.
Definition terminal.h:578
@ TERM_COLOR_NONE
No color support (monochrome terminal)
Definition terminal.h:582
@ TERM_COLOR_16
16-color support (standard ANSI colors)
Definition terminal.h:584
@ TERM_COLOR_256
256-color support (extended ANSI palette)
Definition terminal.h:586
@ TERM_COLOR_AUTO
Auto-detect color support from terminal capabilities.
Definition terminal.h:580
@ TERM_COLOR_TRUECOLOR
24-bit truecolor support (RGB colors)
Definition terminal.h:588

References apply_color_filter(), ascii_convert_with_capabilities(), rgb_pixel_t::b, terminal_capabilities_t::capabilities, terminal_capabilities_t::color_count, terminal_capabilities_t::color_filter, COLOR_FILTER_NONE, COLOR_FILTER_RAINBOW, terminal_capabilities_t::color_level, terminal_capabilities_t::desired_fps, terminal_capabilities_t::detection_reliable, digital_rain_apply(), digital_rain_destroy(), digital_rain_init(), digital_rain_set_color_from_filter(), rgb_pixel_t::g, GET_OPTION, IMAGE_ALLOC_SIMD, log_debug, log_error, digital_rain_t::num_columns, digital_rain_t::num_rows, PALETTE_BLOCKS, PALETTE_CHARS_BLOCKS, PALETTE_CHARS_COOL, PALETTE_CHARS_DIGITAL, PALETTE_CHARS_MINIMAL, PALETTE_CHARS_STANDARD, PALETTE_COOL, PALETTE_CUSTOM, PALETTE_DIGITAL, PALETTE_MINIMAL, PALETTE_STANDARD, terminal_capabilities_t::palette_type, rgb_pixel_t::r, RAIN_UPDATE_INTERVAL_MS, rainbow_replace_ansi_colors(), terminal_capabilities_t::render_mode, RENDER_MODE_BACKGROUND, SAFE_FREE, SAFE_MALLOC, TERM_COLOR_16, TERM_COLOR_256, TERM_COLOR_AUTO, TERM_COLOR_NONE, TERM_COLOR_TRUECOLOR, terminal_get_effective_height(), terminal_get_effective_width(), terminal_capabilities_t::utf8_support, image_t::w, terminal_capabilities_t::wants_background, and terminal_capabilities_t::wants_padding.

◆ mirror_free_string()

EMSCRIPTEN_KEEPALIVE void mirror_free_string ( char *  ptr)

Definition at line 318 of file mirror.c.

318 {
319 SAFE_FREE(ptr);
320}

References SAFE_FREE.

◆ mirror_init_with_args()

EMSCRIPTEN_KEEPALIVE int mirror_init_with_args ( const char *  args_json)

Initialize mirror mode with command-line style arguments

Parameters
args_jsonJSON array of argument strings, e.g. ["mirror", "--width", "80", "--height", "40"]
Returns
0 on success, -1 on error

Definition at line 47 of file mirror.c.

47 {
48 // Initialize platform layer
50 if (err != ASCIICHAT_OK) {
51 return -1;
52 }
53
54 // Initialize logging to stderr (console.error in browser)
55 log_init(NULL, LOG_DEBUG, true, false);
56 // Use debug-style format in WASM so browser console shows full log headers
58
59 // Parse space-separated arguments
60 char *args_copy = NULL;
61 char *argv[64] = {NULL};
62 int argc = wasm_parse_args(args_json, argv, 64, &args_copy);
63 if (argc < 0) {
64 return -1;
65 }
66
67 // Initialize options (sets up RCU, defaults, etc.)
68 err = options_init(argc, argv);
69 free(args_copy);
70
71 if (err != ASCIICHAT_OK) {
72 return -1;
73 }
74
75 // Log option values after initialization
76 log_info("[mirror_init_with_args] After options_init: argc=%d, matrix_rain=%d", argc, GET_OPTION(matrix_rain));
77
78 // Initialize ANSI color code generation (dec3 cache for RGB values)
80
81 return 0;
82}
void ansi_fast_init(void)
Definition ansi.c:319
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ASCIICHAT_OK
Definition error_codes.h:51
void log_init(const char *filename, log_level_t level, bool force_stderr, bool use_mmap)
Initialize the logging system.
Definition log/log.c:533
asciichat_error_t log_set_format(const char *format_str, bool console_only)
Set a custom log format string.
Definition log/log.c:744
asciichat_error_t options_init(int argc, char **argv)
Initialize options by parsing command-line arguments with unified mode detection.
#define OPT_LOG_TEMPLATE_DEFAULT_DEBUG
Default log format string - debug mode (verbose with thread name, file relative path,...
asciichat_error_t platform_init(void)
Initialize platform-specific subsystems.
int wasm_parse_args(const char *args_str, char **argv, int max_args, char **out_args_copy)
#define LOG_DEBUG
Definition types.h:39

References ansi_fast_init(), ASCIICHAT_OK, GET_OPTION, LOG_DEBUG, log_info, log_init(), log_set_format(), OPT_LOG_TEMPLATE_DEFAULT_DEBUG, options_init(), platform_init(), and wasm_parse_args().

◆ mirror_render_audio_visualization()

EMSCRIPTEN_KEEPALIVE char * mirror_render_audio_visualization ( unsigned int  width,
unsigned int  height,
int  source 
)

Definition at line 306 of file mirror.c.

306 {
310 if (GET_OPTION(fft))
311 return audio_visualization_render_fft(width, height, audio_source, true, AUDIO_VISUALIZATION_COLOR_BRIGHTER,
312 GET_OPTION(flip_x), GET_OPTION(flip_y));
313 return audio_visualization_render_waveform(width, height, audio_source, true, AUDIO_VISUALIZATION_COLOR_BRIGHTER,
314 GET_OPTION(flip_x), GET_OPTION(flip_y));
315}
char * audio_visualization_render_waveform(unsigned int width, unsigned int height, audio_visualization_source_t source, bool use_color, int color_mode, bool flip_x, bool flip_y)
char * audio_visualization_render_fft(unsigned int width, unsigned int height, audio_visualization_source_t source, bool use_color, int color_mode, bool flip_x, bool flip_y)
audio_visualization_source_t
@ AUDIO_VISUALIZATION_SOURCE_MEDIA
@ AUDIO_VISUALIZATION_SOURCE_MIC
#define AUDIO_VISUALIZATION_COLOR_BRIGHTER

References AUDIO_VISUALIZATION_COLOR_BRIGHTER, audio_visualization_render_fft(), audio_visualization_render_waveform(), AUDIO_VISUALIZATION_SOURCE_MEDIA, AUDIO_VISUALIZATION_SOURCE_MIC, and GET_OPTION.

◆ mirror_submit_audio_samples()

EMSCRIPTEN_KEEPALIVE void mirror_submit_audio_samples ( const float *  samples,
int  count,
int  source 
)

Definition at line 297 of file mirror.c.

297 {
298 if (!samples || count <= 0 || count > 8192)
299 return;
302 samples, (size_t)count);
303}
void audio_visualization_submit(audio_visualization_source_t source, const float *samples, size_t count)

References AUDIO_VISUALIZATION_SOURCE_MEDIA, AUDIO_VISUALIZATION_SOURCE_MIC, and audio_visualization_submit().

Variable Documentation

◆ g_font_default

const unsigned char g_font_default[]
extern

Referenced by get_font_default_ptr().

◆ g_font_default_size

const size_t g_font_default_size
extern

Referenced by get_font_default_size().

◆ g_font_matrix_resurrected

const unsigned char g_font_matrix_resurrected[]
extern

Referenced by get_font_default_ptr().

◆ g_font_matrix_resurrected_size

const size_t g_font_matrix_resurrected_size
extern

Referenced by get_font_default_size().