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