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