Merge pull request #4687 from ruuk/textboxgettext
[vuplus_xbmc] / xbmc / guilib / GUIFontTTFGL.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "system.h"
22 #include "GUIFont.h"
23 #include "GUIFontTTFGL.h"
24 #include "GUIFontManager.h"
25 #include "Texture.h"
26 #include "TextureManager.h"
27 #include "GraphicContext.h"
28 #include "gui3d.h"
29 #include "utils/log.h"
30 #include "utils/GLUtils.h"
31 #include "windowing/WindowingFactory.h"
32
33 // stuff for freetype
34 #include <ft2build.h>
35 #include FT_FREETYPE_H
36 #include FT_GLYPH_H
37 #include FT_OUTLINE_H
38
39 using namespace std;
40
41 #if defined(HAS_GL) || defined(HAS_GLES)
42
43
44 CGUIFontTTFGL::CGUIFontTTFGL(const CStdString& strFileName)
45 : CGUIFontTTFBase(strFileName)
46 {
47 }
48
49 CGUIFontTTFGL::~CGUIFontTTFGL(void)
50 {
51 }
52
53 void CGUIFontTTFGL::Begin()
54 {
55   if (m_nestedBeginCount == 0 && m_texture != NULL)
56   {
57     if (!m_bTextureLoaded)
58     {
59       // Have OpenGL generate a texture object handle for us
60       glGenTextures(1, (GLuint*) &m_nTexture);
61
62       // Bind the texture object
63       glBindTexture(GL_TEXTURE_2D, m_nTexture);
64 #ifdef HAS_GL
65       glEnable(GL_TEXTURE_2D);
66 #endif
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);
70
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());
74
75       VerifyGLState();
76       m_bTextureLoaded = true;
77     }
78
79     // Turn Blending On
80     glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
81     glEnable(GL_BLEND);
82 #ifdef HAS_GL
83     glEnable(GL_TEXTURE_2D);
84 #endif
85     glBindTexture(GL_TEXTURE_2D, m_nTexture);
86
87 #ifdef HAS_GL
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);
98     VerifyGLState();
99
100     if(g_Windowing.UseLimitedColor())
101     {
102       glActiveTexture(GL_TEXTURE1);
103       glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind
104       glEnable(GL_TEXTURE_2D);
105
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);
116       VerifyGLState();
117     }
118
119 #else
120     g_Windowing.EnableGUIShader(SM_FONTS);
121 #endif
122
123     m_vertex_count = 0;
124   }
125   // Keep track of the nested begin/end calls.
126   m_nestedBeginCount++;
127 }
128
129 void CGUIFontTTFGL::End()
130 {
131   if (m_nestedBeginCount == 0)
132     return;
133
134   if (--m_nestedBeginCount > 0)
135     return;
136
137 #ifdef HAS_GL
138   glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
139
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);
147   glPopClientAttrib();
148
149   glActiveTexture(GL_TEXTURE1);
150   glBindTexture(GL_TEXTURE_2D, 0);
151   glDisable(GL_TEXTURE_2D);
152   glActiveTexture(GL_TEXTURE0);
153   glBindTexture(GL_TEXTURE_2D, 0);
154   glDisable(GL_TEXTURE_2D);
155 #else
156   // GLES 2.0 version. Cannot draw quads. Convert to triangles.
157   GLint posLoc  = g_Windowing.GUIShaderGetPos();
158   GLint colLoc  = g_Windowing.GUIShaderGetCol();
159   GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
160
161   // stack object until VBOs will be used
162   std::vector<SVertex> vecVertices( 6 * (m_vertex_count / 4) );
163   SVertex *vertices = &vecVertices[0];
164
165   for (int i=0; i<m_vertex_count; i+=4)
166   {
167     *vertices++ = m_vertex[i];
168     *vertices++ = m_vertex[i+1];
169     *vertices++ = m_vertex[i+2];
170
171     *vertices++ = m_vertex[i+1];
172     *vertices++ = m_vertex[i+3];
173     *vertices++ = m_vertex[i+2];
174   }
175
176   vertices = &vecVertices[0];
177
178   glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
179   // Normalize color values. Does not affect Performance at all.
180   glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
181   glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
182
183   glEnableVertexAttribArray(posLoc);
184   glEnableVertexAttribArray(colLoc);
185   glEnableVertexAttribArray(tex0Loc);
186
187   glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
188
189   glDisableVertexAttribArray(posLoc);
190   glDisableVertexAttribArray(colLoc);
191   glDisableVertexAttribArray(tex0Loc);
192
193   g_Windowing.DisableGUIShader();
194 #endif
195 }
196
197 CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
198 {
199   newHeight = CBaseTexture::PadPow2(newHeight);
200
201   CBaseTexture* newTexture = new CTexture(m_textureWidth, newHeight, XB_FMT_A8);
202
203   if (!newTexture || newTexture->GetPixels() == NULL)
204   {
205     CLog::Log(LOGERROR, "GUIFontTTFGL::CacheCharacter: Error creating new cache texture for size %f", m_height);
206     delete newTexture;
207     return NULL;
208   }
209   m_textureHeight = newTexture->GetHeight();
210   m_textureScaleY = 1.0f / m_textureHeight;
211   m_textureWidth = newTexture->GetWidth();
212   m_textureScaleX = 1.0f / m_textureWidth;
213   if (m_textureHeight < newHeight)
214     CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
215
216   memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
217   if (m_texture)
218   {
219     unsigned char* src = (unsigned char*) m_texture->GetPixels();
220     unsigned char* dst = (unsigned char*) newTexture->GetPixels();
221     for (unsigned int y = 0; y < m_texture->GetHeight(); y++)
222     {
223       memcpy(dst, src, m_texture->GetPitch());
224       src += m_texture->GetPitch();
225       dst += newTexture->GetPitch();
226     }
227     delete m_texture;
228   }
229
230   return newTexture;
231 }
232
233 bool CGUIFontTTFGL::CopyCharToTexture(FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
234 {
235   FT_Bitmap bitmap = bitGlyph->bitmap;
236
237   unsigned char* source = (unsigned char*) bitmap.buffer;
238   unsigned char* target = (unsigned char*) m_texture->GetPixels() + y1 * m_texture->GetPitch() + x1;
239
240   for (unsigned int y = y1; y < y2; y++)
241   {
242     memcpy(target, source, x2-x1);
243     source += bitmap.width;
244     target += m_texture->GetPitch();
245   }
246   // THE SOURCE VALUES ARE THE SAME IN BOTH SITUATIONS.
247
248   // Since we have a new texture, we need to delete the old one
249   // the Begin(); End(); stuff is handled by whoever called us
250   if (m_bTextureLoaded)
251   {
252     g_graphicsContext.BeginPaint();  //FIXME
253     DeleteHardwareTexture();
254     g_graphicsContext.EndPaint();
255     m_bTextureLoaded = false;
256   }
257
258   return TRUE;
259 }
260
261
262 void CGUIFontTTFGL::DeleteHardwareTexture()
263 {
264   if (m_bTextureLoaded)
265   {
266     if (glIsTexture(m_nTexture))
267       g_TextureManager.ReleaseHwTexture(m_nTexture);
268     m_bTextureLoaded = false;
269   }
270 }
271
272 #endif