aboutsummaryrefslogtreecommitdiff
path: root/extensions/smttfont.cpp
blob: d800b82cdc820e754e19eaa27a38b0069e966cba (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// -*- C++ -*-
/*
 * Simple MultimEdia LiTerator(SMELT)
 * by Chris Xiong 2015
 * Truetype font support implementation
 *
 * WARNING: This library is in development and interfaces would be very
 * unstable.
 * This library is developed for the BLR series games.
 */
#include "smttfont.hpp"

SMELT *smTTChar::sm=NULL;

void smTTChar::free(){if(quad.tex){sm->smTextureFree(quad.tex);quad.tex=0;sm->smRelease();}}
bool smTTChar::setChar(wchar_t c,FT_Face ttface)
{
	if(!sm)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;
	if(FT_Render_Glyph(ttface->glyph,FT_RENDER_MODE_NORMAL))return false;
	_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);
	memset(px,0,sizeof(DWORD)*(rw?rw:1)*(rh?rh:1));
	int ptr=0;
	for(int i=0;i<rh;++i)
	for(int j=0;j<rw;++j)
	{
#ifdef _D3D
		px[i*rw+j]=ARGB(slot->bitmap.buffer[ptr],255,255,255);
#else
		px[(rh-i-1)*rw+j]=ARGB(slot->bitmap.buffer[ptr],255,255,255);
#endif
		++ptr;
	}
	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;
	return true;
}
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)
	{
		quad.v[0].x=x+xofs*scalex;quad.v[0].y=y+(yofs-rh)*scaley;
		quad.v[1].x=x+(rw+xofs)*scalex;quad.v[1].y=y+(yofs-rh)*scaley;
		quad.v[2].x=x+(rw+xofs)*scalex;quad.v[2].y=y+yofs*scaley;
		quad.v[3].x=x+xofs*scalex;quad.v[3].y=y+yofs*scaley;
	}
	else
	{
		quad.v[0].x=x+(-rw+xofs)*scalex;quad.v[0].y=y+(yofs-rh)*scaley;
		quad.v[1].x=x+xofs*scalex;quad.v[1].y=y+(yofs-rh)*scaley;
		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);
}

bool smTTFont::loadTTF(const char* path,int pt)
{
	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();
	return true;
}
bool smTTFont::loadTTFFromMemory(char* ptr,DWORD size,int pt)
{
	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();
	return true;
}
void smTTFont::releaseTTF()
{
	FT_Done_Face(ttface);
	FT_Done_FreeType(ftlib);
}
void smTTFont::updateString(const wchar_t *format,...)
{
	memset(buf,0,sizeof(buf));
	va_list vl;
	va_start(vl,format);
	vswprintf(buf,1024,format,vl);
	va_end(vl);
	buf[1024]='\0';
	w=h=0;float lh=0;
	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]));
		if(chars.find(buf[i])!=chars.end())
		{
			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;
	}
	h+=lh;
}
void smTTFont::render(float x,float y,float z,DWORD col,int align,float scalex,float scaley)
{
	float curx,cury,lh;
	if(align==ALIGN_LEFT)
	{
		curx=x;cury=y;lh=0;
		for(int i=0;buf[i]!=L'\0';++i)
		{
			if(buf[i]!=L'\n')
			{
				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;
				}
			}
			else cury+=lh*scaley,lh=0,curx=x;
		}
	}
	if(align==ALIGN_RIGHT)
	{
		curx=x;cury=y;lh=0;
		for(int i=wcslen(buf)-1;i>=0;--i)
		{
			if(buf[i]!=L'\n')
			{
				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;
				}
			}
			else cury-=lh*scaley,lh=0,curx=x;
		}
	}
}
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();
	chars.clear();
}