#!/usr/bin/env python """ demonstrates usage of osg.TextureRectangle. Actually there isn't much difference to the rest of the osg.Texture* bunch only this: - texture coordinates for texture rectangles must be in image coordinates instead of normalized coordinates (0-1). So for a 500x250 image the coordinates for the entire image would be 0,250 0,0 500,0 500,250 instead of 0,1 0,0 1,0 1,1 - only the following wrap modes are supported (but not enforced) CLAMP, CLAMP_TO_EDGE, CLAMP_TO_BORDER - a border is not supported - mipmap is not supported """ from PyOSG import * from OpenGL.GL import * from math import sin, cos #/********************************************************************** # * # * Texture pan animation callback # * # **********************************************************************/ class TexturePanCallback(osg.NodeCallback): def __init__(self, geom, img, delay = 0.05) : self._geom = geom self._img = img self._phaseS = 35.0 self._phaseT = 18.0 self._phaseScale = 5.0 self._delay = delay self._prevTime = 0.0 self._self = self # XXX def apply(self, node, nv): if not self._geom or not self._img: return if nv.getFrameStamp(): currTime = nv.getFrameStamp().getReferenceTime() if currTime - self._prevTime > self._delay: rad = osg.DegreesToRadians(currTime) # zoom scale (0.2 - 1.0) scale = sin(rad * self._phaseScale) * 0.4 + 0.6 scaleR = 1.0 - scale # calculate texture coordinates s = ((sin(rad * self._phaseS) + 1) * 0.5) * (self._img.s() * scaleR) t = ((sin(rad * self._phaseT) + 1) * 0.5) * (self._img.t() * scaleR) # set texture coordinate array texcoords = self._geom.getTexCoordArray(0) w = self._img.s() * scale h = self._img.t() * scale texcoords[0].set(s, t+h) texcoords[1].set(s, t) texcoords[2].set(s+w, t) texcoords[3].set(s+w, t+h) # record time self._prevTime = currTime def createRectangle(bb, filename): top_left = osg.Vec3(bb.xMin(),bb.yMax(),bb.zMax()) bottom_left = osg.Vec3(bb.xMin(),bb.yMax(),bb.zMin()) bottom_right = osg.Vec3(bb.xMax(),bb.yMax(),bb.zMin()) top_right = osg.Vec3(bb.xMax(),bb.yMax(),bb.zMax()) # create geometry geom = osg.Geometry() vertices = osg.Vec3Array(4) vertices[0] = top_left vertices[1] = bottom_left vertices[2] = bottom_right vertices[3] = top_right geom.setVertexArray(vertices) texcoords = osg.Vec2Array(4) texcoords[0].set(0.0, 0.0) texcoords[1].set(1.0, 0.0) texcoords[2].set(1.0, 1.0) texcoords[3].set(0.0, 1.0) geom.setTexCoordArray(0,texcoords) normals = osg.Vec3Array(1) normals[0].set(0.0,-1.0,0.0) geom.setNormalArray(normals) geom.setNormalBinding(osg.Geometry.BIND_OVERALL) colors = osg.Vec4Array(1) colors[0].set(1.0,1.0,1.0,1.0) geom.setColorArray(colors) geom.setColorBinding(osg.Geometry.BIND_OVERALL) geom.addPrimitiveSet(osg.DrawArrays(GL_QUADS, 0, 4)) # disable display list so our modified tex coordinates show up geom.setUseDisplayList(False) # setup texture texture = osg.TextureRectangle() # load image img = osgDB.readImageFile(filename) texture.setImage(img) # setup state state = geom.getOrCreateStateSet() state.setTextureAttributeAndModes(0, texture, osg.StateAttribute.ON) # turn off lighting state.setMode(GL_LIGHTING, osg.StateAttribute.OFF) # install 'update' callback geode = osg.Geode() geode.addDrawable(geom) geode.setUpdateCallback(TexturePanCallback(geom, img)) return geode def createText(string, pos): font = "fonts/arial.ttf" geode = osg.Geode() text = osgText.Text() geode.addDrawable(text) text.setFont(font) text.setPosition(pos) text.setText(string) return geode def createHUD(): group = osg.Group() # turn off lighting and depth test state = group.getOrCreateStateSet() state.setMode(GL_LIGHTING, osg.StateAttribute.OFF) state.setMode(GL_DEPTH_TEST, osg.StateAttribute.OFF) # add text pos = osg.Vec3(120.0, 800.0, 0.0) delta = osg.Vec3(0.0, -80.0, 0.0) text = [ "TextureRectangle Mini-HOWTO", "- essentially behaves like Texture2D, *except* that:", "- tex coords must be non-normalized (0..pixel) instead of (0..1)", "- wrap modes must be CLAMP, CLAMP_TO_EDGE, or CLAMP_TO_BORDER\n repeating wrap modes are not supported", "- filter modes must be NEAREST or LINEAR since\n mipmaps are not supported", "- texture borders are not supported", "- defaults should be fine" ] for t in text: group.addChild(createText(t, pos)) pos += delta # create HUD modelview_abs = osg.MatrixTransform() modelview_abs.setReferenceFrame(osg.Transform.ABSOLUTE_RF) modelview_abs.setMatrix(osg.Matrix.identity()) modelview_abs.addChild(group) projection = osg.Projection() projection.setMatrix(osg.Matrix.ortho2D(0,1280,0,1024)) projection.addChild(modelview_abs) return projection def createModel(filename): root = osg.Group() if filename != "X": bb = osg.BoundingBox(0.0,0.0,0.0,1.0,1.0,1.0) root.addChild(createRectangle(bb, filename)); # XXX root.addChild(createHUD()) return root def main(argv): # use an ArgumentParser object to manage the program arguments. arguments = osg.ArgumentParser(argv) # set up the usage document, in case we need to print out how to use this program. arguments.getApplicationUsage().setDescription(arguments.getApplicationName()+" is a demo which demonstrates use of osg.TextureRectangle.") arguments.getApplicationUsage().setCommandLineUsage(arguments.getApplicationName()+" [options] ...") arguments.getApplicationUsage().addCommandLineOption("-h or --help","Display this information") # construct the viewer. viewer = osgProducer.Viewer(arguments) # set up the value with sensible default event handlers. viewer.setUpViewer(osgProducer.Viewer.STANDARD_SETTINGS) # get details on keyboard and mouse bindings used by the viewer. viewer.getUsage(arguments.getApplicationUsage()) # if user request help write it out to cout. if arguments.read("-h") or arguments.read("--help"): arguments.getApplicationUsage().write() return 1 # any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized() # report any errors if they have occured when parsing the program aguments. if arguments.errors(): arguments.writeErrorMessages() return 1 # create a model from the images. rootNode = createModel((arguments.argc() > 1 and arguments[1] or "Images/lz.rgb")) # add model to viewer. viewer.setSceneData(rootNode) # create the windows and run the threads. viewer.realize() while not viewer.done(): # wait for all cull and draw threads to complete. viewer.sync() # update the scene by traversing it with the the update visitor which will # call all node update callbacks and animations. viewer.update() # fire off the cull and draw traversals of the scene. viewer.frame() # wait for all cull and draw threads to complete before exit. viewer.sync() return 0 if __name__ == "__main__": import sys main(sys.argv)