Compiling shaders in PyQt - python

I can't get a basic shader program working in PyQt. I think this should at least compile the shader code correctly (I'm no expert here), but addShaderFromSourceFile() always returns false no matter what I try. The shader program log is always empty too.
I'm on Ubuntu 12.04, and I can compile and run GLSL shader programs in C++. So I don't think it's a system issue.
File shader.vert
void main(void)
{
gl_Position = ftransform();
}
File shader.frag
void main(void)
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
File test_shaders.py
from OpenGL.GL import *
from OpenGL.GLU import *
from PyQt4 import QtCore, QtGui
from PyQt4.QtOpenGL import *
class ExampleQGLWidget(QGLWidget):
def __init__(self, parent):
QGLWidget.__init__(self, parent)
self.shaderProgram = QGLShaderProgram()
print self.shaderProgram.addShaderFromSourceFile(QGLShader.Vertex, "shader.vert")
print self.shaderProgram.addShaderFromSourceFile(QGLShader.Fragment, "shader.frag")
print self.shaderProgram.log()
self.shaderProgram.link()
glViewport(0,0, 640, 480)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.shaderProgram.bind()
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 1.0)
glClearDepth(1.0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
class TestContainer(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
widget = ExampleQGLWidget(self)
self.setCentralWidget(widget)
if __name__ == '__main__':
app = QtGui.QApplication(['Shader Example'])
window = TestContainer()
window.show()
app.exec_()

The OpenGL context isn't setup inside the constructor, it's only valid and current inside the paintGL, resizeGL and initializeGL methods, so you should load and compile shaders inside the initializeGL method, and not anywhere else.

I believe that the other answer may be outdated now. There is, at least since PyQt5, a way to make the widgets OpenGL context current (and to clean up afterwards).
It can be achieved with the makeCurrent() and currentDone() methods on the QGlWidget.
A solution would look like:
...
class ExampleQGLWidget(QGLWidget):
def __init__(self, parent):
QGLWidget.__init__(self, parent)
self.shaderProgram = QGLShaderProgram()
self.makeCurrent()
print self.shaderProgram.addShaderFromSourceFile(QGLShader.Vertex, "shader.vert")
print self.shaderProgram.addShaderFromSourceFile(QGLShader.Fragment, "shader.frag")
print self.shaderProgram.log()
self.shaderProgram.link()
self.doneCurrent()
glViewport(0,0, 640, 480)
...

Related

How to achieve Rounded corners for QMenu in pyqt5? [duplicate]

I am trying to override the paintEvent() of QMenu to make it have rounded corners.
The context menu should look something like this.
Here is the code I have tried But nothing appears:
from PyQt5 import QtWidgets, QtGui, QtCore
import sys
class Example(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Context menu')
self.show()
def contextMenuEvent(self, event):
cmenu = AddContextMenu(self)
newAct = cmenu.addAction("New")
openAct = cmenu.addAction("Open")
quitAct = cmenu.addAction("Quit")
action = cmenu.exec_(self.mapToGlobal(event.pos()))
class AddContextMenu(QtWidgets.QMenu):
def __init__(self, *args, **kwargs):
super(AddContextMenu, self).__init__()
self.painter = QtGui.QPainter(self)
self.setMinimumSize(150, 200)
self.pen = QtGui.QPen(QtCore.Qt.red)
#self.setStyleSheet('color:white; background:gray; border-radius:4px; border:2px solid white;')
def paintEvent(self, event) -> None:
self.pen.setWidth(2)
self.painter.setPen(self.pen)
self.painter.setBrush(QtGui.QBrush(QtCore.Qt.blue))
self.painter.drawRoundedRect(10, 10, 100, 100, 4.0, 4.0)
self.update()
#self.repaint()
#super(AddContextMenu, self).paintEvent(event)
def main():
app = QtWidgets.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Note: setting a style sheet doesn't work for me:
this is what I get when using the style sheet It isn't completely rounded.
This is the paintEvent after #musicamante suggestion(This is just for him/her to check)
def paintEvent(self, event) -> None:
painter = QtGui.QPainter(self)
#self.pen.setColor(QtCore.Qt.white)
#painter.setFont(QtGui.QFont("times", 22))
#painter.setPen(self.pen)
#painter.drawText(QtCore.QPointF(0, 0), 'Hello')
self.pen.setColor(QtCore.Qt.red)
painter.setPen(self.pen)
painter.setBrush(QtCore.Qt.gray)
painter.drawRoundedRect(self.rect(), 20.0, 20.0)
and in the init()
self.pen = QtGui.QPen(QtCore.Qt.red)
self.pen.setWidth(2)
I cannot comment on the paintEvent functionality, but it is possible to implement rounded corners using style-sheets. Some qmenu attributes have to be modified in order to disable the default rectangle in the background, which gave you the unwanted result.
Here is a modified version of your Example using style-sheets + custom flags (no frame + transparent background):
from PyQt5 import QtWidgets, QtCore
import sys
class Example(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Context menu')
self.show()
def contextMenuEvent(self, event):
cmenu = QtWidgets.QMenu()
# disable default frame and background
cmenu.setWindowFlags(QtCore.Qt.FramelessWindowHint)
cmenu.setAttribute(QtCore.Qt.WA_TranslucentBackground)
# set stylesheet, add some padding to avoid overlap of selection with rounded corner
cmenu.setStyleSheet("""
QMenu{
background-color: rgb(255, 255, 255);
border-radius: 20px;
}
QMenu::item {
background-color: transparent;
padding:3px 20px;
margin:5px 10px;
}
QMenu::item:selected { background-color: gray; }
""")
newAct = cmenu.addAction("New")
openAct = cmenu.addAction("Open")
quitAct = cmenu.addAction("Quit")
action = cmenu.exec_(self.mapToGlobal(event.pos()))
def main():
app = QtWidgets.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Setting the border radius in the stylesheet for a top level widget (a widget that has its own "window") is not enough.
While the solution proposed by Christian Karcher is fine, two important considerations are required:
The system must support compositing; while this is true for most modern OSes, at least on Linux there is the possibility that even an up-to-date system does not support it by choice (I disabled on my computer); if that's the case, setting the WA_TranslucentBackground attribute will not work.
The FramelessWindowHint should not be set on Linux, as it may lead to problems with the window manager, so it should be set only after ensuring that the OS requires it (Windows).
In light of that, using setMask() is the correct fix whenever compositing is not supported, and this has to happen within the resizeEvent(). Do note that masking is bitmap based, and antialiasing is not supported, so rounded borders are sometimes a bit ugly depending on the border radius.
Also, since you want custom colors, using stylesheets is mandatory, as custom painting of a QMenu is really hard to achieve.
class AddContextMenu(QtWidgets.QMenu):
def __init__(self, *args, **kwargs):
super(AddContextMenu, self).__init__()
self.setMinimumSize(150, 200)
self.radius = 4
self.setStyleSheet('''
QMenu {{
background: blue;
border: 2px solid red;
border-radius: {radius}px;
}}
QMenu::item {{
color: white;
}}
QMenu::item:selected {{
color: red;
}}
'''.format(radius=self.radius))
def resizeEvent(self, event):
path = QtGui.QPainterPath()
# the rectangle must be translated and adjusted by 1 pixel in order to
# correctly map the rounded shape
rect = QtCore.QRectF(self.rect()).adjusted(.5, .5, -1.5, -1.5)
path.addRoundedRect(rect, self.radius, self.radius)
# QRegion is bitmap based, so the returned QPolygonF (which uses float
# values must be transformed to an integer based QPolygon
region = QtGui.QRegion(path.toFillPolygon(QtGui.QTransform()).toPolygon())
self.setMask(region)
Some side notes about your paintEvent implementation, not necessary in this specific case for the above reason, but still important (some points are related to portions of code that have been commented, but the fact that you tried them makes worth mentioning those aspects):
The QPainter used for a widget must never be instanciated outside a paintEvent(): creating the instance in the __init__ as you did is a serious error and might even lead to crash. The painter can only be created when the paintEvent is received, and shall never be reused. This clearly makes useless to set it as an instance attribute (self.painter), since there's no actual reason to access it after the paint event.
If the pen width is always the same, then just set it in the constructor (self.pen = QtGui.QPen(QtCore.Qt.red, 2)), continuously setting it in the paintEvent is useless.
QPen and QBrush can directly accept Qt global colors, so there's no need to create a QBrush instance as the painter will automatically (internally and fastly) set it: self.painter.setBrush(QtCore.Qt.blue).
self.update() should never be called within a paintEvent (and not even self.repaint() should). The result in undefined and possibly dangerous.
If you do some manual painting with a QPainter and then call the super paintEvent, the result is most likely that everything painted before will be hidden; as a general rule, the base implementation should be called first, then any other custom painting should happen after (in this case it obviously won't work, as you'll be painting a filled rounded rect, making the menu items invisible).
I have implemented round corners menu using QListWidget and QWidget. You can download the code in https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/menu/demo.py.

Rounded corners for QMenu in pyqt

I am trying to override the paintEvent() of QMenu to make it have rounded corners.
The context menu should look something like this.
Here is the code I have tried But nothing appears:
from PyQt5 import QtWidgets, QtGui, QtCore
import sys
class Example(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Context menu')
self.show()
def contextMenuEvent(self, event):
cmenu = AddContextMenu(self)
newAct = cmenu.addAction("New")
openAct = cmenu.addAction("Open")
quitAct = cmenu.addAction("Quit")
action = cmenu.exec_(self.mapToGlobal(event.pos()))
class AddContextMenu(QtWidgets.QMenu):
def __init__(self, *args, **kwargs):
super(AddContextMenu, self).__init__()
self.painter = QtGui.QPainter(self)
self.setMinimumSize(150, 200)
self.pen = QtGui.QPen(QtCore.Qt.red)
#self.setStyleSheet('color:white; background:gray; border-radius:4px; border:2px solid white;')
def paintEvent(self, event) -> None:
self.pen.setWidth(2)
self.painter.setPen(self.pen)
self.painter.setBrush(QtGui.QBrush(QtCore.Qt.blue))
self.painter.drawRoundedRect(10, 10, 100, 100, 4.0, 4.0)
self.update()
#self.repaint()
#super(AddContextMenu, self).paintEvent(event)
def main():
app = QtWidgets.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Note: setting a style sheet doesn't work for me:
this is what I get when using the style sheet It isn't completely rounded.
This is the paintEvent after #musicamante suggestion(This is just for him/her to check)
def paintEvent(self, event) -> None:
painter = QtGui.QPainter(self)
#self.pen.setColor(QtCore.Qt.white)
#painter.setFont(QtGui.QFont("times", 22))
#painter.setPen(self.pen)
#painter.drawText(QtCore.QPointF(0, 0), 'Hello')
self.pen.setColor(QtCore.Qt.red)
painter.setPen(self.pen)
painter.setBrush(QtCore.Qt.gray)
painter.drawRoundedRect(self.rect(), 20.0, 20.0)
and in the init()
self.pen = QtGui.QPen(QtCore.Qt.red)
self.pen.setWidth(2)
I cannot comment on the paintEvent functionality, but it is possible to implement rounded corners using style-sheets. Some qmenu attributes have to be modified in order to disable the default rectangle in the background, which gave you the unwanted result.
Here is a modified version of your Example using style-sheets + custom flags (no frame + transparent background):
from PyQt5 import QtWidgets, QtCore
import sys
class Example(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Context menu')
self.show()
def contextMenuEvent(self, event):
cmenu = QtWidgets.QMenu()
# disable default frame and background
cmenu.setWindowFlags(QtCore.Qt.FramelessWindowHint)
cmenu.setAttribute(QtCore.Qt.WA_TranslucentBackground)
# set stylesheet, add some padding to avoid overlap of selection with rounded corner
cmenu.setStyleSheet("""
QMenu{
background-color: rgb(255, 255, 255);
border-radius: 20px;
}
QMenu::item {
background-color: transparent;
padding:3px 20px;
margin:5px 10px;
}
QMenu::item:selected { background-color: gray; }
""")
newAct = cmenu.addAction("New")
openAct = cmenu.addAction("Open")
quitAct = cmenu.addAction("Quit")
action = cmenu.exec_(self.mapToGlobal(event.pos()))
def main():
app = QtWidgets.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Setting the border radius in the stylesheet for a top level widget (a widget that has its own "window") is not enough.
While the solution proposed by Christian Karcher is fine, two important considerations are required:
The system must support compositing; while this is true for most modern OSes, at least on Linux there is the possibility that even an up-to-date system does not support it by choice (I disabled on my computer); if that's the case, setting the WA_TranslucentBackground attribute will not work.
The FramelessWindowHint should not be set on Linux, as it may lead to problems with the window manager, so it should be set only after ensuring that the OS requires it (Windows).
In light of that, using setMask() is the correct fix whenever compositing is not supported, and this has to happen within the resizeEvent(). Do note that masking is bitmap based, and antialiasing is not supported, so rounded borders are sometimes a bit ugly depending on the border radius.
Also, since you want custom colors, using stylesheets is mandatory, as custom painting of a QMenu is really hard to achieve.
class AddContextMenu(QtWidgets.QMenu):
def __init__(self, *args, **kwargs):
super(AddContextMenu, self).__init__()
self.setMinimumSize(150, 200)
self.radius = 4
self.setStyleSheet('''
QMenu {{
background: blue;
border: 2px solid red;
border-radius: {radius}px;
}}
QMenu::item {{
color: white;
}}
QMenu::item:selected {{
color: red;
}}
'''.format(radius=self.radius))
def resizeEvent(self, event):
path = QtGui.QPainterPath()
# the rectangle must be translated and adjusted by 1 pixel in order to
# correctly map the rounded shape
rect = QtCore.QRectF(self.rect()).adjusted(.5, .5, -1.5, -1.5)
path.addRoundedRect(rect, self.radius, self.radius)
# QRegion is bitmap based, so the returned QPolygonF (which uses float
# values must be transformed to an integer based QPolygon
region = QtGui.QRegion(path.toFillPolygon(QtGui.QTransform()).toPolygon())
self.setMask(region)
Some side notes about your paintEvent implementation, not necessary in this specific case for the above reason, but still important (some points are related to portions of code that have been commented, but the fact that you tried them makes worth mentioning those aspects):
The QPainter used for a widget must never be instanciated outside a paintEvent(): creating the instance in the __init__ as you did is a serious error and might even lead to crash. The painter can only be created when the paintEvent is received, and shall never be reused. This clearly makes useless to set it as an instance attribute (self.painter), since there's no actual reason to access it after the paint event.
If the pen width is always the same, then just set it in the constructor (self.pen = QtGui.QPen(QtCore.Qt.red, 2)), continuously setting it in the paintEvent is useless.
QPen and QBrush can directly accept Qt global colors, so there's no need to create a QBrush instance as the painter will automatically (internally and fastly) set it: self.painter.setBrush(QtCore.Qt.blue).
self.update() should never be called within a paintEvent (and not even self.repaint() should). The result in undefined and possibly dangerous.
If you do some manual painting with a QPainter and then call the super paintEvent, the result is most likely that everything painted before will be hidden; as a general rule, the base implementation should be called first, then any other custom painting should happen after (in this case it obviously won't work, as you'll be painting a filled rounded rect, making the menu items invisible).
I have implemented round corners menu using QListWidget and QWidget. You can download the code in https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/menu/demo.py.

pyglet: on_resize breaks graphics

I'm writing an application with pyglet where all rendered objects are children of the window class. I'm trying to draw a simple rectangle, but using on_resize seems to break everything. There's no error message, it just doesn't draw the rectangle.
This is my file structure:
main.py
lib
|-- window.py
|-- quad.py
This code doesn't work, but if I remove the on_resize methods it does:
-------------
FILE: main.py
-------------
import pyglet
import lib
window = lib.window.Window(1280, 720)
window.add_object(lib.quad.Quad())
pyglet.app.run()
-------------------
FILE: lib/window.py
-------------------
import pyglet
from . import quad
class Window(pyglet.window.Window):
def __init__(self, w, h):
super().__init__(width=w, height=h)
self.objects = []
def on_draw(self):
for obj in self.objects:
obj.on_draw()
def on_resize(self, width, height):
for obj in self.objects:
obj.on_resize(width, height)
def add_object(self, obj):
self.objects.extend([obj])
-------------
FILE: lib/quad.py
-------------
import pyglet
import pyglet.gl
class Quad():
def __init__(self):
self.quad = pyglet.graphics.vertex_list(4, ('v2i', (10, 10, 100, 10, 100, 100, 10, 100)), ('c3B', (0, 0, 255, 0, 0, 255, 0, 255, 0, 0, 255, 0)))
def on_draw(self):
self.quad.draw(pyglet.gl.GL_QUADS)
def on_resize(self, width, height):
pass
I would like to be able to keep rendered objects as children of the window class, since that makes running event handlers much easier. Is there any way that I can make this work with the on_resize handler? Any help is appreciated.
EDIT: I tried removing on_resize from the Quad class, and making on_resize do nothing in the Window class. It seems like the existence of the on_resize function is the issue--if on_resize exists, pyglet wont draw the rectangle.
The problem is by subclassing Window, (MyWindow in this case), when you define an on_resize() event handler, you are replacing the inherited handler with your own. What you want to do instead is to push your on_resize() handler onto the event handling stack so that both handlers get called. You want to do the same some for of the others like on_close(). Example:
class MyWindow(pyglet.window.Window):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_minimum_size(400, 300)
#
# Push your handler onto the on_resize handler stack
#
self.push_handlers(on_resize=self.local_on_resize)
def local_on_resize(self, x, y):
# Do stuff
def on_draw(self):
self.clear()
self.triangle.draw()
Note that you can reproduce the failure by having your local_on_resize() handler return a value of pyglet.event.EVENT_HANDLED, (which will stop processing of the remaining handlers), and the graphics won't render.
In the on_resize method add the glViewport function call. And also don't forget to set up an orthogonal projection. Take a look at my code, it draws a triangle at the center of the screen.
from pyglet.gl import *
class Triangle:
def __init__(self):
self.vertices = pyglet.graphics.vertex_list(3, ('v3f', [0,0,0, 300,0,0, 150,300,0]),
('c3B', [255,0,0, 0,255,0, 0,0,255]))
def draw(self):
self.vertices.draw(GL_TRIANGLES)
class MyWindow(pyglet.window.Window):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_minimum_size(400, 300)
glClearColor(0.2, 0.25, 0.2, 1.0)
glOrtho(0, 1280, 0, 720, -10, 10) # setup orthogonal projection
self.triangle = Triangle()
def on_draw(self):
self.clear()
glPushMatrix()
glTranslatef(640-150 ,360-150, 0) # translate the Triangle to the center
self.triangle.draw()
glPopMatrix()
def on_resize(self, width, height):
glViewport(0, 0, width, height) # resize the viewport
if __name__ == "__main__":
MyWindow(1280, 720, 'My window', resizable=True)
pyglet.app.run()

Python multithread does not work with OpenGL

I have a basic OpenGL square drawing code that I want to put another thread using Python. This is the normal code which is working well,
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GLU import *
class Drawer:
def drawQuad(self, x,y,width):
halfW=width/2
glBegin(GL_QUADS)
glVertex3f(x-halfW, y-halfW, 0)
glVertex3f(x-halfW, y+halfW, 0)
glVertex3f(x+halfW, y+halfW, 0)
glVertex3f(x+halfW, y-halfW, 0)
glEnd()
def display(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glColor3f(0, 0, 1)
self.drawQuad(0.0,0.0,0.6)
glutSwapBuffers( )
class Visualizer:
drawer = Drawer()
def __init__(self):
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
glutInitWindowSize(250, 250)
glutInitWindowPosition(100, 100)
glutCreateWindow(sys.argv[0])
glutDisplayFunc( self.drawer.display )
glClearColor ( 0, 0, 0, 0 )
glShadeModel( GL_SMOOTH )
glutMainLoop()
visualizer = Visualizer()
This works on my machine flawlessly. Now, I want to put this on a thread. I did the following,
class Thread(threading.Thread):
visualizer = None
def run(self):
self.visualizer = Visualizer()
thread = Thread()
thread.start()
When I run the thread, instead of visualizer itself, it does not work. The OpenGL window does not appear. I cannot see what the problem is.
I tried the threading with some other examples, they seemed working well. I am confused a bit. What is the problem with my threading approach for OpenGL?

glx opengl gtk python and alpha channels / blending

I have the example code below, simplified from a larger project. I have been trying to make alpha channels work i have enabled blending and written a similar example using pygame which works. How ever setting up opengl to work with a glx context seems to stop blending from working, i have a feeling i need to enabel some parameter to the gl context setup but have not been able to find out what that parameter is.
Any suggestions on why this is not working, i have tried on two different machines one with high end radeon and another with an intel graphics card both do the same however.
#blending is not working any ideas why ?
import sys
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL import GLX
from OpenGL.raw._GLX import struct__XDisplay
from OpenGL import GL
from ctypes import *
import Xlib
from Xlib.display import Display
from gi.repository import Gtk, GdkX11, Gdk
class gtkgl:
""" these method do not seem to exist in python x11 library lets exploit the c methods """
xlib = cdll.LoadLibrary('libX11.so')
xlib.XOpenDisplay.argtypes = [c_char_p]
xlib.XOpenDisplay.restype = POINTER(struct__XDisplay)
xdisplay = xlib.XOpenDisplay("")
display = Xlib.display.Display()
attrs = []
xwindow_id = None
width = height = 200
def __init__(self):
""" lets setup are opengl settings and create the context for our window """
self.add_attribute(GLX.GLX_RGBA, True)
self.add_attribute(GLX.GLX_RED_SIZE, 1)
self.add_attribute(GLX.GLX_GREEN_SIZE, 1)
self.add_attribute(GLX.GLX_BLUE_SIZE, 1)
self.add_attribute(GLX.GLX_ALPHA_SIZE, 1)
self.add_attribute(GLX.GLX_DOUBLEBUFFER, 0)
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glShadeModel(GL_SMOOTH)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glLight(GL_LIGHT0, GL_POSITION, (0, 1, 1, 0))
xvinfo = GLX.glXChooseVisual(self.xdisplay, self.display.get_default_screen(), self.get_attributes())
configs = GLX.glXChooseFBConfig(self.xdisplay, 0, None, byref(c_int()))
self.context = GLX.glXCreateContext(self.xdisplay, xvinfo, None, True)
def add_attribute(self, setting, value):
"""just to nicely add opengl parameters"""
self.attrs.append(setting)
self.attrs.append(value)
def get_attributes(self):
""" return our parameters in the expected structure"""
attrs = self.attrs + [0, 0]
return (c_int * len(attrs))(*attrs)
def configure(self, wid):
""" """
self.xwindow_id = GdkX11.X11Window.get_xid(wid)
if(not GLX.glXMakeCurrent(self.xdisplay, self.xwindow_id, self.context)):
print 'failed'
glViewport(0, 0, self.width, self.height)
def draw_start(self):
"""make cairo context current for drawing"""
if(not GLX.glXMakeCurrent(self.xdisplay, self.xwindow_id, self.context)):
print "failed"
def draw_finish(self):
"""swap buffer when we have finished drawing"""
GLX.glXSwapBuffers(self.xdisplay, self.xwindow_id)
def test(self):
"""Test method to draw something so we can make sure opengl is working and we can see something"""
self.draw_start()
glClearColor(0.0, 0.0, 0.0, 0.0)
glClear(GL_COLOR_BUFFER_BIT)
glBegin(GL_TRIANGLES)
glIndexi(0)
glColor4f(1.0, 0.0, 0.0, 0.2)
glVertex2i(0, 1)
glIndexi(0)
glColor4f(0.0, 1.0, 0.0, 0.2)
glVertex2i(-1, -1)
glIndexi(0)
glColor4f(0.0, 0.0, 1.0, 1.0)
glVertex2i(1, -1)
glEnd()
self.draw_finish()
class gui():
glwrap = gtkgl()
def __init__(self):
self.window = Gtk.Window()
self.window.realize()
self.window.resize(self.glwrap.width, self.glwrap.height)
self.window.set_resizable(True)
self.window.set_reallocate_redraws(True)
self.window.set_title("GTK3 with opengl")
self.window.connect('delete_event', Gtk.main_quit)
self.window.connect('destroy', lambda quit: Gtk.main_quit())
self.drawing_area = Gtk.DrawingArea()
self.drawing_area.connect('configure_event', self.on_configure_event)
self.drawing_area.connect('draw', self.on_draw)
self.drawing_area.set_double_buffered(False)
self.drawing_area.set_size_request(self.glwrap.width, self.glwrap.height)
self.window.add(self.drawing_area)
self.window.show_all()
def on_configure_event(self, widget, event):
self.glwrap.configure(widget.get_window())
return True
def on_draw(self, widget, context):
self.glwrap.test()
def main():
g = gui()
Gtk.main()
if __name__ == '__main__':
main()
It's not the OpenGL context missing something (at the point of creation I mean). You're simply not enabling blending. You need to add a glEnable(GL_BLEND); before drawing primitives that require blending.
BTW: Using 1 bit as minimum requirement for RGB channels can yield to undesired results. Use at least 5 bits (for 16 bit displays) or better yet 8 bits. Also you don't need an alpha channel on the main framebuffer for blending to work. So unless you want to create transparent windows on a compositor, then you should use 0 alpha bits on the window's framebuffer.

Categories

Resources