]> git.saurik.com Git - wxWidgets.git/blob - src/common/glcmn.cpp
adding emulation API for OpenGL ES platforms
[wxWidgets.git] / src / common / glcmn.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/glcmn.cpp
3 // Purpose: wxGLCanvasBase implementation
4 // Author: Vadim Zeitlin
5 // Created: 2007-04-09
6 // RCS-ID: $Id$
7 // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_GLCANVAS
27
28 #ifndef WX_PRECOMP
29 #include "wx/log.h"
30 #endif // WX_PRECOMP
31
32 #include "wx/glcanvas.h"
33
34 // DLL options compatibility check:
35 #include "wx/build.h"
36 WX_CHECK_BUILD_OPTIONS("wxGL")
37
38 IMPLEMENT_CLASS(wxGLApp, wxApp)
39
40 // ============================================================================
41 // implementation
42 // ============================================================================
43
44 wxGLCanvasBase::wxGLCanvasBase()
45 {
46 #if WXWIN_COMPATIBILITY_2_8
47 m_glContext = NULL;
48 #endif
49
50 // we always paint background entirely ourselves so prevent wx from erasing
51 // it to avoid flicker
52 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
53 }
54
55 bool wxGLCanvasBase::SetCurrent(const wxGLContext& context) const
56 {
57 // although on MSW it works even if the window is still hidden, it doesn't
58 // work in other ports (notably X11-based ones) and documentation mentions
59 // that SetCurrent() can only be called for a shown window, so check for it
60 wxASSERT_MSG( IsShownOnScreen(), wxT("can't make hidden GL canvas current") );
61
62
63 return context.SetCurrent(*static_cast<const wxGLCanvas *>(this));
64 }
65
66 #ifndef wxHAS_OPENGL_ES
67 bool wxGLCanvasBase::SetColour(const wxString& colour)
68 {
69 wxColour col = wxTheColourDatabase->Find(colour);
70 if ( !col.Ok() )
71 return false;
72
73 GLboolean isRGBA;
74 glGetBooleanv(GL_RGBA_MODE, &isRGBA);
75 if ( isRGBA )
76 {
77 glColor3f(col.Red() / 256., col.Green() / 256., col.Blue() / 256.);
78 }
79 else // indexed colour
80 {
81 GLint pix = GetColourIndex(col);
82 if ( pix == -1 )
83 {
84 wxLogError(_("Failed to allocate colour for OpenGL"));
85 return false;
86 }
87
88 glIndexi(pix);
89 }
90
91 return true;
92 }
93 #endif
94
95 wxGLCanvasBase::~wxGLCanvasBase()
96 {
97 #if WXWIN_COMPATIBILITY_2_8
98 delete m_glContext;
99 #endif // WXWIN_COMPATIBILITY_2_8
100 }
101
102 #if WXWIN_COMPATIBILITY_2_8
103
104 wxGLContext *wxGLCanvasBase::GetContext() const
105 {
106 return m_glContext;
107 }
108
109 void wxGLCanvasBase::SetCurrent()
110 {
111 if ( m_glContext )
112 SetCurrent(*m_glContext);
113 }
114
115 void wxGLCanvasBase::OnSize(wxSizeEvent& WXUNUSED(event))
116 {
117 }
118
119 #endif // WXWIN_COMPATIBILITY_2_8
120
121 /* static */
122 bool wxGLCanvasBase::IsExtensionInList(const char *list, const char *extension)
123 {
124 if ( !list )
125 return false;
126
127 for ( const char *p = list; *p; p++ )
128 {
129 // advance up to the next possible match
130 p = wxStrstr(p, extension);
131 if ( !p )
132 break;
133
134 // check that the extension appears at the beginning/ending of the list
135 // or is preceded/followed by a space to avoid mistakenly finding
136 // "glExtension" in a list containing some "glFunkyglExtension"
137 if ( (p == list || p[-1] == ' ') )
138 {
139 char c = p[strlen(extension)];
140 if ( c == '\0' || c == ' ' )
141 return true;
142 }
143 }
144
145 return false;
146 }
147
148 // ============================================================================
149 // compatibility layer for OpenGL 3 and OpenGL ES
150 // ============================================================================
151
152 static wxGLAPI s_glAPI;
153
154 #if wxUSE_OPENGL_EMULATION
155
156 #include "wx/vector.h"
157
158 static GLenum s_mode;
159
160 static GLfloat s_currentTexCoord[2];
161 static GLfloat s_currentColor[4];
162 static GLfloat s_currentNormal[3];
163
164 // TODO move this into a different construct with locality for all attributes
165 // of a vertex
166
167 static wxVector<GLfloat> s_texCoords;
168 static wxVector<GLfloat> s_vertices;
169 static wxVector<GLfloat> s_normals;
170 static wxVector<GLfloat> s_colors;
171
172 static bool s_texCoordsUsed;
173 static bool s_colorsUsed;
174 static bool s_normalsUsed;
175
176 bool SetState( int flag, bool desired )
177 {
178 bool former = glIsEnabled( flag );
179 if ( former != desired )
180 {
181 if ( desired )
182 glEnableClientState(flag);
183 else
184 glDisableClientState(flag);
185 }
186 return former;
187 }
188
189 void RestoreState( int flag, bool desired )
190 {
191 if ( desired )
192 glEnableClientState(flag);
193 else
194 glDisableClientState(flag);
195 }
196 #endif
197
198 wxGLAPI::wxGLAPI()
199 {
200 #if wxUSE_OPENGL_EMULATION
201 s_mode = 0xFF;
202 #endif
203 }
204
205 wxGLAPI::~wxGLAPI()
206 {
207 }
208
209 void wxGLAPI::glBegin(GLenum mode)
210 {
211 #if wxUSE_OPENGL_EMULATION
212 if ( s_mode != 0xFF )
213 {
214 wxFAIL_MSG("nested glBegin");
215 }
216
217 s_mode = mode;
218 s_texCoordsUsed = false;
219 s_colorsUsed = false;
220 s_normalsUsed = false;
221
222 s_texCoords.clear();
223 s_normals.clear();
224 s_colors.clear();
225 s_vertices.clear();
226 #else
227 ::glBegin(mode);
228 #endif
229 }
230
231 void wxGLAPI::glTexCoord2f(GLfloat s, GLfloat t)
232 {
233 #if wxUSE_OPENGL_EMULATION
234 if ( s_mode == 0xFF )
235 {
236 wxFAIL_MSG("glTexCoord2f called outside glBegin/glEnd");
237 }
238
239 else
240 {
241 s_texCoordsUsed = true;
242 s_currentTexCoord[0] = s;
243 s_currentTexCoord[1] = t;
244 }
245 #else
246 ::glTexCoord2f(s,t);
247 #endif
248 }
249
250 void wxGLAPI::glVertex3f(GLfloat x, GLfloat y, GLfloat z)
251 {
252 #if wxUSE_OPENGL_EMULATION
253 if ( s_mode == 0xFF )
254 {
255 wxFAIL_MSG("glVertex3f called outside glBegin/glEnd");
256 }
257 else
258 {
259 s_texCoords.push_back(s_currentTexCoord[0]);
260 s_texCoords.push_back(s_currentTexCoord[1]);
261
262 s_normals.push_back(s_currentNormal[0]);
263 s_normals.push_back(s_currentNormal[1]);
264 s_normals.push_back(s_currentNormal[2]);
265
266 s_colors.push_back(s_currentColor[0]);
267 s_colors.push_back(s_currentColor[1]);
268 s_colors.push_back(s_currentColor[2]);
269 s_colors.push_back(s_currentColor[3]);
270
271 s_vertices.push_back(x);
272 s_vertices.push_back(y);
273 s_vertices.push_back(z);
274 }
275 #else
276 ::glVertex3f(x,y,z);
277 #endif
278 }
279
280 void wxGLAPI::glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz)
281 {
282 #if wxUSE_OPENGL_EMULATION
283 if ( s_mode == 0xFF )
284 ::glNormal3f(nx,ny,nz);
285 else
286 {
287 s_normalsUsed = true;
288 s_currentNormal[0] = nx;
289 s_currentNormal[1] = ny;
290 s_currentNormal[2] = nz;
291 }
292 #else
293 ::glNormal3f(nx,ny,nz);
294 #endif
295 }
296
297 void wxGLAPI::glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
298 {
299 #if wxUSE_OPENGL_EMULATION
300 if ( s_mode == 0xFF )
301 ::glColor4f(r,g,b,a);
302 else
303 {
304 s_colorsUsed = true;
305 s_currentColor[0] = r;
306 s_currentColor[1] = g;
307 s_currentColor[2] = b;
308 s_currentColor[3] = a;
309 }
310 #else
311 ::glColor4f(r,g,b,a);
312 #endif
313 }
314
315 void wxGLAPI::glColor3f(GLfloat r, GLfloat g, GLfloat b)
316 {
317 #if wxUSE_OPENGL_EMULATION
318 glColor4f(r,g,b,1.0);
319 #else
320 ::glColor3f(r,g,b);
321 #endif
322 }
323
324 void wxGLAPI::glEnd()
325 {
326 #if wxUSE_OPENGL_EMULATION
327 bool formerColors = SetState( GL_COLOR_ARRAY, s_colorsUsed );
328 bool formerNormals = SetState( GL_NORMAL_ARRAY, s_normalsUsed );
329 bool formerTexCoords = SetState( GL_TEXTURE_COORD_ARRAY, s_texCoordsUsed );
330 bool formerVertex = glIsEnabled(GL_VERTEX_ARRAY);
331
332 if( !formerVertex )
333 glEnableClientState(GL_VERTEX_ARRAY);
334
335 if ( s_colorsUsed )
336 glColorPointer( 4, GL_FLOAT, 0, &s_colors[0] );
337
338 if ( s_normalsUsed )
339 glNormalPointer( GL_FLOAT, 0, &s_normals[0] );
340
341 if ( s_texCoordsUsed )
342 glTexCoordPointer( 2, GL_FLOAT, 0, &s_texCoords[0] );
343
344 glVertexPointer(3, GL_FLOAT, 0, &s_vertices[0]);
345 glDrawArrays( s_mode, 0, s_vertices.size() / 3 );
346
347 if ( s_colorsUsed != formerColors )
348 RestoreState( GL_COLOR_ARRAY, formerColors );
349
350 if ( s_normalsUsed != formerNormals )
351 RestoreState( GL_NORMAL_ARRAY, formerColors );
352
353 if ( s_texCoordsUsed != formerTexCoords )
354 RestoreState( GL_TEXTURE_COORD_ARRAY, formerColors );
355
356 if( !formerVertex )
357 glDisableClientState(GL_VERTEX_ARRAY);
358
359 s_mode = 0xFF;
360 #else
361 ::glEnd();
362 #endif
363 }
364
365 #endif // wxUSE_GLCANVAS
366