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