tomwalters@116: // Copyright 2006, Willem van Engen tomwalters@116: // tomwalters@116: // AIM-C: A C++ implementation of the Auditory Image Model tomwalters@116: // http://www.acousticscale.org/AIMC tomwalters@116: // tomwalters@116: // Licensed under the Apache License, Version 2.0 (the "License"); tomwalters@116: // you may not use this file except in compliance with the License. tomwalters@116: // You may obtain a copy of the License at tomwalters@116: // tomwalters@116: // http://www.apache.org/licenses/LICENSE-2.0 tomwalters@116: // tomwalters@116: // Unless required by applicable law or agreed to in writing, software tomwalters@116: // distributed under the License is distributed on an "AS IS" BASIS, tomwalters@116: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. tomwalters@116: // See the License for the specific language governing permissions and tomwalters@116: // limitations under the License. tomwalters@116: tomwalters@116: /*! tomwalters@116: * \file tomwalters@116: * \brief Output device for output to a wxWidgets OpenGL canvas tomwalters@116: * tomwalters@116: * \author Willem van Engen tomwalters@116: * \date created 2006/09/21 tomwalters@116: * \version \$Id: $ tomwalters@116: */ tomwalters@116: tomwalters@116: #include "Support/Common.h" tomwalters@116: tomwalters@116: /*! \class GraphicsOutputDevicewxGLCanvas tomwalters@116: * tomwalters@116: * Graphics output takes a large part of the application's performance at the tomwalters@116: * moment when it is inline with the Process() loop. Much is gained by tomwalters@116: * putting it in a separate thread, which can be done using ShotTargetThreaded. tomwalters@116: * tomwalters@116: * OpenGL-related documents: tomwalters@116: * - http://www.opengl.org/ tomwalters@116: * - http://www.sgi.com/products/software/opengl/ tomwalters@116: * - http://developer.apple.com/graphicsimaging/opengl/ tomwalters@116: * - http://developer.nvidia.com/page/documentation.html tomwalters@116: * - Vertex arrays tomwalters@116: * - http://www.opengl.org/registry/specs/EXT/vertex_array.txt tomwalters@116: * - http://www.awprofessional.com/articles/article.asp?p=461848&seqNum=2&rl=1 tomwalters@116: * - http://jdobry.webpark.cz/opengl/opengl_maximum_performance.html tomwalters@116: * - Fonts and OpenGL tomwalters@116: * - http://gltt.sourceforge.net/ tomwalters@116: */ tomwalters@116: tomwalters@116: // And finally our own tomwalters@116: #include "Support/util.h" tomwalters@116: #include "Output/GraphicsOutputDevice.h" tomwalters@116: #include "Output/GraphicsOutputDevicewxGLCanvas.h" tomwalters@116: tomwalters@116: BEGIN_EVENT_TABLE(GraphicsOutputDevicewxGLCanvas, wxGLCanvas) tomwalters@116: EVT_SIZE(GraphicsOutputDevicewxGLCanvas::OnSize) tomwalters@116: EVT_PAINT(GraphicsOutputDevicewxGLCanvas::OnPaint) tomwalters@116: EVT_ERASE_BACKGROUND(GraphicsOutputDevicewxGLCanvas::OnEraseBackground) tomwalters@116: END_EVENT_TABLE() tomwalters@116: tomwalters@116: // wxGLCanvas attributes tomwalters@116: int GraphicsOutputDevicewxGLCanvas::GLAttrlist[] = { tomwalters@116: WX_GL_RGBA, 1, tomwalters@116: WX_GL_DOUBLEBUFFER, 1, tomwalters@116: WX_GL_MIN_RED, 5, tomwalters@116: WX_GL_MIN_GREEN, 5, tomwalters@116: WX_GL_MIN_BLUE, 5, tomwalters@116: WX_GL_MIN_ALPHA, 3, tomwalters@116: WX_GL_DEPTH_SIZE, 16, tomwalters@116: 0 tomwalters@116: }; tomwalters@116: tomwalters@116: // OpenGL get procaddress function pointer, differs across platforms tomwalters@116: typedef void (*(*glGetProcAddressPtr_t)(const char*))(); tomwalters@116: tomwalters@116: GraphicsOutputDevicewxGLCanvas::GraphicsOutputDevicewxGLCanvas(Parameters *pParam, tomwalters@116: wxWindow *parent, tomwalters@116: wxWindowID id, tomwalters@116: const wxPoint& pos, tomwalters@116: const wxSize& size, tomwalters@116: long style, tomwalters@116: const wxString& name) tomwalters@116: : wxGLCanvas(parent, (wxGLCanvas*) NULL, id, pos, size, tomwalters@116: style|wxFULL_REPAINT_ON_RESIZE, name, GLAttrlist), tomwalters@116: GraphicsOutputDevice(pParam) { tomwalters@116: m_init = false; tomwalters@116: m_gllist = 0; tomwalters@116: m_pWorkerContext = NULL; tomwalters@116: m_bAntialiasing = true; tomwalters@116: m_pFont = NULL; tomwalters@116: m_sFontFile = NULL; tomwalters@116: m_iFontsize = -1; tomwalters@116: #if !defined(_MACOSX) tomwalters@116: s_bWorkerNeedsInit = false; tomwalters@116: #endif tomwalters@116: tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: m_iVertexType = 0xffff; // no gBegin() has happened yet tomwalters@116: m_bStaticColor = false; tomwalters@116: m_pVertices = NULL; tomwalters@116: m_iVerticesMax = 0; tomwalters@116: // Enable vertex arrays if possible tomwalters@116: #ifdef _MACOSX tomwalters@116: m_glLockArraysEXT = ::glLockArraysEXT; tomwalters@116: m_glUnlockArraysEXT = ::glUnlockArraysEXT; tomwalters@116: m_bVertexArrayLock = true; tomwalters@116: #else tomwalters@116: m_bVertexArrayLock = false; tomwalters@116: // OpenGL command needed to fetch entry point, do it in InitGL() tomwalters@116: #endif /* _MACOSX */ tomwalters@116: #endif /* WITH_GL_VERTEX_ARRAYS */ tomwalters@116: } tomwalters@116: tomwalters@116: GraphicsOutputDevicewxGLCanvas::~GraphicsOutputDevicewxGLCanvas() { tomwalters@116: // Cleanup OpenGL display list tomwalters@116: if (m_init) { tomwalters@116: glDeleteLists(m_gllist, 1); tomwalters@116: } tomwalters@116: DELETE_IF_NONNULL(m_pWorkerContext); tomwalters@116: DELETE_IF_NONNULL(m_pFont); tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: DELETE_ARRAY_IF_NONNULL(m_pVertices); tomwalters@116: #endif tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::Start() { tomwalters@116: // This seems to be needed to prevent a crash on windows, but why???? tomwalters@116: SetCurrent(); tomwalters@116: return GraphicsOutputDevice::Start(); tomwalters@116: } tomwalters@116: tomwalters@116: bool GraphicsOutputDevicewxGLCanvas::Initialize(unsigned int iVerticesMax) { tomwalters@116: AIM_ASSERT(m_pParam); tomwalters@116: // Give a chance to update anti-aliasing settings tomwalters@116: if (m_bAntialiasing != m_pParam->GetBool("output.antialias")) { tomwalters@116: m_bAntialiasing = m_pParam->GetBool("output.antialias"); tomwalters@116: if (SetCurrent()) { tomwalters@116: InitGL(); tomwalters@116: #if !defined(_MACOSX) tomwalters@116: { tomwalters@116: wxMutexLocker lock(s_mutexOpenGL); tomwalters@116: s_bWorkerNeedsInit = true; tomwalters@116: } tomwalters@116: #endif tomwalters@116: } tomwalters@116: } tomwalters@116: tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: // Re-allocate vertices tomwalters@116: if (iVerticesMax > m_iVerticesMax) { tomwalters@116: DELETE_IF_NONNULL(m_pVertices); tomwalters@116: m_iVerticesMax = iVerticesMax; tomwalters@116: // If color is static, we need not store the color tomwalters@116: if (m_bStaticColor) tomwalters@116: m_pVertices = new GLfloat[(iVerticesMax+1)*3]; tomwalters@116: else tomwalters@116: m_pVertices = new GLfloat[(iVerticesMax+1)*6]; tomwalters@116: } tomwalters@116: #endif tomwalters@116: tomwalters@116: // Change font if requested tomwalters@116: const char *sFontFile = m_pParam->GetString("output.gl.fontfile"); tomwalters@116: unsigned int iFontsize = m_pParam->GetUInt("output.fontsize"); tomwalters@116: if (!m_sFontFile tomwalters@116: || !strcmp(m_sFontFile,sFontFile)==0 tomwalters@116: || m_iFontsize!=(int)iFontsize) { tomwalters@116: wxMutexLocker lock(s_mutexOpenGL); tomwalters@116: DELETE_IF_NONNULL(m_pFont); tomwalters@116: wxString sWorkingFontFilename = wxString::FromAscii(sFontFile); tomwalters@116: if (!wxFileExists(sWorkingFontFilename)) { tomwalters@116: sWorkingFontFilename = wxString::FromAscii(aimDataDir()); tomwalters@116: sWorkingFontFilename += _T("/"); tomwalters@116: sWorkingFontFilename += wxString::FromAscii(sFontFile); tomwalters@116: } tomwalters@116: //if (!wxFileExists(sWorkingFontFilename)) tomwalters@116: //sWorkingFontFilename.replace("Font:").append(sFontFile); tomwalters@116: m_pFont = static_cast(new FTGLBitmapFont(sWorkingFontFilename.fn_str())); tomwalters@116: if (!m_pFont || m_pFont->Error()) { tomwalters@116: aimERROR(_T("Couldn't load font '%s'"), sFontFile); tomwalters@116: DELETE_IF_NONNULL(m_pFont); tomwalters@116: } else { tomwalters@116: // Display lists don't mix with our own usage :( tomwalters@116: // May not be needed for a Bitmap font tomwalters@116: //m_pFont->UseDisplayList(false); tomwalters@116: if ( !m_pFont->FaceSize(iFontsize) ) { tomwalters@116: AIM_ERROR(_T("Couldn't select font size %u on font '%s'"), iFontsize, sFontFile); tomwalters@116: DELETE_IF_NONNULL(m_pFont); tomwalters@116: } tomwalters@116: } tomwalters@116: m_sFontFile = sFontFile; tomwalters@116: m_iFontsize = iFontsize; tomwalters@116: } tomwalters@116: return true; tomwalters@116: } tomwalters@116: bool GraphicsOutputDevicewxGLCanvas::Initialize() { tomwalters@116: return Initialize(0); tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::Render() { tomwalters@116: wxPaintDC dc(this); tomwalters@116: // We want to initialize first from main thread. tomwalters@116: if (!m_init) { tomwalters@116: if (!SetCurrent()) return; tomwalters@116: InitGL(); tomwalters@116: } tomwalters@116: // Render saved list only if not animating (redrawn anyway in that case) tomwalters@116: if (!m_bRunning) { tomwalters@116: if (!SetCurrent()) { tomwalters@116: return; tomwalters@116: } tomwalters@116: glClear(GL_COLOR_BUFFER_BIT/*|GL_DEPTH_BUFFER_BIT*/); tomwalters@116: glCallList(m_gllist); tomwalters@116: SwapBuffers(); tomwalters@116: } tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) { tomwalters@116: Render(); tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::OnSize(wxSizeEvent& event) { tomwalters@116: // this is also necessary to update the context on some platforms tomwalters@116: wxGLCanvas::OnSize(event); tomwalters@116: tomwalters@116: // set GL viewport tomwalters@116: // (not called by wxGLCanvas::OnSize on all platforms...) tomwalters@116: if (SetCurrent()) { tomwalters@116: DoResize(); tomwalters@116: // It is only sensible to update the other thread when it's running tomwalters@116: // Don't acquire the mutex when s_bWorkerNeedsInit already to avoid deadlock tomwalters@116: if (/*m_bRunning &&*/ !s_bWorkerNeedsInit) { tomwalters@116: wxMutexLocker lock(s_mutexOpenGL); tomwalters@116: s_bWorkerNeedsInit = true; tomwalters@116: } tomwalters@116: } tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { tomwalters@116: } tomwalters@116: tomwalters@116: bool GraphicsOutputDevicewxGLCanvas::SetCurrent() { tomwalters@116: bool bRet=true; tomwalters@116: tomwalters@116: #ifndef __WXMOTIF__ tomwalters@116: bRet = (GetContext()!=NULL); tomwalters@116: if (bRet) tomwalters@116: #endif tomwalters@116: { tomwalters@116: wxGLCanvas::SetCurrent(); tomwalters@116: } tomwalters@116: return bRet; tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::DoResize() { tomwalters@116: int w, h; tomwalters@116: GetClientSize(&w, &h); tomwalters@116: glViewport(0, 0, (GLint)w, (GLint)h); tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::InitGL() { tomwalters@116: /* No SetCurrent() here, because this can be called from different GL contexts. tomwalters@116: * Convenient for multi-threaded operation. */ tomwalters@116: //aimERROR(_T("InitGL Called")); tomwalters@116: #if defined(WITH_GL_VERTEX_ARRAYS) && !defined(_MACOSX) tomwalters@116: if (!m_init) { tomwalters@116: /* This needs to be done here, because OpenGL commands may need SetCurrent() tomwalters@116: * and an already shown window. */ tomwalters@116: char *extensions = (char *)glGetString(GL_EXTENSIONS); tomwalters@116: if (!extensions) { tomwalters@116: AIM_INFO(_T("Could not query OpenGL extensions, vertex arrays disabled")); tomwalters@116: } else if (strstr(extensions, "GL_EXT_compiled_vertex_array")) { tomwalters@116: m_glLockArraysEXT = (LOCAL_PFNGLLOCKARRAYSEXTPROC)GL_GET_PROC_ADDRESS("glLockArraysEXT"); tomwalters@116: m_glUnlockArraysEXT = (LOCAL_PFNGLUNLOCKARRAYSEXTPROC)GL_GET_PROC_ADDRESS("glUnlockArraysEXT"); tomwalters@116: if(!m_glLockArraysEXT || !m_glUnlockArraysEXT) tomwalters@116: AIM_ERROR(_T("OpenGL error on GL_EXT_compiled_vertex_array")); tomwalters@116: else tomwalters@116: m_bVertexArrayLock = true; tomwalters@116: } tomwalters@116: } tomwalters@116: #endif tomwalters@116: DoResize(); tomwalters@116: glClearColor(0, 0, 0, 1); tomwalters@116: glMatrixMode( GL_PROJECTION ); tomwalters@116: glLoadIdentity( ); tomwalters@116: tomwalters@116: glEnable(GL_VERTEX_ARRAY); tomwalters@116: tomwalters@116: // Window limits in OpenGL co-ordiantes tomwalters@116: //! \todo Make this configurable, or change and document fixed values tomwalters@116: glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0); tomwalters@116: glTranslatef(0.0, 0.0, 0.0); tomwalters@116: tomwalters@116: if (m_bAntialiasing) { tomwalters@116: glEnable(GL_LINE_SMOOTH); tomwalters@116: glEnable(GL_BLEND); tomwalters@116: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); tomwalters@116: //glBlendFunc(GL_ONE, GL_ONE); tomwalters@116: glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); tomwalters@116: } else { tomwalters@116: glDisable(GL_LINE_SMOOTH); tomwalters@116: glDisable(GL_BLEND); tomwalters@116: } tomwalters@116: glLineWidth(1.0); tomwalters@116: tomwalters@116: // Get a free display list only the first time tomwalters@116: if (!m_init) { tomwalters@116: #if !defined(_MACOSX) tomwalters@116: // Windows and Linux need a separate worker context tomwalters@116: aimASSERT(wxIsMainThread()); tomwalters@116: #if wxCHECK_VERSION(2,8,0) tomwalters@116: m_pWorkerContext = new wxGLContext(this, m_glContext); tomwalters@116: #else tomwalters@116: m_pWorkerContext = new wxGLContext(true, tomwalters@116: this, tomwalters@116: wxNullPalette, tomwalters@116: m_glContext); tomwalters@116: #endif tomwalters@116: aimASSERT(m_pWorkerContext); tomwalters@116: s_bWorkerNeedsInit = true; tomwalters@116: #endif tomwalters@116: m_gllist = glGenLists(1); tomwalters@116: aimASSERT(m_gllist); tomwalters@116: // Empty window at start tomwalters@116: glNewList(m_gllist, GL_COMPILE_AND_EXECUTE); tomwalters@116: glEndList(); tomwalters@116: m_init = true; tomwalters@116: } tomwalters@116: } tomwalters@116: tomwalters@116: // Call before any other render* functions tomwalters@116: void GraphicsOutputDevicewxGLCanvas::gGrab() { tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: #if !defined(_MACOSX) tomwalters@116: // Detect if we're the main thread or not. tomwalters@116: if (!wxIsMainThread()) { tomwalters@116: // We're called by a worker thread, make sure there's a right context tomwalters@116: AIM_ASSERT(m_pWorkerContext); tomwalters@116: #if wxCHECK_VERSION(2,8,0) tomwalters@116: m_pWorkerContext->SetCurrent(*this); tomwalters@116: #else tomwalters@116: m_pWorkerContext->SetCurrent(); tomwalters@116: #endif tomwalters@116: // Update OpenGL settings if needed tomwalters@116: wxMutexLocker lock(s_mutexOpenGL); tomwalters@116: if (s_bWorkerNeedsInit) { tomwalters@116: InitGL(); tomwalters@116: s_bWorkerNeedsInit = false; tomwalters@116: } tomwalters@116: } else tomwalters@116: #endif tomwalters@116: { tomwalters@116: // Either called by main thread, or we need no special worker glContext tomwalters@116: if (!SetCurrent()) { tomwalters@116: return; tomwalters@116: } tomwalters@116: // Init OpenGL once, but after SetCurrent tomwalters@116: if (!m_init) { tomwalters@116: InitGL(); tomwalters@116: } tomwalters@116: } tomwalters@116: glClear(GL_COLOR_BUFFER_BIT); tomwalters@116: tomwalters@116: // Start and store in a display list for redrawing tomwalters@116: glNewList(m_gllist, GL_COMPILE); tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::gBeginLineStrip() { tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: aimASSERT(m_iVertexType == 0xffff); // Previous gBegin*() must be gEnd()ed tomwalters@116: // New lines vertex array tomwalters@116: m_iVertexCount = 0; tomwalters@116: m_iVertexType = GL_LINE_STRIP; tomwalters@116: #else tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: glBegin(GL_LINE_STRIP); tomwalters@116: #endif tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::gBeginQuadStrip() { tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: aimASSERT(m_iVertexType == 0xffff); // Previous gBegin*() must be gEnd()ed tomwalters@116: // New quads vertex array tomwalters@116: m_iVertexCount = 0; tomwalters@116: m_iVertexType = GL_QUAD_STRIP; tomwalters@116: #else tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: glBegin(GL_QUAD_STRIP); tomwalters@116: #endif tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::gVertex3f(float x, float y, float z) { tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: aimASSERT(m_iVertexType != 0xffff); // Must be inside gBegin*() tomwalters@116: if (m_iVertexCount>=m_iVerticesMax) { tomwalters@116: static bool errShown=false; tomwalters@116: if (!errShown) { tomwalters@116: aimERROR(_T("Error: max vertex count reached: %d"), m_iVertexCount); tomwalters@116: errShown=true; tomwalters@116: } tomwalters@116: return; tomwalters@116: } tomwalters@116: if (m_bStaticColor) { tomwalters@116: m_pVertices[m_iVertexCount*3+0] = x; tomwalters@116: m_pVertices[m_iVertexCount*3+1] = y; tomwalters@116: m_pVertices[m_iVertexCount*3+2] = z; tomwalters@116: } else { tomwalters@116: m_pVertices[m_iVertexCount*6+0] = m_fCurColorR; tomwalters@116: m_pVertices[m_iVertexCount*6+1] = m_fCurColorG; tomwalters@116: m_pVertices[m_iVertexCount*6+2] = m_fCurColorB; tomwalters@116: m_pVertices[m_iVertexCount*6+3] = x; tomwalters@116: m_pVertices[m_iVertexCount*6+4] = y; tomwalters@116: m_pVertices[m_iVertexCount*6+5] = z; tomwalters@116: } tomwalters@116: m_iVertexCount++; tomwalters@116: #else tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: glVertex3f(x,y,z); tomwalters@116: #endif tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::gColor3f(float r, float g, float b) { tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: if (m_iVertexType==0xffff || m_bStaticColor) { tomwalters@116: // If not inside vertex array run, use the ordinary command tomwalters@116: glColor3f(r, g, b); tomwalters@116: } tomwalters@116: if (!m_bStaticColor) { tomwalters@116: // Set current color for vertex array usage tomwalters@116: m_fCurColorR = r; tomwalters@116: m_fCurColorG = g; tomwalters@116: m_fCurColorB = b; tomwalters@116: } tomwalters@116: #else tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: glColor3f(r, g, b); tomwalters@116: #endif tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::gEnd() { tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: aimASSERT(m_iVertexType != 0xffff); // Must be inside gBegin*() tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: tomwalters@116: // Draw the vertex array tomwalters@116: glEnableClientState(GL_VERTEX_ARRAY); tomwalters@116: tomwalters@116: // Draw vertices tomwalters@116: if (m_bStaticColor) tomwalters@116: glVertexPointer(3, GL_FLOAT, 0, m_pVertices); tomwalters@116: else tomwalters@116: glInterleavedArrays(GL_C3F_V3F, 0, m_pVertices); tomwalters@116: if (m_bVertexArrayLock) m_glLockArraysEXT(0, m_iVertexCount); tomwalters@116: glDrawArrays(m_iVertexType, 0, m_iVertexCount); tomwalters@116: if (m_bVertexArrayLock) m_glUnlockArraysEXT(); tomwalters@116: tomwalters@116: glDisableClientState(GL_VERTEX_ARRAY); tomwalters@116: tomwalters@116: // Remember we're outside a gBegin()..gEnd() loop tomwalters@116: m_iVertexType = 0xffff; tomwalters@116: #else tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: glEnd(); tomwalters@116: #endif tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::gText3f(float x, tomwalters@116: float y, tomwalters@116: float z, tomwalters@116: const char *sStr, tomwalters@116: bool bRotated) { tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: aimASSERT(m_iVertexType == 0xffff); // Must be outside gBegin*() tomwalters@116: #endif tomwalters@116: tomwalters@116: if (!m_pFont) tomwalters@116: return; tomwalters@116: tomwalters@116: //! \todo make rotation work tomwalters@116: if (bRotated) tomwalters@116: return; tomwalters@116: tomwalters@116: { tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: /* tomwalters@116: if (bRotated) { tomwalters@116: glPushMatrix(); tomwalters@116: glTranslatef(x,y,z); tomwalters@116: glRotatef(90.0f, 0, 0, 1.0f); tomwalters@116: glRasterPos3f(0,0,0); tomwalters@116: m_pFont->Render(sStr); tomwalters@116: glPopMatrix(); tomwalters@116: } else { tomwalters@116: */ tomwalters@116: glRasterPos3f(x, y, z); tomwalters@116: m_pFont->Render(sStr); tomwalters@116: } tomwalters@116: } tomwalters@116: tomwalters@116: void GraphicsOutputDevicewxGLCanvas::gRelease() { tomwalters@116: #ifdef WITH_GL_VERTEX_ARRAYS tomwalters@116: aimASSERT(m_iVertexType == 0xffff); // Must be gEnd()ed tomwalters@116: #endif tomwalters@116: AimwxGuiLocker __lock__; tomwalters@116: glEndList(); tomwalters@116: glCallList(m_gllist); tomwalters@116: //glFlush(); tomwalters@116: SwapBuffers(); // Doesn't matter in what context tomwalters@116: }