934 lines
33 KiB
C++
934 lines
33 KiB
C++
|
/***************************************************************************
|
||
|
* font.cpp is part of Math Graphic Library
|
||
|
* Copyright (C) 2007-2016 Alexey Balakin <mathgl.abalakin@gmail.ru> *
|
||
|
* *
|
||
|
* This program is free software; you can redistribute it and/or modify *
|
||
|
* it under the terms of the GNU Library General Public License as *
|
||
|
* published by the Free Software Foundation; either version 3 of the *
|
||
|
* License, or (at your option) any later version. *
|
||
|
* *
|
||
|
* This program 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 General Public License for more details. *
|
||
|
* *
|
||
|
* You should have received a copy of the GNU Library General Public *
|
||
|
* License along with this program; if not, write to the *
|
||
|
* Free Software Foundation, Inc., *
|
||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||
|
***************************************************************************/
|
||
|
#include <locale.h>
|
||
|
#include <ctype.h>
|
||
|
#include <wctype.h>
|
||
|
|
||
|
#if !defined(__BORLANDC__) || (__CODEGEARC__ >= 0x0630)
|
||
|
#include <algorithm>
|
||
|
#else
|
||
|
#include <algorithm.h>
|
||
|
#endif
|
||
|
|
||
|
#include "mgl2/base.h"
|
||
|
#include "mgl2/font.h"
|
||
|
#include "def_font.cc"
|
||
|
#include "tex_table.cc"
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//mglFont mglDefFont("nofont");
|
||
|
mglFont mglDefFont;
|
||
|
//-----------------------------------------------------------------------------
|
||
|
long MGL_EXPORT_PURE mgl_internal_code(unsigned s, const std::vector<mglGlyphDescr> &glyphs)
|
||
|
{
|
||
|
register long i1=0,i2=glyphs.size()-1;
|
||
|
register wchar_t j = wchar_t(s & MGL_FONT_MASK);
|
||
|
// let suppose that id[i]<id[i+1]
|
||
|
while(i1<i2)
|
||
|
{
|
||
|
register long i = (i1+i2)/2;
|
||
|
if(j<glyphs[i].id) i2 = i;
|
||
|
else if(j>glyphs[i].id) i1=i+1;
|
||
|
else return i;
|
||
|
}
|
||
|
return j==glyphs[i2].id ? i2 : -1;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool MGL_EXPORT mglGetStyle(const char *how, int *font, int *align)
|
||
|
{
|
||
|
bool col=false;
|
||
|
if(align) *align = 1; // centering text by default
|
||
|
if(!how || *how==0) return col;
|
||
|
// NOTE: no brightness for text color
|
||
|
for(;*how && *how!=':';how++)
|
||
|
{
|
||
|
if(strchr(MGL_COLORS,*how)) col = true;
|
||
|
if(*how=='{' && how[1]=='x') col = true;
|
||
|
}
|
||
|
if(align)
|
||
|
{
|
||
|
*align = 1;
|
||
|
if(strchr(how,'R')) *align = 2;
|
||
|
if(strchr(how,'C')) *align = 1;
|
||
|
if(strchr(how,'L')) *align = 0;
|
||
|
if(strchr(how,'D')) *align+= 4;
|
||
|
}
|
||
|
if(font)
|
||
|
{
|
||
|
*font = 0;
|
||
|
if(strchr(how,'b')) *font = *font|MGL_FONT_BOLD;
|
||
|
if(strchr(how,'i')) *font = *font|MGL_FONT_ITAL;
|
||
|
if(strchr(how,'w')) *font = *font|MGL_FONT_WIRE;
|
||
|
if(strchr(how,'o')) *font = *font|MGL_FONT_OLINE;
|
||
|
if(strchr(how,'u')) *font = *font|MGL_FONT_ULINE;
|
||
|
}
|
||
|
return col;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::Puts(const char *str,const char *how,float c1,float c2) const
|
||
|
{
|
||
|
int font=0, align=1; float w=0;
|
||
|
mglGetStyle(how,&font,&align);
|
||
|
MGL_TO_WCS(str,w = Puts(wcs,font,align,c1,c2));
|
||
|
return w;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::Width(const char *str,const char *how) const
|
||
|
{
|
||
|
int font=0; float w=0;
|
||
|
mglGetStyle(how,&font);
|
||
|
MGL_TO_WCS(str,w = Width(wcs,font));
|
||
|
return w;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::Puts(const wchar_t *str,const char *how,float c1,float c2) const
|
||
|
{
|
||
|
int font=0, align=1;
|
||
|
mglGetStyle(how,&font,&align);
|
||
|
return Puts(str, font, align,c1,c2);
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::Width(const wchar_t *str,const char *how) const
|
||
|
{
|
||
|
int font=0;
|
||
|
mglGetStyle(how,&font);
|
||
|
return Width(str, font);
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::Puts(const wchar_t *str,int font,int align, float c1,float c2) const
|
||
|
{
|
||
|
if(GetNumGlyph()==0 || !str || *str==0) return 0;
|
||
|
float ww=0,w=0,h = (align&4) ? 500./fact[0] : 0;
|
||
|
size_t size = mgl_wcslen(str)+1,num=0;
|
||
|
if(parse)
|
||
|
{
|
||
|
unsigned *wcs = new unsigned[size], *buf=wcs;
|
||
|
memcpy(wcs,str,size*sizeof(wchar_t));
|
||
|
Convert(str, wcs);
|
||
|
for(size_t i=0;wcs[i];i++)
|
||
|
{
|
||
|
if(wcs[i]=='\n') // parse '\n' symbol
|
||
|
{
|
||
|
wcs[i]=0; w = Puts(buf,0,0,1.f,0x10|font,c1,c2); // find width
|
||
|
Puts(buf,-w*(align&3)/2.f,-h - 500.*num/fact[0],1.f,font,c1,c2); // draw it really
|
||
|
buf=wcs+i+1; num++; if(w>ww) ww=w;
|
||
|
}
|
||
|
if(wcs[i]=='\\' && wcs[i+1]=='n' && (wcs[i+2]>' ' || wcschr(L"{}[]()!@#$%^&*/-?.,_=+\\\"", wcs[i+2]))) // parse '\n' symbol
|
||
|
{
|
||
|
wcs[i]=0; w = Puts(buf,0,0,1.f,0x10|font,c1,c2); // find width
|
||
|
Puts(buf,-w*(align&3)/2.f,-h - 500.*num/fact[0],1.f,font,c1,c2); // draw it really
|
||
|
buf=wcs+i+2; num++; if(w>ww) ww=w;
|
||
|
}
|
||
|
}
|
||
|
// draw string itself
|
||
|
w = Puts(buf,0,0,1.f,0x10|font,c1,c2); // find width
|
||
|
Puts(buf,-w*(align&3)/2.f,-h - 500.*num/fact[0],1.f,font,c1,c2); // draw it really
|
||
|
if(w>ww) ww=w;
|
||
|
delete []wcs;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int s = (font/MGL_FONT_BOLD)&3;
|
||
|
h *= fact[0]/fact[s];
|
||
|
for(size_t i=0;i<size;i++) // find width
|
||
|
{
|
||
|
long j = str[i]!=' ' ? Internal(str[i]) : Internal('!');
|
||
|
if(j==-1) continue;
|
||
|
w+= GetWidth(s,j)/fact[s];
|
||
|
}
|
||
|
ww = w; w *= -(align&3)/2.f;
|
||
|
if(gr) for(size_t i=0;i<size;i++) // draw it
|
||
|
{
|
||
|
long j=0; //Internal('!');
|
||
|
if(str[i]!=' ')
|
||
|
{
|
||
|
j = Internal(str[i]);
|
||
|
if(j==-1) continue;
|
||
|
gr->Glyph(w, -h, 1, (s+(font&MGL_FONT_WIRE))?4:0, j, c1+i*(c2-c1)/(size-1));
|
||
|
}
|
||
|
w+= GetWidth(s,j)/fact[s];
|
||
|
}
|
||
|
}
|
||
|
return ww;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::Width(const wchar_t *str,int font) const
|
||
|
{
|
||
|
if(GetNumGlyph()==0 || !str || *str==0) return 0;
|
||
|
float ww=0,w=0;
|
||
|
size_t size = mgl_wcslen(str)+1;
|
||
|
if(parse)
|
||
|
{
|
||
|
unsigned *wcs = new unsigned[size], *buf=wcs;
|
||
|
memcpy(wcs,str,size*sizeof(wchar_t));
|
||
|
Convert(str, wcs);
|
||
|
for(size_t i=0;wcs[i];i++) if(wcs[i]=='\n') // parse '\n' symbol
|
||
|
{
|
||
|
wcs[i]=0; w = Puts(buf,0,0,1.,0x10|font,'k','k'); // find width
|
||
|
buf=wcs+i+1; if(w>ww) ww=w;
|
||
|
}
|
||
|
w = Puts(buf,0,0,1.,0x10|font,'k','k');
|
||
|
if(w<ww) w=ww;
|
||
|
delete []wcs;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int s = (font/MGL_FONT_BOLD)&3;
|
||
|
for(size_t i=0;i<size;i++)
|
||
|
{
|
||
|
long j = str[i]!=' ' ? Internal(str[i]) : Internal('!');
|
||
|
if(j==-1) continue;
|
||
|
w+= GetWidth(s,j)/fact[s];
|
||
|
}
|
||
|
}
|
||
|
return w;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::Height(int font) const
|
||
|
{
|
||
|
if(GetNumGlyph()==0) return 0;
|
||
|
int s = (font/MGL_FONT_BOLD)&3;
|
||
|
return (500.f)/fact[s];
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::Height(const char *how) const
|
||
|
{
|
||
|
if(GetNumGlyph()==0) return 0;
|
||
|
int s=0;
|
||
|
if(how)
|
||
|
{
|
||
|
if(strchr(how,'b')) s = s|1;
|
||
|
if(strchr(how,'i')) s = s|2;
|
||
|
}
|
||
|
return (500.f)/fact[s];
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
/// Table of acents and its UTF8 codes
|
||
|
MGL_NO_EXPORT mglTeXsymb mgl_act_symb[] = {
|
||
|
{0x02c6, L"hat"}, {0x02dc, L"tilde"}, {0x02d9, L"dot"}, {0x00a8, L"ddot"}, {0x20db, L"dddot"}, {0x20dc, L"ddddot"}, {0x02ca, L"acute"}, {0x02c7, L"check"}, {0x02cb, L"grave"}, {0x20d7, L"vec"}, {0x02c9, L"bar"}, {0x02d8, L"breve"},
|
||
|
/*end*/{0, L"\0"}};
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int MGL_LOCAL_PURE mgl_tex_symb_cmp(const void *a, const void *b)
|
||
|
{
|
||
|
const mglTeXsymb *aa = (const mglTeXsymb *)a;
|
||
|
const mglTeXsymb *bb = (const mglTeXsymb *)b;
|
||
|
return wcscmp(aa->tex, bb->tex);
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// parse LaTeX commands (mostly symbols and acents, and some font-style commands)
|
||
|
unsigned mglFont::Parse(const wchar_t *s) const
|
||
|
{
|
||
|
register long k;
|
||
|
unsigned res = unsigned(-2); // Default is no symbol
|
||
|
if(!s || !s[0]) return res;
|
||
|
// for(k=0;mgl_tex_symb[k].kod;k++); // determine the number of symbols
|
||
|
mglTeXsymb tst, *rts;
|
||
|
tst.tex = s;
|
||
|
rts = (mglTeXsymb *) bsearch(&tst, mgl_tex_symb, mgl_tex_num, sizeof(mglTeXsymb), mgl_tex_symb_cmp);
|
||
|
if(rts) return rts->kod;
|
||
|
|
||
|
// for(k=0;mgl_tex_symb[k].kod;k++) // special symbols
|
||
|
// if(!wcscmp(s,mgl_tex_symb[k].tex))
|
||
|
// return mgl_tex_symb[k].kod;
|
||
|
for(k=0;mgl_act_symb[k].kod;k++) // acents
|
||
|
if(!wcscmp(s,mgl_act_symb[k].tex))
|
||
|
return mgl_act_symb[k].kod | MGL_FONT_ZEROW;
|
||
|
// arbitrary UTF symbol
|
||
|
if(s[0]=='u' && s[1]=='t' && s[2]=='f')
|
||
|
// { wscanf(s+3,"%lx",&k); return wchar_t(k); }
|
||
|
{ k = wcstoul(s+3,NULL,16); return wchar_t(k); }
|
||
|
// font/style changes for next symbol
|
||
|
if(!wcscmp(s,L"big")) res = unsigned(-5);
|
||
|
else if(!wcscmp(s,L"frac")) res = unsigned(-6);
|
||
|
else if(!wcscmp(s,L"stack")) res = unsigned(-7);
|
||
|
else if(!wcscmp(s,L"overset")) res = unsigned(-8);
|
||
|
else if(!wcscmp(s,L"underset")) res = unsigned(-9);
|
||
|
else if(!wcscmp(s,L"stackr")) res = unsigned(-10);
|
||
|
else if(!wcscmp(s,L"stackl")) res = unsigned(-11);
|
||
|
else if(!wcscmp(s,L"sub")) res = unsigned(-12);
|
||
|
else if(!wcscmp(s,L"sup")) res = unsigned(-13);
|
||
|
else if(!wcscmp(s,L"textsc")) res = unsigned(-14); // new
|
||
|
else if(!wcscmp(s,L"b")) res = MGL_FONT_BOLD;
|
||
|
else if(!wcscmp(s,L"i")) res = MGL_FONT_ITAL;
|
||
|
else if(!wcscmp(s,L"bi")) res = MGL_FONT_BOLD|MGL_FONT_ITAL;
|
||
|
else if(!wcscmp(s,L"r")) res = unsigned(-1);
|
||
|
else if(!wcscmp(s,L"a")) res = MGL_FONT_OLINE;
|
||
|
else if(!wcscmp(s,L"u")) res = MGL_FONT_ULINE;
|
||
|
else if(!wcscmp(s,L"n")) res = '\n';
|
||
|
else if(!wcscmp(s,L"overline")) res = MGL_FONT_OLINE;
|
||
|
else if(!wcscmp(s,L"underline"))res = MGL_FONT_ULINE;
|
||
|
else if(!wcscmp(s,L"textbf")) res = MGL_FONT_BOLD;
|
||
|
else if(!wcscmp(s,L"textit")) res = MGL_FONT_ITAL;
|
||
|
else if(!wcscmp(s,L"textrm")) res = unsigned(-1);
|
||
|
else if(!wcscmp(s,L"T2A")) res = unsigned(-1);
|
||
|
else if(!wcscmp(s,L"w")) res = MGL_FONT_WIRE;
|
||
|
else if(!wcscmp(s,L"wire")) res = MGL_FONT_WIRE;
|
||
|
else if(!wcsncmp(s,L"color",5)) res = MGL_COLOR_MASK + (0xff & s[5]);
|
||
|
return res;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void mglFont::Convert(const wchar_t *str, unsigned *res) const
|
||
|
{
|
||
|
register size_t r,i,j,k,i0;
|
||
|
wchar_t s[128]=L""; // TeX command and current char
|
||
|
for(i=j=0;str[i];i++)
|
||
|
{
|
||
|
wchar_t ch = str[i];
|
||
|
if(ch=='\\') // It can be TeX command
|
||
|
{
|
||
|
if(wcschr(L"{}_^\\@# ",str[i+1])) // No, it is usual symbol
|
||
|
res[j++] = str[++i];
|
||
|
else // Yes, it is TeX command
|
||
|
{
|
||
|
i0=i+1;
|
||
|
for(k=0;isalnum(str[++i]) && k<127;k++) s[k] = str[i];
|
||
|
s[k] = 0;
|
||
|
r = Parse(s);
|
||
|
if(r==unsigned(-2)) // command not found, so use next symbol itself
|
||
|
{ res[j++] = str[i0]; i = i0; }
|
||
|
else if(r)
|
||
|
{
|
||
|
res[j++] = r;
|
||
|
if(str[i]>' ') i--;
|
||
|
if(str[i]==0) break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if(ch=='-' && str[i+1]=='-') { res[j++] = 0x2212; i++; }
|
||
|
else if(ch=='\b'){}
|
||
|
else if(ch<=' ' && ch!='\n') res[j++] = ' '; // no \t at this moment :(
|
||
|
else if(ch=='_') res[j++] = MGL_FONT_LOWER;
|
||
|
else if(ch=='^') res[j++] = MGL_FONT_UPPER;
|
||
|
else if(ch=='@') res[j++] = MGL_FONT_UPPER|MGL_FONT_LOWER;
|
||
|
else if(ch=='{') res[j++] = unsigned(-3);
|
||
|
else if(ch=='}') res[j++] = unsigned(-4);
|
||
|
else if(ch=='#' && str[i+1]>' ')
|
||
|
res[j++] = MGL_COLOR_MASK + (0xff & str[++i]); // TODO inline colors -- stack of RGBA colors + index
|
||
|
else res[j++] = ch; // It is just symbol
|
||
|
}
|
||
|
res[j] = 0;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mglFont::get_ptr(long &i,unsigned *str, unsigned **b1, unsigned **b2,float &w1,float &w2, float f1, float f2, int st) const
|
||
|
{
|
||
|
static unsigned s1[2]={0,0}, s2[2]={0,0};
|
||
|
register long k;
|
||
|
i++;
|
||
|
if(str[i]==unsigned(-3))
|
||
|
{
|
||
|
i++; *b1 = str+i;
|
||
|
for(k=1;k>0 && str[i];i++)
|
||
|
{
|
||
|
if(str[i]==unsigned(-4)) k--;
|
||
|
if(str[i]==unsigned(-3)) k++;
|
||
|
}
|
||
|
str[i-1]=0;
|
||
|
}
|
||
|
else { s1[0] = str[i]; *b1 = s1; i++; }
|
||
|
if(str[i]==unsigned(-3))
|
||
|
{
|
||
|
i++; *b2 = str+i;
|
||
|
for(k=1;k>0 && str[i];i++)
|
||
|
{
|
||
|
if(str[i]==unsigned(-4)) k--;
|
||
|
if(str[i]==unsigned(-3)) k++;
|
||
|
}
|
||
|
str[i-1]=0;
|
||
|
}
|
||
|
else { s2[0] = str[i]; *b2 = s2; i++; }
|
||
|
i--;
|
||
|
w1 = Puts(*b1, 0, 0, f1, 0x10|st,'k','k');
|
||
|
w2 = Puts(*b2, 0, 0, f2, 0x10|st,'k','k');
|
||
|
return w1>w2 ? w1 : w2;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void mglFont::draw_ouline(int st, float x, float y, float f, float g, float ww, float ccol) const
|
||
|
{
|
||
|
if(st&MGL_FONT_OLINE)
|
||
|
gr->Glyph(x,y+499*f/g, ww*g, (st&MGL_FONT_WIRE)?12:8, 0, ccol);
|
||
|
if(st&MGL_FONT_ULINE)
|
||
|
gr->Glyph(x,y-200*f/g, ww*g, (st&MGL_FONT_WIRE)?12:8, 0, ccol);
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
#define MGL_CLEAR_STYLE {st = style; yy = y; ff = f; ccol=c1+dc*i; a = (st/MGL_FONT_BOLD)&3;}
|
||
|
float mglFont::Puts(const unsigned *text, float x,float y,float f,int style,float c1,float c2) const
|
||
|
{
|
||
|
if(GetNumGlyph()==0) return 0;
|
||
|
float w=0; // string width
|
||
|
int st = style; // current style
|
||
|
unsigned *b1, *b2; // pointer to substring
|
||
|
unsigned *str; // string itself
|
||
|
float yy=y, ff=f, ww, w1, w2;
|
||
|
int a = (st/MGL_FONT_BOLD)&3;
|
||
|
long i;
|
||
|
for(i=0;text[i];i++);
|
||
|
float dc=i>1?(c2-c1)/(i-1):0;
|
||
|
str = new unsigned[i+1];
|
||
|
memcpy(str,text,(i+1)*sizeof(unsigned));
|
||
|
|
||
|
float ccol = 0;
|
||
|
for(long i=0;str[i];i++)
|
||
|
{
|
||
|
ccol = ccol<0?ccol:c1+dc*i;
|
||
|
unsigned s = str[i]; ww = 0;
|
||
|
if(s==unsigned(-3)) // recursion call here
|
||
|
{
|
||
|
i++; b1 = str+i;
|
||
|
for(long k=1;k>0 && str[i];i++)
|
||
|
{
|
||
|
if(str[i]==unsigned(-4)) k--;
|
||
|
if(str[i]==unsigned(-3)) k++;
|
||
|
}
|
||
|
str[i-1]=0; i--;
|
||
|
ww = Puts(b1, x, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s=='\n') // newline
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff, st);
|
||
|
Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x+(ww-w2)/2, yy-600*ff/fact[a], ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-9)) // underset
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st);
|
||
|
Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x+(ww-w2)/2, yy-150*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-8)) // overset
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st);
|
||
|
Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x+(ww-w2)/2, yy+375*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-12)) // sub
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st);
|
||
|
Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x+(ww-w2)/2, yy-250*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-13)) // sup
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff, ff/4, st);
|
||
|
Puts(b1, x+(ww-w1)/2, yy, ff, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x+(ww-w2)/2, yy+450*ff/fact[a], ff/4, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-11)) // stackl
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st);
|
||
|
Puts(b1, x, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x, yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-10)) // stacr
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st);
|
||
|
Puts(b1, x+(ww-w1), yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x+(ww-w2), yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-7)) // stack
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st);
|
||
|
Puts(b1, x+(ww-w1)/2, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x+(ww-w2)/2, yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-6)) // frac
|
||
|
{
|
||
|
ww = get_ptr(i, str, &b1, &b2, w1, w2, ff*0.45, ff*0.45, st);
|
||
|
Puts(b1, x+(ww-w1)/2, yy+250*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
Puts(b2, x+(ww-w2)/2, yy-110*ff/fact[a], ff*0.45, (st&(~MGL_FONT_OLINE)&(~MGL_FONT_ULINE)), ccol,ccol);
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
{
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
gr->Glyph(x,y+150*f/fact[a], ww*fact[a], (st&MGL_FONT_WIRE)?12:8, 0, ccol);
|
||
|
}
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
else if(s==unsigned(-4)) MGL_CLEAR_STYLE // should be never here but if I miss sth ...
|
||
|
else if(s==unsigned(-14)) // script symbols
|
||
|
{
|
||
|
long k=1;
|
||
|
if(str[i+1]==unsigned(-3)) for(long j=i+2;k>0 && str[j];j++)
|
||
|
{
|
||
|
if(str[j]==unsigned(-3)) k++;
|
||
|
if(str[j]==unsigned(-4)) k--;
|
||
|
if(iswlower(str[j]))
|
||
|
str[j] = MGL_FONT_UPPER|MGL_FONT_LOWER|towupper(str[j]);
|
||
|
}
|
||
|
}
|
||
|
else if(s==unsigned(-5)) // large symbol
|
||
|
ff *= 1.5;
|
||
|
else if(s==unsigned(-1)) // set normal font
|
||
|
st = style & MGL_FONT_ROMAN;
|
||
|
else if((s&MGL_COLOR_MASK)==MGL_COLOR_MASK) // color specification
|
||
|
ccol = -float(s & 0xff); // TODO inline colors -- make textures
|
||
|
else
|
||
|
{
|
||
|
unsigned ss = s&MGL_FONT_MASK;
|
||
|
if(ss) // draw symbol (glyph)
|
||
|
{
|
||
|
long j = Internal('!');
|
||
|
float dx=0;
|
||
|
if(ss>' ')
|
||
|
{
|
||
|
j = Internal(ss);
|
||
|
if(j==-1) continue;
|
||
|
if(s & MGL_FONT_ZEROW)
|
||
|
{
|
||
|
long j=1;
|
||
|
yy += 100*ff/fact[a];
|
||
|
while(str[i+j]>=unsigned(-15)) j++;
|
||
|
unsigned sn = str[i+j];
|
||
|
if(sn<unsigned(-15) && (sn&MGL_FONT_MASK)>' ') // specially center
|
||
|
{
|
||
|
dx = 0.75*ff*(GetWidth(a,Internal(sn&MGL_FONT_MASK))-GetWidth(a,j))/fact[a];
|
||
|
if(dx<0) dx=0;
|
||
|
}
|
||
|
}
|
||
|
if(gr && !(style&0x10))
|
||
|
{
|
||
|
if(st & MGL_FONT_WIRE) gr->Glyph(x+dx,yy,ff,a+4,j,ccol);
|
||
|
else gr->Glyph(x+dx,yy,ff,a,j,ccol);
|
||
|
}
|
||
|
}
|
||
|
ww = ff*GetWidth(a,j)/fact[a];
|
||
|
if(gr && !(style&0x10)) // add under-/over- line now
|
||
|
draw_ouline(st,x,y,f,fact[a],ww,ccol);
|
||
|
if(s & MGL_FONT_ZEROW) ww = 0;
|
||
|
MGL_CLEAR_STYLE
|
||
|
}
|
||
|
// apply new styles
|
||
|
if(s/MGL_FONT_BOLD) st = st | (s & MGL_FONT_STYLE);
|
||
|
a = (st/MGL_FONT_BOLD)&3;
|
||
|
ss = (s/MGL_FONT_UPPER)%4;
|
||
|
if(ss)
|
||
|
{
|
||
|
if(ss==1) { ff *=0.6; yy += 200*ff/fact[a]; } // = 500*0.4
|
||
|
else if(ss==2) { ff *=0.6; yy -= 80*ff/fact[a]; } // = -500*0.16
|
||
|
else if(ss==3) { ff *=0.8; yy += 0*60*ff/fact[a]; } // = 500*0.12
|
||
|
}
|
||
|
}
|
||
|
x += ww; w += ww;
|
||
|
}
|
||
|
delete []str;
|
||
|
return w;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// copy normal style as default for other styles
|
||
|
void mglFont::main_copy()
|
||
|
{
|
||
|
#pragma omp parallel for
|
||
|
for(long i=0;i<long(glyphs.size());i++)
|
||
|
{
|
||
|
mglGlyphDescr &g = glyphs[i];
|
||
|
g.numl[1] = g.numl[2] = g.numl[3] = g.numl[0];
|
||
|
g.numt[1] = g.numt[2] = g.numt[3] = g.numt[0];
|
||
|
g.ln[1] = g.ln[2] = g.ln[3] = g.ln[0];
|
||
|
g.tr[1] = g.tr[2] = g.tr[3] = g.tr[0];
|
||
|
g.width[1] = g.width[2] = g.width[3] = g.width[0];
|
||
|
}
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool mglFont::read_def()
|
||
|
{
|
||
|
// copy default factor for other font styles;
|
||
|
fact[1] = fact[2] = fact[3] = fact[0] = mgl_fact*mgl_fgen;
|
||
|
Buf = new short[mgl_cur]; // prealocate buffer
|
||
|
memset(Buf,0,mgl_cur*sizeof(short));
|
||
|
// now allocate memory for all fonts
|
||
|
mem_alloc(mgl_numg);
|
||
|
// and load symbols itself
|
||
|
#ifndef WIN32 // win32 don't initialized threads before main()
|
||
|
#pragma omp parallel for
|
||
|
#endif
|
||
|
for(size_t i=0;i<mgl_numg;i++)
|
||
|
{
|
||
|
mglGlyphDescr &g = glyphs[i];
|
||
|
g.id = mgl_gen_fnt[i][0];
|
||
|
g.width[0] = g.width[1] = g.width[2] = g.width[3] = mgl_gen_fnt[i][1];
|
||
|
g.numl[0] = g.numl[1] = g.numl[2] = g.numl[3] = mgl_gen_fnt[i][2];
|
||
|
g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = mgl_gen_fnt[i][3];
|
||
|
g.numt[0] = g.numt[1] = g.numt[2] = g.numt[3] = mgl_gen_fnt[i][4];
|
||
|
g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = mgl_gen_fnt[i][5];
|
||
|
}
|
||
|
memcpy(Buf, mgl_buf_fnt, mgl_cur*sizeof(short));
|
||
|
numb = mgl_cur;
|
||
|
return true;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool mglFont::read_data(const char *fname, int s, std::vector<short> &buf, std::vector<mglGlyphDescr> &extra)
|
||
|
{
|
||
|
gzFile fp;
|
||
|
char str[256];
|
||
|
int n, tmpw, tmpnl, tmpnt, retVal;
|
||
|
unsigned ss, tmpi, tmppl, tmppt;
|
||
|
fp = gzopen(fname,"r"); if(!fp) return false; // false if no file
|
||
|
// first string is comment (not used), second string have information
|
||
|
if(!gzgets(fp,str,256) || strncmp(str,"# font",6) || !gzgets(fp,str,256))
|
||
|
{ gzclose(fp); return false; }
|
||
|
retVal = sscanf(str, "%d%f%u", &n, fact+s, &ss);
|
||
|
//Check sscanf read all data (3 items)
|
||
|
if(retVal != 3) { gzclose(fp); return false; }
|
||
|
|
||
|
for(int i=0;i<n;i++)
|
||
|
{
|
||
|
gzgets(fp,str,256);
|
||
|
retVal = sscanf(str,"%u%d%d%u%d%u", &tmpi, &tmpw, &tmpnl, &tmppl, &tmpnt, &tmppt);
|
||
|
if(retVal != 6) { gzclose(fp); buf.clear(); return false; }
|
||
|
long j=Internal(unsigned(tmpi));
|
||
|
if(j>=0) // known symbol
|
||
|
{
|
||
|
mglGlyphDescr &g = glyphs[j]; g.width[s] = tmpw;
|
||
|
g.ln[s] = -1-tmppl; g.tr[s] = -1-tmppt;
|
||
|
g.numl[s] = tmpnl; g.numt[s] = tmpnt;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mglGlyphDescr g; g.id = tmpi;
|
||
|
g.width[0] = g.width[1] = g.width[2] = g.width[3] = tmpw;
|
||
|
g.numl[0] = g.numl[1] = g.numl[2] = g.numl[3] = tmpnl;
|
||
|
g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = -1-tmppl;
|
||
|
g.numt[0] = g.numt[1] = g.numt[2] = g.numt[3] = tmpnt;
|
||
|
g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = -1-tmppt;
|
||
|
#pragma omp critical
|
||
|
extra.push_back(g);
|
||
|
}
|
||
|
}
|
||
|
for(unsigned i=0;i<ss;i++)
|
||
|
{
|
||
|
for(int j=0;j<256;j++) if((str[j] = gzgetc(fp))<=' ') break;
|
||
|
buf.push_back(atoi(str));
|
||
|
}
|
||
|
gzclose(fp); // finish wire normal font
|
||
|
return true;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool mglFont::read_main(const char *fname, std::vector<short> &buf)
|
||
|
{
|
||
|
gzFile fp;
|
||
|
int tmpi, tmpw, tmpnl, tmpnt;
|
||
|
unsigned s, tmppl, tmppt,numg;
|
||
|
char str[256];
|
||
|
|
||
|
fp = gzopen(fname,"r"); if(!fp) return false; // this font must be in any case
|
||
|
// first string is comment (not used), second string have information
|
||
|
if(!gzgets(fp,str,256) || strncmp(str,"# font",6) || !gzgets(fp,str,256))
|
||
|
{ gzclose(fp); return false; }
|
||
|
sscanf(str, "%u%f%u", &numg, fact, &s);
|
||
|
fact[1] = fact[2] = fact[3] = fact[0]; // copy default factor for other font styles;
|
||
|
// now allocate memory for all fonts
|
||
|
mem_alloc(numg);
|
||
|
// and load symbols itself
|
||
|
for(size_t i=0;i<numg;i++)
|
||
|
{
|
||
|
gzgets(fp,str,256);
|
||
|
sscanf(str,"%d%d%d%u%d%u", &tmpi, &tmpw, &tmpnl, &tmppl, &tmpnt, &tmppt);
|
||
|
mglGlyphDescr &g = glyphs[i]; g.id = tmpi;
|
||
|
g.width[0] = g.width[1] = g.width[2] = g.width[3] = tmpw;
|
||
|
g.numl[0] = g.numl[1] = g.numl[2] = g.numl[3] = tmpnl;
|
||
|
g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = tmppl;
|
||
|
g.numt[0] = g.numt[1] = g.numt[2] = g.numt[3] = tmpnt;
|
||
|
g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = tmppt;
|
||
|
}
|
||
|
for(unsigned i=0;i<s;i++)
|
||
|
{
|
||
|
for(int j=0;j<256;j++) if((str[j] = gzgetc(fp))<=' ') break;
|
||
|
buf.push_back(atoi(str));
|
||
|
}
|
||
|
gzclose(fp); // finish wire normal font
|
||
|
return true;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
size_t mglFont::SaveBin(const char *fname)
|
||
|
{
|
||
|
FILE *fp = fopen(fname,"wb");
|
||
|
if(!fp) return 0;
|
||
|
size_t sum=0;
|
||
|
fwrite(&numb,sizeof(size_t),1,fp); sum += sizeof(size_t);
|
||
|
fwrite(fact,sizeof(float),4,fp); sum += sizeof(float)*4;
|
||
|
fwrite(Buf,sizeof(short),numb,fp); sum += sizeof(short)*numb;
|
||
|
size_t len = glyphs.size();
|
||
|
fwrite(&len,sizeof(size_t),1,fp); sum += sizeof(long);
|
||
|
fwrite(&(glyphs[0]),sizeof(mglGlyphDescr),len,fp); sum += sizeof(mglGlyphDescr)*len;
|
||
|
fclose(fp); return sum;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool mglFont::LoadBin(const char *base, const char *path)
|
||
|
{
|
||
|
Clear(); // first clear old
|
||
|
if(!path) path = MGL_FONT_PATH;
|
||
|
char str[256], sep='/';
|
||
|
snprintf(str,256,"%s%c%s.vfmb",path,sep,base?base:""); str[255]=0;
|
||
|
FILE *fp = fopen(str,"rb"); if(!fp) return false;
|
||
|
size_t s, len;
|
||
|
bool res = true;
|
||
|
s = fread(&numb,sizeof(size_t),1,fp);
|
||
|
if(s<1) res = false;
|
||
|
s = fread(fact,sizeof(float),4,fp);
|
||
|
if(s<4) res = false;
|
||
|
Buf = new short[numb];
|
||
|
s = fread(Buf,sizeof(short),numb,fp);
|
||
|
if(s<numb) res = false;
|
||
|
s = fread(&len,sizeof(size_t),1,fp);
|
||
|
if(s<1) res = false;
|
||
|
if(res)
|
||
|
{
|
||
|
glyphs.clear(); glyphs.resize(len);
|
||
|
s = fread(&(glyphs[0]),sizeof(mglGlyphDescr),len,fp);
|
||
|
if(s<len) res = false;
|
||
|
}
|
||
|
// if(!res) Clear();
|
||
|
fclose(fp); return res;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool mglFont::Load(const char *base, const char *path)
|
||
|
{
|
||
|
// base = 0;
|
||
|
char *buf=0,sep='/';
|
||
|
#ifdef WIN32
|
||
|
sep='\\';
|
||
|
#endif
|
||
|
char str[256];
|
||
|
std::string loc = setlocale(LC_NUMERIC,"C");
|
||
|
if(!path) path = MGL_FONT_PATH;
|
||
|
if(base && *base)
|
||
|
{
|
||
|
buf = new char[strlen(base)+1];
|
||
|
strcpy(buf,base);
|
||
|
if(strchr(buf,sep))
|
||
|
{
|
||
|
int i;
|
||
|
for(i=strlen(buf);i>=0 && buf[i]!=sep;i--);
|
||
|
path = buf; buf[i]=0; base = buf+i+1;
|
||
|
}
|
||
|
if(LoadBin(base,path))
|
||
|
{ delete []buf; return true; }
|
||
|
}
|
||
|
Clear(); // first clear old
|
||
|
|
||
|
snprintf(str,256,"%s%c%s.vfm",path,sep,base?base:""); str[255]=0;
|
||
|
std::vector<short> norm, bold, ital, both;
|
||
|
if(!(base && *base) || !read_main(str,norm))
|
||
|
{
|
||
|
read_def(); setlocale(LC_NUMERIC,loc.c_str());
|
||
|
if(buf) delete []buf; return true;
|
||
|
}
|
||
|
fact[1] = fact[2] = fact[3] = fact[0];
|
||
|
|
||
|
std::vector<mglGlyphDescr> ex_b,ex_i,ex_bi;
|
||
|
#pragma omp parallel sections
|
||
|
{
|
||
|
//================== bold ===========================================
|
||
|
#pragma omp section
|
||
|
{ char str[256]; snprintf(str,256,"%s%c%s_b.vfm",path,sep,base); // this file may absent
|
||
|
str[255]=0; read_data(str, 1, bold, ex_b); }
|
||
|
|
||
|
//================== italic =========================================
|
||
|
#pragma omp section
|
||
|
{ char str[256]; snprintf(str,256,"%s%c%s_i.vfm",path,sep,base);
|
||
|
str[255]=0; read_data(str, 2, ital, ex_i); }
|
||
|
|
||
|
//================== bold-italic ====================================
|
||
|
#pragma omp section
|
||
|
{ char str[256]; snprintf(str,256,"%s%c%s_bi.vfm",path,sep,base);
|
||
|
str[255]=0; read_data(str, 3, both, ex_bi); }
|
||
|
}
|
||
|
|
||
|
// now collect data
|
||
|
numb = norm.size()+bold.size()+ital.size()+both.size();
|
||
|
Buf = new short[numb];
|
||
|
memcpy(Buf,&norm[0],norm.size()*sizeof(short));
|
||
|
long cur = norm.size(), len = long(bold.size());
|
||
|
if(bold.size()>0)
|
||
|
memcpy(Buf+cur,&bold[0],bold.size()*sizeof(short));
|
||
|
#pragma omp parallel for
|
||
|
for(long i=0;i<long(GetNumGlyph());i++) if(glyphs[i].ln[1]<0)
|
||
|
{ glyphs[i].ln[1] = cur-1-glyphs[i].ln[1]; glyphs[i].tr[1] = cur-1-glyphs[i].tr[1]; }
|
||
|
#pragma omp parallel for
|
||
|
for(long i=0;i<long(ex_b.size());i++) if(ex_b[i].ln[1]<0)
|
||
|
{
|
||
|
mglGlyphDescr &g = ex_b[i];
|
||
|
g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = cur-1-g.ln[1];
|
||
|
g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = cur-1-g.tr[1];
|
||
|
}
|
||
|
cur += len; len = long(ital.size());
|
||
|
if(ital.size()>0)
|
||
|
memcpy(Buf+cur,&ital[0],ital.size()*sizeof(short));
|
||
|
#pragma omp parallel for
|
||
|
for(long i=0;i<long(GetNumGlyph());i++) if(glyphs[i].ln[2]<0)
|
||
|
{ glyphs[i].ln[2] = cur-1-glyphs[i].ln[2]; glyphs[i].tr[2] = cur-1-glyphs[i].tr[2]; }
|
||
|
#pragma omp parallel for
|
||
|
for(long i=0;i<long(ex_i.size());i++) if(ex_i[i].ln[2]<0)
|
||
|
{
|
||
|
mglGlyphDescr &g = ex_i[i];
|
||
|
g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = cur-1-g.ln[2];
|
||
|
g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = cur-1-g.tr[2];
|
||
|
}
|
||
|
cur += len;
|
||
|
if(both.size()>0)
|
||
|
memcpy(Buf+cur,&both[0],both.size()*sizeof(short));
|
||
|
#pragma omp parallel for
|
||
|
for(long i=0;i<long(GetNumGlyph());i++) if(glyphs[i].ln[3]<0)
|
||
|
{ glyphs[i].ln[3] = cur-1-glyphs[i].ln[3]; glyphs[i].tr[3] = cur-1-glyphs[i].tr[3]; }
|
||
|
#pragma omp parallel for
|
||
|
for(long i=0;i<long(ex_bi.size());i++) if(ex_bi[i].ln[3]<0)
|
||
|
{
|
||
|
mglGlyphDescr &g = ex_bi[i];
|
||
|
g.ln[0] = g.ln[1] = g.ln[2] = g.ln[3] = cur-1-g.ln[3];
|
||
|
g.tr[0] = g.tr[1] = g.tr[2] = g.tr[3] = cur-1-g.tr[3];
|
||
|
}
|
||
|
// now add missing symbols
|
||
|
if(ex_b.size()==0) ex_b = ex_i;
|
||
|
else
|
||
|
{
|
||
|
for(size_t i=0;i<ex_i.size();i++) // add from ex_i
|
||
|
{
|
||
|
long j = mgl_internal_code(ex_i[i].id, ex_b);
|
||
|
if(j>=0) // known symbol
|
||
|
{
|
||
|
mglGlyphDescr &g = ex_b[j], &f = ex_i[i];
|
||
|
g.width[2] = f.width[2];
|
||
|
g.ln[2] = f.ln[2]; g.tr[2] = f.tr[2];
|
||
|
g.numl[2] = f.numl[2]; g.numt[2] = f.numt[2];
|
||
|
}
|
||
|
else ex_b.push_back(ex_i[i]);
|
||
|
}
|
||
|
std::sort(ex_b.begin(),ex_b.end());
|
||
|
}
|
||
|
if(ex_b.size()==0) ex_b = ex_bi;
|
||
|
else
|
||
|
{
|
||
|
for(size_t i=0;i<ex_bi.size();i++) // add from ex_bi
|
||
|
{
|
||
|
long j = mgl_internal_code(ex_bi[i].id, ex_b);
|
||
|
if(j>=0) // known symbol
|
||
|
{
|
||
|
mglGlyphDescr &g = ex_b[j], &f = ex_bi[i];
|
||
|
g.width[2] = f.width[3];
|
||
|
g.ln[2] = f.ln[3]; g.tr[2] = f.tr[3];
|
||
|
g.numl[2] = f.numl[3]; g.numt[2] = f.numt[3];
|
||
|
}
|
||
|
else ex_b.push_back(ex_bi[i]);
|
||
|
}
|
||
|
std::sort(ex_b.begin(),ex_b.end());
|
||
|
}
|
||
|
if(ex_b.size()>0)
|
||
|
{
|
||
|
glyphs.reserve(ex_b.size()); // preallocate memory
|
||
|
glyphs.insert(glyphs.end(), ex_b.begin(), ex_b.end());
|
||
|
std::sort(glyphs.begin(),glyphs.end());
|
||
|
}
|
||
|
|
||
|
// Finally normalize all factors
|
||
|
fact[0] *= mgl_fgen; fact[1] *= mgl_fgen;
|
||
|
fact[2] *= mgl_fgen; fact[3] *= mgl_fgen;
|
||
|
setlocale(LC_NUMERIC,loc.c_str());
|
||
|
if(buf) delete []buf;
|
||
|
return true;
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
#if MGL_HAVE_PTHREAD
|
||
|
extern pthread_mutex_t mutexRnd;
|
||
|
#endif
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float mgl_cos[360];
|
||
|
void MGL_NO_EXPORT mgl_init()
|
||
|
{
|
||
|
#if MGL_HAVE_PTHREAD
|
||
|
pthread_mutex_init(&mutexRnd,0);
|
||
|
#endif
|
||
|
#ifndef WIN32 // win32 don't initialized threads before main()
|
||
|
#pragma omp parallel for
|
||
|
#endif
|
||
|
for(long i=0;i<360;i++) mgl_cos[i] = cos(i*M_PI/180.);
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
mglFont::mglFont(const char *name, const char *path)
|
||
|
{
|
||
|
parse = true; gr=0; Buf=0;
|
||
|
// if(this==&mglDefFont) Load(name, path); else Copy(&mglDefFont);
|
||
|
if(name && *name) Load(name, path);
|
||
|
else if(this!=&mglDefFont) Copy(&mglDefFont);
|
||
|
else
|
||
|
{
|
||
|
mgl_init(); // NOTE: this call init function for the library.
|
||
|
Load(MGL_DEF_FONT_NAME,0);
|
||
|
}
|
||
|
}
|
||
|
mglFont::~mglFont() { if(Buf) delete []Buf; }
|
||
|
void mglFont::Restore() { Copy(&mglDefFont); }
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void mglFont::Clear()
|
||
|
{
|
||
|
//#pragma omp critical(font)
|
||
|
{ if(Buf) delete []Buf; Buf=0; glyphs.clear(); }
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void mglFont::Copy(mglFont *f)
|
||
|
{
|
||
|
if(!f || f==this) return;
|
||
|
#pragma omp critical(font)
|
||
|
{ if(Buf) delete []Buf; Buf=0; }
|
||
|
// copy scale factors
|
||
|
memcpy(fact,f->fact,4*sizeof(float));
|
||
|
// copy symbols descriptions
|
||
|
numb = f->numb; Buf = new short[numb]; memcpy(Buf, f->Buf, numb*sizeof(short));
|
||
|
// copy symbol parameters
|
||
|
glyphs.resize(f->glyphs.size());
|
||
|
memcpy(&glyphs[0],&(f->glyphs)[0],glyphs.size()*sizeof(mglGlyphDescr));
|
||
|
}
|
||
|
//-----------------------------------------------------------------------------
|
||
|
long MGL_EXPORT mgl_check_tex_table()
|
||
|
{
|
||
|
size_t i=0; while(mgl_tex_symb[i].tex[0]) i++;
|
||
|
long res = 0;
|
||
|
if(mgl_tex_num!=i)
|
||
|
{ printf("real=%zu, set=%zu\n",i,mgl_tex_num); res = -1; }
|
||
|
for(i=0;mgl_tex_symb[i].tex[0];i++)
|
||
|
{
|
||
|
mglTeXsymb tst, *rts; tst.tex = mgl_tex_symb[i].tex;
|
||
|
rts = (mglTeXsymb *) bsearch(&tst, mgl_tex_symb, mgl_tex_num, sizeof(mglTeXsymb), mgl_tex_symb_cmp);
|
||
|
if(!rts)
|
||
|
{ printf("Bad '%ls' at %zu\n",mgl_tex_symb[i].tex,i); res = 1+i; }
|
||
|
}
|
||
|
return res;
|
||
|
}
|