create .gitignore
[fbpad.git] / pad.c
blob8c94ddf8d999edbf78ebd51db880f3744a7ba20d
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "conf.h"
6 #include "draw.h"
7 #include "fbpad.h"
9 static int fbroff, fbcoff, fbrows, fbcols;
10 static int rows, cols;
11 static int fnrows, fncols;
12 static int bpp;
13 static struct font *fonts[3];
15 static int gc_init(void);
16 static void gc_free(void);
17 static void gc_refresh(void);
19 int pad_init(void)
21 if (pad_font(FR, FI, FB))
22 return 1;
23 fnrows = font_rows(fonts[0]);
24 fncols = font_cols(fonts[0]);
25 if (gc_init())
26 return 1;
27 rows = fb_rows() / fnrows;
28 cols = fb_cols() / fncols;
29 bpp = FBM_BPP(fb_mode());
30 pad_conf(0, 0, fb_rows(), fb_cols());
31 return 0;
34 void pad_conf(int roff, int coff, int _rows, int _cols)
36 fbroff = roff;
37 fbcoff = coff;
38 fbrows = _rows;
39 fbcols = _cols;
40 rows = fbrows / fnrows;
41 cols = fbcols / fncols;
44 void pad_free(void)
46 gc_free();
47 font_free(fonts[0]);
48 font_free(fonts[1]);
49 font_free(fonts[2]);
52 #define CR(a) (((a) >> 16) & 0x0000ff)
53 #define CG(a) (((a) >> 8) & 0x0000ff)
54 #define CB(a) ((a) & 0x0000ff)
55 #define COLORMERGE(f, b, c) ((b) + (((f) - (b)) * (c) >> 8u))
57 static unsigned mixed_color(int fg, int bg, unsigned val)
59 unsigned char r = COLORMERGE(CR(fg), CR(bg), val);
60 unsigned char g = COLORMERGE(CG(fg), CG(bg), val);
61 unsigned char b = COLORMERGE(CB(fg), CB(bg), val);
62 return FB_VAL(r, g, b);
65 static unsigned color2fb(int c)
67 return FB_VAL(CR(c), CG(c), CB(c));
70 /* glyph bitmap cache: use CGLCNT lists of size CGLLEN each */
71 #define GCLCNT (1 << 7) /* glyph cache list count */
72 #define GCLLEN (1 << 4) /* glyph cache list length */
73 #define GCGLEN (fnrows * fncols * 4) /* bytes to store a glyph */
74 #define GCN (GCLCNT * GCLLEN) /* total glpyhs */
75 #define GCIDX(c) ((c) & (GCLCNT - 1))
77 static char *gc_mem; /* cached glyph's memory */
78 static int gc_next[GCLCNT]; /* the next slot to use in each list */
79 static int gc_glyph[GCN]; /* cached glyphs */
80 static int gc_bg[GCN];
81 static int gc_fg[GCN];
83 static int gc_init(void)
85 gc_mem = malloc(GCLCNT * GCLLEN * GCGLEN);
86 return !gc_mem;
89 static void gc_free(void)
91 free(gc_mem);
94 static char *gc_get(int c, int fg, int bg)
96 int idx = GCIDX(c) * GCLLEN;
97 int i;
98 for (i = idx; i < idx + GCLLEN; i++)
99 if (gc_glyph[i] == c && gc_fg[i] == fg && gc_bg[i] == bg)
100 return gc_mem + i * GCGLEN;
101 return NULL;
104 static char *gc_put(int c, int fg, int bg)
106 int lst = GCIDX(c);
107 int pos = gc_next[lst]++;
108 int idx = lst * GCLLEN + pos;
109 if (gc_next[lst] >= GCLLEN)
110 gc_next[lst] = 0;
111 gc_glyph[idx] = c;
112 gc_fg[idx] = fg;
113 gc_bg[idx] = bg;
114 return gc_mem + idx * GCGLEN;
117 static void gc_refresh(void)
119 memset(gc_next, 0, sizeof(gc_next));
120 memset(gc_glyph, 0, sizeof(gc_glyph));
123 static void bmp2fb(char *d, char *s, int fg, int bg, int nr, int nc)
125 int i, j, k;
126 for (i = 0; i < fnrows; i++) {
127 char *p = d + i * fncols * bpp;
128 for (j = 0; j < fncols; j++) {
129 unsigned v = i < nr && j < nc ?
130 (unsigned char) s[i * nc + j] : 0;
131 unsigned c = mixed_color(fg, bg, v);
132 for (k = 0; k < bpp; k++) /* little-endian */
133 *p++ = (c >> (k << 3)) & 0xff;
138 static char *ch2fb(int fn, int c, int fg, int bg)
140 static char bits[1024 * 4];
141 char *fbbits;
142 if (c < 0 || (c < 128 && (!isprint(c) || isspace(c))))
143 return NULL;
144 if ((fbbits = gc_get(c, fg, bg)))
145 return fbbits;
146 if (font_bitmap(fonts[fn], bits, c))
147 return NULL;
148 fbbits = gc_put(c, fg, bg);
149 bmp2fb(fbbits, bits, fg & FN_C, bg & FN_C,
150 font_rows(fonts[fn]), font_cols(fonts[fn]));
151 return fbbits;
154 static void fb_set(int r, int c, void *mem, int len)
156 memcpy(fb_mem(fbroff + r) + (fbcoff + c) * bpp, mem, len * bpp);
159 static char *rowbuf(unsigned c, int len)
161 static char row[32 * 1024];
162 char *p = row;
163 int i, k;
164 for (i = 0; i < len; i++)
165 for (k = 0; k < bpp; k++) /* little-endian */
166 *p++ = (c >> (k * 8)) & 0xff;
167 return row;
170 static void fb_box(int sr, int er, int sc, int ec, unsigned val)
172 char *row = rowbuf(val, ec - sc);
173 int i;
174 for (i = sr; i < er; i++)
175 fb_set(i, sc, row, ec - sc);
178 void pad_border(unsigned c, int wid)
180 int v = color2fb(c & FN_C);
181 if (fbroff < wid || fbcoff < wid)
182 return;
183 fb_box(-wid, 0, -wid, fbcols + wid, v);
184 fb_box(fbrows, fbrows + wid, -wid, fbcols + wid, v);
185 fb_box(-wid, fbrows + wid, -wid, 0, v);
186 fb_box(-wid, fbrows + wid, fbcols, fbcols + wid, v);
189 static int fnsel(int fg, int bg)
191 if ((fg | bg) & FN_B)
192 return fonts[2] ? 2 : 0;
193 if ((fg | bg) & FN_I)
194 return fonts[1] ? 1 : 0;
195 return 0;
198 void pad_put(int ch, int r, int c, int fg, int bg)
200 int sr = fnrows * r;
201 int sc = fncols * c;
202 char *bits;
203 int i;
204 bits = ch2fb(fnsel(fg, bg), ch, fg, bg);
205 if (!bits)
206 bits = ch2fb(0, ch, fg, bg);
207 if (!bits)
208 fb_box(sr, sr + fnrows, sc, sc + fncols, color2fb(bg & FN_C));
209 else
210 for (i = 0; i < fnrows; i++)
211 fb_set(sr + i, sc, bits + (i * fncols * bpp), fncols);
214 void pad_fill(int sr, int er, int sc, int ec, int c)
216 int fber = er >= 0 ? er * fnrows : fbrows;
217 int fbec = ec >= 0 ? ec * fncols : fbcols;
218 fb_box(sr * fnrows, fber, sc * fncols, fbec, color2fb(c & FN_C));
221 int pad_rows(void)
223 return rows;
226 int pad_cols(void)
228 return cols;
231 int pad_font(char *fr, char *fi, char *fb)
233 struct font *r = fr ? font_open(fr) : NULL;
234 if (!r)
235 return 1;
236 font_free(fonts[0]);
237 font_free(fonts[1]);
238 font_free(fonts[2]);
239 fonts[0] = r;
240 fonts[1] = fi ? font_open(fi) : NULL;
241 fonts[2] = fb ? font_open(fb) : NULL;
242 gc_refresh();
243 return 0;
246 char *pad_fbdev(void)
248 static char fbdev[1024];
249 snprintf(fbdev, sizeof(fbdev), "FBDEV=%s:%dx%d%+d%+d",
250 fb_dev(), fbcols, fbrows, fbcoff, fbroff);
251 return fbdev;
254 /* character height */
255 int pad_crows(void)
257 return fnrows;
260 /* character width */
261 int pad_ccols(void)
263 return fncols;