2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
23 #include "GUIFontTTFGL.h"
24 #include "GUIFontManager.h"
26 #include "TextureManager.h"
27 #include "GraphicContext.h"
29 #include "utils/log.h"
30 #include "utils/GLUtils.h"
31 #include "windowing/WindowingFactory.h"
35 #include FT_FREETYPE_H
41 #if defined(HAS_GL) || defined(HAS_GLES)
44 CGUIFontTTFGL::CGUIFontTTFGL(const CStdString& strFileName)
45 : CGUIFontTTFBase(strFileName)
49 CGUIFontTTFGL::~CGUIFontTTFGL(void)
53 void CGUIFontTTFGL::Begin()
55 if (m_nestedBeginCount == 0 && m_texture != NULL)
57 if (!m_bTextureLoaded)
59 // Have OpenGL generate a texture object handle for us
60 glGenTextures(1, (GLuint*) &m_nTexture);
62 // Bind the texture object
63 glBindTexture(GL_TEXTURE_2D, m_nTexture);
65 glEnable(GL_TEXTURE_2D);
67 // Set the texture's stretching properties
68 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
69 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
71 // Set the texture image -- THIS WORKS, so the pixels must be wrong.
72 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0,
73 GL_ALPHA, GL_UNSIGNED_BYTE, m_texture->GetPixels());
76 m_bTextureLoaded = true;
80 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
83 glEnable(GL_TEXTURE_2D);
85 glBindTexture(GL_TEXTURE_2D, m_nTexture);
88 glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
89 glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE);
90 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
91 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
92 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
93 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
94 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
95 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
96 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
97 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
100 if(g_Windowing.UseLimitedColor())
102 glActiveTexture(GL_TEXTURE1);
103 glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind
104 glEnable(GL_TEXTURE_2D);
106 const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f};
107 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE);
108 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
109 glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB , GL_ADD);
110 glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB , GL_PREVIOUS);
111 glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB , GL_CONSTANT);
112 glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB , GL_SRC_COLOR);
113 glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB , GL_SRC_COLOR);
114 glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA , GL_REPLACE);
115 glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA , GL_PREVIOUS);
120 g_Windowing.EnableGUIShader(SM_FONTS);
125 // Keep track of the nested begin/end calls.
126 m_nestedBeginCount++;
129 void CGUIFontTTFGL::End()
131 if (m_nestedBeginCount == 0)
134 if (--m_nestedBeginCount > 0)
138 glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
140 glColorPointer (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, r));
141 glVertexPointer (3, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, x));
142 glTexCoordPointer(2, GL_FLOAT , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, u));
143 glEnableClientState(GL_COLOR_ARRAY);
144 glEnableClientState(GL_VERTEX_ARRAY);
145 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
146 glDrawArrays(GL_QUADS, 0, m_vertex_count);
149 glBindTexture(GL_TEXTURE_2D, 0);
150 glActiveTexture(GL_TEXTURE0);
152 // GLES 2.0 version. Cannot draw quads. Convert to triangles.
153 GLint posLoc = g_Windowing.GUIShaderGetPos();
154 GLint colLoc = g_Windowing.GUIShaderGetCol();
155 GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
157 // stack object until VBOs will be used
158 std::vector<SVertex> vecVertices( 6 * (m_vertex_count / 4) );
159 SVertex *vertices = &vecVertices[0];
161 for (int i=0; i<m_vertex_count; i+=4)
163 *vertices++ = m_vertex[i];
164 *vertices++ = m_vertex[i+1];
165 *vertices++ = m_vertex[i+2];
167 *vertices++ = m_vertex[i+1];
168 *vertices++ = m_vertex[i+3];
169 *vertices++ = m_vertex[i+2];
172 vertices = &vecVertices[0];
174 glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
175 // Normalize color values. Does not affect Performance at all.
176 glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
177 glVertexAttribPointer(tex0Loc, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
179 glEnableVertexAttribArray(posLoc);
180 glEnableVertexAttribArray(colLoc);
181 glEnableVertexAttribArray(tex0Loc);
183 glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
185 glDisableVertexAttribArray(posLoc);
186 glDisableVertexAttribArray(colLoc);
187 glDisableVertexAttribArray(tex0Loc);
189 g_Windowing.DisableGUIShader();
193 CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
195 newHeight = CBaseTexture::PadPow2(newHeight);
197 CBaseTexture* newTexture = new CTexture(m_textureWidth, newHeight, XB_FMT_A8);
199 if (!newTexture || newTexture->GetPixels() == NULL)
201 CLog::Log(LOGERROR, "GUIFontTTFGL::CacheCharacter: Error creating new cache texture for size %f", m_height);
205 m_textureHeight = newTexture->GetHeight();
206 m_textureScaleY = 1.0f / m_textureHeight;
207 m_textureWidth = newTexture->GetWidth();
208 m_textureScaleX = 1.0f / m_textureWidth;
209 if (m_textureHeight < newHeight)
210 CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
212 memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
215 unsigned char* src = (unsigned char*) m_texture->GetPixels();
216 unsigned char* dst = (unsigned char*) newTexture->GetPixels();
217 for (unsigned int y = 0; y < m_texture->GetHeight(); y++)
219 memcpy(dst, src, m_texture->GetPitch());
220 src += m_texture->GetPitch();
221 dst += newTexture->GetPitch();
229 bool CGUIFontTTFGL::CopyCharToTexture(FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
231 FT_Bitmap bitmap = bitGlyph->bitmap;
233 unsigned char* source = (unsigned char*) bitmap.buffer;
234 unsigned char* target = (unsigned char*) m_texture->GetPixels() + y1 * m_texture->GetPitch() + x1;
236 for (unsigned int y = y1; y < y2; y++)
238 memcpy(target, source, x2-x1);
239 source += bitmap.width;
240 target += m_texture->GetPitch();
242 // THE SOURCE VALUES ARE THE SAME IN BOTH SITUATIONS.
244 // Since we have a new texture, we need to delete the old one
245 // the Begin(); End(); stuff is handled by whoever called us
246 if (m_bTextureLoaded)
248 g_graphicsContext.BeginPaint(); //FIXME
249 DeleteHardwareTexture();
250 g_graphicsContext.EndPaint();
251 m_bTextureLoaded = false;
258 void CGUIFontTTFGL::DeleteHardwareTexture()
260 if (m_bTextureLoaded)
262 if (glIsTexture(m_nTexture))
263 g_TextureManager.ReleaseHwTexture(m_nTexture);
264 m_bTextureLoaded = false;