2424#include < cstdlib>
2525#include < cstring>
2626#include < cstdint>
27+ #include < cmath>
2728#include < algorithm>
28- #include < string>
29- #include < vector>
3029#include < emscripten.h>
31- #include < cmath>
3230
3331#if defined(__wasm_simd128__)
3432#include < wasm_simd128.h>
3937
4038#define CELL_BUFFER_SIZE (ASCII_WIDTH * ASCII_HEIGHT)
4139static AsciiCell cell_buffer[CELL_BUFFER_SIZE];
40+
4241// ASCII 렌더링이 초기화되었는지 여부를 나타내는 플래그
4342static boolean ascii_initialized = false ;
4443
44+ // 감마 보정 룩업 테이블 (pow() 호출 제거로 성능 향상)
45+ static uint8_t gamma_table[256 ];
46+ static boolean gamma_table_initialized = false ;
47+
48+ // ASCII 문자 팔레트 (constexpr 배열로 최적화)
49+ static constexpr char ASCII_CHARS[] = " .:-=+*#%@" ;
50+ static constexpr int ASCII_CHARS_LEN = sizeof (ASCII_CHARS) - 1 ; // null terminator 제외
51+
4552extern " C" {
4653
54+ // 감마 테이블 초기화 (gamma = 0.35, 밝기 2배 증가)
55+ static void init_gamma_table (void )
56+ {
57+ if (gamma_table_initialized)
58+ return ;
59+
60+ // 감마 0.35 = 더 밝은 출력 (기존 0.5에서 약 2배 밝기)
61+ constexpr float gamma = 0 .35f ;
62+ for (int i = 0 ; i < 256 ; ++i) {
63+ float normalized = i / 255 .0f ;
64+ float corrected = std::pow (normalized, gamma);
65+ gamma_table[i] = static_cast <uint8_t >(std::min (255 .0f , corrected * 255 .0f ));
66+ }
67+ gamma_table_initialized = true ;
68+ }
69+
4770void I_InitASCII (void )
4871{
4972 if (ascii_initialized)
5073 return ;
5174
75+ // 감마 테이블 초기화 (최초 1회만)
76+ init_gamma_table ();
77+
5278 // 전체 AsciiCell 버퍼를 0으로 초기화
5379 // → 처음에는 화면 전체가 '빈 문자/검은색' 상태가 됨
5480 std::memset (cell_buffer, 0 , sizeof (cell_buffer));
@@ -70,40 +96,40 @@ const void* I_GetASCIIBuffer(void)
7096 return cell_buffer;
7197}
7298
73- // C++ implementation of RGBA to AsciiCell data conversion
99+ // C++ implementation of RGBA to AsciiCell data conversion (optimized)
74100void I_ConvertRGBAtoASCII (const uint32_t *rgba_buffer,
75101 int src_width, int src_height,
76102 void *output_buffer,
77103 int ascii_width, int ascii_height)
78104{
79- // 화면 밝기에 따라 다른 문자를 사용하는 ASCII 팔레트
80- const std::string ascii_chars = " .:-=+*#%@" ;
81- // 출력으로 사용할 AsciiCell 배열
82105 AsciiCell* out_cells = static_cast <AsciiCell*>(output_buffer);
83106
84- // ascii_width x ascii_height 해상도의 "문자 셀"로 원본 RGBA 화면을 축소 샘플링한다.
107+ // 스케일 비율을 미리 계산 (나눗셈 최소화)
108+ const int scale_x = (src_width << 8 ) / ascii_width; // 8비트 고정소수점
109+ const int scale_y = (src_height << 8 ) / ascii_height;
110+
85111 for (int y = 0 ; y < ascii_height; ++y) {
112+ const int src_y_start = (y * scale_y) >> 8 ;
113+ const int src_y_end = ((y + 1 ) * scale_y) >> 8 ;
114+
86115 for (int x = 0 ; x < ascii_width; ++x) {
87- // 이 문자 셀이 담당하는 원본 화면 상의 영역을 계산
88- int src_x_start = (x * src_width) / ascii_width;
89- int src_y_start = (y * src_height) / ascii_height;
90- int src_x_end = ((x + 1 ) * src_width) / ascii_width;
91- int src_y_end = ((y + 1 ) * src_height) / ascii_height;
116+ const int src_x_start = (x * scale_x) >> 8 ;
117+ const int src_x_end = ((x + 1 ) * scale_x) >> 8 ;
92118
93- // 해당 영역의 RGB 값을 모두 합산하여 평균 색/밝기를 구한다.
94- long long total_r = 0 , total_g = 0 , total_b = 0 ;
119+ // 해당 영역의 RGB 값을 합산
120+ int total_r = 0 , total_g = 0 , total_b = 0 ;
95121 int count = 0 ;
96122
97123 for (int sy = src_y_start; sy < src_y_end; ++sy) {
98124 const uint32_t * row_ptr = &rgba_buffer[sy * src_width + src_x_start];
99- int region_width = src_x_end - src_x_start;
125+ const int region_width = src_x_end - src_x_start;
100126 count += region_width;
101127
102128#if defined(__wasm_simd128__)
103- v128_t sums = wasm_i32x4_const (0 , 0 , 0 , 0 ); // Accumulator for BGRA sums
129+ v128_t sums = wasm_i32x4_const (0 , 0 , 0 , 0 );
104130 int sx = 0 ;
105131 for (; sx <= region_width - 4 ; sx += 4 ) {
106- v128_t pixels = wasm_v128_load (row_ptr + sx); // Load 4 pixels (BGRA)
132+ v128_t pixels = wasm_v128_load (row_ptr + sx);
107133
108134 v128_t wide_low = wasm_u16x8_extend_low_u8x16 (pixels);
109135 v128_t wide_high = wasm_u16x8_extend_high_u8x16 (pixels);
@@ -119,50 +145,47 @@ void I_ConvertRGBAtoASCII(const uint32_t *rgba_buffer,
119145 total_r += wasm_i32x4_extract_lane (sums, 2 );
120146
121147 for (; sx < region_width; ++sx) {
122- uint32_t pixel = row_ptr[sx];
148+ const uint32_t pixel = row_ptr[sx];
123149 total_r += (pixel >> 16 ) & 0xFF ;
124150 total_g += (pixel >> 8 ) & 0xFF ;
125151 total_b += pixel & 0xFF ;
126152 }
127153#else
128- for (int sx = src_x_start ; sx < src_x_end ; ++sx) {
129- uint32_t pixel = rgba_buffer[sy * src_width + sx];
154+ for (int sx = 0 ; sx < region_width ; ++sx) {
155+ const uint32_t pixel = row_ptr[ sx];
130156 total_r += (pixel >> 16 ) & 0xFF ;
131157 total_g += (pixel >> 8 ) & 0xFF ;
132158 total_b += pixel & 0xFF ;
133159 }
134160#endif
135161 }
136162
137- // 2D 좌표 (x, y) 를 1D 인덱스로 변환해서 AsciiCell 에 기록
138163 AsciiCell& cell = out_cells[y * ascii_width + x];
139164
140165 if (count == 0 ) {
141- // 샘플링할 픽셀이 하나도 없으면 공백 문자 + 검은색으로 채움
142166 cell.character = ' ' ;
143167 cell.r = 0 ;
144168 cell.g = 0 ;
145169 cell.b = 0 ;
146170 continue ;
147171 }
148172
149- // 영역 내 평균 색상 계산
150- int avg_r = total_r / count;
151- int avg_g = total_g / count;
152- int avg_b = total_b / count;
173+ // 평균 계산
174+ const int avg_r = total_r / count;
175+ const int avg_g = total_g / count;
176+ const int avg_b = total_b / count;
153177
154- // 가중치를 적용해 '밝기' 값으로 변환 (0~255 )
155- int brightness = (avg_r * 299 + avg_g * 587 + avg_b * 114 ) / 1000 ;
178+ // 밝기 계산 (정수 연산 )
179+ const int brightness = (avg_r * 299 + avg_g * 587 + avg_b * 114 ) / 1000 ;
156180
157- // 밝기를 ascii_chars 인덱스로 매핑
158- int char_idx = (brightness * (ascii_chars.length () - 1 )) / 255 ;
159-
160- // 최종적으로 이 셀에 사용할 문자/색상 값을 저장
161- cell.character = ascii_chars[char_idx];
162- const float gamma = 0.5 ;
163- cell.r = std::min (255 , static_cast <int >(pow (avg_r / 255.0 , gamma) * 255.0 ));
164- cell.g = std::min (255 , static_cast <int >(pow (avg_g / 255.0 , gamma) * 255.0 ));
165- cell.b = std::min (255 , static_cast <int >(pow (avg_b / 255.0 , gamma) * 255.0 ));
181+ // ASCII 문자 인덱스 계산 (constexpr 배열 사용)
182+ const int char_idx = (brightness * (ASCII_CHARS_LEN - 1 )) / 255 ;
183+
184+ // 감마 룩업 테이블 사용 (pow() 호출 제거)
185+ cell.character = ASCII_CHARS[char_idx];
186+ cell.r = gamma_table[avg_r];
187+ cell.g = gamma_table[avg_g];
188+ cell.b = gamma_table[avg_b];
166189 }
167190 }
168191}
0 commit comments