]> git.saurik.com Git - wxWidgets.git/blob - src/common/glcmn.cpp
simplify code so it always returns the same object
[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 bool wxGLCanvasBase::SetColour(const wxString& colour)
67 {
68 wxColour col = wxTheColourDatabase->Find(colour);
69 if ( !col.IsOk() )
70 return false;
71
72 #ifdef wxHAS_OPENGL_ES
73 wxGLAPI::glColor3f((GLfloat) (col.Red() / 256.), (GLfloat) (col.Green() / 256.),
74 (GLfloat) (col.Blue() / 256.));
75 #else
76 GLboolean isRGBA;
77 glGetBooleanv(GL_RGBA_MODE, &isRGBA);
78 if ( isRGBA )
79 {
80 glColor3f((GLfloat) (col.Red() / 256.), (GLfloat) (col.Green() / 256.),
81 (GLfloat) (col.Blue() / 256.));
82 }
83 else // indexed colour
84 {
85 GLint pix = GetColourIndex(col);
86 if ( pix == -1 )
87 {
88 wxLogError(_("Failed to allocate colour for OpenGL"));
89 return false;
90 }
91
92 glIndexi(pix);
93 }
94 #endif
95 return true;
96 }
97
98 wxGLCanvasBase::~wxGLCanvasBase()
99 {
100 #if WXWIN_COMPATIBILITY_2_8
101 delete m_glContext;
102 #endif // WXWIN_COMPATIBILITY_2_8
103 }
104
105 #if WXWIN_COMPATIBILITY_2_8
106
107 wxGLContext *wxGLCanvasBase::GetContext() const
108 {
109 return m_glContext;
110 }
111
112 void wxGLCanvasBase::SetCurrent()
113 {
114 if ( m_glContext )
115 SetCurrent(*m_glContext);
116 }
117
118 void wxGLCanvasBase::OnSize(wxSizeEvent& WXUNUSED(event))
119 {
120 }
121
122 #endif // WXWIN_COMPATIBILITY_2_8
123
124 /* static */
125 bool wxGLCanvasBase::IsExtensionInList(const char *list, const char *extension)
126 {
127 if ( !list )
128 return false;
129
130 for ( const char *p = list; *p; p++ )
131 {
132 // advance up to the next possible match
133 p = wxStrstr(p, extension);
134 if ( !p )
135 break;
136
137 // check that the extension appears at the beginning/ending of the list
138 // or is preceded/followed by a space to avoid mistakenly finding
139 // "glExtension" in a list containing some "glFunkyglExtension"
140 if ( (p == list || p[-1] == ' ') )
141 {
142 char c = p[strlen(extension)];
143 if ( c == '\0' || c == ' ' )
144 return true;
145 }
146 }
147
148 return false;
149 }
150
151 // ============================================================================
152 // compatibility layer for OpenGL 3 and OpenGL ES
153 // ============================================================================
154
155 static wxGLAPI s_glAPI;
156
157 #if wxUSE_OPENGL_EMULATION
158
159 #include "wx/vector.h"
160
161 static GLenum s_mode;
162
163 static GLfloat s_currentTexCoord[2];
164 static GLfloat s_currentColor[4];
165 static GLfloat s_currentNormal[3];
166
167 // TODO move this into a different construct with locality for all attributes
168 // of a vertex
169
170 static wxVector<GLfloat> s_texCoords;
171 static wxVector<GLfloat> s_vertices;
172 static wxVector<GLfloat> s_normals;
173 static wxVector<GLfloat> s_colors;
174
175 static bool s_texCoordsUsed;
176 static bool s_colorsUsed;
177 static bool s_normalsUsed;
178
179 bool SetState( int flag, bool desired )
180 {
181 bool former = glIsEnabled( flag );
182 if ( former != desired )
183 {
184 if ( desired )
185 glEnableClientState(flag);
186 else
187 glDisableClientState(flag);
188 }
189 return former;
190 }
191
192 void RestoreState( int flag, bool desired )
193 {
194 if ( desired )
195 glEnableClientState(flag);
196 else
197 glDisableClientState(flag);
198 }
199 #endif
200
201 wxGLAPI::wxGLAPI()
202 {
203 #if wxUSE_OPENGL_EMULATION
204 s_mode = 0xFF;
205 #endif
206 }
207
208 wxGLAPI::~wxGLAPI()
209 {
210 }
211
212 void wxGLAPI::glFrustum(GLfloat left, GLfloat right, GLfloat bottom,
213 GLfloat top, GLfloat zNear, GLfloat zFar)
214 {
215 #if wxUSE_OPENGL_EMULATION
216 ::glFrustumf(left, right, bottom, top, zNear, zFar);
217 #else
218 ::glFrustum(left, right, bottom, top, zNear, zFar);
219 #endif
220 }
221
222 void wxGLAPI::glBegin(GLenum mode)
223 {
224 #if wxUSE_OPENGL_EMULATION
225 if ( s_mode != 0xFF )
226 {
227 wxFAIL_MSG("nested glBegin");
228 }
229
230 s_mode = mode;
231 s_texCoordsUsed = false;
232 s_colorsUsed = false;
233 s_normalsUsed = false;
234
235 s_texCoords.clear();
236 s_normals.clear();
237 s_colors.clear();
238 s_vertices.clear();
239 #else
240 ::glBegin(mode);
241 #endif
242 }
243
244 void wxGLAPI::glTexCoord2f(GLfloat s, GLfloat t)
245 {
246 #if wxUSE_OPENGL_EMULATION
247 if ( s_mode == 0xFF )
248 {
249 wxFAIL_MSG("glTexCoord2f called outside glBegin/glEnd");
250 }
251
252 else
253 {
254 s_texCoordsUsed = true;
255 s_currentTexCoord[0] = s;
256 s_currentTexCoord[1] = t;
257 }
258 #else
259 ::glTexCoord2f(s,t);
260 #endif
261 }
262
263 void wxGLAPI::glVertex3f(GLfloat x, GLfloat y, GLfloat z)
264 {
265 #if wxUSE_OPENGL_EMULATION
266 if ( s_mode == 0xFF )
267 {
268 wxFAIL_MSG("glVertex3f called outside glBegin/glEnd");
269 }
270 else
271 {
272 s_texCoords.push_back(s_currentTexCoord[0]);
273 s_texCoords.push_back(s_currentTexCoord[1]);
274
275 s_normals.push_back(s_currentNormal[0]);
276 s_normals.push_back(s_currentNormal[1]);
277 s_normals.push_back(s_currentNormal[2]);
278
279 s_colors.push_back(s_currentColor[0]);
280 s_colors.push_back(s_currentColor[1]);
281 s_colors.push_back(s_currentColor[2]);
282 s_colors.push_back(s_currentColor[3]);
283
284 s_vertices.push_back(x);
285 s_vertices.push_back(y);
286 s_vertices.push_back(z);
287 }
288 #else
289 ::glVertex3f(x,y,z);
290 #endif
291 }
292
293 void wxGLAPI::glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz)
294 {
295 #if wxUSE_OPENGL_EMULATION
296 if ( s_mode == 0xFF )
297 ::glNormal3f(nx,ny,nz);
298 else
299 {
300 s_normalsUsed = true;
301 s_currentNormal[0] = nx;
302 s_currentNormal[1] = ny;
303 s_currentNormal[2] = nz;
304 }
305 #else
306 ::glNormal3f(nx,ny,nz);
307 #endif
308 }
309
310 void wxGLAPI::glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
311 {
312 #if wxUSE_OPENGL_EMULATION
313 if ( s_mode == 0xFF )
314 ::glColor4f(r,g,b,a);
315 else
316 {
317 s_colorsUsed = true;
318 s_currentColor[0] = r;
319 s_currentColor[1] = g;
320 s_currentColor[2] = b;
321 s_currentColor[3] = a;
322 }
323 #else
324 ::glColor4f(r,g,b,a);
325 #endif
326 }
327
328 void wxGLAPI::glColor3f(GLfloat r, GLfloat g, GLfloat b)
329 {
330 #if wxUSE_OPENGL_EMULATION
331 glColor4f(r,g,b,1.0);
332 #else
333 ::glColor3f(r,g,b);
334 #endif
335 }
336
337 void wxGLAPI::glEnd()
338 {
339 #if wxUSE_OPENGL_EMULATION
340 bool formerColors = SetState( GL_COLOR_ARRAY, s_colorsUsed );
341 bool formerNormals = SetState( GL_NORMAL_ARRAY, s_normalsUsed );
342 bool formerTexCoords = SetState( GL_TEXTURE_COORD_ARRAY, s_texCoordsUsed );
343 bool formerVertex = glIsEnabled(GL_VERTEX_ARRAY);
344
345 if( !formerVertex )
346 glEnableClientState(GL_VERTEX_ARRAY);
347
348 if ( s_colorsUsed )
349 glColorPointer( 4, GL_FLOAT, 0, &s_colors[0] );
350
351 if ( s_normalsUsed )
352 glNormalPointer( GL_FLOAT, 0, &s_normals[0] );
353
354 if ( s_texCoordsUsed )
355 glTexCoordPointer( 2, GL_FLOAT, 0, &s_texCoords[0] );
356
357 glVertexPointer(3, GL_FLOAT, 0, &s_vertices[0]);
358 glDrawArrays( s_mode, 0, s_vertices.size() / 3 );
359
360 if ( s_colorsUsed != formerColors )
361 RestoreState( GL_COLOR_ARRAY, formerColors );
362
363 if ( s_normalsUsed != formerNormals )
364 RestoreState( GL_NORMAL_ARRAY, formerColors );
365
366 if ( s_texCoordsUsed != formerTexCoords )
367 RestoreState( GL_TEXTURE_COORD_ARRAY, formerColors );
368
369 if( !formerVertex )
370 glDisableClientState(GL_VERTEX_ARRAY);
371
372 s_mode = 0xFF;
373 #else
374 ::glEnd();
375 #endif
376 }
377
378 #endif // wxUSE_GLCANVAS
379