- added libdrawtext
[demo_prior] / libs / drawtext / src / drawrast.c
1 /*
2 libdrawtext - a simple library for fast text rendering in OpenGL
3 Copyright (C) 2011-2016  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include "drawtext.h"
22 #include "drawtext_impl.h"
23
24 static const char *drawchar(const char *str, float *xpos, float *ypos, int *should_flush);
25 static void flush(void);
26 static void draw_glyph(struct glyph *g, float x, float y);
27
28 static unsigned char *fb_pixels;
29 static int fb_width, fb_height;
30 static struct dtx_glyphmap *gmap;
31 static int threshold = -1;
32 static int use_alpha;
33
34 void dtx_target_raster(unsigned char *pixels, int width, int height)
35 {
36         fb_pixels = pixels;
37         fb_width = width;
38         fb_height = height;
39         dtx_drawchar = drawchar;
40         dtx_drawflush = flush;
41 }
42
43 int dtx_rast_setopt(enum dtx_option opt, int val)
44 {
45         switch(opt) {
46         case DTX_RASTER_THRESHOLD:
47                 threshold = val;
48                 break;
49         case DTX_RASTER_BLEND:
50                 use_alpha = val;
51                 break;
52         default:
53                 return -1;
54         }
55         return 0;
56 }
57
58 int dtx_rast_getopt(enum dtx_option opt, int *res)
59 {
60         switch(opt) {
61         case DTX_RASTER_THRESHOLD:
62                 *res = threshold;
63                 break;
64         case DTX_RASTER_BLEND:
65                 *res = use_alpha ? 1 : 0;
66                 break;
67         default:
68                 return -1;
69         }
70         return 0;
71 }
72
73 static const char *drawchar(const char *str, float *xpos, float *ypos, int *should_flush)
74 {
75         float px, py;
76         int code = dtx_utf8_char_code(str);
77         str = dtx_utf8_next_char((char*)str);
78
79         *should_flush = 0;      /* the raster renderer never buffers output */
80
81         px = *xpos;
82         py = *ypos;
83
84         if((gmap = dtx_proc_char(code, xpos, ypos))) {
85                 int idx = code - gmap->cstart;
86                 draw_glyph(gmap->glyphs + idx, px, py);
87         }
88         return str;
89 }
90
91 static void flush(void)
92 {
93 }
94
95 static void blit_opaque(unsigned char *dest, unsigned char *src, int xsz, int ysz)
96 {
97         int i, j;
98         int *col = dtx_cur_color_int;
99
100         for(i=0; i<ysz; i++) {
101                 for(j=0; j<xsz; j++) {
102                         int val = src[j];
103                         *dest++ = val * col[0] / 255;
104                         *dest++ = val * col[1] / 255;
105                         *dest++ = val * col[2] / 255;
106                         *dest++ = val;
107                 }
108                 dest += (fb_width - xsz) * 4;
109                 src += gmap->xsz;
110         }
111 }
112
113 static void blit_thres(unsigned char *dest, unsigned char *src, int xsz, int ysz)
114 {
115         int i, j;
116         int *col = dtx_cur_color_int;
117
118         for(i=0; i<ysz; i++) {
119                 for(j=0; j<xsz; j++) {
120                         int val = src[j];
121                         if(val > threshold) {
122                                 *dest++ = col[0];
123                                 *dest++ = col[1];
124                                 *dest++ = col[2];
125                                 *dest++ = col[3];
126                         } else {
127                                 dest += 4;
128                         }
129                 }
130                 dest += (fb_width - xsz) * 4;
131                 src += gmap->xsz;
132         }
133 }
134
135 static void blit_blend(unsigned char *dest, unsigned char *src, int xsz, int ysz)
136 {
137         int i, j, k;
138         int *col = dtx_cur_color_int;
139
140         for(i=0; i<ysz; i++) {
141                 for(j=0; j<xsz; j++) {
142                         int alpha = src[j];
143                         int inv_alpha = 255 - alpha;
144
145                         for(k=0; k<4; k++) {
146                                 dest[k] = (col[k] * alpha + dest[k] * inv_alpha) / 255;
147                         }
148                         dest += 4;
149                 }
150                 dest += (fb_width - xsz) * 4;
151                 src += gmap->xsz;
152         }
153 }
154
155 static void draw_glyph(struct glyph *g, float x, float y)
156 {
157         unsigned char *dest, *src;
158         int gx = (int)g->x;
159         int gy = (int)g->y;
160         int gwidth = (int)g->width;
161         int gheight = (int)g->height;
162         int ix = (int)(x - g->orig_x);
163         int iy = (int)(y - gheight + g->orig_y);
164
165         if(ix >= fb_width || iy >= fb_height)
166                 return;
167
168         if(ix < 0) {
169                 gwidth += ix;
170                 gx -= ix;
171                 ix = 0;
172         }
173         if(iy < 0) {
174                 gheight += iy;
175                 gy -= iy;
176                 iy = 0;
177         }
178         if(ix + gwidth >= fb_width) {
179                 gwidth = fb_width - ix;
180         }
181         if(iy + gheight >= fb_height) {
182                 gheight = fb_height - iy;
183         }
184
185         if(gwidth <= 0 || gheight <= 0)
186                 return;
187
188         dest = fb_pixels + (iy * fb_width + ix) * 4;
189         src = gmap->pixels + gy * gmap->xsz + gx;
190
191         if(use_alpha) {
192                 blit_blend(dest, src, gwidth, gheight);
193         } else if(threshold > 0) {
194                 blit_thres(dest, src, gwidth, gheight);
195         } else {
196                 blit_opaque(dest, src, gwidth, gheight);
197         }
198 }
199