- added libdrawtext
[demo_prior] / libs / drawtext / src / drawrast.c
diff --git a/libs/drawtext/src/drawrast.c b/libs/drawtext/src/drawrast.c
new file mode 100644 (file)
index 0000000..66543a5
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+libdrawtext - a simple library for fast text rendering in OpenGL
+Copyright (C) 2011-2016  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "drawtext.h"
+#include "drawtext_impl.h"
+
+static const char *drawchar(const char *str, float *xpos, float *ypos, int *should_flush);
+static void flush(void);
+static void draw_glyph(struct glyph *g, float x, float y);
+
+static unsigned char *fb_pixels;
+static int fb_width, fb_height;
+static struct dtx_glyphmap *gmap;
+static int threshold = -1;
+static int use_alpha;
+
+void dtx_target_raster(unsigned char *pixels, int width, int height)
+{
+       fb_pixels = pixels;
+       fb_width = width;
+       fb_height = height;
+       dtx_drawchar = drawchar;
+       dtx_drawflush = flush;
+}
+
+int dtx_rast_setopt(enum dtx_option opt, int val)
+{
+       switch(opt) {
+       case DTX_RASTER_THRESHOLD:
+               threshold = val;
+               break;
+       case DTX_RASTER_BLEND:
+               use_alpha = val;
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+int dtx_rast_getopt(enum dtx_option opt, int *res)
+{
+       switch(opt) {
+       case DTX_RASTER_THRESHOLD:
+               *res = threshold;
+               break;
+       case DTX_RASTER_BLEND:
+               *res = use_alpha ? 1 : 0;
+               break;
+       default:
+               return -1;
+       }
+       return 0;
+}
+
+static const char *drawchar(const char *str, float *xpos, float *ypos, int *should_flush)
+{
+       float px, py;
+       int code = dtx_utf8_char_code(str);
+       str = dtx_utf8_next_char((char*)str);
+
+       *should_flush = 0;      /* the raster renderer never buffers output */
+
+       px = *xpos;
+       py = *ypos;
+
+       if((gmap = dtx_proc_char(code, xpos, ypos))) {
+               int idx = code - gmap->cstart;
+               draw_glyph(gmap->glyphs + idx, px, py);
+       }
+       return str;
+}
+
+static void flush(void)
+{
+}
+
+static void blit_opaque(unsigned char *dest, unsigned char *src, int xsz, int ysz)
+{
+       int i, j;
+       int *col = dtx_cur_color_int;
+
+       for(i=0; i<ysz; i++) {
+               for(j=0; j<xsz; j++) {
+                       int val = src[j];
+                       *dest++ = val * col[0] / 255;
+                       *dest++ = val * col[1] / 255;
+                       *dest++ = val * col[2] / 255;
+                       *dest++ = val;
+               }
+               dest += (fb_width - xsz) * 4;
+               src += gmap->xsz;
+       }
+}
+
+static void blit_thres(unsigned char *dest, unsigned char *src, int xsz, int ysz)
+{
+       int i, j;
+       int *col = dtx_cur_color_int;
+
+       for(i=0; i<ysz; i++) {
+               for(j=0; j<xsz; j++) {
+                       int val = src[j];
+                       if(val > threshold) {
+                               *dest++ = col[0];
+                               *dest++ = col[1];
+                               *dest++ = col[2];
+                               *dest++ = col[3];
+                       } else {
+                               dest += 4;
+                       }
+               }
+               dest += (fb_width - xsz) * 4;
+               src += gmap->xsz;
+       }
+}
+
+static void blit_blend(unsigned char *dest, unsigned char *src, int xsz, int ysz)
+{
+       int i, j, k;
+       int *col = dtx_cur_color_int;
+
+       for(i=0; i<ysz; i++) {
+               for(j=0; j<xsz; j++) {
+                       int alpha = src[j];
+                       int inv_alpha = 255 - alpha;
+
+                       for(k=0; k<4; k++) {
+                               dest[k] = (col[k] * alpha + dest[k] * inv_alpha) / 255;
+                       }
+                       dest += 4;
+               }
+               dest += (fb_width - xsz) * 4;
+               src += gmap->xsz;
+       }
+}
+
+static void draw_glyph(struct glyph *g, float x, float y)
+{
+       unsigned char *dest, *src;
+       int gx = (int)g->x;
+       int gy = (int)g->y;
+       int gwidth = (int)g->width;
+       int gheight = (int)g->height;
+       int ix = (int)(x - g->orig_x);
+       int iy = (int)(y - gheight + g->orig_y);
+
+       if(ix >= fb_width || iy >= fb_height)
+               return;
+
+       if(ix < 0) {
+               gwidth += ix;
+               gx -= ix;
+               ix = 0;
+       }
+       if(iy < 0) {
+               gheight += iy;
+               gy -= iy;
+               iy = 0;
+       }
+       if(ix + gwidth >= fb_width) {
+               gwidth = fb_width - ix;
+       }
+       if(iy + gheight >= fb_height) {
+               gheight = fb_height - iy;
+       }
+
+       if(gwidth <= 0 || gheight <= 0)
+               return;
+
+       dest = fb_pixels + (iy * fb_width + ix) * 4;
+       src = gmap->pixels + gy * gmap->xsz + gx;
+
+       if(use_alpha) {
+               blit_blend(dest, src, gwidth, gheight);
+       } else if(threshold > 0) {
+               blit_thres(dest, src, gwidth, gheight);
+       } else {
+               blit_opaque(dest, src, gwidth, gheight);
+       }
+}
+