[release] version bump to 13.0 beta1
[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   glBindTexture(GL_TEXTURE_2D, 0);
150   glActiveTexture(GL_TEXTURE0);
151 #else
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();
156
157   // stack object until VBOs will be used
158   std::vector<SVertex> vecVertices( 6 * (m_vertex_count / 4) );
159   SVertex *vertices = &vecVertices[0];
160
161   for (int i=0; i<m_vertex_count; i+=4)
162   {
163     *vertices++ = m_vertex[i];
164     *vertices++ = m_vertex[i+1];
165     *vertices++ = m_vertex[i+2];
166
167     *vertices++ = m_vertex[i+1];
168     *vertices++ = m_vertex[i+3];
169     *vertices++ = m_vertex[i+2];
170   }
171
172   vertices = &vecVertices[0];
173
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));
178
179   glEnableVertexAttribArray(posLoc);
180   glEnableVertexAttribArray(colLoc);
181   glEnableVertexAttribArray(tex0Loc);
182
183   glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
184
185   glDisableVertexAttribArray(posLoc);
186   glDisableVertexAttribArray(colLoc);
187   glDisableVertexAttribArray(tex0Loc);
188
189   g_Windowing.DisableGUIShader();
190 #endif
191 }
192
193 CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
194 {
195   newHeight = CBaseTexture::PadPow2(newHeight);
196
197   CBaseTexture* newTexture = new CTexture(m_textureWidth, newHeight, XB_FMT_A8);
198
199   if (!newTexture || newTexture->GetPixels() == NULL)
200   {
201     CLog::Log(LOGERROR, "GUIFontTTFGL::CacheCharacter: Error creating new cache texture for size %f", m_height);
202     delete newTexture;
203     return NULL;
204   }
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);
211
212   memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
213   if (m_texture)
214   {
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++)
218     {
219       memcpy(dst, src, m_texture->GetPitch());
220       src += m_texture->GetPitch();
221       dst += newTexture->GetPitch();
222     }
223     delete m_texture;
224   }
225
226   return newTexture;
227 }
228
229 bool CGUIFontTTFGL::CopyCharToTexture(FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
230 {
231   FT_Bitmap bitmap = bitGlyph->bitmap;
232
233   unsigned char* source = (unsigned char*) bitmap.buffer;
234   unsigned char* target = (unsigned char*) m_texture->GetPixels() + y1 * m_texture->GetPitch() + x1;
235
236   for (unsigned int y = y1; y < y2; y++)
237   {
238     memcpy(target, source, x2-x1);
239     source += bitmap.width;
240     target += m_texture->GetPitch();
241   }
242   // THE SOURCE VALUES ARE THE SAME IN BOTH SITUATIONS.
243
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)
247   {
248     g_graphicsContext.BeginPaint();  //FIXME
249     DeleteHardwareTexture();
250     g_graphicsContext.EndPaint();
251     m_bTextureLoaded = false;
252   }
253
254   return TRUE;
255 }
256
257
258 void CGUIFontTTFGL::DeleteHardwareTexture()
259 {
260   if (m_bTextureLoaded)
261   {
262     if (glIsTexture(m_nTexture))
263       g_TextureManager.ReleaseHwTexture(m_nTexture);
264     m_bTextureLoaded = false;
265   }
266 }
267
268 #endif