aboutsummaryrefslogtreecommitdiff
path: root/extensions/smttfont.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/smttfont.cpp')
-rw-r--r--extensions/smttfont.cpp148
1 files changed, 122 insertions, 26 deletions
diff --git a/extensions/smttfont.cpp b/extensions/smttfont.cpp
index d800b82..02aa54a 100644
--- a/extensions/smttfont.cpp
+++ b/extensions/smttfont.cpp
@@ -10,12 +10,36 @@
*/
#include "smttfont.hpp"
-SMELT *smTTChar::sm=NULL;
+struct _smTexState
+{
+ SMTEX tex;
+ int cx,cy;
+ int mh;
+};
+
+class _smTTChar
+{
+private:
+ smQuad quad;
+ int rw,rh,_w,_h,xofs,yofs;
+ static SMELT *sm;
+public:
+ ~_smTTChar();
+ float w(){return (float)_w;}
+ float h(){return (float)_h;}
+ void free();
+ bool setChar(wchar_t c,FT_Face ttface,smTTFont* par);
+ void render(float x,float y,float z,DWORD col,float scalex,float scaley,bool rtl);
+};
-void smTTChar::free(){if(quad.tex){sm->smTextureFree(quad.tex);quad.tex=0;sm->smRelease();}}
-bool smTTChar::setChar(wchar_t c,FT_Face ttface)
+SMELT *_smTTChar::sm=NULL;
+SMELT *smTTFont::sm=NULL;
+
+_smTTChar::~_smTTChar(){free();}
+void _smTTChar::free(){sm->smRelease();}
+bool _smTTChar::setChar(wchar_t c,FT_Face ttface,smTTFont* par)
{
- if(!sm)sm=smGetInterface(SMELT_APILEVEL);
+ sm=smGetInterface(SMELT_APILEVEL);
FT_GlyphSlot slot=ttface->glyph;
FT_UInt glyph_index=FT_Get_Char_Index(ttface,c);
if(FT_Load_Glyph(ttface,glyph_index,FT_LOAD_DEFAULT))return false;
@@ -23,8 +47,10 @@ bool smTTChar::setChar(wchar_t c,FT_Face ttface)
_w=slot->advance.x>>6;_h=3*slot->bitmap.rows-2*slot->bitmap_top;
rw=slot->bitmap.width;rh=slot->bitmap.rows;
xofs=slot->bitmap_left;yofs=slot->bitmap.rows-slot->bitmap_top;
- quad.tex=sm->smTextureCreate(rw?rw:1,rh?rh:1);
- DWORD* px=sm->smTextureLock(quad.tex,0,0,rw?rw:1,rh?rh:1,false);
+ std::pair<SMTEX,std::pair<int,int>> loc=par->_allocate_char(rw?rw:1,rh?rh:1);
+ int dx=loc.second.first,dy=loc.second.second;
+ quad.tex=loc.first;
+ DWORD* px=sm->smTextureLock(quad.tex,dx,dy,rw?rw:1,rh?rh:1,false);
memset(px,0,sizeof(DWORD)*(rw?rw:1)*(rh?rh:1));
int ptr=0;
for(int i=0;i<rh;++i)
@@ -39,11 +65,13 @@ bool smTTChar::setChar(wchar_t c,FT_Face ttface)
}
sm->smTexutreUnlock(quad.tex);
quad.blend=BLEND_ALPHABLEND;
- quad.v[0].tx=0;quad.v[0].ty=0;quad.v[1].tx=1;quad.v[1].ty=0;
- quad.v[2].tx=1;quad.v[2].ty=1;quad.v[3].tx=0;quad.v[3].ty=1;
+ quad.v[0].tx=1.*dx/par->texw;quad.v[0].ty=1.*dy/par->texh;
+ quad.v[1].tx=1.*(rw+dx)/par->texw;quad.v[1].ty=1.*dy/par->texh;
+ quad.v[2].tx=1.*(rw+dx)/par->texw;quad.v[2].ty=1.*(rh+dy)/par->texh;
+ quad.v[3].tx=1.*dx/par->texw;quad.v[3].ty=1.*(rh+dy)/par->texh;
return true;
}
-void smTTChar::render(float x,float y,float z,DWORD col,float scalex,float scaley,bool rtl)
+void _smTTChar::render(float x,float y,float z,DWORD col,float scalex,float scaley,bool rtl)
{
for(int i=0;i<4;++i)quad.v[i].col=col,quad.v[i].z=z;
if(!rtl)
@@ -60,29 +88,84 @@ void smTTChar::render(float x,float y,float z,DWORD col,float scalex,float scale
quad.v[2].x=x+xofs*scalex;quad.v[2].y=y+yofs*scaley;
quad.v[3].x=x+(-rw+xofs)*scalex;quad.v[3].y=y+yofs*scaley;
}
-sm->smRenderQuad(&quad);
+ sm->smRenderQuad(&quad);
}
-bool smTTFont::loadTTF(const char* path,int pt)
+smTTFont::~smTTFont(){}
+unsigned smTTFont::_npot(unsigned x)
+{
+ --x;
+ for(unsigned i=1;i<sizeof(unsigned)*8;i<<=1)x|=x>>i;
+ return x+1;
+}
+std::pair<SMTEX,std::pair<int,int>> smTTFont::_allocate_char(int rw,int rh)
+{
+ std::pair<SMTEX,std::pair<int,int>> ret;
+ ret.first=0;ret.second.first=ret.second.second=-1;
+ if(~texw&&(rw>texw||rh>texh))return ret;//allocation failure
+ for(_smTexState* i:textures)
+ if(i->cx+rw<=texw&&i->cy+rh<=texh)
+ {
+ ret.first=i->tex;
+ ret.second.first=i->cx;
+ ret.second.second=i->cy;
+ i->cx+=rw;
+ if(rh>i->mh)i->mh=rh;
+ break;
+ }
+ else if(i->cy+i->mh+rh<=texh)
+ {
+ i->cx=rw;i->cy+=i->mh;
+ i->mh=rh;
+ ret.first=i->tex;
+ ret.second.first=0;
+ ret.second.second=i->cy;
+ break;
+ }
+ if(ret.first)return ret;
+ if(!~texw)
+ {
+ int rd=rw>rh?rw:rh;
+ texw=_npot(mx*rd);
+ texh=_npot(my*rd);
+ }
+ _smTexState* ptex=new _smTexState;
+ ptex->cx=ptex->cy=ptex->mh=0;
+ ptex->tex=sm->smTextureCreate(texw,texh);
+ DWORD* px=sm->smTextureLock(ptex->tex,0,0,texw,texh,false);
+ sm->smTexutreUnlock(ptex->tex);
+ ret.first=ptex->tex;
+ ret.second.first=ret.second.second=0;
+ ptex->cx+=rw;
+ textures.push_back(ptex);
+ return ret;
+}
+bool smTTFont::loadTTF(const char* path,int pt,int cachesize_x,int cachesize_y)
{
+ sm=smGetInterface(SMELT_APILEVEL);
if(FT_Init_FreeType(&ftlib))return false;
if(FT_New_Face(ftlib,path,0,&ttface))return false;
if(FT_Set_Char_Size(ttface,0,pt*64,96,96))return false;
- chars.clear();
+ chars.clear();textures.clear();texw=texh=-1;
+ mx=cachesize_x;my=cachesize_y;
return true;
}
-bool smTTFont::loadTTFFromMemory(char* ptr,DWORD size,int pt)
+bool smTTFont::loadTTFFromMemory(char* ptr,DWORD size,int pt,int cachesize_x,int cachesize_y)
{
+ sm=smGetInterface(SMELT_APILEVEL);
if(FT_Init_FreeType(&ftlib))return false;
if(FT_New_Memory_Face(ftlib,(const FT_Byte*)ptr,(FT_Long)size,0,&ttface))return false;
if(FT_Set_Char_Size(ttface,0,pt*64,96,96))return false;
- chars.clear();
+ chars.clear();textures.clear();texw=texh=-1;
+ mx=cachesize_x;my=cachesize_y;
return true;
}
void smTTFont::releaseTTF()
{
+ clearCache();
FT_Done_Face(ttface);
FT_Done_FreeType(ftlib);
+ sm->smRelease();
}
void smTTFont::updateString(const wchar_t *format,...)
{
@@ -96,12 +179,18 @@ void smTTFont::updateString(const wchar_t *format,...)
for(int i=0;buf[i]!='\0';++i)
{
if(chars.find(buf[i])==chars.end()&&buf[i]!=L'\n')
- if(!chars[buf[i]].setChar(buf[i],ttface))
- chars.erase(chars.find(buf[i]));
+ {
+ chars[buf[i]]=new _smTTChar();
+ if(!chars[buf[i]]->setChar(buf[i],ttface,this))
+ {
+ delete chars[buf[i]];
+ chars.erase(chars.find(buf[i]));
+ }
+ }
if(chars.find(buf[i])!=chars.end())
{
- w+=chars[buf[i]].w();
- if(chars[buf[i]].h()>lh)lh=chars[buf[i]].h();
+ w+=chars[buf[i]]->w();
+ if(chars[buf[i]]->h()>lh)lh=chars[buf[i]]->h();
}
if(buf[i]==L'\n')h+=lh,lh=0;
}
@@ -119,9 +208,9 @@ void smTTFont::render(float x,float y,float z,DWORD col,int align,float scalex,f
{
if(chars.find(buf[i])!=chars.end())
{
- chars[buf[i]].render(curx,cury,z,col,scalex,scaley,false);
- curx+=chars[buf[i]].w()*scalex;
- lh=chars[buf[i]].h()>lh?chars[buf[i]].h():lh;
+ chars[buf[i]]->render(curx,cury,z,col,scalex,scaley,false);
+ curx+=chars[buf[i]]->w()*scalex;
+ lh=chars[buf[i]]->h()>lh?chars[buf[i]]->h():lh;
}
}
else cury+=lh*scaley,lh=0,curx=x;
@@ -136,9 +225,9 @@ void smTTFont::render(float x,float y,float z,DWORD col,int align,float scalex,f
{
if(chars.find(buf[i])!=chars.end())
{
- chars[buf[i]].render(curx,cury,z,col,scalex,scaley,true);
- curx-=chars[buf[i]].w()*scalex;
- lh=chars[buf[i]].h()>lh?chars[buf[i]].h():lh;
+ chars[buf[i]]->render(curx,cury,z,col,scalex,scaley,true);
+ curx-=chars[buf[i]]->w()*scalex;
+ lh=chars[buf[i]]->h()>lh?chars[buf[i]]->h():lh;
}
}
else cury-=lh*scaley,lh=0,curx=x;
@@ -148,7 +237,14 @@ void smTTFont::render(float x,float y,float z,DWORD col,int align,float scalex,f
DWORD smTTFont::getCacheSize(){return chars.size();}
void smTTFont::clearCache()
{
- for(std::map<wchar_t,smTTChar>::iterator i=chars.begin();i!=chars.end();++i)
- i->second.free();
+ for(std::map<wchar_t,_smTTChar*>::iterator i=chars.begin();i!=chars.end();++i)
+ delete i->second;
+ for(_smTexState* i:textures)
+ {
+ sm->smTextureFree(i->tex);
+ delete i;
+ }
+ textures.clear();
+ texw=texh=-1;
chars.clear();
}