From a811f20cdad1a63b16d4a3f9349ae88ff9f8c6d6 Mon Sep 17 00:00:00 2001 From: Metallicow Date: Thu, 1 Oct 2020 00:15:01 -0500 Subject: [PATCH 1/2] Fix GLCanvas Demo Add a bit more example to the cube and the cone. Made note to DO NOT USE glut. It is old. Folks seem to always have hard time figuring out how to load images. Added image texturing example. Also changed cone to meshmode. --- demo/GLCanvas.py | 193 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 146 insertions(+), 47 deletions(-) diff --git a/demo/GLCanvas.py b/demo/GLCanvas.py index 7c158b28..b69308f8 100644 --- a/demo/GLCanvas.py +++ b/demo/GLCanvas.py @@ -1,7 +1,10 @@ #!/usr/bin/env python -import wx +import os import sys +from math import pi, sin, cos + +import wx try: from wx import glcanvas @@ -13,11 +16,17 @@ try: # The Python OpenGL package can be found at # http://PyOpenGL.sourceforge.net/ from OpenGL.GL import * - from OpenGL.GLUT import * + from OpenGL.GLU import * + #### OpenGL.GLUT Very old, DO NOT USE! haveOpenGL = True except ImportError: haveOpenGL = False +## try: +## from PIL import Image +## havePIL = True +## except ImportError: +## havePIL = False #---------------------------------------------------------------------- @@ -28,7 +37,7 @@ buttonDefs = { class ButtonPanel(wx.Panel): def __init__(self, parent, log): - wx.Panel.__init__(self, parent, -1) + wx.Panel.__init__(self, parent, wx.ID_ANY) self.log = log box = wx.BoxSizer(wx.VERTICAL) @@ -37,14 +46,14 @@ class ButtonPanel(wx.Panel): for k in keys: text = buttonDefs[k][1] btn = wx.Button(self, k, text) - box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 15) + box.Add(btn, 0, wx.ALIGN_CENTER | wx.ALL, 15) self.Bind(wx.EVT_BUTTON, self.OnButton, btn) - #** Enable this to show putting a GLCanvas on the wx.Panel + #** Enable this to show putting a GLCanvas on the wx.Panel . if 0: c = CubeCanvas(self) c.SetSize((200, 200)) - box.Add(c, 0, wx.ALIGN_CENTER|wx.ALL, 15) + box.Add(c, 0, wx.ALIGN_CENTER | wx.ALL, 15) self.SetAutoLayout(True) self.SetSizer(box) @@ -62,6 +71,7 @@ class ButtonPanel(wx.Panel): dlg = wx.MessageDialog(self, 'The OpenGL package was not found. You can get it at\n' 'http://PyOpenGL.sourceforge.net/', + '/nor $ pip install PyOpenGL PyOpenGL_accelerate', 'Sorry', wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy() @@ -69,7 +79,7 @@ class ButtonPanel(wx.Panel): else: canvasClassName = buttonDefs[evt.GetId()][0] canvasClass = eval(canvasClassName) - frame = wx.Frame(None, -1, canvasClassName, size=(400,400)) + frame = wx.Frame(None, wx.ID_ANY, canvasClassName, size=(400, 400)) canvas = canvasClass(frame) frame.Show(True) @@ -80,7 +90,7 @@ class MyCanvasBase(glcanvas.GLCanvas): self.init = False self.context = glcanvas.GLContext(self) - # initial mouse position + # Initial mouse position. self.lastx = self.x = 30 self.lasty = self.y = 30 self.size = None @@ -93,20 +103,17 @@ class MyCanvasBase(glcanvas.GLCanvas): def OnEraseBackground(self, event): - pass # Do nothing, to avoid flashing on MSW. - + pass # Do nothing, to avoid flashing on MSW. def OnSize(self, event): wx.CallAfter(self.DoSetViewport) event.Skip() - def DoSetViewport(self): size = self.size = self.GetClientSize() * self.GetContentScaleFactor() self.SetCurrent(self.context) glViewport(0, 0, size.width, size.height) - def OnPaint(self, event): dc = wx.PaintDC(self) self.SetCurrent(self.context) @@ -115,34 +122,79 @@ class MyCanvasBase(glcanvas.GLCanvas): self.init = True self.OnDraw() - - def OnMouseDown(self, evt): + def OnMouseDown(self, event): + if self.HasCapture(): + self.ReleaseMouse() self.CaptureMouse() - self.x, self.y = self.lastx, self.lasty = evt.GetPosition() + self.x, self.y = self.lastx, self.lasty = event.GetPosition() + def OnMouseUp(self, event): + if self.HasCapture(): + self.ReleaseMouse() - def OnMouseUp(self, evt): - self.ReleaseMouse() - - - def OnMouseMotion(self, evt): - if evt.Dragging() and evt.LeftIsDown(): + def OnMouseMotion(self, event): + if event.Dragging() and event.LeftIsDown(): self.lastx, self.lasty = self.x, self.y - self.x, self.y = evt.GetPosition() + self.x, self.y = event.GetPosition() self.Refresh(False) +def ReadTexture(filename): + # Load texture with PIL/PILLOW. RGBA png seems to load fine with pillow. + ## with Image.open(filename) as img: + ## imgWidth, imgHeight = img.size + ## img_data = img.tobytes("raw", "RGB", 0, -1) + + # Load texture with wxPython. + # Hmmm this seems to be wrong channel order or something for wx.Image + # with png alpha when using RGBA. Oh well. We will send jpg Robin instead. + img = wx.Image(filename) + ## if not img.HasAlpha(): + ## img.InitAlpha() + imgWidth, imgHeight = img.GetSize() + img_data = bytes(img.GetData()) + return (imgWidth, imgHeight, img_data) + +def GenerateTexture(imgWidth, imgHeight, img_data): + textureID = glGenTextures(1) + glPixelStorei(GL_UNPACK_ALIGNMENT, 1) + glBindTexture(GL_TEXTURE_2D, textureID) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + + # https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml + target = GL_TEXTURE_2D + level = 0 + internalformat = GL_RGB # GL_RGBA + width = imgWidth + height = imgHeight + border = 0 + format = GL_RGB # GL_RGBA + type = GL_UNSIGNED_BYTE + data = img_data + glTexImage2D(target, level, internalformat, width, height, border, format, type, data) + # https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTexEnv.xml + target = GL_TEXTURE_ENV + pname = GL_TEXTURE_ENV_MODE + params = GL_MODULATE + glTexEnvf(target, pname, params) + return textureID + + class CubeCanvas(MyCanvasBase): def InitGL(self): - # set viewing projection + # Set viewing projection. glMatrixMode(GL_PROJECTION) glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0) - # position viewer + # Position viewer. glMatrixMode(GL_MODELVIEW) glTranslatef(0.0, 0.0, -2.0) - # position object + # Position object. glRotatef(self.y, 1.0, 0.0, 0.0) glRotatef(self.x, 0.0, 1.0, 0.0) @@ -150,18 +202,24 @@ class CubeCanvas(MyCanvasBase): glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) + self.textureID = None + path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'bmp_source')) + rd = 'robin.jpg' + if os.path.exists(os.path.join(path, rd)): + self.textureID = GenerateTexture(*ReadTexture(os.path.join(path, rd))) + def OnDraw(self): - # clear color and depth buffers + # Clear color and depth buffers. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - # draw six faces of a cube + # Draw six faces of a cube. glBegin(GL_QUADS) - glNormal3f( 0.0, 0.0, 1.0) - glVertex3f( 0.5, 0.5, 0.5) - glVertex3f(-0.5, 0.5, 0.5) - glVertex3f(-0.5,-0.5, 0.5) - glVertex3f( 0.5,-0.5, 0.5) + ## glNormal3f( 0.0, 0.0, 1.0) + ## glVertex3f( 0.5, 0.5, 0.5) + ## glVertex3f(-0.5, 0.5, 0.5) + ## glVertex3f(-0.5,-0.5, 0.5) + ## glVertex3f( 0.5,-0.5, 0.5) glNormal3f( 0.0, 0.0,-1.0) glVertex3f(-0.5,-0.5,-0.5) @@ -194,6 +252,21 @@ class CubeCanvas(MyCanvasBase): glVertex3f(-0.5, 0.5,-0.5) glEnd() + if self.textureID: + glEnable(GL_TEXTURE_2D) + ## glBindTexture(GL_TEXTURE_2D, self.textureID) + glBegin(GL_QUADS) + glNormal3f( 0.0, 0.0, 1.0) + glTexCoord2f(0.0, 0.0) + glVertex3fv((0.5, 0.5, 0.5)) + glTexCoord2f(1.0, 0.0) + glVertex3fv((-0.5, 0.5, 0.5)) + glTexCoord2f(1.0, 1.0) + glVertex3fv((-0.5,-0.5, 0.5)) + glTexCoord2f(0.0, 1.0) + glVertex3fv((0.5,-0.5, 0.5)) + glEnd() + if self.size is None: self.size = self.GetClientSize() w, h = self.size @@ -210,7 +283,7 @@ class CubeCanvas(MyCanvasBase): class ConeCanvas(MyCanvasBase): def InitGL( self ): glMatrixMode(GL_PROJECTION) - # camera frustrum setup + # Camera frustrum setup. glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0) glMaterial(GL_FRONT, GL_AMBIENT, [0.2, 0.2, 0.2, 1.0]) glMaterial(GL_FRONT, GL_DIFFUSE, [0.8, 0.8, 0.8, 1.0]) @@ -226,35 +299,64 @@ class ConeCanvas(MyCanvasBase): glDepthFunc(GL_LESS) glEnable(GL_DEPTH_TEST) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - # position viewer + # Position viewer. glMatrixMode(GL_MODELVIEW) - # position viewer + # Position viewer. glTranslatef(0.0, 0.0, -2.0); - # - glutInit(sys.argv) def OnDraw(self): - # clear color and depth buffers + # Clear color and depth buffers. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - # use a fresh transformation matrix + # Use a fresh transformation matrix. glPushMatrix() - # position object - #glTranslate(0.0, 0.0, -2.0) + # Position object. + ## glTranslate(0.0, 0.0, -2.0) glRotate(30.0, 1.0, 0.0, 0.0) glRotate(30.0, 0.0, 1.0, 0.0) glTranslate(0, -1, 0) glRotate(250, 1, 0, 0) - glutSolidCone(0.5, 1, 30, 5) + + glEnable(GL_BLEND) + glEnable(GL_POLYGON_SMOOTH) + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (0.5, 0.5, 1.0, 0.5)) + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 1.0) + glShadeModel(GL_FLAT) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) + # glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + + quad = gluNewQuadric() + base = .5 + top = 0.0 + height = 1.0 + slices = 16 + stacks = 16 + # stacks = 0 + if stacks: + # This is the premade way to make a cone. + gluCylinder(quad, base, top, height, slices, stacks) + else: + # Draw cone open ended without glu. + tau = pi * 2 + glBegin(GL_TRIANGLE_FAN) + centerX, centerY, centerZ = 0.0, 0.0, height + glVertex3f(centerX, centerY, centerZ) # Center of circle. + centerX, centerY, centerZ = 0.0, 0.0, 0.0 + for i in range(slices + 1): + theta = tau * float(i) / float(slices) # Get the current angle. + x = base * cos(theta) # Calculate the x component. + y = base * sin(theta) # Calculate the y component. + glVertex3f(x + centerX, y + centerY, centerZ) # Output vertex. + glEnd() + glPopMatrix() glRotatef((self.y - self.lasty), 0.0, 0.0, 1.0); glRotatef((self.x - self.lastx), 1.0, 0.0, 0.0); - # push into visible buffer + # Push into visible buffer. self.SwapBuffers() - #---------------------------------------------------------------------- @@ -263,13 +365,10 @@ def runTest(frame, nb, log): return win - - overview = """\ """ - if __name__ == '__main__': import sys,os import run From 6306a565406d0c6941b9f3cecd355950e8145cf3 Mon Sep 17 00:00:00 2001 From: Metallicow Date: Fri, 9 Oct 2020 09:58:45 -0500 Subject: [PATCH 2/2] Fix MessageDialog typo and apply Robins REQz --- demo/GLCanvas.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/demo/GLCanvas.py b/demo/GLCanvas.py index b69308f8..d236f01b 100644 --- a/demo/GLCanvas.py +++ b/demo/GLCanvas.py @@ -17,16 +17,11 @@ try: # http://PyOpenGL.sourceforge.net/ from OpenGL.GL import * from OpenGL.GLU import * - #### OpenGL.GLUT Very old, DO NOT USE! haveOpenGL = True except ImportError: haveOpenGL = False -## try: -## from PIL import Image -## havePIL = True -## except ImportError: -## havePIL = False + #---------------------------------------------------------------------- @@ -70,8 +65,8 @@ class ButtonPanel(wx.Panel): elif not haveOpenGL: dlg = wx.MessageDialog(self, 'The OpenGL package was not found. You can get it at\n' - 'http://PyOpenGL.sourceforge.net/', - '/nor $ pip install PyOpenGL PyOpenGL_accelerate', + 'http://PyOpenGL.sourceforge.net/ \n' + 'or $ pip install PyOpenGL PyOpenGL_accelerate', 'Sorry', wx.OK | wx.ICON_WARNING) dlg.ShowModal() dlg.Destroy()