graphics

experiments with opengl3.2/ogles3.3 on linux and win7
git clone http://frotz.net/git/graphics.git
Log | Files | Refs

texturefont.cc (5472B)


      1 /* Copyright 2013 Brian Swetland <swetland@frotz.net>
      2  *
      3  * Licensed under the Apache License, Version 2.0 (the "License");
      4  * you may not use this file except in compliance with the License.
      5  * You may obtain a copy of the License at
      6  *
      7  *     http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software
     10  * distributed under the License is distributed on an "AS IS" BASIS,
     11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12  * See the License for the specific language governing permissions and
     13  * limitations under the License.
     14  */
     15 
     16 #include <stdio.h>
     17 
     18 #include "util.h"
     19 #include "matrix.h"
     20 #include "app.h"
     21 #include "texturefont.h"
     22 
     23 /* performance experiments to try sometime:
     24  * - pass color via vtx attr instead of unpacking in shader
     25  * - pass character vertex table via uniform instead of texturebuffer
     26  * - instead of DrawArraysInstanced:
     27  *   - call DrawElements with a fixed 1,1,1,1,1,1,2,2,2,2,2,2,3,... index buffer
     28  *   - call DrawArrays with unpacked vtx array (6 per character)
     29  * - explore different vtx formats (int vs float vs short, etc)
     30 */
     31 
     32 TextureFont* TextureFont::load(const char *fontname) {
     33 	TextureFont *f = new TextureFont();
     34 	if (f->init(fontname)) {
     35 		delete f;
     36 		return nullptr;
     37 	}
     38 	return f;
     39 }
     40 
     41 int TextureFont::init(const char *fontname) {
     42 	char tmp[256];
     43 	float *cdata, *cp; 
     44 	float dim, adj;
     45 	unsigned sz;
     46 	header = NULL;
     47 
     48 	sprintf(tmp, "%s.font.png", fontname);
     49 	if (glyphs.load(tmp, OPT_TEX2D_GRAY))
     50 		goto fail;
     51 
     52 	sprintf(tmp, "%s.font.dat", fontname);
     53 	header = (FontInfo*) load_file(tmp, &sz);
     54 	info = header->info;
     55 	if (sz < sizeof(FontInfo)) {
     56 		error("invalid font header"); 
     57 		goto fail;
     58 	}
     59 	if (header->magic != TEXTUREFONT_MAGIC) {
     60 		error("invalid font magic");
     61 		goto fail;
     62 	}
     63 	if (sz < (sizeof(FontInfo) + sizeof(CharInfo) * header->count)) {
     64 		error("missing font data");
     65 		goto fail;
     66 	}
     67 	first = header->first;
     68 	last = first + header->count - 1;
     69 
     70 	if (!(effect = Effect::load("texturefont")))
     71 		goto fail;
     72 
     73 	cp = cdata = (float*) malloc(sizeof(float) * 4 * 6 * header->count);
     74 
     75 	/* to adjust int coords to texture coords */
     76 	dim = glyphs.width;
     77 	adj = 0.5 / float(glyphs.width);
     78 
     79 	/* generate a 2d+uv quad for each character */
     80 	for (unsigned n = 0; n < header->count; n++) {
     81 		*cp++ = 0;
     82 		*cp++ = -info[n].h;
     83 		*cp++ = float(info[n].x) / dim + adj;
     84 		*cp++ = float(info[n].y) / dim + adj;
     85 
     86 		*cp++ = info[n].w;
     87 		*cp++ = -info[n].h;
     88 		*cp++ = float(info[n].x + info[n].w - 1) / dim + adj;
     89 		*cp++ = float(info[n].y) / dim + adj;
     90 
     91 		*cp++ = 0;
     92 		*cp++ = 0;
     93 		*cp++ = float(info[n].x) / dim + adj;
     94 		*cp++ = float(info[n].y + info[n].h - 1) / dim + adj;
     95 
     96 		*cp++ = info[n].w;
     97 		*cp++ = 0;
     98 		*cp++ = float(info[n].x + info[n].w - 1) / dim + adj;
     99 		*cp++ = float(info[n].y + info[n].h - 1) / dim + adj;
    100 
    101 		*cp++ = 0;
    102 		*cp++ = 0;
    103 		*cp++ = float(info[n].x) / dim + adj;
    104 		*cp++ = float(info[n].y + info[n].h - 1) / dim + adj;
    105 
    106 		*cp++ = info[n].w;
    107 		*cp++ = -info[n].h;
    108 		*cp++ = float(info[n].x + info[n].w - 1) / dim + adj;
    109 		*cp++ = float(info[n].y) / dim + adj;
    110 	}
    111 	cbuf.load(cdata, sizeof(float) * 4 * 6 * header->count);
    112 
    113 	glGenTextures(1, &tbid);
    114 	glActiveTexture(GL_TEXTURE0 + 15);
    115 	glBindTexture(GL_TEXTURE_BUFFER, tbid);
    116 	glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, cbuf.id);
    117 	return 0;
    118 fail:
    119 	if (header) {
    120 		free(header);
    121 		header = NULL;
    122 	}
    123 
    124 	return 0;
    125 }
    126 
    127 void TextureFont::measure(const char *s, unsigned *width, unsigned *height) {
    128 	unsigned w = 0;
    129 	unsigned h = 0;
    130 	while (*s) {
    131 		unsigned n = *s++;
    132 		if (n == 0)
    133 			break;
    134 		if ((n < first) || (n > last))
    135 			continue;
    136 		n -= first;
    137 		unsigned ch = info[n].h;
    138 		if (ch > h)
    139 			h = ch;
    140 		w += info[n].advance;
    141 	}
    142 	*width = w;
    143 	*height = h;
    144 }
    145 
    146 // idx, src, dst, count, offset, stride, divisor
    147 static VertexAttrDesc layout[] = {
    148 	{ 0, SRC_INT32, DST_INTEGER, 4, 0, 16, 6 },
    149 };
    150 
    151 Text* Text::create(TextureFont *font) {
    152 	Text *t = new Text();
    153 	VertexBuffer *vdata[] = { &t->vtx };
    154 	t->font = font;
    155 	t->max = 128;
    156 	t->count = 0;
    157 	t->data = (CharData*) malloc(sizeof(CharData) * t->max);
    158 	t->next = t->data;
    159 	t->color = RGBA(255,255,255,255);
    160 	t->dirty = 0;
    161 	
    162 	t->vtx.load(t->data, sizeof(CharData) * t->max);
    163 	t->attr.init(layout, vdata, sizeof(layout) / sizeof(layout[0]));
    164 
    165 	return t;
    166 };
    167 
    168 void Text::clear(void) {
    169 	next = data;
    170 	count = 0;
    171 	dirty = 1;
    172 }
    173 
    174 void Text::setColor(unsigned rgba) {
    175 	color = rgba;
    176 }
    177 
    178 void Text::render(void) {
    179 	if (count == 0)
    180 		return;
    181 
    182 	if (dirty) {
    183 		vtx.load(data, sizeof(CharData) * count);
    184 		dirty = 0;
    185 	}
    186 
    187 	font->effect->apply();
    188 	font->glyphs.use(1);
    189 	attr.use();
    190 	glActiveTexture(GL_TEXTURE0 + 0);
    191 	glBindTexture(GL_TEXTURE_BUFFER, font->tbid);
    192 	glEnable(GL_BLEND);
    193 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    194 	glDrawArraysInstanced(GL_TRIANGLES, 0, 6, count * 6);
    195 	glDisable(GL_BLEND);
    196 }
    197 
    198 void Text::puts(int x, int y, const char *s) {
    199 	while (count < max) {
    200 		unsigned n = *s++;
    201 		if (n == 0)
    202 			break;
    203 		if ((n < font->first) || (n > font->last))
    204 			continue;
    205 		n -= font->first;
    206 		data[count].x = x + font->info[n].dx;
    207 		data[count].y = y - font->info[n].dy;
    208 		data[count].id = n * 6;
    209 		data[count].rgba = color & 0xFFFFFF; // strip alpha
    210 		count++;
    211 		x += font->info[n].advance;
    212 	}
    213 	dirty = 1;
    214 }
    215 
    216 void Text::printf(int x, int y, const char *fmt, ...) {
    217 	char buf[128];
    218 	int len;
    219 	va_list ap;
    220 	va_start(ap, fmt);
    221 	len = vsnprintf(buf, sizeof(buf), fmt, ap);
    222 	va_end(ap);
    223 	buf[127] = 0;
    224 	if (len > 127) len = 127;
    225 	puts(x, y, buf);
    226 }