Skip to content

Commit c95ae49

Browse files
authored
Merge pull request #9 from einarf/package-refactor
Convert into a proper package
2 parents 0fde710 + 1109148 commit c95ae49

File tree

8 files changed

+727
-711
lines changed

8 files changed

+727
-711
lines changed

pyopengltk.py

Lines changed: 0 additions & 708 deletions
This file was deleted.

pyopengltk/__init__.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# An opengl frame for pyopengl-tkinter based on ctypes (no togl compilation)
2+
#
3+
# Collected together by Jon Wright, Jan 2018.
4+
#
5+
# Based on the work of others:
6+
#
7+
# C + Tcl/Tk
8+
# http://github.com/codeplea/opengl-tcltk/
9+
# (zlib license)
10+
# Article at:
11+
# https://codeplea.com/opengl-with-c-and-tcl-tk
12+
#
13+
# Python + Tkinter (no pyopengl)
14+
# http://github.com/arcanosam/pytkogl/
15+
# (The Code Project Open License)
16+
# Article at
17+
# http://www.codeproject.com/Articles/1073475/OpenGL-in-Python-with-TKinter
18+
#
19+
# Large parts copied from pyopengl/Tk/__init__.py
20+
import sys
21+
22+
# Platform specific frames
23+
if sys.platform.startswith('linux'):
24+
from pyopengltk.linux import OpenGLFrame
25+
26+
if sys.platform.startswith('win32'):
27+
from pyopengltk.win32 import OpenGLFrame
28+
29+
# if sys.platform.startswith('darwin'):
30+
# from pyopengltk.darwin import OpenGLFrame
31+
32+
# opengl
33+
from pyopengltk.opengl import RawOpengl
34+
from pyopengltk.opengl import Opengl
35+
from pyopengltk.opengl import glTranslateScene
36+
from pyopengltk.opengl import glRotateScene
37+
from pyopengltk.opengl import v3distsq

pyopengltk/base.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import sys
2+
from OpenGL import GL
3+
4+
if sys.version_info[0] < 3:
5+
import Tkinter as tk
6+
import Dialog as dialog
7+
else:
8+
import tkinter as tk
9+
from tkinter import dialog as dialog
10+
11+
12+
class BaseOpenGLFrame(tk.Frame):
13+
""" Common code for windows/x11 """
14+
def __init__(self, *args, **kw):
15+
# Set background to empty string to avoid
16+
# flickering overdraw by Tk
17+
kw['bg'] = ""
18+
tk.Frame.__init__(self, *args, **kw)
19+
self.bind('<Map>', self.tkMap)
20+
self.bind('<Configure>', self.tkResize)
21+
self.bind('<Expose>', self.tkExpose)
22+
self.animate = 0
23+
self.cb = None
24+
25+
def tkMap(self, evt):
26+
"""" Called when frame goes onto the screen """
27+
self._wid = self.winfo_id()
28+
self.tkCreateContext()
29+
self.initgl()
30+
31+
def printContext(self, extns=False):
32+
""" For debugging """
33+
exts = GL.glGetString(GL.GL_EXTENSIONS)
34+
if extns:
35+
print("Extension list:")
36+
for e in sorted(exts.split()):
37+
print("\t", e)
38+
else:
39+
print("Number of extensions:", len(exts.split()))
40+
41+
print("GL_VENDOR :", GL.glGetString(GL.GL_VENDOR))
42+
print("GL_RENDERER:", GL.glGetString(GL.GL_RENDERER))
43+
print("GL_VERSION :", GL.glGetString(GL.GL_VERSION))
44+
try:
45+
print(" GL_MAJOR_VERSION:", GL.glGetIntegerv(GL.GL_MAJOR_VERSION))
46+
print(" GL_MINOR_VERSION:", GL.glGetIntegerv(GL.GL_MINOR_VERSION))
47+
print(" GL_SHADING_LANGUAGE_VERSION :",
48+
GL.glGetString(GL.GL_SHADING_LANGUAGE_VERSION))
49+
msk = GL.glGetIntegerv(GL.GL_CONTEXT_PROFILE_MASK)
50+
print(" GL_CONTEXT_CORE_PROFILE_BIT :",
51+
bool(msk & GL.GL_CONTEXT_CORE_PROFILE_BIT))
52+
print(" GL_CONTEXT_COMPATIBILITY_PROFILE_BIT :",
53+
bool(msk & GL.GL_CONTEXT_COMPATIBILITY_PROFILE_BIT))
54+
except:
55+
print("Old context errors arose")
56+
# raise
57+
58+
def tkCreateContext(self):
59+
# Platform dependent part
60+
raise NotImplementedError
61+
62+
def tkMakeCurrent(self):
63+
# Platform dependent part
64+
raise NotImplementedError
65+
66+
def tkSwapBuffers(self):
67+
# Platform dependent part
68+
raise NotImplementedError
69+
70+
def tkExpose(self, evt):
71+
if self.cb:
72+
self.after_cancel(self.cb)
73+
self._display()
74+
75+
def tkResize(self, evt):
76+
"""
77+
Things to do on window resize:
78+
Adjust viewport:
79+
glViewPort(0,0, width, height)
80+
Adjust projection matrix:
81+
glFrustum(left * ratio, right * ratio, bottom, top, nearClip,farClip)
82+
or
83+
glOrtho(left * ratio, right * ratio, bottom, top, nearClip,farClip)
84+
or
85+
gluOrtho2D(left * ratio, right * ratio, bottom, top)
86+
(assuming that left, right, bottom and top are all equal and
87+
ratio=width/height)
88+
"""
89+
self.width, self.height = evt.width, evt.height
90+
if self.winfo_ismapped():
91+
GL.glViewport(0, 0, self.width, self.height)
92+
self.initgl()
93+
94+
def _display(self):
95+
self.update_idletasks()
96+
self.tkMakeCurrent()
97+
self.redraw()
98+
self.tkSwapBuffers()
99+
if self.animate > 0:
100+
self.cb = self.after(self.animate, self._display)
101+
102+
def initgl(self):
103+
# For the user code
104+
raise NotImplementedError
105+
106+
def redraw(self):
107+
# For the user code
108+
raise NotImplementedError

pyopengltk/darwin.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Currently not implemented"""

pyopengltk/linux.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"""
2+
Linux implementation of the opengl frame
3+
"""
4+
from __future__ import print_function
5+
import logging
6+
from ctypes import c_int, c_char_p, c_void_p, cdll, POINTER, util, \
7+
pointer, CFUNCTYPE, c_bool
8+
from OpenGL import GL, GLX
9+
from pyopengltk.base import BaseOpenGLFrame
10+
11+
try:
12+
from OpenGL.raw._GLX import Display
13+
except:
14+
from OpenGL.raw.GLX._types import Display
15+
16+
_log = logging.getLogger(__name__)
17+
18+
19+
_x11lib = cdll.LoadLibrary(util.find_library("X11"))
20+
XOpenDisplay = _x11lib.XOpenDisplay
21+
XOpenDisplay.argtypes = [c_char_p]
22+
XOpenDisplay.restype = POINTER(Display)
23+
24+
Colormap = c_void_p
25+
# Attributes for old style creation
26+
att = [
27+
GLX.GLX_RGBA, GLX.GLX_DOUBLEBUFFER,
28+
GLX.GLX_RED_SIZE, 4,
29+
GLX.GLX_GREEN_SIZE, 4,
30+
GLX.GLX_BLUE_SIZE, 4,
31+
GLX.GLX_DEPTH_SIZE, 16,
32+
0,
33+
]
34+
# Attributes for newer style creations
35+
fbatt = [
36+
GLX.GLX_X_RENDERABLE, 1,
37+
GLX.GLX_DRAWABLE_TYPE, GLX.GLX_WINDOW_BIT,
38+
GLX.GLX_RENDER_TYPE, GLX.GLX_RGBA_BIT,
39+
GLX.GLX_RED_SIZE, 1,
40+
GLX.GLX_GREEN_SIZE, 1,
41+
GLX.GLX_BLUE_SIZE, 1,
42+
GLX.GLX_DOUBLEBUFFER, 1,
43+
0,
44+
]
45+
46+
47+
# Inherits the base and fills in the 3 platform dependent functions
48+
class OpenGLFrame(BaseOpenGLFrame):
49+
50+
def tkCreateContext(self):
51+
self.__window = XOpenDisplay(self.winfo_screen().encode('utf-8'))
52+
# Check glx version:
53+
major = c_int(0)
54+
minor = c_int(0)
55+
GLX.glXQueryVersion(self.__window, major, minor)
56+
print("GLX version: %d.%d" % (major.value, minor.value))
57+
if major.value == 1 and minor.value < 3: # e.g. 1.2 and down
58+
visual = GLX.glXChooseVisual(self.__window, 0, (GL.GLint * len(att))(* att))
59+
if not visual:
60+
_log.error("glXChooseVisual call failed")
61+
self.__context = GLX.glXCreateContext(self.__window,
62+
visual,
63+
None,
64+
GL.GL_TRUE)
65+
GLX.glXMakeCurrent(self.__window, self._wid, self.__context)
66+
return # OUT HERE FOR 1.2 and less
67+
else:
68+
# 1.3 or higher
69+
# which screen - should it be winfo_screen instead ??
70+
XDefaultScreen = _x11lib.XDefaultScreen
71+
XDefaultScreen.argtypes = [POINTER(Display)]
72+
XDefaultScreen.restype = c_int
73+
screen = XDefaultScreen(self.__window)
74+
print("Screen is ", screen)
75+
# Look at framebuffer configs
76+
ncfg = GL.GLint(0)
77+
cfgs = GLX.glXChooseFBConfig(
78+
self.__window,
79+
screen,
80+
(GL.GLint * len(fbatt))(* fbatt),
81+
ncfg,
82+
)
83+
print("Number of FBconfigs", ncfg.value)
84+
#
85+
# Try to match to the current window
86+
# ... might also be possible to set this for the frame
87+
# ... but for now we just take what Tk gave us
88+
ideal = int(self.winfo_visualid(), 16) # convert from hex
89+
best = -1
90+
for i in range(ncfg.value):
91+
vis = GLX.glXGetVisualFromFBConfig(self.__window, cfgs[i])
92+
if ideal == vis.contents.visualid:
93+
best = i
94+
print("Got a matching visual: index %d %d xid %s" % (
95+
best, vis.contents.visualid, hex(ideal)))
96+
if best < 0:
97+
print("oh dear - visual does not match")
98+
# Take the first in the list (should be another I guess)
99+
best = 0
100+
# Here we insist on RGBA - but didn't check earlier
101+
self.__context = GLX.glXCreateNewContext(
102+
self.__window,
103+
cfgs[best],
104+
GLX.GLX_RGBA_TYPE,
105+
None, # share list
106+
GL.GL_TRUE, # direct
107+
)
108+
print("Is Direct?: ", GLX.glXIsDirect(self.__window, self.__context))
109+
# Not creating another window ... some tutorials do
110+
# print("wid: ", self._wid)
111+
# self._wid = GLX.glXCreateWindow(self.__window, cfgs[best], self._wid, None)
112+
# print("wid: ", self._wid)
113+
GLX.glXMakeContextCurrent(self.__window, self._wid, self._wid, self.__context)
114+
print("Done making a first context")
115+
extensions = GLX.glXQueryExtensionsString(self.__window, screen)
116+
# Here we quit - getting a modern context needs further work below
117+
return
118+
if "GLX_ARB_create_context" in extensions:
119+
# We can try to upgrade it ??
120+
print("Trying to upgrade context")
121+
s = "glXCreateContextAttribsARB"
122+
p = GLX.glXGetProcAddress(c_char_p(s))
123+
124+
print(p)
125+
if not p:
126+
p = GLX.glXGetProcAddressARB((GL.GLubyte * len(s)).from_buffer_copy(s))
127+
print(p)
128+
if p:
129+
print(" p is true")
130+
p.restype = GLX.GLXContext
131+
p.argtypes = [
132+
POINTER(Display),
133+
GLX.GLXFBConfig,
134+
GLX.GLXContext,
135+
c_bool,
136+
POINTER(c_int),
137+
]
138+
arb_attrs = fbatt[:-1] + []
139+
140+
# GLX.GLX_CONTEXT_MAJOR_VERSION_ARB , 3
141+
# GLX.GLX_CONTEXT_MINOR_VERSION_ARB , 1,
142+
# 0 ]
143+
#
144+
# GLX.GLX_CONTEXT_FLAGS_ARB
145+
# GLX.GLX_CONTEXT_PROFILE_MASK_ARB
146+
# ]
147+
# import pdb
148+
# pdb.set_trace()
149+
self.__context = p(
150+
self.__window, cfgs[best], None, GL.GL_TRUE,
151+
(GL.GLint * len(arb_attrs))(* arb_attrs),
152+
)
153+
154+
def tkMakeCurrent(self):
155+
if self.winfo_ismapped():
156+
GLX.glXMakeCurrent(self.__window, self._wid, self.__context)
157+
158+
def tkSwapBuffers(self):
159+
if self.winfo_ismapped():
160+
GLX.glXSwapBuffers(self.__window, self._wid)

0 commit comments

Comments
 (0)