font_*: fully parameterize source/destination bit depth
After implementing this, I realized I don't like the appearance of the monochrome font as much as the antialiased font.
This commit is contained in:
parent
ffbfcd9fd5
commit
b484b5d4fe
Binary file not shown.
Binary file not shown.
@ -189,7 +189,9 @@ inline void inflate_character(const uint8_t * src, const uint8_t c)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
twiddle::texture2<4>(&texture[offset / 4], temp, 8, 8, 0, 0);
|
twiddle::texture2<4>(&texture[offset / 4], temp,
|
||||||
|
8,
|
||||||
|
8 * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void inflate_font(const uint8_t * src)
|
void inflate_font(const uint8_t * src)
|
||||||
|
@ -125,14 +125,16 @@ void init_texture_memory(const struct opb_size& opb_size)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void inflate_font(const uint32_t * src, const uint32_t size)
|
void inflate_font(const uint32_t * src,
|
||||||
|
const uint32_t stride,
|
||||||
|
const uint32_t curve_end_ix)
|
||||||
{
|
{
|
||||||
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory64);
|
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory64);
|
||||||
auto texture = reinterpret_cast<volatile uint32_t *>(mem->texture);
|
auto texture = reinterpret_cast<volatile uint32_t *>(mem->texture);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < (size / 4); i++) {
|
twiddle::texture3<8, 8>(texture, reinterpret_cast<const uint8_t *>(src),
|
||||||
texture[i] = src[i];
|
stride,
|
||||||
}
|
curve_end_ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int C>
|
template <int C>
|
||||||
@ -150,7 +152,6 @@ void palette_data()
|
|||||||
| ((i >> 2) << 5)
|
| ((i >> 2) << 5)
|
||||||
| ((i >> 3) << 0);
|
| ((i >> 3) << 0);
|
||||||
}
|
}
|
||||||
holly.PALETTE_RAM[255] = 0xffff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4];
|
uint32_t _ta_parameter_buf[((32 * 10 * 17) + 32) / 4];
|
||||||
@ -167,6 +168,7 @@ void main()
|
|||||||
serial::integer<uint32_t>(font->first_char_code);
|
serial::integer<uint32_t>(font->first_char_code);
|
||||||
serial::integer<uint32_t>(font->glyph_count);
|
serial::integer<uint32_t>(font->glyph_count);
|
||||||
serial::integer<uint32_t>(font->glyph_height);
|
serial::integer<uint32_t>(font->glyph_height);
|
||||||
|
serial::integer<uint32_t>(font->texture_stride);
|
||||||
serial::integer<uint32_t>(font->texture_width);
|
serial::integer<uint32_t>(font->texture_width);
|
||||||
serial::integer<uint32_t>(font->texture_height);
|
serial::integer<uint32_t>(font->texture_height);
|
||||||
serial::character('\n');
|
serial::character('\n');
|
||||||
@ -174,8 +176,9 @@ void main()
|
|||||||
serial::integer<uint32_t>(((uint32_t)texture) - ((uint32_t)font));
|
serial::integer<uint32_t>(((uint32_t)texture) - ((uint32_t)font));
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32_t texture_size = font->max_z_curve_ix + 1;
|
inflate_font(texture,
|
||||||
inflate_font(texture, texture_size);
|
font->texture_stride,
|
||||||
|
font->max_z_curve_ix);
|
||||||
palette_data<256>();
|
palette_data<256>();
|
||||||
|
|
||||||
// The address of `ta_parameter_buf` must be a multiple of 32 bytes.
|
// The address of `ta_parameter_buf` must be a multiple of 32 bytes.
|
||||||
|
@ -130,18 +130,16 @@ constexpr inline uint32_t b(uint32_t v, uint32_t n)
|
|||||||
return ((v >> n) & 1) << (4 * n);
|
return ((v >> n) & 1) << (4 * n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void inflate_font(const uint32_t * src, const uint32_t size)
|
void inflate_font(const uint32_t * src,
|
||||||
|
const uint32_t stride,
|
||||||
|
const uint32_t curve_end_ix)
|
||||||
{
|
{
|
||||||
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory64);
|
auto mem = reinterpret_cast<volatile texture_memory_alloc *>(texture_memory64);
|
||||||
auto texture = reinterpret_cast<volatile uint32_t *>(mem->texture);
|
auto texture = reinterpret_cast<volatile uint32_t *>(mem->texture);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < (size / 4); i++) {
|
twiddle::texture3<4, 1>(texture, reinterpret_cast<const uint8_t *>(src),
|
||||||
uint32_t v = src[i];
|
stride,
|
||||||
texture[(i * 4) + 0] = b(v, 7 ) | b(v, 6 ) | b(v, 5 ) | b(v, 4 ) | b(v, 3 ) | b(v, 2 ) | b(v, 1 ) | b(v, 0 );
|
curve_end_ix);
|
||||||
texture[(i * 4) + 1] = b(v, 15) | b(v, 14) | b(v, 13) | b(v, 12) | b(v, 11) | b(v, 10) | b(v, 9 ) | b(v, 8 );
|
|
||||||
texture[(i * 4) + 2] = b(v, 23) | b(v, 22) | b(v, 21) | b(v, 20) | b(v, 19) | b(v, 18) | b(v, 17) | b(v, 16);
|
|
||||||
texture[(i * 4) + 3] = b(v, 31) | b(v, 30) | b(v, 29) | b(v, 28) | b(v, 27) | b(v, 26) | b(v, 25) | b(v, 24);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int C>
|
template <int C>
|
||||||
@ -188,8 +186,9 @@ void main()
|
|||||||
serial::integer<uint32_t>(((uint32_t)texture) - ((uint32_t)font));
|
serial::integer<uint32_t>(((uint32_t)texture) - ((uint32_t)font));
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32_t texture_size = font->max_z_curve_ix + 1;
|
inflate_font(texture,
|
||||||
inflate_font(texture, texture_size);
|
font->texture_stride,
|
||||||
|
font->max_z_curve_ix);
|
||||||
palette_data_mono();
|
palette_data_mono();
|
||||||
|
|
||||||
// The address of `ta_parameter_buf` must be a multiple of 32 bytes.
|
// The address of `ta_parameter_buf` must be a multiple of 32 bytes.
|
||||||
|
@ -32,9 +32,12 @@ struct font {
|
|||||||
uint32_t first_char_code;
|
uint32_t first_char_code;
|
||||||
uint16_t glyph_count;
|
uint16_t glyph_count;
|
||||||
uint16_t glyph_height;
|
uint16_t glyph_height;
|
||||||
|
uint16_t texture_stride;
|
||||||
uint16_t texture_width;
|
uint16_t texture_width;
|
||||||
uint16_t texture_height;
|
uint16_t texture_height;
|
||||||
|
uint16_t _pad;
|
||||||
|
uint32_t texture_size;
|
||||||
uint32_t max_z_curve_ix;
|
uint32_t max_z_curve_ix;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
static_assert((sizeof (font)) == ((sizeof (uint32_t)) * 4));
|
static_assert((sizeof (font)) == ((sizeof (uint32_t)) * 6));
|
||||||
|
@ -55,9 +55,11 @@ int32_t
|
|||||||
load_outline_char(const FT_Face face,
|
load_outline_char(const FT_Face face,
|
||||||
const FT_Int32 load_flags,
|
const FT_Int32 load_flags,
|
||||||
const FT_Render_Mode render_mode,
|
const FT_Render_Mode render_mode,
|
||||||
|
const uint32_t bits_per_pixel,
|
||||||
const FT_ULong char_code,
|
const FT_ULong char_code,
|
||||||
glyph * glyph,
|
glyph * glyph,
|
||||||
uint8_t * texture,
|
uint8_t * texture,
|
||||||
|
uint32_t texture_width,
|
||||||
struct rect& rect)
|
struct rect& rect)
|
||||||
{
|
{
|
||||||
FT_Error error;
|
FT_Error error;
|
||||||
@ -87,9 +89,16 @@ load_outline_char(const FT_Face face,
|
|||||||
assert(face->glyph->bitmap.width == rect.width);
|
assert(face->glyph->bitmap.width == rect.width);
|
||||||
assert(face->glyph->bitmap.rows == rect.height);
|
assert(face->glyph->bitmap.rows == rect.height);
|
||||||
|
|
||||||
|
assert(bits_per_pixel == 8 || bits_per_pixel == 4 || bits_per_pixel == 2 || bits_per_pixel == 1);
|
||||||
|
const uint32_t pixels_per_byte = 8 / bits_per_pixel;
|
||||||
|
const uint32_t texture_stride = texture_width / pixels_per_byte;
|
||||||
|
std::cerr << "pixels per byte: " << pixels_per_byte << '\n';
|
||||||
|
std::cerr << "texture stride: " << texture_stride << '\n';
|
||||||
|
|
||||||
for (uint32_t y = 0; y < rect.height; y++) {
|
for (uint32_t y = 0; y < rect.height; y++) {
|
||||||
for (uint32_t x = 0; x < rect.width; x++) {
|
for (uint32_t x = 0; x < rect.width; x++) {
|
||||||
uint32_t texture_ix = (rect.y + y) * max_texture_dim + (rect.x + x);
|
const uint32_t texture_ix = (rect.y + y) * texture_stride + (rect.x + x) / pixels_per_byte;
|
||||||
|
const uint32_t texture_ix_mod = (rect.x + x) % pixels_per_byte;
|
||||||
assert(texture_ix < max_texture_size);
|
assert(texture_ix < max_texture_size);
|
||||||
|
|
||||||
uint8_t level;
|
uint8_t level;
|
||||||
@ -108,12 +117,13 @@ load_outline_char(const FT_Face face,
|
|||||||
assert(face->glyph->bitmap.num_grays == 256);
|
assert(face->glyph->bitmap.num_grays == 256);
|
||||||
//std::cerr << "num_grays " << face->glyph->bitmap.num_grays << '\n';
|
//std::cerr << "num_grays " << face->glyph->bitmap.num_grays << '\n';
|
||||||
level = face->glyph->bitmap.buffer[y * face->glyph->bitmap.pitch + x];
|
level = face->glyph->bitmap.buffer[y * face->glyph->bitmap.pitch + x];
|
||||||
|
level >>= (8 - bits_per_pixel);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
texture[texture_ix] = level;
|
texture[texture_ix] |= level << (bits_per_pixel * texture_ix_mod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,8 +164,6 @@ load_all_positions(const FT_Face face,
|
|||||||
const uint32_t num_glyphs = (end - start) + 1;
|
const uint32_t num_glyphs = (end - start) + 1;
|
||||||
struct rect rects[num_glyphs];
|
struct rect rects[num_glyphs];
|
||||||
|
|
||||||
uint8_t temp[max_texture_size];
|
|
||||||
|
|
||||||
FT_Int32 load_flags;
|
FT_Int32 load_flags;
|
||||||
FT_Render_Mode render_mode;
|
FT_Render_Mode render_mode;
|
||||||
if (monochrome) {
|
if (monochrome) {
|
||||||
@ -177,36 +185,23 @@ load_all_positions(const FT_Face face,
|
|||||||
// calculate a 2-dimensional packing for the rectangles
|
// calculate a 2-dimensional packing for the rectangles
|
||||||
auto window_curve_ix = pack_all(rects, num_glyphs);
|
auto window_curve_ix = pack_all(rects, num_glyphs);
|
||||||
|
|
||||||
// render all of the glyps to a temporary buffer;
|
const uint32_t bits_per_pixel = monochrome ? 1 : 8;
|
||||||
|
|
||||||
|
// render all of the glyphs to the texture;
|
||||||
for (uint32_t i = 0; i < num_glyphs; i++) {
|
for (uint32_t i = 0; i < num_glyphs; i++) {
|
||||||
const uint32_t char_code = rects[i].char_code;
|
const uint32_t char_code = rects[i].char_code;
|
||||||
int32_t err = load_outline_char(face,
|
int32_t err = load_outline_char(face,
|
||||||
load_flags,
|
load_flags,
|
||||||
render_mode,
|
render_mode,
|
||||||
|
bits_per_pixel,
|
||||||
char_code,
|
char_code,
|
||||||
&glyphs[char_code - start],
|
&glyphs[char_code - start],
|
||||||
temp,
|
reinterpret_cast<uint8_t *>(texture),
|
||||||
|
window_curve_ix.window.width,
|
||||||
rects[i]);
|
rects[i]);
|
||||||
if (err < 0) assert(false);
|
if (err < 0) assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// twiddle the temporary buffer to become the final texture
|
|
||||||
if (monochrome) {
|
|
||||||
twiddle::texture2<1>(texture, temp,
|
|
||||||
window_curve_ix.window.width,
|
|
||||||
window_curve_ix.window.height,
|
|
||||||
max_texture_dim);
|
|
||||||
} else {
|
|
||||||
twiddle::texture2<8>(texture, temp,
|
|
||||||
window_curve_ix.window.width,
|
|
||||||
window_curve_ix.window.height,
|
|
||||||
max_texture_dim);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monochrome) {
|
|
||||||
window_curve_ix.max_z_curve_ix = window_curve_ix.max_z_curve_ix / 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return window_curve_ix;
|
return window_curve_ix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,18 +275,32 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
auto window_curve_ix = load_all_positions(face, monochrome, start, end, glyphs, texture);
|
auto window_curve_ix = load_all_positions(face, monochrome, start, end, glyphs, texture);
|
||||||
|
|
||||||
|
uint32_t texture_stride;
|
||||||
|
uint32_t texture_size;
|
||||||
|
if (monochrome) {
|
||||||
|
texture_stride = window_curve_ix.window.width / 8;
|
||||||
|
texture_size = byteswap((window_curve_ix.max_z_curve_ix / 8) + 1);
|
||||||
|
} else {
|
||||||
|
texture_stride = window_curve_ix.window.width;
|
||||||
|
texture_size = byteswap((window_curve_ix.max_z_curve_ix / 1) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
font font;
|
font font;
|
||||||
font.first_char_code = byteswap(start);
|
font.first_char_code = byteswap(start);
|
||||||
font.glyph_count = byteswap(num_glyphs);
|
font.glyph_count = byteswap(num_glyphs);
|
||||||
font.glyph_height = byteswap(face->size->metrics.height);
|
font.glyph_height = byteswap(face->size->metrics.height);
|
||||||
|
font.texture_stride = byteswap(texture_stride);
|
||||||
font.texture_width = byteswap(window_curve_ix.window.width);
|
font.texture_width = byteswap(window_curve_ix.window.width);
|
||||||
font.texture_height = byteswap(window_curve_ix.window.height);
|
font.texture_height = byteswap(window_curve_ix.window.height);
|
||||||
|
font.texture_size = byteswap(texture_size);
|
||||||
font.max_z_curve_ix = byteswap(window_curve_ix.max_z_curve_ix);
|
font.max_z_curve_ix = byteswap(window_curve_ix.max_z_curve_ix);
|
||||||
|
|
||||||
std::cerr << "start: 0x" << std::hex << start << '\n';
|
std::cerr << "start: 0x" << std::hex << start << '\n';
|
||||||
std::cerr << "end: 0x" << std::hex << end << '\n';
|
std::cerr << "end: 0x" << std::hex << end << '\n';
|
||||||
std::cerr << "texture_width: " << std::dec << window_curve_ix.window.width << '\n';
|
std::cerr << "texture_stride: " << std::dec << texture_stride << '\n';
|
||||||
|
std::cerr << "texture_width: " << std::dec << window_curve_ix.window.width << '\n';
|
||||||
std::cerr << "texture_height: " << std::dec << window_curve_ix.window.height << '\n';
|
std::cerr << "texture_height: " << std::dec << window_curve_ix.window.height << '\n';
|
||||||
|
std::cerr << "texture_size: " << std::dec << texture_size << '\n';
|
||||||
std::cerr << "max_z_curve_ix: " << std::dec << window_curve_ix.max_z_curve_ix << '\n';
|
std::cerr << "max_z_curve_ix: " << std::dec << window_curve_ix.max_z_curve_ix << '\n';
|
||||||
|
|
||||||
FILE * out = fopen(argv[output_file_path], "w");
|
FILE * out = fopen(argv[output_file_path], "w");
|
||||||
@ -302,7 +311,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
fwrite(reinterpret_cast<void*>(&font), (sizeof (font)), 1, out);
|
fwrite(reinterpret_cast<void*>(&font), (sizeof (font)), 1, out);
|
||||||
fwrite(reinterpret_cast<void*>(&glyphs[0]), (sizeof (glyph)), num_glyphs, out);
|
fwrite(reinterpret_cast<void*>(&glyphs[0]), (sizeof (glyph)), num_glyphs, out);
|
||||||
fwrite(reinterpret_cast<void*>(&texture[0]), (sizeof (uint8_t)), window_curve_ix.max_z_curve_ix + 1, out);
|
fwrite(reinterpret_cast<void*>(&texture[0]), (sizeof (uint8_t)), texture_size, out);
|
||||||
|
|
||||||
fclose(out);
|
fclose(out);
|
||||||
}
|
}
|
||||||
|
57
twiddle.hpp
57
twiddle.hpp
@ -137,28 +137,63 @@ void texture_4bpp(volatile T * dst, const T * src, const uint32_t width, const u
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int B, typename T, typename U>
|
template <uint32_t dst_bits_per_pixel, typename T, typename U>
|
||||||
void texture2(volatile T * dst, const U * src,
|
void texture2(volatile T * dst, const U * src,
|
||||||
const uint32_t width, const uint32_t height,
|
const uint32_t src_stride,
|
||||||
const uint32_t stride)
|
const uint32_t curve_end_ix)
|
||||||
{
|
{
|
||||||
constexpr uint32_t t_bits = (sizeof (T)) * 8;
|
constexpr uint32_t t_bits = (sizeof (T)) * 8;
|
||||||
constexpr uint32_t bits_per_pixel = B;
|
static_assert(t_bits >= dst_bits_per_pixel);
|
||||||
static_assert(t_bits >= bits_per_pixel);
|
static_assert((t_bits / dst_bits_per_pixel) * dst_bits_per_pixel == t_bits);
|
||||||
static_assert((t_bits / bits_per_pixel) * bits_per_pixel == t_bits);
|
constexpr uint32_t pixels_per_t = t_bits / dst_bits_per_pixel;
|
||||||
constexpr uint32_t pixels_per_t = t_bits / bits_per_pixel;
|
|
||||||
static_assert(pixels_per_t == 1 || pixels_per_t == 2 || pixels_per_t == 4 || pixels_per_t == 8 || pixels_per_t == 16 || pixels_per_t == 32);
|
static_assert(pixels_per_t == 1 || pixels_per_t == 2 || pixels_per_t == 4 || pixels_per_t == 8 || pixels_per_t == 16 || pixels_per_t == 32);
|
||||||
|
|
||||||
T dst_val = 0;
|
T dst_val = 0;
|
||||||
const uint32_t end_ix = from_xy(width - 1, height - 1);
|
for (uint32_t curve_ix = 0; curve_ix <= curve_end_ix; curve_ix++) {
|
||||||
for (uint32_t curve_ix = 0; curve_ix <= end_ix; curve_ix++) {
|
|
||||||
auto [x, y] = from_ix(curve_ix);
|
auto [x, y] = from_ix(curve_ix);
|
||||||
const U src_val = src[y * stride + x];
|
const U src_val = src[y * src_stride + x];
|
||||||
if constexpr (pixels_per_t == 1) {
|
if constexpr (pixels_per_t == 1) {
|
||||||
dst[curve_ix] = src_val;
|
dst[curve_ix] = src_val;
|
||||||
} else {
|
} else {
|
||||||
const uint32_t curve_ix_mod = curve_ix & (pixels_per_t - 1);
|
const uint32_t curve_ix_mod = curve_ix & (pixels_per_t - 1);
|
||||||
dst_val |= src_val << (bits_per_pixel * curve_ix_mod);
|
dst_val |= src_val << (dst_bits_per_pixel * curve_ix_mod);
|
||||||
|
|
||||||
|
if (curve_ix_mod == (pixels_per_t - 1)) {
|
||||||
|
dst[curve_ix / pixels_per_t] = dst_val;
|
||||||
|
dst_val = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <uint32_t dst_bits_per_pixel, uint32_t src_bits_per_pixel, typename T, typename U>
|
||||||
|
void texture3(volatile T * dst, const U * src,
|
||||||
|
const uint32_t src_stride,
|
||||||
|
const uint32_t curve_end_ix)
|
||||||
|
{
|
||||||
|
constexpr uint32_t t_bits = (sizeof (T)) * 8;
|
||||||
|
static_assert(t_bits >= dst_bits_per_pixel);
|
||||||
|
static_assert((t_bits / dst_bits_per_pixel) * dst_bits_per_pixel == t_bits);
|
||||||
|
constexpr uint32_t pixels_per_t = t_bits / dst_bits_per_pixel;
|
||||||
|
static_assert(pixels_per_t == 1 || pixels_per_t == 2 || pixels_per_t == 4 || pixels_per_t == 8 || pixels_per_t == 16 || pixels_per_t == 32);
|
||||||
|
|
||||||
|
constexpr uint32_t u_bits = (sizeof (U)) * 8;
|
||||||
|
static_assert(u_bits >= src_bits_per_pixel);
|
||||||
|
static_assert((u_bits / src_bits_per_pixel) * src_bits_per_pixel == u_bits);
|
||||||
|
constexpr uint32_t pixels_per_u = u_bits / src_bits_per_pixel;
|
||||||
|
static_assert(pixels_per_u == 1 || pixels_per_u == 2 || pixels_per_u == 4 || pixels_per_u == 8 || pixels_per_u == 16 || pixels_per_u == 32);
|
||||||
|
|
||||||
|
T dst_val = 0;
|
||||||
|
for (uint32_t curve_ix = 0; curve_ix <= curve_end_ix; curve_ix++) {
|
||||||
|
auto [x, y] = from_ix(curve_ix);
|
||||||
|
const uint32_t src_ix = y * src_stride + (x / pixels_per_u);
|
||||||
|
const uint32_t src_ix_mod = x & (pixels_per_u - 1);
|
||||||
|
const U src_val = (src[src_ix] >> (src_bits_per_pixel * src_ix_mod)) & ((1 << src_bits_per_pixel) - 1);
|
||||||
|
if constexpr (pixels_per_t == 1) {
|
||||||
|
dst[curve_ix] = src_val;
|
||||||
|
} else {
|
||||||
|
const uint32_t curve_ix_mod = curve_ix & (pixels_per_t - 1);
|
||||||
|
dst_val |= src_val << (dst_bits_per_pixel * curve_ix_mod);
|
||||||
|
|
||||||
if (curve_ix_mod == (pixels_per_t - 1)) {
|
if (curve_ix_mod == (pixels_per_t - 1)) {
|
||||||
dst[curve_ix / pixels_per_t] = dst_val;
|
dst[curve_ix / pixels_per_t] = dst_val;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user