PyOpenGL on Macbook Retina Display

I have a code that displays graphics using PyOpenGL in a glut window. On the Macbook Pro's retina, this window appears in low-resolution mode, with one OpenGL pixel represented by four physical pixels. It would be much better if it was displayed in full native resolution.

My question
Is there a way to get the OpenGL context with native resolution in Python on Retina displays using glut or otherwise?

Problem example
The following is a minimal working example of PyOpenGL. There is nothing special about this - this question will be presented by any working PyOpenGL code. Here is a brief overview of the screen shot. Note that the pixels that make up the white triangle are four times the pixel size of OS X widgets. This is the default value for programs not specifically designed for Retina devices. I want to know how to disable it for PyOpenGL programs.

enter image description here

Here is the code:

from OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import * import os def initFunc(): glDisable(GL_DEPTH_TEST) glClearColor(0.0, 0.0, 0.0, 0.0) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(0.0, 400.0, 0.0, 400.0) def displayFunc(): glClear(GL_COLOR_BUFFER_BIT) glColor3f(1.0, 1.0, 1.0) glBegin(GL_TRIANGLES) glVertex2f(10.0, 10.0) glVertex2f(10.0, 100.0) glVertex2f(100.0, 100.0) glEnd() glFlush() if __name__ == '__main__': glutInit() glutInitWindowSize(400,400) glutCreateWindow("GL test") glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB) glutDisplayFunc(displayFunc) initFunc() os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''') # prevent GL window from appearing behind other applications glutMainLoop() 
+4
source share
3 answers

In order to correctly execute the resolution you need, you will need to use NSView and then indicate that the view should use the best resolution (this also means that you should no longer use GLUT). Since this is outside the scope of OpenGL, and you want to use Python, you will need to use a package that will access these types of objects along with py2app (but full py2app build not required).

To access NSView or, more specifically, NSOpenGLView , NSOpenGLView for your needs. The following code imports Cocoa (provided by pyobjc ) for clarity only, the same objects can be accessed through AppKit . The code creates an NSWindow , and then a view that defines the drawRect to call if necessary. The only line that solves the permission problem: view.setWantsBestResolutionOpenGLSurface_(True) .

 import Cocoa from OpenGL.GL import * from OpenGL.GLU import * class GLView(Cocoa.NSOpenGLView): def initWithFrame_(self, frame): format = Cocoa.NSOpenGLPixelFormat.alloc().initWithAttributes_((0, )) view = super(GLView, self).initWithFrame_pixelFormat_(frame, format) view.setWantsBestResolutionOpenGLSurface_(True) view.openGLContext().makeCurrentContext() glDisable(GL_DEPTH_TEST) glClearColor(0.0, 0.0, 0.0, 0.0) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(0.0, 1.0, 0.0, 1.0) return view def drawRect_(self, bounds): glClear(GL_COLOR_BUFFER_BIT) glColor3f(1.0, 1.0, 1.0) glBegin(GL_TRIANGLES) glVertex2f(0.1, 0.1) glVertex2f(0.1, 0.9) glVertex2f(0.9, 0.9) glEnd() glFlush() class AppDelegate(Cocoa.NSObject): def windowWillClose_(self, notification): app.terminate_(self) app = Cocoa.NSApplication.sharedApplication() rect = Cocoa.NSMakeRect(0, 0, 300, 300) winflags = Cocoa.NSTitledWindowMask | Cocoa.NSClosableWindowMask win = Cocoa.NSWindow.alloc().initWithContentRect_styleMask_backing_defer_( rect, winflags, Cocoa.NSBackingStoreBuffered, False) delegate = AppDelegate.alloc().init() win.setDelegate_(delegate) view = GLView.alloc().initWithFrame_(rect) win.setContentView_(view) win.makeKeyAndOrderFront_(None) app.run() 

If you try to run this code, it will work fine, but you will not notice any difference in the resolution problem. To solve this problem, you need to build a simple setup.py , assuming that the above code was saved in a file called test1.py :

 from distutils.core import setup import py2app setup(app=["test1.py"]) 

Then run mypythonexecutable setup.py py2app -A (where, of course, mypythonexecutable is replaced with something that makes sense, like python or python2.7 for example). Now you run open dist/test1.app and the problem is resolved ( dist/test1.app will be created after running the earlier command).

+3
source

You can get a fixed version of GLUT, which possibly supports HiDPI from here: http://iihm.imag.fr/blanch/software/glut-macosx/

If you use this GLUT environment, your applications may give up OpenGL context at real screen resolution. You just need to change the display initialization in your code (be it C, Python / PyOpenGL or any thing related to the GLUT map):

 glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE) 

in

 glutInitDisplayString("rgba double hidpi") 

The patch version gracefully handles multiple screens with different storage scaling factors and provides consistent behavior for different functions that expect pixel sizes or sizes (i.e. glutInitWindowSize, glutReshapeWindow, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT) position and glutInitWindowSize, glutReshapeWindow, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT) passed to event callbacks).

This version of GLUT is also fully backward compatible for other applications, which decides to abandon HiDPI support. Patches and instructions for creating the framework themselves are also provided if you prefer to create your own version.

The patch version also adds mouse wheel support if you need it.

+3
source

I think you will have to use some PyObjC bindings to get the NSWindow created by Glut and then the scale factor fiddle. Here is some information about parts of Objective-C: http://supermegaultragroovy.com/2012/10/24/coding-for-high-resolution-on-os-x-read-this/

0
source

All Articles