pad: improve the hash function
[fbpad.git] / pad.c
blob61382a3cc7ce542679e9fd7a242bbe392fa1fd22
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "config.h"
6 #include "draw.h"
7 #include "font.h"
8 #include "util.h"
9 #include "pad.h"
11 #define NCACHE (1 << 11)
12 #define MAXFBWIDTH (1 << 12)
14 static unsigned int cd[] = {
15 COLOR0, COLOR1, COLOR2, COLOR3,
16 COLOR4, COLOR5, COLOR6, COLOR7,
17 COLOR8, COLOR9, COLOR10, COLOR11,
18 COLOR12, COLOR13, COLOR14, COLOR15};
19 static int rows, cols;
20 static int fnrows, fncols;
21 static struct font *fonts[32];
22 static int nfonts;
23 static int font;
25 static int fnsets[16][3];
26 static char *fnpaths[][3] = {F0, F1, F2, F3, F4};
28 static int fontadd(char *path)
30 fonts[nfonts] = font_open(path);
31 if (!fonts[nfonts]) {
32 fprintf(stderr, "pad: bad font <%s>\n", path);
33 return -1;
35 return nfonts++;
38 int pad_init(void)
40 int i, j;
41 if (fb_init())
42 return 1;
43 if (sizeof(fbval_t) != FBM_BPP(fb_mode())) {
44 fprintf(stderr, "pad_init: fbval_t doesn't match fb depth\n");
45 return 1;
47 for (i = 0; i < ARRAY_SIZE(fnpaths); i++) {
48 for (j = 0; j < 3; j++) {
49 int fn = -1;
50 if (fnpaths[i][j])
51 if ((fn = fontadd(fnpaths[i][j])) < 0)
52 return 1;
53 if (fn < 0 && j > 0)
54 fn = fnsets[i][0];
55 if (fn < 0 && i > 0)
56 fn = fnsets[0][j];
57 fnsets[i][j] = fn;
60 pad_font(0);
61 return 0;
64 void pad_free(void)
66 int i;
67 for (i = 0; i < nfonts; i++)
68 font_free(fonts[i]);
69 fb_free();
72 #define CR(a) (((a) >> 16) & 0x0000ff)
73 #define CG(a) (((a) >> 8) & 0x0000ff)
74 #define CB(a) ((a) & 0x0000ff)
75 #define COLORMERGE(f, b, c) ((b) + (((f) - (b)) * (c) >> 8u))
77 static unsigned mixed_color(int fg, int bg, unsigned val)
79 unsigned int fore = cd[fg], back = cd[bg];
80 unsigned char r = COLORMERGE(CR(fore), CR(back), val);
81 unsigned char g = COLORMERGE(CG(fore), CG(back), val);
82 unsigned char b = COLORMERGE(CB(fore), CB(back), val);
83 return FB_VAL(r, g, b);
86 static unsigned color2fb(int c)
88 return FB_VAL(CR(cd[c]), CG(cd[c]), CB(cd[c]));
91 static fbval_t cache[NCACHE][MAXDOTS];
92 static struct glyph {
93 int c;
94 int fn;
95 short fg, bg;
96 } glyphs[NCACHE];
98 static struct glyph *glyph_entry(int c, int fn, int fg, int bg)
100 return &glyphs[((c - 32) ^ (fg << 6) ^ (bg << 5) ^ (fn << 8)) & (NCACHE - 1)];
103 static fbval_t *glyph_cache(int c, int fn, short fg, short bg)
105 struct glyph *g = glyph_entry(c, fn, fg, bg);
106 if (g->c == c && g->fn == fn && g->fg == fg && g->bg == bg)
107 return cache[g - glyphs];
108 return NULL;
111 static fbval_t *glyph_add(int c, int fn, short fg, short bg)
113 struct glyph *g = glyph_entry(c, fn, fg, bg);
114 g->c = c;
115 g->fg = fg;
116 g->bg = bg;
117 g->fn = fn;
118 return cache[g - glyphs];
121 static void bmp2fb(fbval_t *d, char *s, int fg, int bg, int nr, int nc)
123 int i, j;
124 for (i = 0; i < fnrows; i++) {
125 for (j = 0; j < fncols; j++) {
126 unsigned v = i < nr && j < nc ?
127 (unsigned char) s[i * nc + j] : 0;
128 d[i * fncols + j] = mixed_color(fg, bg, v);
133 static fbval_t *ch2fb(int fn, int c, short fg, short bg)
135 char bits[MAXDOTS];
136 fbval_t *fbbits;
137 if (c < 0 || (c < 256 && (!isprint(c) || isspace(c))))
138 return NULL;
139 if ((fbbits = glyph_cache(c, fn, fg, bg)))
140 return fbbits;
141 if (font_bitmap(fonts[fn], bits, c))
142 return NULL;
143 fbbits = glyph_add(c, fn, fg, bg);
144 bmp2fb(fbbits, bits, FN_C(fg), FN_C(bg),
145 font_rows(fonts[fn]), font_cols(fonts[fn]));
146 return fbbits;
149 static void fb_box(int sr, int sc, int er, int ec, fbval_t val)
151 static fbval_t line[MAXFBWIDTH];
152 int cn = ec - sc;
153 int i;
154 for (i = 0; i < cn; i++)
155 line[i] = val;
156 for (i = sr; i < er; i++)
157 fb_set(i, sc, line, cn);
160 static int fnsel(int fg, int bg)
162 if ((fg | bg) & FN_B)
163 return fnsets[font][2];
164 if ((fg | bg) & FN_I)
165 return fnsets[font][1];
166 return fnsets[font][0];
169 void pad_put(int ch, int r, int c, int fg, int bg)
171 int sr = fnrows * r;
172 int sc = fncols * c;
173 int i;
174 fbval_t *bits = ch2fb(fnsel(fg, bg), ch, fg, bg);
175 if (!bits)
176 bits = ch2fb(0, ch, fg, bg);
177 if (!bits)
178 fb_box(sr, sc, sr + fnrows, sc + fncols, color2fb(FN_C(bg)));
179 else
180 for (i = 0; i < fnrows; i++)
181 fb_set(sr + i, sc, bits + (i * fncols), fncols);
184 void pad_blank(int c)
186 fb_box(0, 0, fb_rows(), fb_cols(), color2fb(FN_C(c)));
189 void pad_blankrow(int r, int bg)
191 int sr = r * fnrows;
192 int er = r == rows - 1 ? fb_rows() : (r + 1) * fnrows;
193 fb_box(sr, 0, er, fb_cols(), color2fb(FN_C(bg)));
196 int pad_rows(void)
198 return rows;
201 int pad_cols(void)
203 return cols;
206 void pad_font(int i)
208 font = i < ARRAY_SIZE(fnpaths) ? i : 0;
209 fnrows = font_rows(fonts[fnsets[0][0]]);
210 fncols = font_cols(fonts[fnsets[0][0]]);
211 rows = fb_rows() / fnrows;
212 cols = fb_cols() / fncols;