On behalf of Mika Saari, the famous Unicode Font support!

Further information is available here:

http://wiki.blender.org/bin/view.pl/Blenderdev/UnicodeFont3D

Shortlist of features:

- Unicode character support for Font3D
- UI to select characters from Unicode character list
- UI to select Unicode table areas
- Optimized character loading (Load only those characters which are used
  in font object)

Please test extensively if it breaks anything, try also loading/saving
files, packing fonts, etc.

The official text regression file in the regression suite should be a
good start.

Thanks to mikasaari for this very useful addition!
This commit is contained in:
Alexander Ewering 2005-09-14 14:02:21 +00:00
parent 2cb24cefb2
commit 98bd4615b5
16 changed files with 1517 additions and 300 deletions

@ -56,6 +56,10 @@ int mat_to_sel(void);
void font_duplilist(struct Object *par);
int getselection(int *start, int *end);
void chtoutf8(unsigned long c, char *o);
void wcs2utf8s(char *dst, wchar_t *src);
int wcsleninu8(wchar_t *src);
int utf8towchar_(wchar_t *w, char *c);
#endif

@ -117,6 +117,11 @@ typedef struct Global {
/* Rob's variables */
int have_quicktime;
int ui_international;
int charstart;
int charmin;
int charmax;
struct VFont *selfont;
struct ListBase ttfdata;
/* this variable is written to / read from FileGlobal->fileflags */
int fileflags;

@ -217,6 +217,10 @@ void initglobals(void)
#endif
clear_workob(); /* object.c */
G.charstart = 0x0000;
G.charmin = 0x0000;
G.charmax = 0xffff;
}
/***/

@ -37,6 +37,7 @@
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <wchar.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -80,19 +81,151 @@ struct chartrans {
char dobreak;
};
/* UTF-8 <-> wchar transformations */
void
chtoutf8(unsigned long c, char *o)
{
// Variables and initialization
memset(o, 0, 16);
// Create the utf-8 string
if (c < 0x80)
{
o[0] = (char) c;
}
else if (c < 0x800)
{
o[0] = (0xC0 | (c>>6));
o[1] = (0x80 | (c & 0x3f));
}
else if (c < 0x10000)
{
o[0] = (0xe0 | (c >> 12));
o[1] = (0x80 | (c >>6 & 0x3f));
o[2] = (0x80 | (c & 0x3f));
}
else if (c < 0x200000)
{
o[0] = (0xf0 | (c>>18));
o[1] = (0x80 | (c >>12 & 0x3f));
o[2] = (0x80 | (c >> 6 & 0x3f));
o[3] = (0x80 | (c & 0x3f));
}
}
void
wcs2utf8s(char *dst, wchar_t *src)
{
char ch[5];
while(*src)
{
memset(ch, 0, 5);
chtoutf8(*src++, ch);
strcat(dst, ch);
}
}
int
wcsleninu8(wchar_t *src)
{
char ch[16];
int len = 0;
while(*src)
{
memset(ch, 0, 16);
chtoutf8(*src++, ch);
len = len + strlen(ch);
}
return len;
}
int
utf8slen(char *src)
{
int size = 0, index = 0;
unsigned char c;
c = src[index++];
while(c)
{
if((c & 0x80) == 0)
{
index += 0;
}
else if((c & 0xe0) == 0xe0)
{
index += 2;
}
else
{
index += 1;
}
size += 1;
c = src[index++];
}
return size;
}
int utf8towchar_(wchar_t *w, char *c)
{
int len=0;
if(w==NULL || c==NULL) return(0);
//printf("%s\n",c);
while(*c)
{
if(*c & 0x80)
{
if(*c & 0x40)
{
if(*c & 0x20)
{
if(*c & 0x10)
{
*w=(c[0] & 0x0f)<<18 | (c[1]&0x1f)<<12 | (c[2]&0x3f)<<6 | (c[3]&0x7f);
c++;
}
else
*w=(c[0] & 0x1f)<<12 | (c[1]&0x3f)<<6 | (c[2]&0x7f);
c++;
}
else
*w=(((c[0] &0x3f)<<6) | (c[1]&0x7f));
c++;
}
else
*w=(c[0] & 0x7f);
}
else
*w=(c[0] & 0x7f);
c++;
w++;
len++;
}
return len;
}
/* The vfont code */
void free_vfont(struct VFont *vf)
{
int i;
if (vf == 0) return;
if (vf->data) {
for (i = 0; i < MAX_VF_CHARS; i++){
while (vf->data->nurbsbase[i].first) {
Nurb *nu = vf->data->nurbsbase[i].first;
while(vf->data->characters.first)
{
VChar *che = vf->data->characters.first;
while (che->nurbsbase.first) {
Nurb *nu = che->nurbsbase.first;
if (nu->bezt) MEM_freeN(nu->bezt);
BLI_freelinkN(&vf->data->nurbsbase[i], nu);
BLI_freelinkN(&che->nurbsbase, nu);
}
BLI_freelinkN(&vf->data->characters, che);
}
MEM_freeN(vf->data);
@ -131,6 +264,20 @@ static PackedFile *get_builtin_packedfile(void)
static VFontData *vfont_get_data(VFont *vfont)
{
struct TmpFont *tmpfnt = NULL;
PackedFile *tpf;
// Try finding the font from font list
tmpfnt = G.ttfdata.first;
while(tmpfnt)
{
if(tmpfnt->vfont == vfont)
break;
tmpfnt = tmpfnt->next;
}
// And then set the data
if (!vfont->data) {
PackedFile *pf;
@ -139,8 +286,34 @@ static VFontData *vfont_get_data(VFont *vfont)
} else {
if (vfont->packedfile) {
pf= vfont->packedfile;
// We need to copy a tmp font to memory unless it is already there
if(!tmpfnt)
{
tpf= MEM_callocN(sizeof(*tpf), "PackedFile");
tpf->data= MEM_mallocN(pf->size, "packFile");
tpf->size= pf->size;
memcpy(tpf->data, pf->data, pf->size);
// Add temporary packed file to globals
tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
tmpfnt->pf= tpf;
tmpfnt->vfont= vfont;
BLI_addtail(&G.ttfdata, tmpfnt);
}
} else {
pf= newPackedFile(vfont->name);
if(!tmpfnt)
{
tpf= newPackedFile(vfont->name);
// Add temporary packed file to globals
tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
tmpfnt->pf= tpf;
tmpfnt->vfont= vfont;
BLI_addtail(&G.ttfdata, tmpfnt);
}
}
if(!pf) {
printf("Font file doesn't exist: %s\n", vfont->name);
@ -170,7 +343,9 @@ VFont *load_vfont(char *name)
char filename[FILE_MAXFILE];
VFont *vfont= NULL;
PackedFile *pf;
PackedFile *tpf = NULL;
int is_builtin;
struct TmpFont *tmpfnt;
if (BLI_streq(name, "<builtin>")) {
strcpy(filename, name);
@ -184,6 +359,8 @@ VFont *load_vfont(char *name)
BLI_splitdirstring(dir, filename);
pf= newPackedFile(name);
tpf= newPackedFile(name);
is_builtin= 0;
}
@ -196,7 +373,7 @@ VFont *load_vfont(char *name)
vfd= BLI_vfontdata_from_freetypefont(pf);
#else
vfd= BLI_vfontdata_from_psfont(pf);
#endif
#endif
if (vfd) {
vfont = alloc_libblock(&G.main->vfont, ID_VF, filename);
@ -208,7 +385,18 @@ VFont *load_vfont(char *name)
if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
vfont->packedfile = pf;
}
// Do not add <builtin> to temporary listbase
if(strcmp(filename, "<builtin>"))
{
tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
tmpfnt->pf= tpf;
tmpfnt->vfont= vfont;
BLI_addtail(&G.ttfdata, tmpfnt);
}
}
// Free the packed file
if (!vfont || vfont->packedfile != pf) {
freePackedFile(pf);
}
@ -281,12 +469,13 @@ static void build_underline(Curve *cu, float x1, float y1, float x2, float y2, i
}
static void buildchar(Curve *cu, unsigned char ascii, CharInfo *info, float ofsx, float ofsy, float rot, int charidx)
static void buildchar(Curve *cu, unsigned long character, CharInfo *info, float ofsx, float ofsy, float rot, int charidx)
{
BezTriple *bezt1, *bezt2;
Nurb *nu1, *nu2;
Nurb *nu1 = NULL, *nu2 = NULL;
float *fp, fsize, shear, x, si, co;
VFontData *vfd;
VFontData *vfd = NULL;
VChar *che = NULL;
int i, sel=0;
vfd= vfont_get_data(which_vfont(cu, info));
@ -307,7 +496,20 @@ static void buildchar(Curve *cu, unsigned char ascii, CharInfo *info, float ofsx
si= (float)sin(rot);
co= (float)cos(rot);
nu1 = vfd->nurbsbase[ascii].first;
// Find the correct character from the font
che = vfd->characters.first;
while(che)
{
if(che->index == character)
break;
che = che->next;
}
// Select the glyph data
if(che)
nu1 = che->nurbsbase.first;
// Create the character
while(nu1)
{
bezt1 = nu1->bezt;
@ -419,7 +621,7 @@ struct chartrans *text_to_curve(Object *ob, int mode)
float *f, maxlen=0, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4;
int i, slen, oldflag, j;
short cnr=0, lnr=0, wsnr= 0;
char ascii, *mem;
wchar_t *mem, *tmp, ascii;
int outta;
float vecyo[3], curofs;
CharInfo *info;
@ -429,22 +631,39 @@ struct chartrans *text_to_curve(Object *ob, int mode)
int curbox;
int selstart, selend;
SelBox *sb= NULL; /* to please gcc */
VChar *che;
float twidth;
int utf8len;
/* renark: do calculations including the trailing '\0' of a string
because the cursor can be at that location */
if(ob->type!=OB_FONT) return 0;
cu= ob->data;
mem= cu->str;
slen = strlen(mem);
// Set font data
cu= (Curve *) ob->data;
vfont= cu->vfont;
if(cu->str == 0) return 0;
if(vfont == 0) return 0;
// Create unicode string
utf8len = utf8slen(cu->str);
tmp = mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem");
utf8towchar_(mem, cu->str);
// Count the wchar_t string length
slen = wcslen(mem);
if (cu->ulheight == 0.0) cu->ulheight = 0.05;
if (cu->str==0) return 0;
if (cu->strinfo==NULL) { /* old file */
cu->strinfo = MEM_callocN((slen+1) * sizeof(CharInfo), "strinfo compat");
}
vfd= vfont_get_data(vfont);
if(!vfd) goto errcse;
/* calc offset and rotation of each char */
ct = chartransdata =
(struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext");
@ -476,23 +695,65 @@ struct chartrans *text_to_curve(Object *ob, int mode)
curbox= 0;
for (i = 0 ; i<=slen ; i++) {
makebreak:
ascii = cu->str[i];
// Characters in the list
che = vfd->characters.first;
ascii = mem[i];
info = &(cu->strinfo[i]);
vfont = which_vfont(cu, info);
if (vfont==0) return 0;
// Find the character
while(che)
{
if(che->index == ascii)
break;
che = che->next;
}
#ifdef WITH_FREETYPE2
// The character wasn't in the current curve base so load it
// But if the font is <builtin> then do not try loading since whole font is in the memory already
if(che == NULL && strcmp(vfont->name, "<builtin>"))
{
BLI_vfontchar_from_freetypefont(vfont, ascii);
}
// Try getting the character again from the list
che = vfd->characters.first;
while(che)
{
if(che->index == ascii)
break;
che = che->next;
}
#endif
if (vfont==0) goto errcse;
if (vfont != oldvfont) {
vfd= vfont_get_data(vfont);
oldvfont = vfont;
}
if (!vfd) return 0;
if((tb->w != 0.0) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+vfd->width[ascii])*cu->fsize) > tb->w) {
// fprintf(stderr, "linewidth exceeded: %c%c%c...\n", cu->str[i], cu->str[i+1], cu->str[i+2]);
for (j=i; j && (cu->str[j] != '\n') && (cu->str[j] != '\r') && (chartransdata[j].dobreak==0); j--) {
if (cu->str[j]==' ' || cu->str[j]=='-') {
if (!vfd) goto errcse;
// The character wasn't found, propably ascii = 0, then the width shall be 0 as well
if(!che)
{
twidth = 0;
}
else
{
twidth = che->width;
}
// Calculate positions
if((tb->w != 0.0) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+twidth)*cu->fsize) > tb->w) {
// fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]);
for (j=i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak==0); j--) {
if (mem[j]==' ' || mem[j]=='-') {
ct -= (i-(j-1));
cnr -= (i-(j-1));
if (cu->str[j] == ' ') wsnr--;
if (cu->str[j] == '-') wsnr++;
if (mem[j] == ' ') wsnr--;
if (mem[j] == '-') wsnr++;
i = j-1;
xof = ct->xof;
ct[1].dobreak = 1;
@ -500,7 +761,7 @@ struct chartrans *text_to_curve(Object *ob, int mode)
goto makebreak;
}
if (chartransdata[j].dobreak) {
// fprintf(stderr, "word too long: %c%c%c...\n", cu->str[j], cu->str[j+1], cu->str[j+2]);
// fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]);
ct->dobreak= 1;
cu->strinfo[i+1].flag |= CU_WRAP;
ct -= 1;
@ -533,7 +794,12 @@ struct chartrans *text_to_curve(Object *ob, int mode)
curbox++;
yof= cu->yof + tb->y/cu->fsize;
}
if(ascii == '\n' || ascii == '\r')
xof = cu->xof;
else
xof= cu->xof + (tb->x/cu->fsize);
xof= cu->xof + (tb->x/cu->fsize);
lnr++;
cnr= 0;
@ -566,7 +832,16 @@ struct chartrans *text_to_curve(Object *ob, int mode)
wsfac = cu->wordspace;
wsnr++;
} else wsfac = 1.0;
xof += (vfd->width[ascii]*wsfac*(1.0+(info->kern/40.0)) ) + xtrax;
// Set the width of the character
if(!che)
{
twidth = 0;
}
else
{
twidth = che->width;
}
xof += (twidth*wsfac*(1.0+(info->kern/40.0)) ) + xtrax;
if (selboxes && (i>=selstart) && (i<=selend)) sb->w = (xof*cu->fsize) - sb->w;
}
@ -577,8 +852,9 @@ struct chartrans *text_to_curve(Object *ob, int mode)
cu->lines= 1;
ct= chartransdata;
for (i= 0; i<=slen; i++, mem++, ct++) {
ascii = *mem;
tmp = mem;
for (i= 0; i<=slen; i++, tmp++, ct++) {
ascii = *tmp;
if(ascii== '\n' || ascii== '\r' || ct->dobreak) cu->lines++;
}
@ -608,9 +884,9 @@ struct chartrans *text_to_curve(Object *ob, int mode)
if(linedata2[i]>1)
linedata[i]= (linedata3[i]-linedata[i])/(linedata2[i]-1);
for (i=0; i<=slen; i++) {
for (j=i; (cu->str[j]) && (cu->str[j]!='\n') &&
(cu->str[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
// if ((cu->str[j]!='\r') && (cu->str[j]!='\n') && (cu->str[j])) {
for (j=i; (mem[j]) && (mem[j]!='\n') &&
(mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
// if ((mem[j]!='\r') && (mem[j]!='\n') && (mem[j])) {
ct->xof+= ct->charnr*linedata[ct->linenr];
// }
ct++;
@ -619,14 +895,14 @@ struct chartrans *text_to_curve(Object *ob, int mode)
(cu->tb[0].w != 0.0)) {
curofs= 0;
for (i=0; i<=slen; i++) {
for (j=i; (cu->str[j]) && (cu->str[j]!='\n') &&
(cu->str[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
if ((cu->str[j]!='\r') && (cu->str[j]!='\n') &&
for (j=i; (mem[j]) && (mem[j]!='\n') &&
(mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
if ((mem[j]!='\r') && (mem[j]!='\n') &&
((chartransdata[j].dobreak!=0))) {
if (cu->str[i]==' ') curofs += (linedata3[ct->linenr]-linedata[ct->linenr])/linedata4[ct->linenr];
if (mem[i]==' ') curofs += (linedata3[ct->linenr]-linedata[ct->linenr])/linedata4[ct->linenr];
ct->xof+= curofs;
}
if (cu->str[i]=='\n' || cu->str[i]=='\r' || chartransdata[i].dobreak) curofs= 0;
if (mem[i]=='\n' || mem[i]=='\r' || chartransdata[i].dobreak) curofs= 0;
ct++;
}
}
@ -685,9 +961,28 @@ struct chartrans *text_to_curve(Object *ob, int mode)
for (i=0; i<=slen; i++, ct++) {
/* rotate around centre character */
ascii = cu->str[i];
dtime= distfac*0.35f*vfd->width[ascii]; /* why not 0.5? */
dtime= distfac*0.0f*vfd->width[ascii]; /* why not 0.5? */
ascii = mem[i];
// Find the character
che = vfd->characters.first;
while(che)
{
if(che->index == ascii)
break;
che = che->next;
}
if(che)
{
twidth = che->width;
}
else
{
twidth = 0;
}
dtime= distfac*0.35f*twidth; /* why not 0.5? */
dtime= distfac*0.0f*twidth; /* why not 0.5? */
ctime= timeofs + distfac*( ct->xof - minx);
CLAMP(ctime, 0.0, 1.0);
@ -782,32 +1077,47 @@ struct chartrans *text_to_curve(Object *ob, int mode)
if (mode == FO_SELCHANGE) {
MEM_freeN(chartransdata);
MEM_freeN(mem);
return NULL;
}
if(mode==0) {
/* make nurbdata */
unsigned long cha;
freeNurblist(&cu->nurb);
ct= chartransdata;
if (cu->sepchar==0) {
for (i= 0; i<slen; i++) {
ascii = cu->str[i];
cha = (unsigned long) mem[i];
info = &(cu->strinfo[i]);
if (info->mat_nr > (ob->totcol)) {
printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr);
info->mat_nr = 0;
}
buildchar(cu, ascii, info, ct->xof, ct->yof, ct->rot, i);
if ((info->flag & CU_UNDERLINE) && (ascii != '\n') && (ascii != '\r')) {
// We do not want to see any character for \n or \r
if(cha != '\n' && cha != '\r')
buildchar(cu, cha, info, ct->xof, ct->yof, ct->rot, i);
if ((info->flag & CU_UNDERLINE) && (cha != '\n') && (cha != '\r')) {
uloverlap = 0;
if ( (i<(slen-1)) && (cu->str[i+1] != '\n') && (cu->str[i+1] != '\r') &&
((cu->str[i+1] != ' ') || (cu->strinfo[i+1].flag & CU_UNDERLINE)) && ((cu->strinfo[i+1].flag & CU_WRAP)==0)
if ( (i<(slen-1)) && (mem[i+1] != '\n') && (mem[i+1] != '\r') &&
((mem[i+1] != ' ') || (cu->strinfo[i+1].flag & CU_UNDERLINE)) && ((cu->strinfo[i+1].flag & CU_WRAP)==0)
) {
uloverlap = xtrax + 0.1;
}
ulwidth = cu->fsize * ((vfd->width[ascii]* (1.0+(info->kern/40.0)))+uloverlap);
// Find the character, the characters has to be in the memory already
// since character checking has been done earlier already.
che = vfd->characters.first;
while(che)
{
if(che->index == cha)
break;
che = che->next;
}
if(!che) twidth =0; else twidth=che->width;
ulwidth = cu->fsize * ((twidth* (1.0+(info->kern/40.0)))+uloverlap);
build_underline(cu, ct->xof*cu->fsize, ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize,
ct->xof*cu->fsize + ulwidth,
ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize - cu->ulheight*cu->fsize,
@ -819,11 +1129,11 @@ struct chartrans *text_to_curve(Object *ob, int mode)
else {
outta = 0;
for (i= 0; (i<slen) && (outta==0); i++) {
ascii = cu->str[i];
ascii = mem[i];
info = &(cu->strinfo[i]);
if (cu->sepchar == (i+1)) {
cu->str[0] = ascii;
cu->str[1] = 0;
mem[0] = ascii;
mem[1] = 0;
cu->strinfo[0]= *info;
cu->pos = 1;
cu->len = 1;
@ -841,9 +1151,14 @@ struct chartrans *text_to_curve(Object *ob, int mode)
}
if(mode==FO_DUPLI) {
MEM_freeN(mem);
return chartransdata;
}
errcse:
if(mem)
MEM_freeN(mem);
MEM_freeN(chartransdata);
return 0;
}

@ -41,17 +41,36 @@
#include "DNA_listBase.h"
struct PackedFile;
struct VFont;
#define MAX_VF_CHARS 256
typedef struct VFontData {
ListBase nurbsbase[MAX_VF_CHARS];
float resol[MAX_VF_CHARS];
float width[MAX_VF_CHARS];
float *points[MAX_VF_CHARS];
char name[128];
ListBase characters;
// ListBase nurbsbase[MAX_VF_CHARS];
// float resol[MAX_VF_CHARS];
// float width[MAX_VF_CHARS];
// float *points[MAX_VF_CHARS];
char name[128];
} VFontData;
typedef struct VChar {
struct VChar *next, *prev;
ListBase nurbsbase;
unsigned long index;
float resol;
float width;
float *points;
} VChar;
struct TmpFont
{
struct TmpFont *next, *prev;
struct PackedFile *pf;
struct VFont *vfont;
};
/**
* Construct a new VFontData structure from
* PostScript font data in a PackedFile.
@ -75,5 +94,10 @@ BLI_vfontdata_from_psfont(
VFontData*
BLI_vfontdata_from_freetypefont(
struct PackedFile *pf);
int
BLI_vfontchar_from_freetypefont(
struct VFont *vfont, unsigned long character);
#endif

@ -54,8 +54,10 @@
#include "BIF_toolbox.h"
#include "BKE_global.h"
#include "BKE_utildefines.h"
#include "DNA_vfont_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_curve_types.h"
@ -67,18 +69,265 @@ static FT_Library library;
static FT_Error err;
static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
{
// Blender
VFontData *vfd;
struct Nurb *nu;
struct VChar *che;
struct BezTriple *bezt;
// Freetype2
FT_Face face;
FT_GlyphSlot glyph;
FT_UInt glyph_index;
FT_Outline ftoutline;
FT_GlyphSlot glyph;
FT_UInt glyph_index;
FT_Outline ftoutline;
const char *fontname;
float scale, height;
float dx, dy;
int i,j,k,l,m=0;
// Variables
int *npoints;
int *onpoints;
// adjust font size
height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
if(height != 0.0)
scale = 1.0 / height;
else
scale = 1.0 / 1000.0;
//
// Generate the character 3D data
//
// Get the FT Glyph index and load the Glyph
glyph_index= FT_Get_Char_Index(face, charcode);
err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
// If loading succeeded, convert the FT glyph to the internal format
if(!err)
{
// First we create entry for the new character to the character list
che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
BLI_addtail(&vfd->characters, che);
// Take some data for modifying purposes
glyph= face->glyph;
ftoutline= glyph->outline;
// Set the width and character code
che->index= charcode;
che->width= glyph->advance.x * scale;
// Start converting the FT data
npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
// calculate total points of each contour
for(j = 0; j < ftoutline.n_contours; j++) {
if(j == 0)
npoints[j] = ftoutline.contours[j] + 1;
else
npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
}
// get number of on-curve points for beziertriples (including conic virtual on-points)
for(j = 0; j < ftoutline.n_contours; j++) {
l = 0;
for(k = 0; k < npoints[j]; k++) {
if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
if(ftoutline.tags[l] == FT_Curve_Tag_On)
onpoints[j]++;
if(k < npoints[j] - 1 )
if( ftoutline.tags[l] == FT_Curve_Tag_Conic &&
ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
onpoints[j]++;
}
}
//contour loop, bezier & conic styles merged
for(j = 0; j < ftoutline.n_contours; j++) {
// add new curve
nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
BLI_addtail(&che->nurbsbase, nu);
nu->type= CU_BEZIER+CU_2D;
nu->pntsu = onpoints[j];
nu->resolu= 8;
nu->flagu= 1;
nu->bezt = bezt;
//individual curve loop, start-end
for(k = 0; k < npoints[j]; k++) {
if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
if(k == 0) m = l;
//virtual conic on-curve points
if(k < npoints[j] - 1 )
{
if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
//left handle
bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
//midpoint (virtual on-curve point)
bezt->vec[1][0] = dx;
bezt->vec[1][1] = dy;
//right handle
bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
bezt->h1= bezt->h2= HD_ALIGN;
bezt++;
}
}
//on-curve points
if(ftoutline.tags[l] == FT_Curve_Tag_On) {
//left handle
if(k > 0) {
if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
bezt->h1= HD_FREE;
} else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
bezt->h1= HD_FREE;
} else {
bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
bezt->h1= HD_VECT;
}
} else { //first point on curve
if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
bezt->h1= HD_FREE;
} else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
bezt->h1= HD_FREE;
} else {
bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
bezt->h1= HD_VECT;
}
}
//midpoint (on-curve point)
bezt->vec[1][0] = ftoutline.points[l].x* scale;
bezt->vec[1][1] = ftoutline.points[l].y* scale;
//right handle
if(k < (npoints[j] - 1)) {
if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
bezt->h2= HD_FREE;
} else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
bezt->h2= HD_FREE;
} else {
bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
bezt->h2= HD_VECT;
}
} else { //last point on curve
if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
bezt->vec[2][0] = ftoutline.points[m].x* scale;
bezt->vec[2][1] = ftoutline.points[m].y* scale;
bezt->h2= HD_FREE;
} else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
bezt->h2= HD_FREE;
} else {
bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
bezt->h2= HD_VECT;
}
}
// get the handles that are aligned, tricky...
// DistVL2Dfl, check if the three beztriple points are on one line
// VecLenf, see if there's a distance between the three points
// VecLenf again, to check the angle between the handles
// finally, check if one of them is a vector handle
if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
(VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
(VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
(VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
(VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
{
bezt->h1= bezt->h2= HD_ALIGN;
}
bezt++;
}
}
}
}
if(npoints) MEM_freeN(npoints);
if(onpoints) MEM_freeN(onpoints);
}
int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
{
// Freetype2
FT_Face face;
FT_UInt glyph_index;
struct TmpFont *tf;
// Find the correct FreeType font
tf= G.ttfdata.first;
while(tf)
{
if(tf->vfont == vfont)
break;
tf= tf->next;
}
// What, no font found. Something strange here
if(!tf) return FALSE;
// Load the font to memory
if(tf->pf)
{
err= FT_New_Memory_Face( library,
tf->pf->data,
tf->pf->size,
0,
&face);
}
else
err= TRUE;
// Read the char
freetypechar_to_vchar(face, charcode, vfont->data);
// And everything went ok
return TRUE;
}
static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
{
// Variables
FT_Face face;
FT_ULong charcode = 0, lcode;
FT_UInt glyph_index;
FT_UInt temp;
const char *fontname;
VFontData *vfd;
/*
FT_CharMap found = 0;
FT_CharMap charmap;
@ -86,10 +335,6 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
int n;
*/
const char *fontname;
float scale, height;
float dx, dy;
int i, j, k, l, m =0;
// load the freetype font
err = FT_New_Memory_Face( library,
@ -125,187 +370,52 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
fontname = FT_Get_Postscript_Name(face);
strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
// adjust font size
height = ((double) face->bbox.yMax - (double) face->bbox.yMin);
// Extract the first 256 character from TTF
lcode= charcode= FT_Get_First_Char(face, &glyph_index);
if(height != 0.0)
scale = 1.0 / height;
else
scale = 1.0 / 1000.0;
// No charmap found from the ttf so we need to figure it out
if(glyph_index == 0)
{
FT_CharMap found = 0;
FT_CharMap charmap;
int n;
// extract generic ascii character range
for(i = myMIN_ASCII; i <= myMAX_ASCII; i++) {
int *npoints = NULL; //total points of each contour
int *onpoints = NULL; //num points on curve
glyph_index = FT_Get_Char_Index( face, i );
err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
if(!err) {
glyph = face->glyph;
ftoutline = glyph->outline;
vfd->width[i] = glyph->advance.x* scale;
npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
// calculate total points of each contour
for(j = 0; j < ftoutline.n_contours; j++) {
if(j == 0)
npoints[j] = ftoutline.contours[j] + 1;
else
npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
}
// get number of on-curve points for beziertriples (including conic virtual on-points)
for(j = 0; j < ftoutline.n_contours; j++) {
l = 0;
for(k = 0; k < npoints[j]; k++) {
if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
if(ftoutline.tags[l] == FT_Curve_Tag_On)
onpoints[j]++;
if(k < npoints[j] - 1 )
if( ftoutline.tags[l] == FT_Curve_Tag_Conic &&
ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
onpoints[j]++;
}
}
//contour loop, bezier & conic styles merged
for(j = 0; j < ftoutline.n_contours; j++) {
// add new curve
nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
BLI_addtail(&vfd->nurbsbase[i], nu);
nu->type= CU_BEZIER+CU_2D;
nu->pntsu = onpoints[j];
nu->resolu= 8;
nu->flagu= 1;
nu->bezt = bezt;
//individual curve loop, start-end
for(k = 0; k < npoints[j]; k++) {
if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
if(k == 0) m = l;
//virtual conic on-curve points
if(k < npoints[j] - 1 )
if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
//left handle
bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
//midpoint (virtual on-curve point)
bezt->vec[1][0] = dx;
bezt->vec[1][1] = dy;
//right handle
bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
bezt->h1= bezt->h2= HD_ALIGN;
bezt++;
}
//on-curve points
if(ftoutline.tags[l] == FT_Curve_Tag_On) {
//left handle
if(k > 0) {
if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
bezt->h1= HD_FREE;
} else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
bezt->h1= HD_FREE;
} else {
bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
bezt->h1= HD_VECT;
}
} else { //first point on curve
if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
bezt->h1= HD_FREE;
} else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
bezt->h1= HD_FREE;
} else {
bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
bezt->h1= HD_VECT;
}
}
//midpoint (on-curve point)
bezt->vec[1][0] = ftoutline.points[l].x* scale;
bezt->vec[1][1] = ftoutline.points[l].y* scale;
//right handle
if(k < (npoints[j] - 1)) {
if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
bezt->h2= HD_FREE;
} else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
bezt->h2= HD_FREE;
} else {
bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
bezt->h2= HD_VECT;
}
} else { //last point on curve
if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
bezt->vec[2][0] = ftoutline.points[m].x* scale;
bezt->vec[2][1] = ftoutline.points[m].y* scale;
bezt->h2= HD_FREE;
} else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
bezt->h2= HD_FREE;
} else {
bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
bezt->h2= HD_VECT;
}
}
// get the handles that are aligned, tricky...
// DistVL2Dfl, check if the three beztriple points are on one line
// VecLenf, see if there's a distance between the three points
// VecLenf again, to check the angle between the handles
// finally, check if one of them is a vector handle
if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
(VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
(VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
(VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
(VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
{
bezt->h1= bezt->h2= HD_ALIGN;
}
bezt++;
}
}
for ( n = 0; n < face->num_charmaps; n++ )
{
charmap = face->charmaps[n];
if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
{
found = charmap;
break;
}
}
if(npoints) MEM_freeN(npoints);
if(onpoints) MEM_freeN(onpoints);
err = FT_Set_Charmap( face, found );
if( err )
return NULL;
lcode= charcode= FT_Get_First_Char(face, &glyph_index);
}
return vfd;
// Load characters
while(charcode < 256)
{
// Generate the font data
freetypechar_to_vchar(face, charcode, vfd);
// Next glyph
charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
// Check that we won't start infinite loop
if(charcode <= lcode)
break;
lcode = charcode;
}
err = FT_Set_Charmap( face, FT_ENCODING_UNICODE );
return vfd;
}
@ -393,6 +503,30 @@ VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
return vfd;
}
int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
{
int success = FALSE;
if(!vfont) return FALSE;
// Init Freetype
err = FT_Init_FreeType(&library);
if(err) {
error("Failed to load the Freetype font library");
return 0;
}
// Load the character
success = objchr_to_ftvfontdata(vfont, character);
if(success == FALSE) return FALSE;
// Free Freetype
FT_Done_FreeType(library);
// Ahh everything ok
return TRUE;
}
#endif // WITH_FREETYPE2

@ -1956,6 +1956,7 @@ static VFontData *objfnt_to_vfontdata(objfnt *fnt)
struct Nurb *nu;
struct BezTriple *bezt, *bez2;
float scale, dx, dy;
struct VChar *che;
if (!fnt || (fnt->type!=SP_TYPE)) {
return NULL;
@ -1967,7 +1968,10 @@ static VFontData *objfnt_to_vfontdata(objfnt *fnt)
for (i = 0; i < MAX_VF_CHARS; i++) {
cd = getchardesc(fnt, i);
if (cd && cd->data && cd->datalen) {
vfd->width[i] = scale * cd->movex;
che = (VChar *) MEM_callocN(sizeof(VChar), "objfnt_char");
BLI_addtail(&vfd->characters, che);
che->index = i;
che->width = scale * cd->movex;
_data = data = cd->data;
@ -2015,7 +2019,7 @@ static VFontData *objfnt_to_vfontdata(objfnt *fnt)
nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
bezt = (BezTriple*)MEM_callocN((count)* sizeof(BezTriple),"objfnt_bezt") ;
if (nu != 0 && bezt != 0) {
BLI_addtail(&vfd->nurbsbase[i], nu);
BLI_addtail(&che->nurbsbase, nu);
nu->type= CU_BEZIER+CU_2D;
nu->pntsu = count;
nu->resolu= 8;

@ -848,6 +848,13 @@ static void write_mballs(WriteData *wd, ListBase *idbase)
}
}
int amount_of_chars(char *str)
{
// Since the data is saved as UTF-8 to the cu->str
// The cu->len is not same as the strlen(cu->str)
return strlen(str);
}
static void write_curves(WriteData *wd, ListBase *idbase)
{
Curve *cu;
@ -863,7 +870,7 @@ static void write_curves(WriteData *wd, ListBase *idbase)
writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat);
if(cu->vfont) {
writedata(wd, DATA, cu->len+1, cu->str);
writedata(wd, DATA, amount_of_chars(cu->str)+1, cu->str);
writestruct(wd, DATA, "CharInfo", cu->len, cu->strinfo);
writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);
}

@ -30,16 +30,26 @@
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#include <wchar.h>
#ifndef BIF_EDITFONT_H
#define BIF_EDITFONT_H
struct Text;
extern char *BIF_lorem;
extern char *copybuf;
extern char *copybufinfo;
extern wchar_t *copybuf;
extern wchar_t *copybufinfo;
void do_textedit(unsigned short event, short val, char _ascii);
typedef struct unicodect
{
char *name;
char *longname;
int start;
int end;
} unicodect;
void do_textedit(unsigned short event, short val, unsigned long _ascii);
void make_editText(void);
void load_editText(void);
void remake_editText(void);

@ -151,6 +151,7 @@ struct ScrArea;
#define HSVCUBE (26<<9)
#define PULLDOWN (27<<9)
#define ROUNDBOX (28<<9)
#define CHARTAB (29<<9)
#define BUTTYPE (31<<9)

@ -408,6 +408,12 @@ enum {
#define B_STYLETOSELU 2213
#define B_STYLETOSELI 2214
#define B_SETCHAR 2215
#define B_SETUPCHAR 2216
#define B_SETDOWNCHAR 2217
#define B_SETCAT 2218
#define B_SETUNITEXT 2219
/* *********************** */
#define B_ARMBUTS 2400

@ -86,6 +86,7 @@
#include "BLI_arithb.h"
#include "BLI_vfontdata.h"
#include "BLI_editVert.h"
#include "BLI_dynstr.h"
#include "BSE_filesel.h"
@ -159,6 +160,202 @@ short uv_calc_mapdir= 1, uv_calc_mapalign= 1, facesel_draw_edges= 0;
extern ListBase editNurb;
/* *************************** Unicode Character Groups ****************** */
unicodect uctabname[125] = {
{"All", "All", 0x0000, 0xffff},
{"Basic Latin", "Basic Latin", 0x0000, 0x007f},
{"Latin 1 Supp", "Latin-1 Supplement", 0x0080, 0x00ff},
{"Latin Ext. A.", "Latin Extended-A", 0x0100, 0x017F},
{"Latin Ext. B.", "Latin Extended-B", 0x0180,0x024F},
{"Latin Ext. Add.", "Latin Extended Additional", 0x1e00, 0x1eff},
{"IPA Ext", "IPA Extensions", 0x0250, 0x02AF},
{"Spacing Mod.", "Spacing Modifier Letters", 0x02b0, 0x02ff},
{"Comb. Dia.", "Combining Diacritical Marks", 0x0300, 0x036F},
{"Greek, Coptic", "Greek and Coptic", 0x0370, 0x03ff},
{"Greek Ext.", "Greek Extended", 0x1f00, 0x1fff},
{"Cyrillic", "Cyrillic", 0x0400, 0x04ff},
{"Cyrillic Supp.", "Cyrillic Supplementary", 0x0500, 0x052f},
{"Armenian", "Armenian", 0x0530, 0x058f},
{"Hebrew", "Hebrew", 0x0590, 0x05ff},
{"Arabic", "Arabic", 0x0600, 0x06ff},
{"Syriac", "Syriac", 0x0700, 0x074f},
{"Thaana", "Thaana", 0x0780, 0x07bf},
{"Devanagari", "Devanagari", 0x0900, 0x097f},
{"Bengali", "Bengali", 0x0980, 0x09ff},
{"Gurmukhi", "Gurmukhi", 0x0a00, 0x0a7f},
{"Gujarati", "Gujarati", 0x0a80, 0x0aff},
{"Oriya", "Oriya", 0x0b00, 0x0b7f},
{"Tamil", "Tamil", 0x0b80, 0x0bff},
{"Tegulu", "Tegulu", 0x0c00, 0x0c7f},
{"Kannada", "Kannada", 0x0c80, 0x0cff},
{"Malayalam", "Malayalam", 0x0d00, 0x0d7f},
{"Sinhala", "Sinhala", 0x0d80, 0x0dff},
{"Thai", "Thai", 0x0e00, 0x0e7f},
{"Lao", "Lao", 0x0e80, 0x0eff},
{"Tibetan", "Tibetan", 0x0f00, 0x0fff},
{"Myanmar", "Myanmar", 0x1000, 0x109f},
{"Georgian", "Georgian", 0x10a0, 0x10ff},
{"Ethiopic", "Ethiopic", 0x1200, 0x137f},
{"Cherokee", "Cherokee", 0x13a0, 0x13ff},
{"Unif. Canadian", "Unified Canadian Aboriginal Syllabics", 0x1400, 0x167f},
{"Ogham", "Ogham", 0x1680, 0x169f},
{"Runic", "Runic", 0x16a0, 0x16ff},
{"Tagalog", "Tagalog", 0x1700, 0x171f},
{"Hanunoo", "Hanunoo", 0x1720, 0x173f},
{"Buhid", "Buhid", 0x1740, 0x175f},
{"Tagbanwa", "Tagbanwa", 0x1760, 0x177f},
{"Khmer", "Khmer", 0x1780, 0x17ff},
{"Khmer Symb", "Khmer Symbols", 0x19e0, 0x19ff},
{"Mongolian", "Mongolian", 0x1800, 0x18af},
{"Limbu", "Limbu", 0x1900, 0x194f},
{"Tai Le", "Tai Le", 0x1950, 0x197f},
{"Phon. Ext.", "Phonetic Extensions", 0x1d00, 0x1d7f},
{"Gen. Punct.", "General Punctutation", 0x2000, 0x206f},
{"Super, Sub", "Superscripts and Subscripts", 0x2070, 0x209f},
{"Curr. Symb.", "Currency Symbols", 0x20a0, 0x20cf},
{"Comb. Diacrit.", "Combining Diacritical Marks for Symbols", 0x20d0, 0x20ff},
{"Letter Symb", "Letterlike Symbols", 0x2100, 0x214f},
{"Numb. Forms", "Number Forms", 0x2150, 0x218f},
{"Arrows", "Arrows", 0x2190, 0x21ff},
{"Math Oper.", "Mathematical Operators", 0x2200, 0x22ff},
{"Misc. Tech.", "Miscellaneous Technical", 0x2300, 0x23ff},
{"Ctrl. Pict.", "Control Pictures", 0x2400, 0x243f},
{"OCR", "Optical Character Recognition", 0x2440, 0x245f},
{"Enc. Alpha", "Enclosed Alphanumerics", 0x2460, 0x24ff},
{"Bow Drawing", "Box Drawing", 0x2500, 0x257f},
{"BLock Elem.", "Block Elements", 0x2580, 0x259f},
{"Geom. Shapes", "Geometric Shapes", 0x25a0, 0x25ff},
{"Misc. Symb.", "Miscellaneous Symbols", 0x2600, 0x26ff},
{"Dingbats", "Dingbats", 0x2700, 0x27bf},
{"Misc. Math A", "Miscellaneous Mathematical Symbols-A", 0x27c0, 0x27ef},
{"Supp. Arrows-A", "Supplemental Arrows-A", 0x27f0, 0x27ff},
{"Braille Pat.", "Braille Patterns", 0x2800, 0x28ff},
{"Supp. Arrows-B", "Supplemental Arrows-B", 0x2900, 0x297f},
{"Misc. Math B", "Miscellaneous Mathematical Symbols-B", 0x2980, 0x29ff},
{"Supp. Math Op.", "Supplemental Mathematical Operators", 0x2a00, 0x2aff},
{"Misc. Symb.", "Miscellaneous Symbols and Arrows", 0x2b00, 0x2bff},
{"Kangxi Rad.", "Kangxi Radicals", 0x2f00, 0x2fdf},
{"Ideographic", "Ideographic Description Characters", 0x2ff0, 0x2fff},
{"Hiragana", "Hiragana", 0x3040, 0x309f},
{"Katakana", "Katakana", 0x30a0, 0x30ff},
{"Katakana Ext.", "Katakana Phonetic Extensions", 0x31f0, 0x31ff},
{"Bopomofo", "Bopomofo", 0x3100, 0x312f},
{"Bopomofo Ext.", "Bopomofo Extended", 0x31a0, 0x31bf},
{"Hangul", "Hangul Jamo", 0x1100, 0x11ff},
{"Hangul Comp.", "Hangul Compatibility Jamo", 0x3130, 0x318f},
{"Hangul Syll.", "Hangul Syllables", 0xac00, 0xd7af},
{"Kanbun", "Kanbun", 0x3190, 0x319f},
{"Yijing Hex.", "Yijing Hexagram Symbols", 0x4dc0, 0x4dff},
{"Yi Syllables", "Yi Syllables", 0xa000, 0xa48f},
{"Yi Radicals", "Yi Radicals", 0xa490, 0xa4cf},
{"High Surr.", "High Surrogate Area", 0xd800, 0xdbff},
{"Low Surr.", "Low Surrogates", 0xdc00, 0xdfff},
{"Priv. Use Area", "Private Use Area", 0xe000, 0xf8ff},
{"CJK Rad. Supp.", "CJK Radicals Supplement", 0x2e80, 0x2eff},
{"CJK Ideographs", "CJK Unified Ideographs", 0x4e00, 0x9faf},
{"CJK Ideog. Ext. A", "CJK Unified Ideographs Extension A", 0x3400, 0x4dbf},
{"CJK Ideog. Ext. B", "CJK Unified Ideographs Extension B", 0x20000, 0x2a6df},
{"CJK Symbols.", "CJK Symbols and Punctuation", 0x3000, 0x303f},
{"Enclosed CJK", "Enclosed CJK Letters and Months", 0x3200, 0x32ff},
{"CJK Comp.", "CJK Compatibility", 0x3300, 0x33ff},
{"CJK Comp. Ideog.", "CJK Compatibility Ideographs", 0xf900, 0xfaff},
{"CJK Comp. Forms", "CJK Compatibility Forms", 0xfe30, 0xfe4f},
{"CJK Comp. Supp.", "CJK Compatibility Ideographs Supplement", 0x2f800, 0x2fa1f},
{"Alpha. Pres. Forms", "Alphabetic Presentation Forms", 0xfb00, 0xfb4f},
{"Arabic Pres. A", "Arabic Presentation Forms-A", 0xfb50, 0xfdff},
{"Arabic Pres. B", "Arabic Presentation Forms-B", 0xfe70, 0xfeff},
{"Var. Sel.", "Variation Selectors", 0xfe00, 0xfe0f},
{"Comb. Half", "Combining Half Marks", 0xfe20, 0xfe2f},
{"Sml. From Var.", "Small Form Variants", 0xfe50, 0xfe6f},
{"Half, Full Forms", "Halfwidth and Fullwidth Forms", 0xff00, 0xffef},
{"Specials", "Specials", 0xfff0, 0xffff},
{"Lin. B Syllab.", "Linear B Syllabary", 0x10000, 0x1007f},
{"Lin. B Idog.", "Linear B Ideograms", 0x10080, 0x100ff},
{"Aegean Num.", "Aegean Numbers", 0x10100, 0x1013f},
{"Old Italic", "Old Italic", 0x10300, 0x1032f},
{"Gothic", "Gothic", 0x10330, 0x1034f},
{"Ugaritic", "Ugaritic", 0x10380, 0x1039f},
{"Deseret", "Deseret", 0x10400, 0x1044f},
{"Shavian", "Shavian", 0x10450, 0x1047f},
{"Osmanya", "Osmanya", 0x10480, 0x104af},
{"Cypriot Syll", "Cypriot Syllabary", 0x10800, 0x1083f},
{"Bysantine Mus.", "Bysantine Musical Symbols", 0x1d000, 0x1d0ff},
{"Music Symb.", "Musical Symbols", 0x1d100, 0x1d1ff},
{"Tai Xuan Symb", "Tai Xuan Jing Symbols", 0x1d300, 0x1d35f},
{"Math. Alpha Symb.", "Mathematical Alpanumeric Symbols", 0x1d400, 0x1d7ff},
{"Tags", "Tags", 0xe0000, 0xe007f},
{"Var. Supp", "Variation Selectors Supplement", 0xe0100, 0xe01ef},
{"Supp. Priv. A", "Supplementary Private Use Area-A", 0xf0000, 0xffffd},
{"Supp. Priv. B", "Supplementary Private Use Area-B", 0x100000, 0x10fffd}
};
/* *************************** static functions prototypes ****************** */
VFont *exist_vfont(char *str);
@ -1268,6 +1465,11 @@ static void load_buts_vfont(char *name)
allqueue(REDRAWBUTSEDIT, 0);
}
static void set_unicode_text_fs(char *file)
{
if (file > 0) paste_unicodeText(file);
}
void do_fontbuts(unsigned short event)
{
Curve *cu;
@ -1275,6 +1477,9 @@ void do_fontbuts(unsigned short event)
Object *ob;
ScrArea *sa;
char str[80];
int ctevt;
char *ctmenu;
DynStr *ds;
int i, style=0;
ob= OBACT;
@ -1422,6 +1627,74 @@ void do_fontbuts(unsigned short event)
}
}
break;
case B_SETCHAR:
G.charmin = 0x0000;
G.charmax = 0xffff;
if(G.charstart < 0)
G.charstart = 0;
if(G.charstart > (0xffff - 12*6))
G.charstart = 0xffff - (12*6);
allqueue(REDRAWBUTSEDIT, 0);
break;
case B_SETUPCHAR:
G.charstart = G.charstart - (12*6);
if(G.charstart < 0)
G.charstart = 0;
if(G.charstart < G.charmin)
G.charstart = G.charmin;
allqueue(REDRAWBUTSEDIT, 0);
break;
case B_SETCAT:
// Create new dynamic string
ds = BLI_dynstr_new();
// Fill the dynamic string with entries
for(i=0;i<104;i++)
{
BLI_dynstr_append(ds, "|");
BLI_dynstr_append(ds, uctabname[i].name);
}
// Create the menu string from dyn string
ctmenu = BLI_dynstr_get_cstring(ds);
// Call the popup menu
ctevt = pupmenu_col(ctmenu, 40);
G.charstart = uctabname[ctevt-1].start;
G.charmin = uctabname[ctevt-1].start;
G.charmax = uctabname[ctevt-1].end;
// Free all data
BLI_dynstr_free(ds);
MEM_freeN(ctmenu);
// And refresh
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWBUTSEDIT, 0);
break;
case B_SETDOWNCHAR:
G.charstart = G.charstart + (12*6);
if(G.charstart > (0xffff - 12*6))
G.charstart = 0xffff - (12*6);
if(G.charstart > G.charmax - 12*6)
G.charstart = G.charmax - 12*6;
allqueue(REDRAWBUTSEDIT, 0);
break;
case B_SETUNITEXT:
sa= closest_bigger_area();
areawinset(sa->win);
if(ob==G.obedit) {
activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, set_unicode_text_fs);
}
break;
case B_TEXTONCURVE:
if(ob) {
cu= ob->data;
@ -1437,6 +1710,32 @@ void do_fontbuts(unsigned short event)
}
}
static void editing_panel_char_type(Object *ob, Curve *cu)
{
uiBlock *block;
block= uiNewBlock(&curarea->uiblocks, "editing_panel_char_type", UI_EMBOSS, UI_HELV, curarea->win);
uiNewPanelTabbed("Font", "Editing");
if(uiNewPanel(curarea, block, "Char", "Editing", 640, 0, 318, 204)==0)
return;
// Set the selected font
G.selfont = cu->vfont;
uiDefIconBut(block, BUT, B_SETUNITEXT, ICON_TEXT, 0,210,20,20, 0, 0, 0, 0, 0, "Load Unicode Text file");
// Unicode categorization selection button
uiDefBut(block, BUT, B_SETCAT, "Unicode Table", 22,210,226,20, 0, 0, 0, 0, 0, "Select Unicode Table");
uiDefButI(block, NUM, /*B_SETUPCHAR*/ 0, "", 250,210,50,20, &G.charstart, 0, 0xffff, 0, 0, "UT");
// Character selection button
uiDefBut(block, CHARTAB, B_SETCHAR, "", 0, 0, 264, 200, 0, 0, 0, 0, 0, "Select character");
// Buttons to change the max, min
uiDefButI(block, BUT, B_SETUPCHAR, "U", 280, 185, 15, 15, &G.charstart, 0, 0xffff, 0, 0, "Scroll character table up");
uiDefButI(block, BUT, B_SETDOWNCHAR, "D", 280, 0, 15, 15, &G.charstart, 0, 0xffff, 0, 0, "Scroll character table down");
}
static void editing_panel_font_type(Object *ob, Curve *cu)
{
uiBlock *block;
@ -3354,6 +3653,13 @@ void editing_panels()
editing_panel_links(ob); // no editmode!
editing_panel_curve_type(ob, cu);
editing_panel_font_type(ob, cu);
#ifdef INTERNATIONAL
if(G.obedit)
{
editing_panel_char_type(ob, cu);
}
#endif
editing_panel_modifiers(ob);
break;

@ -33,6 +33,7 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <wchar.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
@ -86,7 +87,7 @@ int textediting=0;
extern struct SelBox *selboxes; /* from blenkernel/font.c */
static char findaccent(char char1, char code)
static char findaccent(char char1, unsigned int code)
{
char new= 0;
@ -217,15 +218,25 @@ static char findaccent(char char1, char code)
else return char1;
}
char *copybuf=NULL;
char *copybufinfo=NULL;
wchar_t *copybuf=NULL;
wchar_t *copybufinfo=NULL;
static char *textbuf=NULL;
static wchar_t *textbuf=NULL;
static CharInfo *textbufinfo=NULL;
static char *oldstr=NULL;
static wchar_t *oldstr=NULL;
static CharInfo *oldstrinfo=NULL;
static int insert_into_textbuf(Curve *cu, char c)
void update_string(Curve *cu)
{
int len;
MEM_freeN(cu->str);
len = wcsleninu8(textbuf);
cu->str = MEM_callocN(len + sizeof(wchar_t), "str");
wcs2utf8s(cu->str, textbuf);
}
static int insert_into_textbuf(Curve *cu, unsigned long c)
{
if (cu->len<MAXTEXT-1) {
int x;
@ -244,6 +255,8 @@ static int insert_into_textbuf(Curve *cu, char c)
cu->len++;
textbuf[cu->len]='\0';
update_string(cu);
return 1;
} else {
return 0;
@ -280,16 +293,36 @@ void add_lorem(void)
void load_3dtext_fs(char *file)
{
FILE *fp;
int c;
int filelen;
char *strp;
Curve *cu=G.obedit->data;
fp= fopen(file, "r");
if (!fp) return;
while (!feof(fp)) {
c = fgetc(fp);
if (c!=EOF) insert_into_textbuf(OBACT->data, c);
}
fseek(fp, 0L, SEEK_END);
filelen = ftell(fp);
fseek(fp, 0L, SEEK_SET);
strp = MEM_callocN(filelen+4, "tempstr");
filelen = fread(strp, 1, filelen, fp);
fclose(fp);
strp[filelen]= 0;
if(cu->len+filelen<MAXTEXT)
{
int tmplen;
wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
tmplen = utf8towchar_(mem, strp);
wcscat(textbuf, mem);
MEM_freeN(mem);
cu->len += tmplen;
cu->pos= cu->len;
}
MEM_freeN(strp);
update_string(cu);
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
allqueue(REDRAWVIEW3D, 0);
@ -479,6 +512,7 @@ static int killselection(int ins) /* 1 == new character */
direction = getselection(&selstart, &selend);
if (direction) {
int size;
if (ins) offset = 1;
if (cu->pos >= selstart) cu->pos = selstart+offset;
if ((direction == -1) && ins) {
@ -487,7 +521,8 @@ static int killselection(int ins) /* 1 == new character */
}
getfrom = selend+offset;
if (ins==0) getfrom++;
memmove(textbuf+selstart, textbuf+getfrom, (cu->len-selstart)+offset);
size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t));
memmove(textbuf+selstart, textbuf+getfrom, size);
memmove(textbufinfo+selstart, textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo));
cu->len -= (selend-selstart)+offset;
cu->selstart = cu->selend = 0;
@ -500,7 +535,7 @@ static void copyselection(void)
int selstart, selend;
if (getselection(&selstart, &selend)) {
memcpy(copybuf, textbuf+selstart, (selend-selstart)+1);
memcpy(copybuf, textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t));
copybuf[(selend-selstart)+1]=0;
memcpy(copybufinfo, textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo));
}
@ -509,11 +544,12 @@ static void copyselection(void)
static void pasteselection(void)
{
Curve *cu= G.obedit->data;
int len= strlen(copybuf);
int len= wcslen(copybuf);
if (len) {
memmove(textbuf+cu->pos+len, textbuf+cu->pos, cu->len-cu->pos+1);
memcpy(textbuf+cu->pos, copybuf, len);
int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t);
memmove(textbuf+cu->pos+len, textbuf+cu->pos, size);
memcpy(textbuf+cu->pos, copybuf, len * sizeof(wchar_t));
memmove(textbufinfo+cu->pos+len, textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo));
memcpy(textbufinfo+cu->pos, copybufinfo, len*sizeof(CharInfo));
@ -564,12 +600,12 @@ int mat_to_sel(void) {
return 0;
}
void do_textedit(unsigned short event, short val, char _ascii)
void do_textedit(unsigned short event, short val, unsigned long _ascii)
{
Curve *cu;
static int accentcode= 0;
int x, doit=0, cursmove=0;
int ascii = _ascii;
unsigned long ascii = _ascii;
short kern;
cu= G.obedit->data;
@ -608,7 +644,6 @@ void do_textedit(unsigned short event, short val, char _ascii)
else if(ascii=='>') ascii= 187;
else if(ascii=='<') ascii= 171;
}
if(ascii==1001) {
int file, filelen;
char *strp;
@ -627,9 +662,14 @@ void do_textedit(unsigned short event, short val, char _ascii)
read(file, strp, filelen);
close(file);
strp[filelen]= 0;
if(cu->len+filelen<MAXTEXT) {
strcat( textbuf, strp);
cu->len= strlen(textbuf);
int tmplen;
wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
tmplen = utf8towchar_(mem, strp);
wcscat(textbuf, mem);
MEM_freeN(mem);
cu->len += tmplen;
cu->pos= cu->len;
}
MEM_freeN(strp);
@ -644,6 +684,11 @@ void do_textedit(unsigned short event, short val, char _ascii)
doit= 1;
}
else
{
insert_into_textbuf(cu, ascii);
doit = 1;
}
}
else if(val) {
cursmove= 0;
@ -841,6 +886,7 @@ void do_textedit(unsigned short event, short val, char _ascii)
if ((G.qual & LR_SHIFTKEY)==0) {
if (cu->selstart) {
cu->selstart = cu->selend = 0;
update_string(cu);
text_to_curve(G.obedit, FO_SELCHANGE);
allqueue(REDRAWVIEW3D, 0);
}
@ -860,6 +906,7 @@ void do_textedit(unsigned short event, short val, char _ascii)
G.obedit->actcol = textbufinfo[cu->pos-1].mat_nr;
}
allqueue(REDRAWBUTSEDIT, 0);
update_string(cu);
text_to_curve(G.obedit, cursmove);
if (cursmove && (G.qual & LR_SHIFTKEY)) {
cu->selend = cu->pos;
@ -874,16 +921,64 @@ void do_textedit(unsigned short event, short val, char _ascii)
}
}
void paste_unicodeText(char *filename)
{
Curve *cu;
int filelen, doit= 0;
char *strp;
FILE *fp = NULL;
fp= fopen(filename, "r");
if(fp) {
cu= G.obedit->data;
fseek( fp, 0L, SEEK_END );
filelen = ftell( fp );
fseek( fp, 0L, SEEK_SET );
strp= MEM_mallocN(filelen+4, "tempstr");
//fread() instead of read(),
//because windows read() converts text to DOS \r\n linebreaks
//causing double linebreaks in the 3d text
filelen = fread(strp, 1, filelen, fp);
fclose(fp);
strp[filelen]= 0;
if(cu->len+filelen<MAXTEXT)
{
int tmplen;
wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
tmplen = utf8towchar_(mem, strp);
// mem =utf8s2wc(strp);
wcscat(textbuf, mem);
MEM_freeN(mem);
// cu->len = wcslen(textbuf);
cu->len += tmplen;
cu->pos= cu->len;
}
MEM_freeN(strp);
doit = 1;
}
if(doit) {
update_string(cu);
text_to_curve(G.obedit, 0);
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
allqueue(REDRAWVIEW3D, 0);
BIF_undo_push("Paste text");
}
}
void paste_editText(void)
{
Curve *cu;
int file, filelen, doit= 0;
int filelen, doit= 0;
char *strp;
FILE *fp = NULL;
#ifdef WIN32
file= open("C:\\windows\\temp\\cutbuf.txt", O_BINARY|O_RDONLY);
fp= fopen("C:\\windows\\temp\\cutbuf.txt", "r");
// The following is more likely to work on all Win32 installations.
// suggested by Douglas Toltzman. Needs windows include files...
@ -900,26 +995,39 @@ void paste_editText(void)
}
*/
#else
file= open("/tmp/.cutbuffer", O_BINARY|O_RDONLY);
fp= fopen("/tmp/.cutbuffer", "r");
#endif
if(file>0) {
if(fp) {
cu= G.obedit->data;
filelen = BLI_filesize(file);
fseek(fp, 0L, SEEK_END);
filelen = ftell( fp );
fseek(fp, 0L, SEEK_SET);
strp= MEM_mallocN(filelen+4, "tempstr");
read(file, strp, filelen);
close(file);
// fread() instead of read(),
// because windows read() converts text to DOS \r\n linebreaks
// causing double linebreaks in the 3d text
filelen = fread(strp, 1, filelen, fp);
fclose(fp);
strp[filelen]= 0;
if(cu->len+filelen<MAXTEXT) {
strcat( textbuf, strp);
cu->len= strlen(textbuf);
cu->pos= cu->len;
int tmplen;
wchar_t *mem = MEM_callocN((sizeof(wchar_t) * filelen) + (4 * sizeof(wchar_t)), "temporary");
tmplen = utf8towchar_(mem, strp);
wcscat(textbuf, mem);
MEM_freeN(mem);
cu->len += tmplen;
cu->pos= cu->len;
}
MEM_freeN(strp);
doit = 1;
}
if(doit) {
update_string(cu);
text_to_curve(G.obedit, 0);
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
allqueue(REDRAWVIEW3D, 0);
BIF_undo_push("Paste text");
@ -930,19 +1038,23 @@ void paste_editText(void)
void make_editText(void)
{
Curve *cu;
cu= G.obedit->data;
if(textbuf==NULL) textbuf= MEM_mallocN(MAXTEXT+4, "texteditbuf");
if(textbuf==NULL) textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf");
if(textbufinfo==NULL) textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo");
if(copybuf==NULL) copybuf= MEM_callocN(MAXTEXT+4, "texteditcopybuf");
if(copybuf==NULL) copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf");
if(copybufinfo==NULL) copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo");
BLI_strncpy(textbuf, cu->str, MAXTEXT);
cu->len= strlen(textbuf);
if(oldstr==NULL) oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf");
// Convert the original text to wchar_t
utf8towchar_(textbuf, cu->str);
wcscpy(oldstr, textbuf);
cu->len= wcslen(textbuf);
memcpy(textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
oldstr= cu->str;
oldstrinfo= cu->strinfo;
cu->str= textbuf;
cu->strinfo= textbufinfo;
if(cu->pos>cu->len) cu->pos= cu->len;
@ -951,6 +1063,9 @@ void make_editText(void)
cu->curinfo = textbufinfo[cu->pos-1];
} else cu->curinfo = textbufinfo[0];
// Convert to UTF-8
update_string(cu);
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
textediting= 1;
@ -969,8 +1084,8 @@ void load_editText(void)
MEM_freeN(oldstrinfo);
oldstrinfo= NULL;
cu->str= MEM_mallocN(cu->len+4, "textedit");
strcpy(cu->str, textbuf);
update_string(cu);
cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo");
memcpy(cu->strinfo, textbufinfo, (cu->len)*sizeof(CharInfo));
@ -1000,7 +1115,10 @@ void remake_editText(void)
if(okee("Reload original text")==0) return;
BLI_strncpy(textbuf, oldstr, MAXTEXT);
// Copy the oldstr to textbuf temporary global variable
wcscpy(textbuf, oldstr);
// Set the object length and position
cu= G.obedit->data;
cu->len= strlen(textbuf);
if(cu->pos>cu->len) cu->pos= cu->len;
@ -1055,7 +1173,7 @@ void to_upper(void)
{
Curve *cu;
int len, ok;
char *str;
wchar_t *str;
if(G.obedit==0) {
return;
@ -1064,8 +1182,8 @@ void to_upper(void)
ok= 0;
cu= G.obedit->data;
len= strlen(cu->str);
str= cu->str;
len= wcslen(textbuf);
str= textbuf;
while(len) {
if( *str>=97 && *str<=122) {
ok= 1;
@ -1076,8 +1194,8 @@ void to_upper(void)
}
if(ok==0) {
len= strlen(cu->str);
str= cu->str;
len= wcslen(textbuf);
str= textbuf;
while(len) {
if( *str>=65 && *str<=90) {
*str+= 32;
@ -1089,6 +1207,8 @@ void to_upper(void)
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
allqueue(REDRAWVIEW3D, 0);
BIF_undo_push("To upper");
update_string(cu);
}
@ -1099,9 +1219,10 @@ static void undoFont_to_editFont(void *strv)
Curve *cu= G.obedit->data;
char *str= strv;
strncpy(textbuf, str+2, MAXTEXT);
utf8towchar_(textbuf, str);
cu->pos= *((short *)str);
cu->len= strlen(textbuf);
cu->len= wcslen(textbuf);
memcpy(textbufinfo, str+2+cu->len+1, cu->len*sizeof(CharInfo));
cu->selstart = cu->selend = 0;
@ -1117,7 +1238,8 @@ static void *editFont_to_undoFont(void)
str= MEM_callocN(MAXTEXT+4+(MAXTEXT+4)*sizeof(CharInfo), "string undo");
strncpy(str+2, textbuf, MAXTEXT);
wcs2utf8s(str, textbuf);
*((short *)str)= cu->pos;
memcpy(str+2+cu->len+1, textbufinfo, cu->len*sizeof(CharInfo));

@ -68,6 +68,8 @@
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
#include "BKE_blender.h"
#include "BKE_utildefines.h"
@ -2687,6 +2689,56 @@ static int ui_do_but_HSVCUBE(uiBut *but)
return but->retval;
}
#ifdef INTERNATIONAL
static int ui_do_but_CHARTAB(uiBut *but)
{
/* Variables */
short mval[2];
float sx, sy, ex, ey;
float width, height;
float butw, buth;
int x, y;
unsigned long cs;
unsigned long che;
/* Check the position */
uiGetMouse(mywinget(), mval);
/* Calculate the size of the button */
width = abs(but->x2 - but->x1);
height = abs(but->y2 - but->y1);
butw = floor(width / 12);
buth = floor(height / 6);
/* Initialize variables */
sx = but->x1;
ex = but->x1 + butw;
sy = but->y1 + height - buth;
ey = but->y1 + height;
cs = G.charstart;
/* And the character is */
x = (int) ((mval[0] / butw) - 0.5);
y = (int) (6 - ((mval[1] / buth) - 0.5));
che = cs + (y*12) + x;
if(che > G.charmax)
che = 0;
if(G.obedit)
{
do_textedit(0,0,che);
}
return but->retval;
}
#endif
/* ************************************************ */
@ -2925,6 +2977,12 @@ static int ui_do_button(uiBlock *block, uiBut *but, uiEvent *uevent)
case HSVCUBE:
retval= ui_do_but_HSVCUBE(but);
break;
#ifdef INTERNATIONAL
case CHARTAB:
retval= ui_do_but_CHARTAB(but);
break;
#endif
}
block->flag &= ~UI_BLOCK_BUSY;
@ -3383,7 +3441,66 @@ static int ui_do_block(uiBlock *block, uiEvent *uevent)
}
}
break;
#ifdef INTERNATIONAL
//HACK to let the chartab button react to the mousewheel and PGUP/PGDN keys
case WHEELUPMOUSE:
case PAGEUPKEY:
for(but= block->buttons.first; but; but= but->next)
{
if(but->type == CHARTAB && (but->flag & UI_MOUSE_OVER))
{
G.charstart = G.charstart - (12*6);
if(G.charstart < 0)
G.charstart = 0;
if(G.charstart < G.charmin)
G.charstart = G.charmin;
ui_draw_but(but);
//Really nasty... to update the num button from the same butblock
for(bt= block->buttons.first; bt; bt= bt->next)
{
if(bt->type == NUM) {
ui_check_but(bt);
ui_draw_but(bt);
}
}
retval=UI_CONT;
break;
}
}
break;
case WHEELDOWNMOUSE:
case PAGEDOWNKEY:
for(but= block->buttons.first; but; but= but->next)
{
if(but->type == CHARTAB && (but->flag & UI_MOUSE_OVER))
{
G.charstart = G.charstart + (12*6);
if(G.charstart > (0xffff - 12*6))
G.charstart = 0xffff - (12*6);
if(G.charstart > G.charmax - 12*6)
G.charstart = G.charmax - 12*6;
ui_draw_but(but);
for(bt= block->buttons.first; bt; bt= bt->next)
{
if(bt->type == NUM) {
ui_check_but(bt);
ui_draw_but(bt);
}
}
but->flag |= UI_ACTIVE;
retval=UI_RETURN_OK;
break;
}
}
break;
#endif
case PADENTER:
case RETKEY: // prevent treating this as mousemove. for example when you enter at popup
if(block->flag & UI_BLOCK_LOOP) break;

@ -1,3 +1,4 @@
/**
* $Id$
*
@ -58,6 +59,8 @@
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
#include "DNA_vfont_types.h"
#include "DNA_packedFile_types.h"
#include "BKE_blender.h"
#include "BKE_utildefines.h"
@ -79,6 +82,8 @@
#include "BSE_view.h"
#include "FTF_Api.h"
#include "mydevice.h"
#include "interface.h"
#include "blendef.h"
@ -1698,6 +1703,129 @@ static void ui_draw_but_HSVCUBE(uiBut *but)
fdrawbox((but->x1), (but->y1), (but->x2), (but->y2));
}
#ifdef INTERNATIONAL
static void ui_draw_but_CHARTAB(uiBut *but)
{
/* Some local variables */
float sx, sy, ex, ey;
float width, height;
float butw, buth;
int x, y;
unsigned long cs;
wchar_t wstr[2];
unsigned char ustr[16];
PackedFile *pf;
/* Calculate the size of the button */
width = abs(but->x2 - but->x1);
height = abs(but->y2 - but->y1);
butw = floor(width / 12);
buth = floor(height / 6);
/* Initialize variables */
sx = but->x1;
ex = but->x1 + butw;
sy = but->y1 + height - buth;
ey = but->y1 + height;
cs = G.charstart;
/* Set the font */
if(G.selfont && strcmp(G.selfont->name, "<builtin>"))
{
char tmpStr[256];
// Is the font file packed, if so then use the packed file
if(G.selfont->packedfile)
{
pf = G.selfont->packedfile;
FTF_SetFont(pf->data, pf->size, 14.0);
}
else
{
int err;
strcpy(tmpStr, G.selfont->name);
BLI_convertstringcode(tmpStr, G.sce, 0);
err = FTF_SetFont(tmpStr, 0, 14.0);
}
}
/* Start drawing the button itself */
glShadeModel(GL_SMOOTH);
glColor3ub(200, 200, 200);
glRectf((but->x1), (but->y1), (but->x2), (but->y2));
glColor3ub(0, 0, 0);
for(y = 0; y < 6; y++)
{
// Do not draw more than the category allows
if(cs > G.charmax) break;
for(x = 0; x < 12; x++)
{
// Do not draw more than the category allows
if(cs > G.charmax) break;
// Draw one grid cell
glBegin(GL_LINE_LOOP);
glVertex2f(sx, sy);
glVertex2f(ex, sy);
glVertex2f(ex, ey);
glVertex2f(sx, ey);
glEnd();
// Draw character inside the cell
memset(wstr, 0, sizeof(wchar_t)*2);
memset(ustr, 0, 16);
wstr[0] = cs;
wcs2utf8s(ustr, wstr);
if(G.selfont && strcmp(G.selfont->name, "<builtin>"))
{
float wid;
float llx, lly, llz, urx, ury, urz;
float dx, dy;
float px, py;
// Calculate the position
wid = FTF_GetStringWidth(ustr, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
FTF_GetBoundingBox(ustr, &llx,&lly,&llz,&urx,&ury,&urz, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
dx = urx-llx;
dy = ury-lly;
// This isn't fully functional since the but->aspect isn't working like I suspected
px = sx + ((butw/but->aspect)-dx)/2;
py = sy + ((buth/but->aspect)-dy)/2;
// Set the position and draw the character
ui_rasterpos_safe(px, py, but->aspect);
FTF_DrawString(ustr, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
}
else
{
ui_rasterpos_safe(sx + butw/2, sy + buth/2, but->aspect);
BIF_DrawString(but->font, ustr, 0);
}
// Calculate the next position and character
sx += butw; ex +=butw;
cs++;
}
/* Add the y position and reset x position */
sy -= buth;
ey -= buth;
sx = but->x1;
ex = but->x1 + butw;
}
glShadeModel(GL_FLAT);
}
#endif // INTERNATIONAL
static void ui_draw_roundbox(uiBut *but)
{
BIF_ThemeColorShade(but->themecol, but->a2);
@ -1754,7 +1882,6 @@ void ui_set_embossfunc(uiBut *but, int drawtype)
// note: if you want aligning, adapt the call uiBlockEndAlign in interface.c
}
void ui_draw_but(uiBut *but)
{
double value;
@ -1796,6 +1923,13 @@ void ui_draw_but(uiBut *but)
ui_draw_but_HSVCUBE(but); // box for colorpicker, three types
break;
#ifdef INTERNATIONAL
case CHARTAB:
value= ui_get_but_val(but);
ui_draw_but_CHARTAB(but);
break;
#endif
case LINK:
case INLINK:
ui_draw_icon(but, but->icon);

@ -78,6 +78,8 @@
#include "BKE_packedFile.h"
#include "BKE_utildefines.h"
#include "BLI_vfontdata.h"
#include "BIF_fsmenu.h"
#include "BIF_gl.h"
#include "BIF_interface.h"
@ -291,9 +293,20 @@ int BIF_read_homefile(void)
char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR];
char *home= BLI_gethome();
int success;
struct TmpFont *tf;
BLI_clean(home);
tf= G.ttfdata.first;
while(tf)
{
freePackedFile(tf->pf);
tf->pf = NULL;
tf->vfont = NULL;
tf= tf->next;
}
BLI_freelistN(&G.ttfdata);
#if 0
//#ifdef _WIN32 // FULLSCREEN
static int screenmode = -1;
@ -632,6 +645,17 @@ extern ListBase editelems;
void exit_usiblender(void)
{
struct TmpFont *tf;
tf= G.ttfdata.first;
while(tf)
{
freePackedFile(tf->pf);
tf->pf= NULL;
tf->vfont= NULL;
tf= tf->next;
}
BLI_freelistN(&G.ttfdata);
freeAllRad();
BKE_freecubetable();