📄 text.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / 3D rendering module * * GPAC 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 2, or (at your option) * any later version. * * GPAC 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 library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "render3d_nodes.h"#include "grouping.h"#include <gpac/utf.h>typedef struct{ GF_Node *owner; GF_Renderer *compositor; GF_Mesh *mesh; Bool (*IntersectWithRay)(GF_Node *owner, GF_Ray *ray, SFVec3f *outPoint); Bool (*ClosestFace)(GF_Node *owner, SFVec3f user_pos, Fixed min_dist, SFVec3f *outPoint); GF_Path *path; GF_List *strike_list; Fixed ascent, descent; GF_List *text_lines; GF_Rect bounds; Bool texture_text_flag;} TextStack;/*default value when no fontStyle*/#define FSFAMILY (fs && fs->family.count) ? (const char *)fs->family.vals[0] : ""/*here it's tricky since it depends on our metric system...*/#define FSSIZE (fs ? fs->size : FIX_ONE)#define FSSTYLE (fs && fs->style.buffer) ? (const char *)fs->style.buffer : ""#define FSMAJOR ( (fs && fs->justify.count && fs->justify.vals[0]) ? (const char *)fs->justify.vals[0] : "FIRST")#define FSMINOR ( (fs && (fs->justify.count>1) && fs->justify.vals[1]) ? (const char *)fs->justify.vals[1] : "FIRST")#define FSHORIZ (fs ? fs->horizontal : 1)#define FSLTR (fs ? fs->leftToRight : 1)#define FSTTB (fs ? fs->topToBottom : 1)#define FSLANG (fs ? fs->language : "")#define FSSPACE (fs ? fs->spacing : FIX_ONE)typedef struct{ GF_Path *path; GF_Path *outline; GF_Mesh *mesh; GF_Mesh *outline_mesh; GF_Rect bounds; /*for text texturing*/ GF_TextureHandler txh; Render3D *sr; /*RGBA data*/ char *tx_data; /*a simple rectangle*/ GF_Mesh *tx_mesh; Bool tx_ready; u32 tx_width, tx_height; Bool failed; GF_Rect tx_bounds;} CachedTextLine;static CachedTextLine *new_text_line(Render3D *sr, GF_List *lines_register){ CachedTextLine *tl; GF_SAFEALLOC(tl, CachedTextLine); tl->path = gf_path_new(); /*text texturing enabled*/ tl->sr = sr; memset(&tl->txh, 0, sizeof(GF_TextureHandler)); tl->txh.compositor = sr->compositor; tl->txh.transparent = 1; gf_list_add(lines_register, tl); return tl;}static void delete_text_line(CachedTextLine *tl){ gf_path_del(tl->path); if (tl->outline) gf_path_del(tl->outline); if (tl->mesh) { mesh_free(tl->mesh); tl->mesh = NULL; } if (tl->outline_mesh) { mesh_free(tl->outline_mesh); tl->outline_mesh = NULL; } tx_delete(&tl->txh); if (tl->tx_data) free(tl->tx_data); if (tl->tx_mesh) mesh_free(tl->tx_mesh); free(tl);}/*don't build too large textures*/#define MAX_TX_SIZE 512/*and don't build too small ones otherwise result is as crap as non-textured*/#define MIN_TX_SIZE 16Bool TextLine_TextureIsReady(CachedTextLine *tl){ GF_Matrix2D mx; GF_STENCIL stenc; GF_SURFACE surf; Fixed cx, cy, sx, sy, max, min; u32 tw, th; GF_Err e; Fixed scale; GF_STENCIL texture2D; GF_Raster2D *r2d = tl->sr->compositor->r2d; if (tl->failed) return 0; if (tl->tx_ready) { if (!tl->sr->compositor->reset_graphics) goto exit; tx_delete(&tl->txh); if (tl->tx_mesh) mesh_free(tl->tx_mesh); tl->tx_mesh = NULL; if (tl->tx_data) free(tl->tx_data); tl->tx_data = NULL; tl->failed = 0; tl->tx_ready = 0; } gf_path_get_bounds(tl->path, &tl->tx_bounds); /*check not too big, but also not really small (meter metrics)*/ max = INT2FIX(MAX_TX_SIZE); min = INT2FIX(MIN_TX_SIZE); scale = FIX_ONE; if ((gf_mulfix(scale, tl->tx_bounds.width)>max) || (gf_mulfix(scale, tl->tx_bounds.height)>max)) { scale = MIN(gf_divfix(max, tl->tx_bounds.width), gf_divfix(max, tl->tx_bounds.height)); } else if ((gf_mulfix(scale, tl->tx_bounds.width)<min) || (gf_mulfix(scale, tl->tx_bounds.height)<min)) { scale = MAX(gf_divfix(min, tl->tx_bounds.width), gf_divfix(min, tl->tx_bounds.height)); } if (scale<FIX_ONE) scale = FIX_ONE; /*get closest pow2 sizes*/ tw = FIX2INT( gf_ceil(gf_mulfix(scale,tl->tx_bounds.width)) ); tl->tx_width = MIN_TX_SIZE; while (tl->tx_width<tw) { if (tl->tx_width>=MAX_TX_SIZE) break; tl->tx_width*=2; } th = FIX2INT( gf_ceil(gf_mulfix(scale, tl->tx_bounds.height)) ); tl->tx_height = MIN_TX_SIZE; while (tl->tx_height<th) { tl->tx_height*=2; if (tl->tx_height>=MAX_TX_SIZE) break; } /*and get scaling*/ sx = gf_divfix( INT2FIX(tl->tx_width), tl->tx_bounds.width); sy = gf_divfix( INT2FIX(tl->tx_height), tl->tx_bounds.height); texture2D = r2d->stencil_new(r2d, GF_STENCIL_TEXTURE); if (!texture2D) { tl->failed = 1; return 0; } surf = r2d->surface_new(r2d, 1); if (!surf) { r2d->stencil_delete(texture2D); return 0; } tl->tx_data = (char *) malloc(sizeof(char)*tl->tx_width*tl->tx_height*4); memset(tl->tx_data, 0, sizeof(char)*tl->tx_width*tl->tx_height*4); /*FIXME - make it work with alphagrey...*/ e = r2d->stencil_set_texture(texture2D, tl->tx_data, tl->tx_width, tl->tx_height, 4*tl->tx_width, GF_PIXEL_ARGB, GF_PIXEL_ARGB, 1); if (!e) e = r2d->surface_attach_to_texture(surf, texture2D); stenc = r2d->stencil_new(r2d, GF_STENCIL_SOLID); r2d->stencil_set_brush_color(stenc, 0xFF000000); cx = tl->tx_bounds.x + tl->tx_bounds.width/2; cy = tl->tx_bounds.y - tl->tx_bounds.height/2; gf_mx2d_init(mx); gf_mx2d_add_translation(&mx, -cx, -cy);// gf_mx2d_add_scale(&mx, scale, -scale); gf_mx2d_add_scale(&mx, sx, -sy); r2d->surface_set_matrix(surf, &mx); r2d->surface_set_raster_level(surf, GF_RASTER_HIGH_QUALITY); r2d->surface_set_path(surf, tl->path); r2d->surface_fill(surf, stenc); r2d->stencil_delete(stenc); r2d->surface_delete(surf); r2d->stencil_delete(texture2D); tl->tx_mesh = new_mesh(); mesh_set_vertex(tl->tx_mesh, tl->tx_bounds.x, tl->tx_bounds.y-tl->tx_bounds.height, 0, 0, 0, FIX_ONE, 0, 0); mesh_set_vertex(tl->tx_mesh, tl->tx_bounds.x+tl->tx_bounds.width, tl->tx_bounds.y-tl->tx_bounds.height, 0, 0, 0, FIX_ONE, FIX_ONE, 0); mesh_set_vertex(tl->tx_mesh, tl->tx_bounds.x+tl->tx_bounds.width, tl->tx_bounds.y, 0, 0, 0, FIX_ONE, FIX_ONE, FIX_ONE); mesh_set_vertex(tl->tx_mesh, tl->tx_bounds.x, tl->tx_bounds.y, 0, 0, 0, FIX_ONE, 0, FIX_ONE); mesh_set_triangle(tl->tx_mesh, 0, 1, 2); mesh_set_triangle(tl->tx_mesh, 0, 2, 3); tl->tx_mesh->flags |= MESH_IS_2D; tl->tx_mesh->mesh_type = MESH_TRIANGLES; mesh_update_bounds(tl->tx_mesh); /*and setup the texture*/ tl->txh.width = tl->tx_width; tl->txh.height = tl->tx_height; tl->txh.stride = 4*tl->tx_width; /*back to RGBA texturing*/ { u32 i, j; for (i=0; i<tl->tx_height; i++) { char *data = tl->tx_data + i*tl->txh.stride; for (j=0; j<tl->txh.width; j++) { u32 val = *(u32 *) &data[4*j]; data[4*j] = (val>>16) & 0xFF; data[4*j+1] = (val>>8) & 0xFF; data[4*j+2] = (val) & 0xFF; data[4*j+3] = (val>>24) & 0xFF; } } } tl->txh.data = tl->tx_data; tl->txh.pixelformat = GF_PIXEL_RGBA; if (!e) e = tx_allocate(&tl->txh); if (e) { tl->failed = 1; mesh_free(tl->tx_mesh); tl->tx_mesh = NULL; free(tl->tx_data); tl->tx_data = NULL; return 0; } tx_set_blend_mode(&tl->txh, TX_BLEND); tl->tx_ready = 1;exit: R3D_SetTextureData(&tl->txh); return 1;}static void clean_paths(TextStack *stack){ CachedTextLine *tl; /*delete all path objects*/ while (gf_list_count(stack->text_lines)) { tl = (CachedTextLine *)gf_list_get(stack->text_lines, 0); gf_list_rem(stack->text_lines, 0); delete_text_line(tl); } stack->bounds.width = stack->bounds.height = 0;}static Fixed get_font_size(M_FontStyle *fs, RenderEffect3D *eff){ Fixed fontSize = FSSIZE; if (fontSize <= 0) { fontSize = INT2FIX(12); if (!eff->is_pixel_metrics) { Fixed w, h; R3D_GetSurfaceSizeInfo(eff, &w, &h); fontSize = gf_divfix(fontSize, w); } } return fontSize;}static void split_text_letters(TextStack *st, M_Text *txt, RenderEffect3D *eff){ CachedTextLine *tl; unsigned short wcTemp[5000]; unsigned short letter[2]; u32 i, j, len; Fixed fontSize, start_y, font_height, line_spacing; GF_FontRaster *ft_r = st->compositor->font_engine; M_FontStyle *fs = (M_FontStyle *)txt->fontStyle; fontSize = get_font_size(fs, eff); line_spacing = gf_mulfix(FSSPACE, fontSize); if (ft_r->set_font(ft_r, FSFAMILY, FSSTYLE) != GF_OK) { if (ft_r->set_font(ft_r, NULL, NULL) != GF_OK) { return; } } ft_r->set_font_size(ft_r, fontSize); ft_r->get_font_metrics(ft_r, &st->ascent, &st->descent, &font_height); if (!strcmp(FSMINOR, "MIDDLE")) { start_y = (st->descent + st->ascent)/2; } else if (!strcmp(FSMINOR, "BEGIN")) { start_y = st->descent; } else if (!strcmp(FSMINOR, "END")) { start_y = st->descent + st->ascent; } else { start_y = st->ascent; } st->bounds.width = st->bounds.height = 0; for (i=0; i < txt->string.count; i++) { char *str = txt->string.vals[i]; if (!str) continue; len = gf_utf8_mbstowcs(wcTemp, 5000, (const char **) &str); if (len == (size_t) (-1)) continue; letter[1] = (unsigned short) 0; for (j=0; j<len; j++) { if (FSLTR) { letter[0] = wcTemp[j]; } else { letter[0] = wcTemp[len - j - 1]; } tl = new_text_line(eff->surface->render, st->text_lines); ft_r->add_text_to_path(ft_r, tl->path, 1, letter, 0, start_y, FIX_ONE, FIX_ONE, st->ascent, &tl->bounds); tl->bounds.height = MAX(st->ascent + st->descent, tl->bounds.height); } }}static void split_text_words(TextStack *st, M_Text *txt, RenderEffect3D *eff){ CachedTextLine *tl; unsigned short wcTemp[5000]; unsigned short letter[5000]; u32 i, j, len, k, first_char; Fixed fontSize, font_height, line_spacing; GF_Rect rc; GF_FontRaster *ft_r = st->compositor->font_engine; M_FontStyle *fs = (M_FontStyle *)txt->fontStyle; fontSize = get_font_size(fs, eff); line_spacing = gf_mulfix(FSSPACE, fontSize); if (ft_r->set_font(ft_r, FSFAMILY, FSSTYLE) != GF_OK) { if (ft_r->set_font(ft_r, NULL, NULL) != GF_OK) { return; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -