|
Blender
V2.59
|
00001 /* 00002 * $Id: blf_glyph.c 35453 2011-03-10 13:49:46Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2009 Blender Foundation. 00021 * All rights reserved. 00022 * 00023 * 00024 * Contributor(s): Blender Foundation 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include <stdio.h> 00035 #include <stdlib.h> 00036 #include <string.h> 00037 #include <math.h> 00038 00039 #include <ft2build.h> 00040 00041 #include FT_FREETYPE_H 00042 #include FT_GLYPH_H 00043 #include FT_OUTLINE_H 00044 #include FT_BITMAP_H 00045 00046 #include "MEM_guardedalloc.h" 00047 00048 #include "DNA_vec_types.h" 00049 #include "DNA_userdef_types.h" 00050 00051 #include "BLI_blenlib.h" 00052 00053 #include "BIF_gl.h" 00054 #include "BLF_api.h" 00055 00056 #include "blf_internal_types.h" 00057 #include "blf_internal.h" 00058 00059 00060 GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, int size, int dpi) 00061 { 00062 GlyphCacheBLF *p; 00063 00064 p= (GlyphCacheBLF *)font->cache.first; 00065 while (p) { 00066 if (p->size == size && p->dpi == dpi) 00067 return(p); 00068 p= p->next; 00069 } 00070 return(NULL); 00071 } 00072 00073 /* Create a new glyph cache for the current size and dpi. */ 00074 GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) 00075 { 00076 GlyphCacheBLF *gc; 00077 int i; 00078 00079 gc= (GlyphCacheBLF *)MEM_mallocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); 00080 gc->next= NULL; 00081 gc->prev= NULL; 00082 gc->size= font->size; 00083 gc->dpi= font->dpi; 00084 00085 for (i= 0; i < 257; i++) { 00086 gc->bucket[i].first= NULL; 00087 gc->bucket[i].last= NULL; 00088 } 00089 00090 gc->textures= (GLuint *)malloc(sizeof(GLuint)*256); 00091 gc->ntex= 256; 00092 gc->cur_tex= -1; 00093 gc->x_offs= 0; 00094 gc->y_offs= 0; 00095 gc->pad= 3; 00096 00097 gc->num_glyphs= font->face->num_glyphs; 00098 gc->rem_glyphs= font->face->num_glyphs; 00099 gc->ascender= ((float)font->face->size->metrics.ascender) / 64.0f; 00100 gc->descender= ((float)font->face->size->metrics.descender) / 64.0f; 00101 00102 if (FT_IS_SCALABLE(font->face)) { 00103 gc->max_glyph_width= (float)((font->face->bbox.xMax - font->face->bbox.xMin) * 00104 (((float)font->face->size->metrics.x_ppem) / 00105 ((float)font->face->units_per_EM))); 00106 00107 gc->max_glyph_height= (float)((font->face->bbox.yMax - font->face->bbox.yMin) * 00108 (((float)font->face->size->metrics.y_ppem) / 00109 ((float)font->face->units_per_EM))); 00110 } 00111 else { 00112 gc->max_glyph_width= ((float)font->face->size->metrics.max_advance) / 64.0f; 00113 gc->max_glyph_height= ((float)font->face->size->metrics.height) / 64.0f; 00114 } 00115 00116 gc->p2_width= 0; 00117 gc->p2_height= 0; 00118 00119 BLI_addhead(&font->cache, gc); 00120 return(gc); 00121 } 00122 00123 void blf_glyph_cache_clear(FontBLF *font) 00124 { 00125 GlyphCacheBLF *gc; 00126 GlyphBLF *g; 00127 int i; 00128 00129 for(gc=font->cache.first; gc; gc=gc->next) { 00130 for (i= 0; i < 257; i++) { 00131 while (gc->bucket[i].first) { 00132 g= gc->bucket[i].first; 00133 BLI_remlink(&(gc->bucket[i]), g); 00134 blf_glyph_free(g); 00135 } 00136 } 00137 } 00138 00139 memset(font->glyph_ascii_table, 0, sizeof(font->glyph_ascii_table)); 00140 } 00141 00142 void blf_glyph_cache_free(GlyphCacheBLF *gc) 00143 { 00144 GlyphBLF *g; 00145 int i; 00146 00147 for (i= 0; i < 257; i++) { 00148 while (gc->bucket[i].first) { 00149 g= gc->bucket[i].first; 00150 BLI_remlink(&(gc->bucket[i]), g); 00151 blf_glyph_free(g); 00152 } 00153 } 00154 00155 if (gc->cur_tex+1 > 0) 00156 glDeleteTextures(gc->cur_tex+1, gc->textures); 00157 free((void *)gc->textures); 00158 MEM_freeN(gc); 00159 } 00160 00161 static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) 00162 { 00163 int tot_mem, i; 00164 unsigned char *buf; 00165 00166 /* move the index. */ 00167 gc->cur_tex++; 00168 00169 if (gc->cur_tex >= gc->ntex) { 00170 gc->ntex *= 2; 00171 gc->textures= (GLuint *)realloc((void *)gc->textures, sizeof(GLuint)*gc->ntex); 00172 } 00173 00174 gc->p2_width= blf_next_p2((gc->rem_glyphs * gc->max_glyph_width) + (gc->pad * 2)); 00175 if (gc->p2_width > font->max_tex_size) 00176 gc->p2_width= font->max_tex_size; 00177 00178 i= (int)((gc->p2_width - (gc->pad * 2)) / gc->max_glyph_width); 00179 gc->p2_height= blf_next_p2(((gc->num_glyphs / i) + 1) * gc->max_glyph_height); 00180 00181 if (gc->p2_height > font->max_tex_size) 00182 gc->p2_height= font->max_tex_size; 00183 00184 tot_mem= gc->p2_width * gc->p2_height; 00185 buf= (unsigned char *)malloc(tot_mem); 00186 memset((void *)buf, 0, tot_mem); 00187 00188 glGenTextures(1, &gc->textures[gc->cur_tex]); 00189 glBindTexture(GL_TEXTURE_2D, gc->textures[gc->cur_tex]); 00190 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00191 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00192 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 00193 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 00194 00195 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buf); 00196 free((void *)buf); 00197 } 00198 00199 GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c) 00200 { 00201 GlyphBLF *p; 00202 unsigned int key; 00203 00204 key= blf_hash(c); 00205 p= gc->bucket[key].first; 00206 while (p) { 00207 if (p->c == c) 00208 return(p); 00209 p= p->next; 00210 } 00211 return(NULL); 00212 } 00213 00214 GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) 00215 { 00216 FT_GlyphSlot slot; 00217 GlyphBLF *g; 00218 FT_Error err; 00219 FT_Bitmap bitmap, tempbitmap; 00220 int sharp = (U.text_render & USER_TEXT_DISABLE_AA); 00221 FT_BBox bbox; 00222 unsigned int key; 00223 00224 g= blf_glyph_search(font->glyph_cache, c); 00225 if (g) 00226 return(g); 00227 00228 if (sharp) 00229 err = FT_Load_Glyph(font->face, (FT_UInt)index, FT_LOAD_TARGET_MONO); 00230 else 00231 err = FT_Load_Glyph(font->face, (FT_UInt)index, FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP); /* Sure about NO_* flags? */ 00232 if (err) 00233 return(NULL); 00234 00235 /* get the glyph. */ 00236 slot= font->face->glyph; 00237 00238 if (sharp) { 00239 err = FT_Render_Glyph(slot, FT_RENDER_MODE_MONO); 00240 00241 /* Convert result from 1 bit per pixel to 8 bit per pixel */ 00242 /* Accum errors for later, fine if not interested beyond "ok vs any error" */ 00243 FT_Bitmap_New(&tempbitmap); 00244 err += FT_Bitmap_Convert(font->ft_lib, &slot->bitmap, &tempbitmap, 1); /* Does Blender use Pitch 1 always? It works so far */ 00245 err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &slot->bitmap); 00246 err += FT_Bitmap_Done(font->ft_lib, &tempbitmap); 00247 } else { 00248 err = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); 00249 } 00250 00251 if (err || slot->format != FT_GLYPH_FORMAT_BITMAP) 00252 return(NULL); 00253 00254 g= (GlyphBLF *)MEM_mallocN(sizeof(GlyphBLF), "blf_glyph_add"); 00255 g->next= NULL; 00256 g->prev= NULL; 00257 g->c= c; 00258 g->idx= (FT_UInt)index; 00259 g->tex= 0; 00260 g->build_tex= 0; 00261 g->bitmap= NULL; 00262 g->xoff= -1; 00263 g->yoff= -1; 00264 g->uv[0][0]= 0.0f; 00265 g->uv[0][1]= 0.0f; 00266 g->uv[1][0]= 0.0f; 00267 g->uv[1][1]= 0.0f; 00268 bitmap= slot->bitmap; 00269 g->width= bitmap.width; 00270 g->height= bitmap.rows; 00271 00272 if (g->width && g->height) { 00273 if (sharp) { 00274 /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */ 00275 int i; 00276 for (i=0; i < (g->width * g->height); i++) { 00277 bitmap.buffer[i] = 255 * bitmap.buffer[i]; 00278 } 00279 } 00280 00281 g->bitmap= (unsigned char *)MEM_mallocN(g->width * g->height, "glyph bitmap"); 00282 memcpy((void *)g->bitmap, (void *)bitmap.buffer, g->width * g->height); 00283 } 00284 00285 g->advance= ((float)slot->advance.x) / 64.0f; 00286 g->pos_x= slot->bitmap_left; 00287 g->pos_y= slot->bitmap_top; 00288 g->pitch= slot->bitmap.pitch; 00289 00290 FT_Outline_Get_CBox(&(slot->outline), &bbox); 00291 g->box.xmin= ((float)bbox.xMin) / 64.0f; 00292 g->box.xmax= ((float)bbox.xMax) / 64.0f; 00293 g->box.ymin= ((float)bbox.yMin) / 64.0f; 00294 g->box.ymax= ((float)bbox.yMax) / 64.0f; 00295 00296 key= blf_hash(g->c); 00297 BLI_addhead(&(font->glyph_cache->bucket[key]), g); 00298 return(g); 00299 } 00300 00301 void blf_glyph_free(GlyphBLF *g) 00302 { 00303 /* don't need free the texture, the GlyphCache already 00304 * have a list of all the texture and free it. 00305 */ 00306 if (g->bitmap) 00307 MEM_freeN(g->bitmap); 00308 MEM_freeN(g); 00309 } 00310 00311 static void blf_texture_draw(float uv[2][2], float dx, float y1, float dx1, float y2) 00312 { 00313 00314 glBegin(GL_QUADS); 00315 glTexCoord2f(uv[0][0], uv[0][1]); 00316 glVertex2f(dx, y1); 00317 00318 glTexCoord2f(uv[0][0], uv[1][1]); 00319 glVertex2f(dx, y2); 00320 00321 glTexCoord2f(uv[1][0], uv[1][1]); 00322 glVertex2f(dx1, y2); 00323 00324 glTexCoord2f(uv[1][0], uv[0][1]); 00325 glVertex2f(dx1, y1); 00326 glEnd(); 00327 00328 } 00329 00330 static void blf_texture5_draw(float uv[2][2], float x1, float y1, float x2, float y2) 00331 { 00332 float soft[25]= { 00333 1/60.0f, 1/60.0f, 2/60.0f, 1/60.0f, 1/60.0f, 00334 1/60.0f, 3/60.0f, 5/60.0f, 3/60.0f, 1/60.0f, 00335 2/60.0f, 5/60.0f, 8/60.0f, 5/60.0f, 2/60.0f, 00336 1/60.0f, 3/60.0f, 5/60.0f, 3/60.0f, 1/60.0f, 00337 1/60.0f, 1/60.0f, 2/60.0f, 1/60.0f, 1/60.0f}; 00338 00339 float color[4], *fp= soft; 00340 int dx, dy; 00341 00342 glGetFloatv(GL_CURRENT_COLOR, color); 00343 00344 for(dx=-2; dx<3; dx++) { 00345 for(dy=-2; dy<3; dy++, fp++) { 00346 glColor4f(color[0], color[1], color[2], fp[0]*color[3]); 00347 blf_texture_draw(uv, x1+dx, y1+dy, x2+dx, y2+dy); 00348 } 00349 } 00350 00351 glColor4fv(color); 00352 } 00353 00354 static void blf_texture3_draw(float uv[2][2], float x1, float y1, float x2, float y2) 00355 { 00356 float soft[9]= {1/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 4/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 1/16.0f}; 00357 float color[4], *fp= soft; 00358 int dx, dy; 00359 00360 glGetFloatv(GL_CURRENT_COLOR, color); 00361 00362 for(dx=-1; dx<2; dx++) { 00363 for(dy=-1; dy<2; dy++, fp++) { 00364 glColor4f(color[0], color[1], color[2], fp[0]*color[3]); 00365 blf_texture_draw(uv, x1+dx, y1+dy, x2+dx, y2+dy); 00366 } 00367 } 00368 00369 glColor4fv(color); 00370 } 00371 00372 int blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) 00373 { 00374 GlyphCacheBLF *gc; 00375 GLint cur_tex; 00376 float dx, dx1; 00377 float y1, y2; 00378 float xo, yo; 00379 float color[4]; 00380 00381 if ((!g->width) || (!g->height)) 00382 return(1); 00383 00384 if (g->build_tex == 0) { 00385 gc= font->glyph_cache; 00386 00387 if (font->max_tex_size == -1) 00388 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->max_tex_size); 00389 00390 if (gc->cur_tex == -1) { 00391 blf_glyph_cache_texture(font, gc); 00392 gc->x_offs= gc->pad; 00393 gc->y_offs= gc->pad; 00394 } 00395 00396 if (gc->x_offs > (gc->p2_width - gc->max_glyph_width)) { 00397 gc->x_offs= gc->pad; 00398 gc->y_offs += gc->max_glyph_height; 00399 00400 if (gc->y_offs > (gc->p2_height - gc->max_glyph_height)) { 00401 gc->y_offs= gc->pad; 00402 blf_glyph_cache_texture(font, gc); 00403 } 00404 } 00405 00406 g->tex= gc->textures[gc->cur_tex]; 00407 g->xoff= gc->x_offs; 00408 g->yoff= gc->y_offs; 00409 00410 glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); 00411 glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); 00412 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 00413 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 00414 00415 glBindTexture(GL_TEXTURE_2D, g->tex); 00416 glTexSubImage2D(GL_TEXTURE_2D, 0, g->xoff, g->yoff, g->width, g->height, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap); 00417 glPopClientAttrib(); 00418 00419 g->uv[0][0]= ((float)g->xoff) / ((float)gc->p2_width); 00420 g->uv[0][1]= ((float)g->yoff) / ((float)gc->p2_height); 00421 g->uv[1][0]= ((float)(g->xoff + g->width)) / ((float)gc->p2_width); 00422 g->uv[1][1]= ((float)(g->yoff + g->height)) / ((float)gc->p2_height); 00423 00424 /* update the x offset for the next glyph. */ 00425 gc->x_offs += (int)(g->box.xmax - g->box.xmin + gc->pad); 00426 00427 gc->rem_glyphs--; 00428 g->build_tex= 1; 00429 } 00430 00431 xo= 0.0f; 00432 yo= 0.0f; 00433 00434 if (font->flags & BLF_SHADOW) { 00435 xo= x; 00436 yo= y; 00437 x += font->shadow_x; 00438 y += font->shadow_y; 00439 } 00440 00441 dx= floor(x + g->pos_x); 00442 dx1= dx + g->width; 00443 y1= y + g->pos_y; 00444 y2= y + g->pos_y - g->height; 00445 00446 if (font->flags & BLF_CLIPPING) { 00447 if (!BLI_in_rctf(&font->clip_rec, dx + font->pos[0], y1 + font->pos[1])) 00448 return(0); 00449 if (!BLI_in_rctf(&font->clip_rec, dx + font->pos[0], y2 + font->pos[1])) 00450 return(0); 00451 if (!BLI_in_rctf(&font->clip_rec, dx1 + font->pos[0], y2 + font->pos[1])) 00452 return(0); 00453 if (!BLI_in_rctf(&font->clip_rec, dx1 + font->pos[0], y1 + font->pos[1])) 00454 return(0); 00455 } 00456 00457 glGetIntegerv(GL_TEXTURE_2D_BINDING_EXT, &cur_tex); 00458 if (cur_tex != g->tex) 00459 glBindTexture(GL_TEXTURE_2D, g->tex); 00460 00461 if (font->flags & BLF_SHADOW) { 00462 glGetFloatv(GL_CURRENT_COLOR, color); 00463 glColor4fv(font->shadow_col); 00464 00465 if (font->shadow == 3) 00466 blf_texture3_draw(g->uv, dx, y1, dx1, y2); 00467 else if (font->shadow == 5) 00468 blf_texture5_draw(g->uv, dx, y1, dx1, y2); 00469 else 00470 blf_texture_draw(g->uv, dx, y1, dx1, y2); 00471 00472 glColor4fv(color); 00473 x= xo; 00474 y= yo; 00475 00476 dx= floor(x + g->pos_x); 00477 dx1= dx + g->width; 00478 y1= y + g->pos_y; 00479 y2= y + g->pos_y - g->height; 00480 } 00481 00482 if (font->blur==3) 00483 blf_texture3_draw(g->uv, dx, y1, dx1, y2); 00484 else if (font->blur==5) 00485 blf_texture5_draw(g->uv, dx, y1, dx1, y2); 00486 else 00487 blf_texture_draw(g->uv, dx, y1, dx1, y2); 00488 00489 return(1); 00490 }