This document discusses the NeHe8 tutorial by Jeff Molofee. It introduces blending and the Background customisation point for Contexts.
See NeHe7 for discussion of the Context
setup procedure here...
from OpenGLContext import testingcontext
BaseContext, MainFunction = testingcontext.getInteractive()
from OpenGLContext import interactivecontext, drawcube
from OpenGL.GL import *
from OpenGL.GLU import *
import time
from Image import open
class TestContext( BaseContext ):
"""New customization point: Background
Background, like Lights is called by the default
RenderMode.SetupBindables method. It is used here
because the blending mode used by the tutorial
will not work unless the background is black.
"""
usage ="""Demonstrates blending functions:
press 'b' to toggle blending functions
press 'f' to toggle filter functions
press 'l' to toggle lighting
press '<pageup>' to speed up rotation
press '<pagedown>' to slow down rotation
"""
initialPosition = (0,0,2)
def OnInit( self ):
"""Load the image on initial load of the application"""
self.imageIDs = self.loadImages()
self.currentFilter = 0 # index into imageIDs
self.lightsOn = 0 # boolean
self.blendOn = 1
self.currentZOffset = -6
self.rotationCycle = 8.0
# note that these are different bindings from the tutorial,
# as you can wander around with the arrow keys already...
self.addEventHandler(
'keypress', name = 'f', function = self.OnFilter
)
self.addEventHandler(
'keypress', name = 'l', function = self.OnLightToggle
)
self.addEventHandler(
'keypress', name = '<pageup>', function = self.OnSpeedUp
)
self.addEventHandler(
'keypress', name = '<pagedown>', function = self.OnSlowDown
)
Our first change from the NeHe7 tutorial code, and the only one in
OnInit is to bind a handler from the blending functions. The
Lights method is identical to the NeHe7 code, and not reproduced here.
self.addEventHandler(
'keypress', name = 'b', function = self.OnBlendToggle
)
print self.usage
glLightfv( GL_LIGHT1, GL_AMBIENT, (0.2, .2, .2, 1.0) );
glLightfv(GL_LIGHT1, GL_DIFFUSE, (.8,.8,.8));
glLightfv(GL_LIGHT1, GL_POSITION, (-2,0,3,1) );
The Background method is called if there is no scenegraph. It is called before Render, and is responsible for clearing the various buffers. This version simple clears the depth and colour buffers, setting the colour buffer to black (which is why we wanted it, since the tutorial's blending approach only works on a black background).
def Background( self, mode = 0):
"""Demo's use of GL_ONE assumes that background is black"""
if mode.passCount == 0:
glClearColor(0,0,0,0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
We provide a Render method as normal, disable culling (assumed by the tutorial) and do some rotation.
def Render( self, mode = 0):
BaseContext.Render( self, mode )
glTranslatef(1.5,0.0,self.currentZOffset);
glDisable( GL_CULL_FACE )
glRotated( time.time()%(self.rotationCycle)/self.rotationCycle * -360, 1,0,0)
Now we call the "blend" method to select and enable the current blending mode before rendering our geometry. The rest of the Render method we've seen before.
self.blend()
glEnable(GL_TEXTURE_2D)
# re-select our texture, could use other generated textures
# if we had generated them earlier...
glBindTexture(GL_TEXTURE_2D, self.imageIDs[self.currentFilter]) # 2d texture (x and y size)
self.drawCube()
glDisable(GL_TEXTURE_2D)
BLENDSTYLES = [
(),
(GL_SRC_ALPHA, GL_ONE), # what the demo uses originally
(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), # this is what should be used with sorted triangles
(GL_SRC_ALPHA, GL_DST_ALPHA), # just for kicks...
]
def blend( self ):
"""Choose and enable blending mode"""
if self.blendOn == 0:
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glDepthMask( ~0 )
else:
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glBlendFunc( * self.BLENDSTYLES[ self.blendOn] )
glDepthMask( 0 ) # prevent updates to the depth buffer...
We add a handler for the keyboard callback used to select different blending functions. The loadImages method is identical to the NeHe7 version and isn't copied here. The other keyboard callbacks, the Idle-time callback, and the drawCube function are also identical and not reproduced here.
def OnBlendToggle( self, event ):
self.blendOn = self.blendOn + 1
if self.blendOn == len( self.BLENDSTYLES ):
self.blendOn = 0
print 'Blend now %s, %s'% [
("None", "None"),
("GL_SRC_ALPHA", "GL_ONE"),
("GL_SRC_ALPHA", "GL_ONE_MINUS_SRC_ALPHA"),
("GL_SRC_ALPHA", "GL_DST_ALPHA"),
][ self.blendOn ]
You can find the complete code for this sample in
OpenGLContext/tests/nehe8.py