draw: update draw.c from fbpad
[cnoor.git] / draw.c
blob457c0b0127d5d76c2f76105cf29b49ab52805501
1 #include <fcntl.h>
2 #include <linux/fb.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <sys/ioctl.h>
6 #include <sys/mman.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include "draw.h"
10 #include "util.h"
12 #define FBDEV_PATH "/dev/fb0"
13 #define MAXFBWIDTH (1 << 12)
14 #define BPP sizeof(fbval_t)
15 #define NLEVELS (1 << 8)
17 static int fd;
18 static unsigned char *fb;
19 static struct fb_var_screeninfo vinfo;
20 static struct fb_fix_screeninfo finfo;
21 static int rl, rr, gl, gr, bl, br;
22 static int nr, ng, nb;
24 static int fb_len()
26 return vinfo.xres_virtual * vinfo.yres_virtual * BPP;
29 static void fb_cmap_save(int save)
31 static unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS];
32 struct fb_cmap cmap;
33 if (finfo.visual == FB_VISUAL_TRUECOLOR)
34 return;
35 cmap.start = 0;
36 cmap.len = MAX(nr, MAX(ng, nb));
37 cmap.red = red;
38 cmap.green = green;
39 cmap.blue = blue;
40 cmap.transp = 0;
41 ioctl(fd, save ? FBIOGETCMAP : FBIOPUTCMAP, &cmap);
44 void fb_cmap(void)
46 unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS];
47 struct fb_cmap cmap;
48 int i;
49 if (finfo.visual == FB_VISUAL_TRUECOLOR)
50 return;
52 for (i = 0; i < nr; i++)
53 red[i] = (65535 / (nr - 1)) * i;
54 for (i = 0; i < ng; i++)
55 green[i] = (65535 / (ng - 1)) * i;
56 for (i = 0; i < nb; i++)
57 blue[i] = (65535 / (nb - 1)) * i;
59 cmap.start = 0;
60 cmap.len = MAX(nr, MAX(ng, nb));
61 cmap.red = red;
62 cmap.green = green;
63 cmap.blue = blue;
64 cmap.transp = 0;
66 ioctl(fd, FBIOPUTCMAP, &cmap);
69 static void xdie(char *msg)
71 fprintf(stderr, "%s\n", msg);
72 exit(1);
75 static void init_colors(void)
77 nr = 1 << vinfo.red.length;
78 ng = 1 << vinfo.green.length;
79 nb = 1 << vinfo.blue.length;
80 rr = 8 - vinfo.red.length;
81 rl = vinfo.red.offset;
82 gr = 8 - vinfo.green.length;
83 gl = vinfo.green.offset;
84 br = 8 - vinfo.blue.length;
85 bl = vinfo.blue.offset;
88 void fb_init(void)
90 fd = open(FBDEV_PATH, O_RDWR);
91 if (fd == -1)
92 xerror("can't open " FBDEV_PATH);
93 if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
94 xerror("ioctl failed");
95 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
96 xerror("ioctl failed");
97 if ((vinfo.bits_per_pixel + 7) >> 3 != BPP)
98 xdie("fbval_t does not match framebuffer depth");
99 init_colors();
100 fb = mmap(NULL, fb_len(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
101 if (fb == MAP_FAILED)
102 xerror("can't map the framebuffer");
103 fb_cmap_save(1);
104 fb_cmap();
107 void fb_set(int r, int c, fbval_t *mem, int len)
109 long loc = (c + vinfo.xoffset) * BPP +
110 (r + vinfo.yoffset) * finfo.line_length;
111 memcpy(fb + loc, mem, len * BPP);
114 void fb_free()
116 fb_cmap_save(0);
117 munmap(fb, fb_len());
118 close(fd);
121 fbval_t fb_color(unsigned char r, unsigned char g, unsigned char b)
123 return ((r >> rr) << rl) | ((g >> gr) << gl) | ((b >> br) << bl);
126 int fb_rows(void)
128 return vinfo.yres;
131 int fb_cols(void)
133 return vinfo.xres;
136 static unsigned char *rowaddr(int r)
138 return fb + (r + vinfo.yoffset) * finfo.line_length;
141 static unsigned long cache[MAXFBWIDTH];
142 void fb_box(int sr, int sc, int er, int ec, fbval_t val)
144 int i;
145 int pc = sizeof(cache[0]) / sizeof(val);
146 int cn = MIN((ec - sc) / pc + 1, MAXFBWIDTH);
147 unsigned long nv = val;
148 for (i = 1; i < pc; i++)
149 nv = (nv << (sizeof(val) * 8)) | val;
150 for (i = 0; i < cn; i++)
151 cache[i] = nv;
152 for (i = sr; i < er; i++)
153 memcpy(rowaddr(i) + sc * BPP, cache, (ec - sc) * BPP);