+// some color transforming functions I made in attempt to fix font_diskcache
+// until the point I realize it's not worthwhile anymore
+
+static inline void rgba_to_bgra(unsigned char *source, unsigned char *target, int source_size)
+{
+ int x;
+ for (x = 0; x < source_size; x += 4)
+ {
+ target[0] = source[2];
+ target[1] = source[1];
+ target[2] = source[0];
+ target[3] = source[3];
+ }
+}
+static inline void rgba_to_alpha(unsigned char *source, unsigned char *target, int source_size)
+{
+ int x, i;
+ for (x = 0, i = 0; x < source_size; x += 4)
+ {
+ target[i++] = (
+ source[x+0] * 0.2125 + // r
+ source[x+1] * 0.7154 + // g
+ source[x+2] * 0.0721 // b
+ ) / 3 * (source[x+3] / 256); // a
+ }
+}
+static inline void alpha_to_rgba(unsigned char *source, unsigned char *target, int source_size)
+{
+ int x, i;
+ for (x = 0, i = 0; x < source_size; x += 4)
+ {
+ target[x+0] = target[x+1] = target[x+2] = 0xff - source[i];
+ target[x+3] = source[i++];
+ }
+}
+#define alpha_to_bgra alpha_to_rgba
+
+// helper inline functions for incmap_post_process
+
+static inline void update_pic_for_fontmap(ft2_font_map_t *fontmap, const char *identifier,
+ int width, int height, unsigned char *data)
+{
+ fontmap->pic = Draw_NewPic(identifier, width, height, data,
+ r_font_use_alpha_textures.integer ? TEXTYPE_ALPHA : TEXTYPE_RGBA,
+ TEXF_ALPHA | TEXF_CLAMP | (r_font_compress.integer > 0 ? TEXF_COMPRESS : 0));
+}
+
+// glyphs' texture coords needs to be fixed when merging to bigger texture
+static inline void transform_glyph_coords(glyph_slot_t *glyph, float shiftx, float shifty, float scalex, float scaley)
+{
+ glyph->txmin = glyph->txmin * scalex + shiftx;
+ glyph->txmax = glyph->txmax * scalex + shiftx;
+ glyph->tymin = glyph->tymin * scaley + shifty;
+ glyph->tymax = glyph->tymax * scaley + shifty;
+}
+#define fix_glyph_coords_tier1(glyph, order) transform_glyph_coords(glyph, order / (float)FONT_CHARS_PER_LINE, 0.0f, 1.0f / (float)FONT_CHARS_PER_LINE, 1.0f)
+#define fix_glyph_coords_tier2(glyph, order) transform_glyph_coords(glyph, 0.0f, order / (float)FONT_CHARS_PER_LINE, 1.0f, 1.0f / (float)FONT_CHARS_PER_LINE)
+
+// pull glyph things from sourcemap to targetmap
+static inline void merge_single_map(ft2_font_map_t *targetmap, int targetindex, ft2_font_map_t *sourcemap, int sourceindex)
+{
+ targetmap->glyphs[targetindex] = sourcemap->glyphs[sourceindex];
+ targetmap->glyphchars[targetindex] = sourcemap->glyphchars[sourceindex];
+}
+
+#define calc_data_arguments(w, h) \
+ width = startmap->glyphSize * w; \
+ height = startmap->glyphSize * h; \
+ pitch = width * bytes_per_pixel; \
+ datasize = height * pitch;
+
+// do incremental map process
+static inline void incmap_post_process(font_incmap_t *incmap, Uchar ch,
+ unsigned char *data, ft2_font_map_t **outmap, int *outmapch)
+{
+ int index, targetmap_at;
+ // where will the next `data` be placed
+ int tier1_data_index, tier2_data_index;
+ // metrics of data to manipulate
+ int width, height, bytes_per_pixel, pitch, datasize;
+ int i, j, x, y;
+ unsigned char *newdata, *chunk;
+ ft2_font_map_t *startmap, *targetmap, *currentmap;
+ #define M FONT_CHARS_PER_LINE
+ #define N FONT_CHAR_LINES
+
+ bytes_per_pixel = r_font_use_alpha_textures.integer ? 1 : 4;
+
+ startmap = incmap->fontmap;
+ index = incmap->charcount;
+ tier1_data_index = index % M;
+ tier2_data_index = incmap->tier1_merged;
+
+ if (bytes_per_pixel != incmap->bytes_per_pixel)
+ {
+ // should it really happen...
+ int olddata_size;
+ calc_data_arguments(1, 1);
+ olddata_size = datasize / bytes_per_pixel * incmap->bytes_per_pixel;
+ for (i = 0; i < M; ++i)
+ {
+ chunk = incmap->data_tier1[i];
+ if (chunk == NULL) break;
+ newdata = (unsigned char *)Mem_Alloc(font_mempool, datasize);
+ if (bytes_per_pixel == 1)
+ rgba_to_alpha(chunk, newdata, olddata_size);
+ else if (bytes_per_pixel == 4)
+ alpha_to_rgba(chunk, newdata, olddata_size);
+ Mem_Free(chunk);
+ incmap->data_tier1[i] = newdata;
+ }
+ chunk = NULL;
+ olddata_size *= M;
+ for (i = 0; i < N; ++i)
+ {
+ chunk = incmap->data_tier2[i];
+ if (chunk == NULL) break;
+ newdata = (unsigned char *)Mem_Alloc(font_mempool, datasize);
+ if (bytes_per_pixel == 1)
+ rgba_to_alpha(chunk, newdata, olddata_size);
+ else if (bytes_per_pixel == 4)
+ alpha_to_rgba(chunk, newdata, olddata_size);
+ Mem_Free(chunk);
+ incmap->data_tier2[i] = newdata;
+ }
+ chunk = NULL;
+ incmap->bytes_per_pixel = bytes_per_pixel;
+ }
+
+ incmap->data_tier1[tier1_data_index] = data;
+
+ if (index % M == M - 1)
+ {
+ // tier 1 reduction, pieces to line
+ calc_data_arguments(1, 1);
+ targetmap_at = incmap->tier2_merged + incmap->tier1_merged;
+ targetmap = startmap;
+ for (i = 0; i < targetmap_at; ++i)
+ targetmap = targetmap->next;
+ currentmap = targetmap;
+ newdata = (unsigned char *)Mem_Alloc(font_mempool, datasize * M);
+ for (i = 0; i < M; ++i)
+ {
+ chunk = incmap->data_tier1[i];
+ if (chunk == NULL)
+ continue;
+ for (y = 0; y < datasize; y += pitch)
+ for (x = 0; x < pitch; ++x)
+ newdata[y * M + i * pitch + x] = chunk[y + x];
+ Mem_Free(chunk);
+ incmap->data_tier1[i] = NULL;
+ merge_single_map(targetmap, i, currentmap, 0);
+ fix_glyph_coords_tier1(&targetmap->glyphs[i], (float)i);
+ currentmap = currentmap->next;
+ }
+ update_pic_for_fontmap(targetmap, Draw_GetPicName(targetmap->pic), width * M, height, newdata);
+ UnloadMapChain(targetmap->next);
+ targetmap->next = NULL;
+ incmap->data_tier2[tier2_data_index] = newdata;
+ ++incmap->tier1_merged;
+ incmap->tier1_merged %= M;
+ incmap->newmap_start = INCMAP_START + targetmap_at + 1;
+ // then give this merged map
+ *outmap = targetmap;
+ *outmapch = i;
+ }
+ if (index % (M * N) == M * N - 1)
+ {
+ // tier 2 reduction, lines to full map
+ calc_data_arguments(M, 1);
+ targetmap_at = incmap->tier2_merged;
+ targetmap = startmap;
+ for (i = 0; i < targetmap_at; ++i)
+ targetmap = targetmap->next;
+ currentmap = targetmap;
+ newdata = (unsigned char *)Mem_Alloc(font_mempool, datasize * N);
+ for (i = 0; i < N; ++i)
+ {
+ chunk = incmap->data_tier2[i];
+ if (chunk == NULL)
+ continue;
+ for (x = 0; x < datasize; ++x)
+ newdata[i * datasize + x] = chunk[x];
+ Mem_Free(chunk);
+ incmap->data_tier2[i] = NULL;
+ for (j = 0; j < M; ++j)
+ {
+ merge_single_map(targetmap, i * M + j, currentmap, j);
+ fix_glyph_coords_tier2(&targetmap->glyphs[i * M + j], (float)i);
+ }
+ currentmap = currentmap->next;
+ }
+ update_pic_for_fontmap(targetmap, Draw_GetPicName(targetmap->pic), width, height * N, newdata);
+ UnloadMapChain(targetmap->next);
+ targetmap->next = NULL;
+ Mem_Free(newdata);
+ ++incmap->tier2_merged;
+ incmap->newmap_start = INCMAP_START + targetmap_at + 1;
+ // then give this merged map
+ *outmap = targetmap;
+ *outmapch = i * M + j;
+ }
+
+ ++incmap->charcount;
+ ++incmap->newmap_start;
+
+ #undef M
+ #undef N
+}
+
+static qbool Font_LoadMap(ft2_font_t *font, ft2_font_map_t *mapstart, Uchar _ch,
+ ft2_font_map_t **outmap, int *outmapch, qbool use_incmap)