1 /***************************************************************************
2  *
3  * Project:  OpenCPN
4  * Purpose:  texture OpenGL text rendering built from wxFont
5  * Author:   Sean D'Epagnier
6  *
7  ***************************************************************************
8  *   Copyright (C) 2014 Sean D'Epagnier                                    *
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program; if not, write to the                         *
22  *   Free Software Foundation, Inc.,                                       *
23  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
24  **************************************************************************/
25 
26 #include <wx/wx.h>
27 
28 #include "DepthFont.h"
29 
30 #ifdef USE_ANDROID_GLES2
31 #include <gl2.h>
32 #include "linmath.h"
33 #include "shaders.h"
34 #else
35  #include <GL/gl.h>
36  #include <GL/glu.h>
37 #endif
38 
39 #if 0
40 #define TXF_CACHE 8
41 static TexFontCache s_txf[TXF_CACHE];
42 
43 TexFont *GetTexFont(wxFont *pFont)
44 {
45     // rebuild font if needed
46     TexFont *f_cache;
47     unsigned int i;
48     for (i = 0; i < TXF_CACHE && s_txf[i].key != nullptr; i++)
49     {
50         if (s_txf[i].key == pFont) {
51             return &s_txf[i].cache;
52         }
53     }
54     if (i == TXF_CACHE) {
55         i = rand() & (TXF_CACHE -1);
56     }
57     s_txf[i].key = pFont;
58     f_cache = &s_txf[i].cache;
59     f_cache->Build(*pFont);
60     return f_cache;
61 }
62 #endif
63 
DepthFont()64 DepthFont::DepthFont( )
65 {
66     texobj = 0;
67     m_built = false;
68     m_scaleFactor = 0;
69 }
70 
~DepthFont()71 DepthFont::~DepthFont( )
72 {
73     Delete( );
74 }
75 
76 
Build(wxFont * font,double scale)77 void DepthFont::Build( wxFont *font, double scale )
78 {
79     /* avoid rebuilding if the parameters are the same */
80     if(m_built && (*font == m_font) )
81         return;
82 
83     m_font = *font;
84     m_scaleFactor = scale;
85 
86     m_maxglyphw = 0;
87     m_maxglyphh = 0;
88 
89     wxScreenDC sdc;
90 
91     sdc.SetFont( *font );
92 
93     for( int i=0 ; i < 10 ; i++){
94         wxCoord gw, gh;
95         wxString text;
96         text = wxString::Format(_T("%d"), i);
97         wxCoord descent, exlead;
98         sdc.GetTextExtent( text, &gw, &gh, &descent, &exlead, font ); // measure the text
99 
100         tgi[i].width = gw;
101         tgi[i].height = gh;// - descent;
102 
103         tgi[i].advance = gw;
104 
105 
106         m_maxglyphw = wxMax(tgi[i].width,  m_maxglyphw);
107         m_maxglyphh = wxMax(tgi[i].height, m_maxglyphh);
108     }
109 
110     int w = 10 * m_maxglyphw;
111     int h = m_maxglyphh;
112 
113     /* make power of 2 */
114 
115     for(tex_w = 1; tex_w < w; tex_w *= 2);
116     for(tex_h = 1; tex_h < h; tex_h *= 2);
117 
118     wxBitmap tbmp(tex_w, tex_h);
119     wxMemoryDC dc;
120     dc.SelectObject(tbmp);
121     dc.SetFont( *font );
122 
123     /* fill bitmap with black */
124     dc.SetBackground( wxBrush( wxColour( 0, 0, 0 ) ) );
125     dc.Clear();
126 
127     /* draw the text white */
128     dc.SetTextForeground( wxColour( 255, 255, 255 ) );
129 
130  /*    wxPen pen(wxColour( 255, 255, 255 ));
131      wxBrush brush(wxColour( 255, 255, 255 ), wxTRANSPARENT);
132      dc.SetPen(pen);
133      dc.SetBrush(brush);
134   */
135     int row = 0, col = 0;
136     for( int i = 0; i < 10; i++ ) {
137 
138         tgi[i].x = col * m_maxglyphw;
139         tgi[i].y = row * m_maxglyphh;
140 
141         wxString text;
142         text = wxString::Format(_T("%d"), i);
143 
144         dc.DrawText(text, tgi[i].x, tgi[i].y );
145 
146         col++;
147     }
148 
149     dc.SelectObject(wxNullBitmap);
150 
151     wxImage image = tbmp.ConvertToImage();
152 
153     GLuint format, internalformat;
154     int stride;
155 
156     format = GL_ALPHA;
157     internalformat = format;
158     stride = 1;
159 
160     unsigned char *imgdata = image.GetData();
161 
162     if(imgdata){
163         unsigned char *teximage = (unsigned char *) malloc( stride * tex_w * tex_h );
164 
165         for( int j = 0; j < tex_w*tex_h; j++ )
166             for( int k = 0; k < stride; k++ )
167                 teximage[j * stride + k] = imgdata[3*j];
168 
169         glGenTextures( 1, &texobj );
170         glBindTexture( GL_TEXTURE_2D, texobj );
171 
172         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
173         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
174         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST/*GL_LINEAR*/ );
175         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
176 
177         glTexImage2D( GL_TEXTURE_2D, 0, internalformat, tex_w, tex_h, 0,
178                     format, GL_UNSIGNED_BYTE, teximage );
179 
180         free(teximage);
181     }
182 
183     m_built = true;
184 }
185 
Delete()186 void DepthFont::Delete( )
187 {
188     if (texobj) {
189         glDeleteTextures(1, &texobj);
190         texobj = 0;
191     }
192     m_built = false;
193     m_scaleFactor = 0;
194 }
195 
GetGLTextureRect(wxRect & texrect,int symIndex)196 bool DepthFont::GetGLTextureRect(wxRect &texrect, int symIndex)
197 {
198     if(symIndex < 10){
199         texrect.x = tgi[symIndex].x;
200         texrect.y = tgi[symIndex].y;
201         texrect.width = tgi[symIndex].width;
202         texrect.height = tgi[symIndex].height;
203         return true;
204     }
205     else{
206         texrect.x = tgi[0].x;
207         texrect.y = tgi[0].y;
208         texrect.width = tgi[0].width;
209         texrect.height = tgi[0].height;
210         return false;
211     }
212 }
213 
214 #if 0
215 void DepthFont::RenderGlyph( int c )
216 {
217 
218     SoundTexGlyphInfo &tgic = tgi[c];
219 
220     int x = tgic.x, y = tgic.y;
221     float w = m_maxglyphw, h = m_maxglyphh;
222     float tx1 = (float)x / (float)tex_w;
223     float tx2 = (float)(x + w) / (float)tex_w;
224     float ty1 = (float)y / (float)tex_h;
225     float ty2 = (float)(y + h) / (float)tex_h;
226 
227 #ifndef USE_ANDROID_GLES2
228 
229     glBegin( GL_QUADS );
230 
231     glTexCoord2f( tx1, ty1 );  glVertex2i( 0, 0 );
232     glTexCoord2f( tx2, ty1 );  glVertex2i( w, 0 );
233     glTexCoord2f( tx2, ty2 );  glVertex2i( w, h );
234     glTexCoord2f( tx1, ty2 );  glVertex2i( 0, h );
235 
236     glEnd();
237     glTranslatef( tgic.advance, 0.0, 0.0 );
238 #else
239 
240     float uv[8];
241     float coords[8];
242 
243     //normal uv
244     uv[0] = tx1; uv[1] = ty1; uv[2] = tx2; uv[3] = ty1;
245     uv[4] = tx2; uv[5] = ty2; uv[6] = tx1; uv[7] = ty2;
246 
247     // pixels
248     coords[0] = 0; coords[1] = 0; coords[2] = w; coords[3] = 0;
249     coords[4] = w; coords[5] = h; coords[6] = 0; coords[7] = h;
250 
251     glUseProgram( texture_2DA_shader_program );
252 
253     // Get pointers to the attributes in the program.
254     GLint mPosAttrib = glGetAttribLocation( texture_2DA_shader_program, "aPos" );
255     GLint mUvAttrib  = glGetAttribLocation( texture_2DA_shader_program, "aUV" );
256 
257     // Set up the texture sampler to texture unit 0
258     GLint texUni = glGetUniformLocation( texture_2DA_shader_program, "uTex" );
259     glUniform1i( texUni, 0 );
260 
261     // Disable VBO's (vertex buffer objects) for attributes.
262     glBindBuffer( GL_ARRAY_BUFFER, 0 );
263     glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
264 
265     // Set the attribute mPosAttrib with the vertices in the screen coordinates...
266     glVertexAttribPointer( mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, coords );
267     // ... and enable it.
268     glEnableVertexAttribArray( mPosAttrib );
269 
270     // Set the attribute mUvAttrib with the vertices in the GL coordinates...
271     glVertexAttribPointer( mUvAttrib, 2, GL_FLOAT, GL_FALSE, 0, uv );
272     // ... and enable it.
273     glEnableVertexAttribArray( mUvAttrib );
274 
275     float colorv[4];
276     colorv[0] = m_color.Red() / float(256);
277     colorv[1] = m_color.Green() / float(256);
278     colorv[2] = m_color.Blue() / float(256);
279     colorv[3] = 0;
280 
281     GLint colloc = glGetUniformLocation(texture_2DA_shader_program,"color");
282     glUniform4fv(colloc, 1, colorv);
283 
284     // Rotate
285     float angle = 0;
286     mat4x4 I, Q;
287     mat4x4_identity(I);
288     mat4x4_rotate_Z(Q, I, angle);
289 
290     // Translate
291     Q[3][0] = m_dx;
292     Q[3][1] = m_dy;
293 
294 
295     //mat4x4 X;
296     //mat4x4_mul(X, (float (*)[4])vp->vp_transform, Q);
297 
298     GLint matloc = glGetUniformLocation(texture_2DA_shader_program,"TransformMatrix");
299     glUniformMatrix4fv( matloc, 1, GL_FALSE, (const GLfloat*)Q);
300 
301     // Select the active texture unit.
302     glActiveTexture( GL_TEXTURE0 );
303 
304     // For some reason, glDrawElements is busted on Android
305     // So we do this a hard ugly way, drawing two triangles...
306     #if 0
307     GLushort indices1[] = {0,1,3,2};
308     glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices1);
309     #else
310 
311     float co1[8];
312     co1[0] = coords[0];
313     co1[1] = coords[1];
314     co1[2] = coords[2];
315     co1[3] = coords[3];
316     co1[4] = coords[6];
317     co1[5] = coords[7];
318     co1[6] = coords[4];
319     co1[7] = coords[5];
320 
321     float tco1[8];
322     tco1[0] = uv[0];
323     tco1[1] = uv[1];
324     tco1[2] = uv[2];
325     tco1[3] = uv[3];
326     tco1[4] = uv[6];
327     tco1[5] = uv[7];
328     tco1[6] = uv[4];
329     tco1[7] = uv[5];
330 
331     glVertexAttribPointer( mPosAttrib, 2, GL_FLOAT, GL_FALSE, 0, co1 );
332     glVertexAttribPointer( mUvAttrib, 2, GL_FLOAT, GL_FALSE, 0, tco1 );
333 
334     glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
335 
336     #endif
337 
338 
339 
340 
341     m_dx += tgic.advance;
342 
343 #endif
344 }
345 #endif
346 
347 #if 0
348 void DepthFont::RenderString( const char *string, int x, int y )
349 {
350 
351 #ifndef USE_ANDROID_GLES2
352 
353     glPushMatrix();
354     glTranslatef(x, y, 0);
355 
356     glPushMatrix();
357     glBindTexture( GL_TEXTURE_2D, texobj);
358 
359     for( int i = 0; string[i]; i++ ) {
360         if(string[i] == '\n') {
361             glPopMatrix();
362             glTranslatef(0, tgi[(int)'A'].height, 0);
363             glPushMatrix();
364             continue;
365         }
366         /* degree symbol */
367         if((unsigned char)string[i] == 0xc2 &&
368            (unsigned char)string[i+1] == 0xb0) {
369             RenderGlyph( DEGREE_GLYPH );
370             i++;
371             continue;
372         }
373         RenderGlyph( string[i] );
374     }
375 
376     glPopMatrix();
377     glPopMatrix();
378 #else
379     m_dx = x;
380     m_dy = y;
381 
382     glBindTexture( GL_TEXTURE_2D, texobj);
383 
384     for( int i = 0; string[i]; i++ ) {
385         if(string[i] == '\n') {
386             m_dy += tgi[(int)'A'].height;
387             continue;
388         }
389         /* degree symbol */
390         if((unsigned char)string[i] == 0xc2 &&
391             (unsigned char)string[i+1] == 0xb0) {
392             RenderGlyph( DEGREE_GLYPH );
393             i++;
394             continue;
395         }
396         RenderGlyph( string[i] );
397     }
398 
399 #endif
400 }
401 
402 void DepthFont::RenderString( const wxString &string, int x, int y )
403 {
404     RenderString((const char*)string.ToUTF8(), x, y);
405 }
406 #endif
407 //#endif     //#ifdef ocpnUSE_GL
408