├── .gitignore ├── MANIFEST.in ├── README.md ├── README.txt ├── examples ├── handbook │ ├── 05_waves.py │ ├── 3D_02.py │ ├── 3D_03.py │ ├── 9-08.py │ ├── 9-09.py │ ├── 9-18.py │ └── centipede.py ├── misc │ ├── boxandsphere.py │ ├── circles.py │ ├── coordsystem.py │ ├── falloff.py │ ├── fonttest.py │ ├── fpstest.py │ ├── helloworld.py │ ├── helloworldrot.py │ ├── orthoandperspective.py │ ├── piechart.py │ ├── polygons.py │ ├── recursion.py │ ├── triflower.py │ └── widthandheight.py ├── reference │ ├── ambientlight.py │ ├── applymatrix.py │ ├── arc.py │ ├── backgroundimage.py │ ├── bezier.py │ ├── bezierdetail.py │ ├── bezierpoint.py │ ├── beziertangent.py │ ├── beziervertex.py │ ├── blendcolor.py │ ├── box.py │ ├── camera.py │ ├── colormode.py │ ├── createimage.py │ ├── cursor.py │ ├── curve.py │ ├── curvedetail.py │ ├── curvepoint.py │ ├── curvetangent.py │ ├── curvevertex.py │ ├── directionallight.py │ ├── ellipse.py │ ├── emissive.py │ ├── exit.py │ ├── filter.py │ ├── get.py │ ├── images │ │ ├── Foto-Aerea-Fundao.gif │ │ ├── arch.jpg │ │ ├── doll.jpg │ │ ├── tex.jpg │ │ └── tower.jpg │ ├── keycode.py │ ├── keytyped.py │ ├── lerpcolor.py │ ├── lights.py │ ├── line.py │ ├── loadimage.py │ ├── loop.py │ ├── modelx.py │ ├── mousebutton.py │ ├── mouseclicked.py │ ├── mousedragged.py │ ├── mousemoved.py │ ├── nocursor.py │ ├── ortho.py │ ├── perspective.py │ ├── pimageset.py │ ├── pmousex.py │ ├── pointlight.py │ ├── popmatrix.py │ ├── rect.py │ ├── redraw.py │ ├── resetmatrix.py │ ├── save.py │ ├── screen.py │ ├── screenx.py │ ├── set.py │ ├── shearx.py │ ├── sheary.py │ ├── shininess.py │ ├── specular.py │ ├── sphere.py │ ├── spotlight.py │ ├── text.py │ ├── text2.py │ ├── text3.py │ ├── textAscent.py │ ├── textDescent.py │ ├── texture.py │ ├── textwidth.py │ └── tint.py └── usage │ ├── animation.py │ ├── basicusage.py │ ├── interaction.py │ └── interactioncallback.py ├── ez_setup.py ├── pyprocessing ├── __init__.py ├── attribs.py ├── colors.py ├── config.py ├── constants.py ├── fbo.py ├── flippolicy.py ├── fonts.py ├── globalconfig.txt ├── globs.py ├── lights.py ├── materials.py ├── mathfunctions.py ├── pimage.py ├── primitives.py ├── pvector.py ├── shapes.py └── transformations.py ├── setup.py └── tools ├── accumfliptest.py ├── fbo.py ├── flip_setup.py ├── flippolicy.py └── takesnapshot.py /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.pyc -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.txt 2 | recursive-include examples *.py *.jpg *.gif *.png 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WHAT IS THIS? 2 | 3 | The pyprocessing project provides a Python package that creates an environment 4 | for graphics applications that closely resembles that of the Processing system. 5 | Usage is mostly restricted to importing the package and calling run(). 6 | 7 | The project mission is to implement Processing's friendly graphics functions and 8 | interaction model in Python. Not all of Processing is to be ported, though, 9 | since Python itself already provides alternatives for many features of 10 | Processing, such as XML parsing. 11 | 12 | The pyprocessing backend is built upon OpenGL and Pyglet, which provide the 13 | actual graphics rendering. Since these are multiplatform, so is pyprocessing. 14 | 15 | We hope that, much in the same spirit of the Processing project, pyprocessing 16 | will appeal to people who want to easily program and interact with computer 17 | generated imagery. It is also meant to help teaching computer programming by 18 | making it possible to write compact code with rich visual semantics. 19 | 20 | WHAT ARE THE REQUIREMENTS? 21 | 22 | In essence, all you need is the pyglet package (see www.pyglet.org) and its 23 | requirements, i.e., OpenGL and Python (2.5 or 2.6). If you are able to run 24 | pyglet's sample programs, you are in good shape to run pyprocessing. 25 | 26 | HOW TO INSTALL IT? 27 | 28 | Put the pyprocessing directory (the one which contains __init__.py, attribs.py, 29 | etc) in any place Python expects to find modules and packages. The simplest 30 | way of achieving this is to run the provided setup.py program: 31 | 32 | python setup.py install 33 | 34 | This will copy the files to the proper places. You might have to have 35 | administration privileges to do this, however. In most flavors of Linux, for 36 | instance, you might have to type: 37 | 38 | sudo python setup.py install 39 | 40 | HOW TO USE IT? 41 | 42 | There are several example programs in the examples folder that you may try. 43 | You may also take a look at the [project wiki](../../wiki) 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | WHAT IS THIS? 2 | 3 | The pyprocessing project provides a Python package that creates an environment 4 | for graphics applications that closely resembles that of the Processing system. 5 | Usage is mostly restricted to importing the package and calling run(). 6 | 7 | The project mission is to implement Processing's friendly graphics functions and 8 | interaction model in Python. Not all of Processing is to be ported, though, 9 | since Python itself already provides alternatives for many features of 10 | Processing, such as XML parsing. 11 | 12 | The pyprocessing backend is built upon OpenGL and Pyglet, which provide the 13 | actual graphics rendering. Since these are multiplatform, so is pyprocessing. 14 | 15 | We hope that, much in the same spirit of the Processing project, pyprocessing 16 | will appeal to people who want to easily program and interact with computer 17 | generated imagery. It is also meant to help teaching computer programming by 18 | making it possible to write compact code with rich visual semantics. 19 | 20 | WHAT ARE THE REQUIREMENTS? 21 | 22 | In essence, all you need is the pyglet package (see www.pyglet.org) and its 23 | requirements, i.e., OpenGL and Python (2.5 or 2.6). If you are able to run 24 | pyglet's sample programs, you are in good shape to run pyprocessing. 25 | 26 | HOW TO INSTALL IT? 27 | 28 | Put the pyprocessing directory (the one which contains __init__.py, attribs.py, 29 | etc) in any place Python expects to find modules and packages. The simplest 30 | way of achieving this is to run the provided setup.py program: 31 | 32 | python setup.py install 33 | 34 | This will copy the files to the proper places. You might have to have 35 | administration privileges to do this, however. In most flavors of Linux, for 36 | instance, you might have to type: 37 | 38 | sudo python setup.py install 39 | 40 | Alternatively, if you are running some flavor of MS-Windows, there is a binary 41 | installation file which you will find in the pyprocessing site 42 | (http://code.google.com/p/pyprocessing/downloads). 43 | 44 | HOW TO USE IT? 45 | 46 | There are several example programs in the examples folder that you may try. 47 | You may also take a look at the project wiki for simple usage instructions 48 | (http://code.google.com/p/pyprocessing/wiki/UsageInstructions) 49 | 50 | 51 | -------------------------------------------------------------------------------- /examples/handbook/05_waves.py: -------------------------------------------------------------------------------- 1 | """ 2 | Adapted from 3 | /** 4 | * Synthesis 1: Form and Code 5 | * Riley Waves by Casey Reas (www.processing.org) 6 | * p. 151 7 | * 8 | * Step 3, values are modified to create a new pattern. 9 | */ 10 | """ 11 | 12 | from pyprocessing import * 13 | 14 | size(1200, 280); 15 | background(255); 16 | smooth(); 17 | noStroke(); 18 | #fill(0); 19 | angle = PI; 20 | angle2 = PI; 21 | magnitude = 3; 22 | 23 | for i in range(-magnitude,height+magnitude,12): 24 | 25 | angle2 = angle; 26 | 27 | fill(0); 28 | beginShape(TRIANGLE_STRIP); 29 | for x in range(0,width+1,8): 30 | y = i + (sin(angle)* magnitude); 31 | angle += PI/24.0; 32 | y2 = i+4 + (sin(angle+PI/12)* magnitude); 33 | vertex(x, y); 34 | vertex(x, y2); 35 | endShape(); 36 | 37 | run() 38 | -------------------------------------------------------------------------------- /examples/handbook/3D_02.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | # Draw a sphere on top of a box and moves the coordinates with the mouse 4 | # Press a mouse button to turn on the lights 5 | def setup(): 6 | size(400, 400); 7 | 8 | def draw(): 9 | background(0); 10 | if mouse.pressed == True: 11 | # If the mouse is pressed, 12 | lights(); # turn on lights 13 | noStroke(); 14 | pushMatrix(); 15 | translate(mouse.x, mouse.y, -500); 16 | rotateY(PI / 6); # Rotate around y-axis 17 | box(400, 100, 400); # Draw box 18 | pushMatrix(); 19 | popMatrix(); 20 | translate(0, -200, 0); # Position the sphere 21 | sphere(150); # Draw sphere on top of box 22 | popMatrix(); 23 | 24 | run() 25 | -------------------------------------------------------------------------------- /examples/handbook/3D_03.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | # Draw a cylinder centered on the y-axis, going down from y=0 to y=height. 4 | # The radius at the top can be different from the radius at the bottom, 5 | # and the number of sides drawn is variable. 6 | 7 | def setup() : 8 | size(400, 400); 9 | 10 | def draw(): 11 | background(0); 12 | lights(); 13 | translate(width / 2, height / 2); 14 | rotateY(mouse.x * PI / width); 15 | rotateZ(mouse.y * -PI / height); 16 | noStroke(); 17 | fill(255, 255, 255); 18 | translate(0, -40, 0); 19 | drawCylinder(10, 180, 200, 16); # Draw a mix between a cylinder and a cone 20 | #drawCylinder(70, 70, 120, 16); # Draw a cylinder 21 | #drawCylinder(0, 180, 200, 4); # Draw a pyramid 22 | 23 | def drawCylinder(topRadius, bottomRadius, tall, sides): 24 | angle = 0; 25 | angleIncrement = TWO_PI / sides; 26 | beginShape(QUAD_STRIP); 27 | for i in range(sides+1): 28 | #normal(cos(angle),sin(angle),0) 29 | vertex(topRadius*cos(angle), 0, topRadius*sin(angle)); 30 | vertex(bottomRadius*cos(angle), tall, bottomRadius*sin(angle)); 31 | angle += angleIncrement; 32 | endShape(); 33 | 34 | # If it is not a cone, draw the circular top cap 35 | if (topRadius != 0): 36 | angle = 0; 37 | beginShape(TRIANGLE_FAN); 38 | 39 | # Center point 40 | vertex(0, 0, 0); 41 | for i in range(sides+1): 42 | vertex(topRadius * cos(angle), 0, topRadius * sin(angle)); 43 | angle += angleIncrement; 44 | endShape(); 45 | 46 | # If it is not a cone, draw the circular bottom cap 47 | if (bottomRadius != 0): 48 | angle = 0; 49 | beginShape(TRIANGLE_FAN); 50 | 51 | # Center point 52 | vertex(0, tall, 0); 53 | for i in range(sides+1): 54 | vertex(bottomRadius * cos(angle), tall, bottomRadius * sin(angle)); 55 | angle += angleIncrement; 56 | 57 | endShape(); 58 | 59 | run() 60 | -------------------------------------------------------------------------------- /examples/handbook/9-08.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | background(56, 90, 94); 4 | smooth(); 5 | x = 0; 6 | strokeWeight(12); 7 | for i in range(51,256,51): 8 | stroke(242, 204, 47, i); 9 | line(x, 20, x+20, 80); 10 | x += 20; 11 | 12 | run() 13 | -------------------------------------------------------------------------------- /examples/handbook/9-09.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | background(0); 4 | noStroke(); 5 | smooth(); 6 | fill(242, 204, 47, 160); 7 | ellipse(47, 36, 64, 64); 8 | fill(174, 221, 60, 160); 9 | ellipse(90, 47, 64, 64); 10 | fill(116, 193, 206, 160); 11 | ellipse(57, 79, 64, 64); 12 | 13 | run() 14 | -------------------------------------------------------------------------------- /examples/handbook/9-18.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | # Change the saturation and brightness, hue constant 4 | colorMode(HSB); 5 | for i in range(100): 6 | for j in range(100): 7 | stroke(132, j*2.5, i*2.5); 8 | point(i, j) 9 | 10 | run() 11 | 12 | -------------------------------------------------------------------------------- /examples/handbook/centipede.py: -------------------------------------------------------------------------------- 1 | """ 2 | Adapted from 3 | 4 | /** 5 | * Synthesis 3: Motion and Arrays 6 | * Centipede by Ariel Malka (www.chronotext.org) 7 | * p. 372 8 | */ 9 | """ 10 | from pyprocessing import * 11 | 12 | node_length = 30 13 | node_size = node_length-1 14 | n_nodes = 70 15 | nodes = [] 16 | delay = 20.0 17 | col_head = color(255, 0, 0) 18 | col_body = color(0) 19 | 20 | def setup(): 21 | size(600, 600) 22 | smooth() 23 | noStroke() 24 | 25 | global x,y 26 | x = width/2 27 | y = height/2 28 | 29 | r1 = 10 30 | r2 = 100 31 | dr = r2-r1 32 | D = 0.0 33 | 34 | for i in range(n_nodes): 35 | r = sqrt(r1 * r1 + 2.0 * dr * D); 36 | d = (r - r1) / dr; 37 | 38 | nodes.append((x - sin(d) * r, y + cos(d) * r)) 39 | 40 | D += node_length; 41 | 42 | 43 | def draw(): 44 | background(204); 45 | 46 | # Set the position of the head 47 | setTarget(mouse.x, mouse.y) 48 | 49 | # Draw the head 50 | fill(col_head) 51 | ellipse(nodes[0][0], nodes[0][1], node_size, node_size); 52 | 53 | # Draw the body 54 | fill(col_body); 55 | for x,y in nodes[1:]: 56 | ellipse(x,y, node_size, node_size) 57 | 58 | 59 | def setTarget(tx, ty): 60 | # Motion interpolation for the head 61 | global x,y 62 | x += (tx - x) / delay; 63 | y += (ty - y) / delay; 64 | nodes[0] = (x,y) 65 | 66 | # Constrained motion for the other nodes 67 | for i in range(1,n_nodes): 68 | dx = nodes[i - 1][0] - nodes[i][0] 69 | dy = nodes[i - 1][1] - nodes[i][1] 70 | length = sqrt(sq(dx) + sq(dy)) 71 | nodes[i] = (nodes[i - 1][0] - (dx/length * node_length), 72 | nodes[i - 1][1] - (dy/length * node_length)) 73 | 74 | run() 75 | 76 | -------------------------------------------------------------------------------- /examples/misc/boxandsphere.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | import math 3 | import OpenGL.GL as gl 4 | 5 | def setup(): 6 | size(200,200) 7 | noLoop() 8 | 9 | def draw(): 10 | # clear the whole screen 11 | background(200) 12 | lights() 13 | noStroke() 14 | background(200) 15 | pushMatrix() 16 | fill(255,255,0) 17 | translate(130,130) 18 | rotate(PI/6,1,1,0) 19 | box(50) 20 | popMatrix() 21 | fill(255,0,255) 22 | translate(60, 50) 23 | sphere(50) 24 | 25 | 26 | run() 27 | -------------------------------------------------------------------------------- /examples/misc/circles.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(300,300) 4 | hint(DISABLE_DEPTH_TEST) 5 | smooth() 6 | 7 | l = [] 8 | 9 | def mousePressed(): 10 | l.append ([mouse.x,mouse.y,1]) 11 | 12 | def mouseDragged(): 13 | l.append ([mouse.x,mouse.y,1]) 14 | 15 | def draw(): 16 | fill(0,10) 17 | noStroke() 18 | rect(0,0,width,height) 19 | stroke(255) 20 | nl = l[:] 21 | l[:]=[] 22 | for x,y,w in nl: 23 | g = 255-w 24 | if g<0: continue 25 | stroke(g) 26 | ellipse(x,y,w,w) 27 | l.append([x,y,w+2]) 28 | 29 | run() 30 | -------------------------------------------------------------------------------- /examples/misc/coordsystem.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(200,200); 4 | rectMode(CENTER); 5 | rect(100,100,20,100); 6 | ellipse(100,70,60,60); 7 | ellipse(81,70,16,32); 8 | ellipse(119,70,16,32); 9 | line(90,150,80,160); 10 | line(110,150,120,160); 11 | 12 | run() 13 | -------------------------------------------------------------------------------- /examples/misc/falloff.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup(): 4 | size(200,200) 5 | noStroke() 6 | 7 | def draw(): 8 | background(200) 9 | if mouse.pressed: lightFalloff(1,0,1e-4) 10 | pointLight(255,255,255,100,100,50) 11 | nx = 6 12 | ny = 6 13 | for i in range(nx): 14 | for j in range(ny): 15 | pushMatrix() 16 | translate((i+0.5)*width/nx,(j+0.5)*height/ny) 17 | sphere(10) 18 | popMatrix() 19 | 20 | run() 21 | -------------------------------------------------------------------------------- /examples/misc/fonttest.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(200,200) 4 | font = createFont("Times New Roman", 20); 5 | textFont(font); 6 | textAlign(CENTER,CENTER) 7 | text("The quick brown\nfox jumps over\nthe lazy dogs", width/2, height/2) 8 | 9 | run() 10 | -------------------------------------------------------------------------------- /examples/misc/fpstest.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | from random import random 3 | 4 | # Choose the total number of bouncing balls 5 | nballs = 100 6 | balls = [] 7 | 8 | def setup(): 9 | hint('DOUBLE_FLIP_POLICY') 10 | size(400,400) 11 | smooth() 12 | noStroke() 13 | colorMode(HSB,1.0) 14 | ellipseMode(CENTER) 15 | # generate n balls with random positions, sizes, speeds and colors 16 | for i in range(nballs): 17 | # position 18 | x = int(random()*width) 19 | y = int(random()*height) 20 | # speed 21 | vel = random()*4+2 22 | ang = random()*TWO_PI 23 | dx = vel*cos(ang) 24 | dy = vel*sin(ang) 25 | # radius 26 | r = random()*20+4 27 | # color 28 | c = color(random(),random()*0.5+0.5,random()*0.5+0.5) 29 | balls.append([x,y,dx,dy,r,c]) 30 | colorMode(RGB,256) 31 | 32 | def draw(): 33 | # fade the last frame by drawing background in transparent color 34 | fill(255,50) 35 | rect(0,0,width,height) 36 | # draw/bounce balls 37 | for i,(x,y,dx,dy,r,c) in enumerate(balls): 38 | fill(c) 39 | x += dx 40 | newx = constrain(x,r,width-r) 41 | if newx != x: dx,x = -dx,newx 42 | y += dy 43 | newy = constrain(y,r,height-r) 44 | if newy != y: dy,y = -dy,newy 45 | balls[i][0:4] = x,y,dx,dy 46 | ellipse(x,y,r,r) 47 | fill(0) 48 | text("%3d"%frame.rate,0,20) 49 | 50 | run() 51 | -------------------------------------------------------------------------------- /examples/misc/helloworld.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(300,300,caption="Hello") 4 | 5 | textFont(createFont("Times", 36, bold=True, italic=True)) 6 | textAlign(CENTER) 7 | text("Hello world", width/2, height/2) 8 | 9 | run() 10 | 11 | -------------------------------------------------------------------------------- /examples/misc/helloworldrot.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(300,300) 4 | textFont(createFont("Times New Roman", 36)) 5 | textAlign(CENTER,CENTER) 6 | ang = 0 7 | 8 | def draw(): 9 | global ang 10 | background(0,0,0) 11 | fill (255) 12 | translate (width/2, height/2) 13 | rotateZ (ang) 14 | ang += 0.01 15 | text("Hello world", 0, 0) 16 | 17 | run() 18 | 19 | -------------------------------------------------------------------------------- /examples/misc/orthoandperspective.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup(): 4 | size(640, 360); 5 | noStroke(); 6 | fill(204); 7 | 8 | def draw(): 9 | background(0); 10 | lights(); 11 | if (mouse.pressed): 12 | fov = PI/3.0; 13 | cameraZ = (height/2.0) / tan(fov / 2.0); 14 | perspective(fov, float(width)/float(height), cameraZ/10.0, cameraZ*10.0); 15 | else: 16 | ortho(-width/2, width/2, -height/2, height/2, -height, height); 17 | 18 | translate(width/2, height/2, 0); 19 | rotateX(-PI/6); 20 | rotateY(PI/3); 21 | box(160); 22 | 23 | 24 | run() 25 | -------------------------------------------------------------------------------- /examples/misc/piechart.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(200, 200); 4 | background(100); 5 | noStroke(); 6 | 7 | diameter = 150; 8 | angs = [30, 10, 45, 35, 60, 38, 75, 67]; 9 | lastAng = 0; 10 | smooth() 11 | for a in angs: 12 | fill(a * 3.0); 13 | arc(width/2, height/2, diameter, diameter, lastAng, 14 | lastAng+radians(a)) 15 | lastAng += radians(a) 16 | 17 | run() 18 | -------------------------------------------------------------------------------- /examples/misc/polygons.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(200,200) 4 | poly = [] 5 | smooth() 6 | def mousePressed(): 7 | poly [:] = [(mouse.x,mouse.y)] 8 | 9 | def mouseDragged(): 10 | poly.append((mouse.x,mouse.y)) 11 | 12 | def draw(): 13 | background(200) 14 | beginShape() 15 | for x,y in poly: vertex(x,y) 16 | endShape(CLOSE) 17 | 18 | run() 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/misc/recursion.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup() : 4 | size(200, 200) 5 | noStroke() 6 | smooth() 7 | noLoop() 8 | 9 | def draw(): 10 | drawCircle (126, 170, 6) 11 | 12 | def drawCircle (x, radius, level): 13 | fill(126 * level/4.0) 14 | ellipse(x, 100, radius*2, radius*2) 15 | if level > 1: 16 | level = level - 1 17 | drawCircle(x - radius/2, radius/2, level) 18 | drawCircle(x + radius/2, radius/2, level) 19 | 20 | run() 21 | -------------------------------------------------------------------------------- /examples/misc/triflower.py: -------------------------------------------------------------------------------- 1 | """ 2 | Adapted from the TriFlower sketch of Ira Greenberg 3 | """ 4 | 5 | # 6 | # Triangle Flower 7 | # by Ira Greenberg. 8 | # 9 | # Using rotate() and triangle() functions generate a pretty 10 | # flower. Uncomment the line "// rotate(rot+=radians(spin));" 11 | # in the triBlur() function for a nice variation. 12 | # 13 | 14 | from pyprocessing import * 15 | 16 | p = [None]*3 17 | shift = 1.0 18 | fade = 0 19 | fillCol = 0 20 | rot = 0 21 | spin = 0 22 | 23 | def setup(): 24 | size(200, 200); 25 | background(0); 26 | smooth(); 27 | global fade,spin 28 | fade = 255.0/(width/2.0/shift); 29 | spin = 360.0/(width/2.0/shift); 30 | p[0] = PVector (-width/2, height/2) 31 | p[1] = PVector (width/2, height/2) 32 | p[2] = PVector (0, -height/2) 33 | noStroke() 34 | translate(width/2, height/2) 35 | triBlur() 36 | 37 | def triBlur(): 38 | global fillCol,rot 39 | fill(fillCol) 40 | fillCol+=fade 41 | rotate(spin) 42 | # another interesting variation: uncomment the line below 43 | # rot+=radians(spin); rotate(rot) 44 | p[0].x+=shift; p[0].y-=shift; p[1].x-=shift; p[1].y-=shift; p[2].y+=shift; 45 | triangle (p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y) 46 | if p[0].x<0: 47 | # recursive call 48 | triBlur() 49 | 50 | run() 51 | -------------------------------------------------------------------------------- /examples/misc/widthandheight.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(200, 200); 4 | background(127); 5 | noStroke(); 6 | for i in range(0,height,20): 7 | fill(0); 8 | rect(0, i, width, 10); 9 | fill(255); 10 | rect(i, 0, 10, height); 11 | 12 | 13 | run() 14 | -------------------------------------------------------------------------------- /examples/reference/ambientlight.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | background(0); 5 | noStroke(); 6 | directionalLight(126, 126, 126, 0, 0, -1); 7 | ambientLight(102, 102, 102); 8 | translate(32, 50, 0); 9 | rotateY(PI/5); 10 | box(40); 11 | translate(60, 0, 0); 12 | sphere(30); 13 | 14 | run() 15 | -------------------------------------------------------------------------------- /examples/reference/applymatrix.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill(); 4 | translate(50, 50, 0); 5 | rotateY(PI/6); 6 | stroke(153); 7 | box(35); 8 | # Set rotation angles 9 | ct = math.cos(PI/9.0); 10 | st = math.sin(PI/9.0); 11 | #Matrix for rotation around the Y axis 12 | applyMatrix( ct, 0.0, st, 0.0, 13 | 0.0, 1.0, 0.0, 0.0, 14 | -st, 0.0, ct, 0.0, 15 | 0.0, 0.0, 0.0, 1.0); 16 | stroke(255); 17 | box(50); 18 | 19 | run() 20 | -------------------------------------------------------------------------------- /examples/reference/arc.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | arc(50, 55, 50, 50, 0, PI/2); 4 | noFill(); 5 | arc(50, 55, 60, 60, PI/2, PI); 6 | arc(50, 55, 70, 70, PI, TWO_PI-PI/2); 7 | arc(50, 55, 80, 80, TWO_PI-PI/2, TWO_PI); 8 | 9 | run() 10 | -------------------------------------------------------------------------------- /examples/reference/backgroundimage.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup() : 4 | global bg 5 | size(200,200) 6 | frameRate(30) 7 | bg = loadImage("images/doll.jpg") 8 | 9 | def draw(): 10 | global bg, a 11 | background(bg) 12 | a = (a + 1)%(width+32); 13 | stroke(226, 204, 0); 14 | line(0, a, width, a-26); 15 | line(0, a-6, width, a-32); 16 | 17 | 18 | a = 0 19 | run() 20 | -------------------------------------------------------------------------------- /examples/reference/bezier.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill(); 4 | stroke(255, 102, 0); 5 | line(30, 20, 80, 5); 6 | line(80, 75, 30, 75); 7 | stroke(0, 0, 0); 8 | bezier(30, 20, 80, 5, 80, 75, 30, 75); 9 | 10 | run() 11 | -------------------------------------------------------------------------------- /examples/reference/bezierdetail.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup(): 4 | size(100, 100); 5 | noFill(); 6 | noLoop() 7 | 8 | def draw(): 9 | bezierDetail(1); 10 | bezier(85, 20, 10, 10, 90, 90, 15, 80); 11 | stroke(126); 12 | bezierDetail(3); 13 | bezier(85, 20, 10, 10, 90, 90, 15, 80); 14 | stroke(255); 15 | bezierDetail(12); 16 | bezier(85, 20, 10, 10, 90, 90, 15, 80); 17 | 18 | run() 19 | -------------------------------------------------------------------------------- /examples/reference/bezierpoint.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill(); 4 | bezier(85, 20, 10, 10, 90, 90, 15, 80); 5 | fill(255); 6 | steps = 10; 7 | for i in range(steps+1): 8 | t = i / float(steps); 9 | x = bezierPoint(85, 10, 90, 15, t); 10 | y = bezierPoint(20, 10, 90, 80, t); 11 | ellipse(x, y, 5, 5); 12 | 13 | run() 14 | -------------------------------------------------------------------------------- /examples/reference/beziertangent.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill() 4 | bezier(85, 20, 10, 10, 90, 90, 15, 80); 5 | steps = 6; 6 | fill(255); 7 | for i in range(steps+1): 8 | t = i / float(steps); 9 | # Get the location of the point 10 | x = bezierPoint(85, 10, 90, 15, t); 11 | y = bezierPoint(20, 10, 90, 80, t); 12 | # Get the tangent points 13 | tx = bezierTangent(85, 10, 90, 15, t); 14 | ty = bezierTangent(20, 10, 90, 80, t); 15 | # Calculate an angle from the tangent points 16 | a = math.atan2(ty, tx); 17 | a += PI; 18 | stroke(255, 102, 0); 19 | line(x, y, math.cos(a)*30 + x, math.sin(a)*30 + y); 20 | # This follwing line of code makes a line 21 | # inverse of the above line 22 | # line(x, y, cos(a)*-30 + x, sin(a)*-30 + y); 23 | stroke(0); 24 | ellipse(x, y, 5, 5); 25 | 26 | run() 27 | -------------------------------------------------------------------------------- /examples/reference/beziervertex.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | beginShape() 4 | vertex(30, 20) 5 | bezierVertex(80, 0, 80, 75, 30, 75) 6 | bezierVertex(50, 75, 60, 25, 30, 20) 7 | endShape() 8 | 9 | run() 10 | -------------------------------------------------------------------------------- /examples/reference/blendcolor.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | orange = color(204, 102, 0); 4 | blue = color(0, 102, 153); 5 | print orange,blue 6 | orangeblueadd = blendColor(orange, blue, ADD); 7 | background(51); 8 | noStroke(); 9 | fill(orange); 10 | rect(14, 20, 20, 60); 11 | fill(orangeblueadd); 12 | rect(40, 20, 20, 60); 13 | fill(blue); 14 | rect(66, 20, 20, 60); 15 | 16 | run() 17 | -------------------------------------------------------------------------------- /examples/reference/box.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | translate(58, 48, 0); 4 | rotateY(0.5); 5 | box(40); 6 | 7 | run() 8 | -------------------------------------------------------------------------------- /examples/reference/camera.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill(); 4 | background(204); 5 | camera(70.0, 35.0, 120.0, 50.0, 50.0, 0.0, 6 | 0.0, 1.0, 0.0); 7 | translate(50, 50, 0); 8 | rotateX(-PI/6); 9 | rotateY(PI/3); 10 | box(45); 11 | 12 | run() 13 | -------------------------------------------------------------------------------- /examples/reference/colormode.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noStroke() 4 | colorMode(HSB, 100) 5 | for i in range(100): 6 | for j in range(100): 7 | stroke(i, j, 100) 8 | point(i, j) 9 | 10 | run() 11 | -------------------------------------------------------------------------------- /examples/reference/createimage.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | 5 | def setup(): 6 | global a 7 | size(200,200) 8 | a = createImage(120,120,'ARGB') 9 | for i in range(a.width*a.height): 10 | a.pixels[i] = color(0,90,102, i%a.width * 2) 11 | a.updatePixels() 12 | 13 | 14 | def draw(): 15 | global a 16 | background(204) 17 | image(a, 33, 33) 18 | image(a, mouse.x - 60, mouse.y - 60) 19 | 20 | 21 | run() 22 | -------------------------------------------------------------------------------- /examples/reference/cursor.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | # Move the mouse left and right across the image 4 | # to see the cursor change from a cross to a hand 5 | 6 | def draw() : 7 | if mouse.x < 50: 8 | cursor(CROSS) 9 | else: 10 | cursor(HAND) 11 | 12 | run() 13 | -------------------------------------------------------------------------------- /examples/reference/curve.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill(); 4 | stroke(255, 102, 0); 5 | curve(5, 26, 5, 26, 73, 24, 73, 61); 6 | stroke(0); 7 | curve(5, 26, 73, 24, 73, 61, 15, 65); 8 | stroke(255, 102, 0); 9 | curve(73, 24, 73, 61, 15, 65, 15, 65); 10 | 11 | run() 12 | -------------------------------------------------------------------------------- /examples/reference/curvedetail.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup(): 4 | size(100, 100); 5 | noFill(); 6 | noLoop(); 7 | 8 | def draw(): 9 | curveDetail(1); 10 | drawCurves(-15); 11 | stroke(126); 12 | curveDetail(2); 13 | drawCurves(0); 14 | stroke(255); 15 | curveDetail(4); 16 | drawCurves(15); 17 | 18 | def drawCurves(y): 19 | curve( 5, 28+y, 5, 28+y, 73, 26+y, 73, 63+y); 20 | curve( 5, 28+y, 73, 26+y, 73, 63+y, 15, 67+y); 21 | curve(73, 26+y, 73, 63+y, 15, 67+y, 15, 67+y); 22 | 23 | run() 24 | -------------------------------------------------------------------------------- /examples/reference/curvepoint.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill() 4 | curve(5, 26, 5, 26, 73, 24, 73, 61); 5 | curve(5, 26, 73, 24, 73, 61, 15, 65); 6 | ellipseMode(CENTER); 7 | steps = 6; 8 | fill(255) 9 | for i in range(steps+1): 10 | t = i / float(steps); 11 | x = curvePoint(5, 5, 73, 73, t); 12 | y = curvePoint(26, 26, 24, 61, t); 13 | ellipse(x, y, 5, 5); 14 | x = curvePoint(5, 73, 73, 15, t); 15 | y = curvePoint(26, 24, 61, 65, t); 16 | ellipse(x, y, 5, 5); 17 | 18 | run() 19 | -------------------------------------------------------------------------------- /examples/reference/curvetangent.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | from math import atan2, cos, sin 3 | 4 | noFill() 5 | curve(5, 26, 73, 24, 73, 61, 15, 65) 6 | steps = 6; 7 | for i in range(steps+1): 8 | t = i / float(steps); 9 | x = curvePoint(5, 73, 73, 15, t); 10 | y = curvePoint(26, 24, 61, 65, t); 11 | #ellipse(x, y, 5, 5); 12 | tx = curveTangent(5, 73, 73, 15, t); 13 | ty = curveTangent(26, 24, 61, 65, t); 14 | a = atan2(ty, tx); 15 | a -= PI/2.0; 16 | line(x, y, cos(a)*8 + x, sin(a)*8 + y); 17 | 18 | run() 19 | -------------------------------------------------------------------------------- /examples/reference/curvevertex.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill(); 4 | beginShape(); 5 | curveVertex(84, 91); 6 | curveVertex(84, 91); 7 | curveVertex(68, 19); 8 | curveVertex(21, 17); 9 | curveVertex(32, 100); 10 | curveVertex(32, 100); 11 | endShape(); 12 | 13 | run() 14 | -------------------------------------------------------------------------------- /examples/reference/directionallight.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | hint(ENABLE_DEPTH_TEST) 4 | 5 | size(100, 100); 6 | background(0); 7 | noStroke(); 8 | directionalLight(51, 102, 126, -1, 0, 0); 9 | translate(20, 50, 0); 10 | sphere(30); 11 | 12 | run() 13 | -------------------------------------------------------------------------------- /examples/reference/ellipse.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(200,200,resizable=True) 4 | def draw(): 5 | background(200) 6 | ellipse(width/2,height/2,width-40,height-40) 7 | 8 | run() 9 | -------------------------------------------------------------------------------- /examples/reference/emissive.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(100, 100); 4 | background(0); 5 | noStroke(); 6 | background(0); 7 | directionalLight(204, 204, 204, .5, 0, -1); 8 | emissive(0, 26, 51); 9 | translate(70, 50, 0); 10 | sphere(30); 11 | 12 | run() 13 | -------------------------------------------------------------------------------- /examples/reference/exit.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | x = 0 4 | 5 | def setup(): 6 | size(200, 200); 7 | 8 | def draw(): 9 | background(204); 10 | global x 11 | x = (x+1)%width 12 | line(x, 0, x, height); 13 | 14 | def mousePressed(): 15 | exit() 16 | 17 | run() 18 | 19 | -------------------------------------------------------------------------------- /examples/reference/filter.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | def setup(): 5 | global i1,i2,i3,i4,i5,i6 6 | size(200,300) 7 | frameRate(30) 8 | i1 = loadImage("images/arch.jpg") 9 | i2 = loadImage("images/arch.jpg") 10 | i3 = loadImage("images/arch.jpg") 11 | i4 = loadImage("images/arch.jpg") 12 | i5 = loadImage("images/arch.jpg") 13 | i6 = loadImage("images/arch.jpg") 14 | i1.filter(GRAY) 15 | i2.filter(THRESHOLD,0.4) 16 | i3.filter(POSTERIZE,5) 17 | i4.filter(DILATE) 18 | i5.filter(INVERT) 19 | i6.filter(OPAQUE) 20 | 21 | 22 | 23 | def draw(): 24 | global i1,i2,i3,i4,i5,i6 25 | image(i1,0,0) 26 | image(i2,100,0) 27 | image(i3,0,100) 28 | image(i4,100,100) 29 | image(i5,0,200) 30 | image(i6,100,200) 31 | 32 | 33 | 34 | run() 35 | -------------------------------------------------------------------------------- /examples/reference/get.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | myImage = loadImage("images/arch.jpg"); 4 | image(myImage, 0, 0); 5 | cp = get(); 6 | image(cp, 50, 0); 7 | 8 | run() 9 | -------------------------------------------------------------------------------- /examples/reference/images/Foto-Aerea-Fundao.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esperanc/pyprocessing/9765bbe9974e29dd06fe1b50b4390251d210218b/examples/reference/images/Foto-Aerea-Fundao.gif -------------------------------------------------------------------------------- /examples/reference/images/arch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esperanc/pyprocessing/9765bbe9974e29dd06fe1b50b4390251d210218b/examples/reference/images/arch.jpg -------------------------------------------------------------------------------- /examples/reference/images/doll.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esperanc/pyprocessing/9765bbe9974e29dd06fe1b50b4390251d210218b/examples/reference/images/doll.jpg -------------------------------------------------------------------------------- /examples/reference/images/tex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esperanc/pyprocessing/9765bbe9974e29dd06fe1b50b4390251d210218b/examples/reference/images/tex.jpg -------------------------------------------------------------------------------- /examples/reference/images/tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esperanc/pyprocessing/9765bbe9974e29dd06fe1b50b4390251d210218b/examples/reference/images/tower.jpg -------------------------------------------------------------------------------- /examples/reference/keycode.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | fillVal = color(126); 4 | 5 | def draw(): 6 | fill(fillVal); 7 | rect(25, 25, 50, 50); 8 | 9 | def keyPressed(): 10 | global fillVal 11 | if (key.char == CODED): 12 | if (key.code == UP): 13 | fillVal = 255; 14 | elif (key.code == DOWN): 15 | fillVal = 0; 16 | else: 17 | fillVal = 126; 18 | 19 | run() 20 | -------------------------------------------------------------------------------- /examples/reference/keytyped.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | # Run this program to learn how each of these functions 5 | # relate to the others 6 | 7 | def draw(): pass # Empty draw() needed to keep the program running 8 | 9 | def keyPressed(): 10 | print "pressed ", ord(key.char), " ", key.code; 11 | 12 | def keyTyped(): 13 | print "typed ", ord(key.char), " ", key.code; 14 | 15 | def keyReleased() : 16 | print "released ", ord(key.char), " ", key.code; 17 | 18 | 19 | run() 20 | -------------------------------------------------------------------------------- /examples/reference/lerpcolor.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | stroke(255); 4 | background(51); 5 | frm = color(204, 102, 0); 6 | to = color(0, 102, 153); 7 | interA = lerpColor(frm, to, .33); 8 | interB = lerpColor(frm, to, .66); 9 | fill(frm); 10 | rect(10, 20, 20, 60); 11 | fill(interA); 12 | rect(30, 20, 20, 60); 13 | fill(interB); 14 | rect(50, 20, 20, 60); 15 | fill(to); 16 | rect(70, 20, 20, 60); 17 | 18 | run() 19 | -------------------------------------------------------------------------------- /examples/reference/lights.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | background(0); 4 | noStroke(); 5 | # Sets the default ambient 6 | # and directional light 7 | lights(); 8 | translate(20, 50, 0); 9 | sphere(30); 10 | translate(60, 0, 0); 11 | sphere(30); 12 | 13 | run() 14 | -------------------------------------------------------------------------------- /examples/reference/line.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(100, 100); 4 | line(30, 20, 0, 85, 20, 15); 5 | stroke(126); 6 | line(85, 20, 15, 85, 75, 0); 7 | stroke(255); 8 | line(85, 75, 0, 30, 75, -50); 9 | 10 | run() 11 | -------------------------------------------------------------------------------- /examples/reference/loadimage.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | b = loadImage("images/arch.jpg") 4 | image (b,0,0) 5 | 6 | run() 7 | 8 | -------------------------------------------------------------------------------- /examples/reference/loop.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup(): 4 | size(200,200) 5 | noLoop() 6 | 7 | x = 0 8 | 9 | def draw(): 10 | global x 11 | background(204) 12 | x = x+0.5 13 | if x>width: x = 0 14 | line(x,0,x,height) 15 | 16 | 17 | def mousePressed(): loop() 18 | 19 | def mouseReleased(): noLoop() 20 | 21 | run() 22 | -------------------------------------------------------------------------------- /examples/reference/modelx.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup(): 4 | size(500, 500); 5 | noFill(); 6 | 7 | def draw(): 8 | background(0); 9 | 10 | pushMatrix(); 11 | # start at the middle of the screen 12 | translate(width/2, height/2, -200); 13 | # some random rotation to make things interesting 14 | rotateY(1.0); #yrot); 15 | rotateZ(2.0); #zrot); 16 | # rotate in X a little more each frame 17 | rotateX(frame.count / 100.0); 18 | # offset from center 19 | translate(0, 150, 0); 20 | 21 | # draw a white box outline at (0, 0, 0) 22 | stroke(255); 23 | box(50); 24 | 25 | # the box was drawn at (0, 0, 0), store that location 26 | 27 | x = modelX(0, 0, 0); 28 | y = modelY(0, 0, 0); 29 | z = modelZ(0, 0, 0); 30 | 31 | # clear out all the transformations 32 | popMatrix(); 33 | 34 | # draw another box at the same (x, y, z) coordinate as the other 35 | pushMatrix(); 36 | translate(x, y, z); 37 | stroke(255, 0, 0); 38 | box(50); 39 | popMatrix(); 40 | 41 | 42 | run() 43 | -------------------------------------------------------------------------------- /examples/reference/mousebutton.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | # Click within the image and press 4 | # the left and right mouse buttons to 5 | # change the value of the rectangle 6 | def draw(): 7 | if (mouse.pressed and (mouse.button == LEFT)): 8 | fill(0); 9 | elif (mouse.pressed and (mouse.button == RIGHT)): 10 | fill(255); 11 | else: 12 | fill(126); 13 | 14 | rect(25, 25, 50, 50); 15 | 16 | 17 | run() 18 | -------------------------------------------------------------------------------- /examples/reference/mouseclicked.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | # Click within the image to change 5 | # the value of the rectangle after 6 | # after the mouse has been clicked 7 | 8 | value = 0; 9 | 10 | def draw(): 11 | fill(value); 12 | rect(25, 25, 50, 50); 13 | 14 | def mouseClicked(): 15 | global value 16 | if(value == 0): 17 | value = 255; 18 | else: 19 | value = 0; 20 | 21 | run() 22 | -------------------------------------------------------------------------------- /examples/reference/mousedragged.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | # Drag (click and hold) your mouse across the 4 | # image to change the value of the rectangle 5 | 6 | value = 0; 7 | 8 | def draw(): 9 | fill(value); 10 | rect(25, 25, 50, 50); 11 | 12 | def mouseDragged(): 13 | global value 14 | value = value + 5; 15 | if (value > 255): 16 | value = 0; 17 | 18 | run() 19 | -------------------------------------------------------------------------------- /examples/reference/mousemoved.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | # Move your mouse across the 4 | # image to change the value of the rectangle 5 | 6 | value = 0; 7 | 8 | def draw(): 9 | fill(value); 10 | rect(25, 25, 50, 50); 11 | 12 | def mouseMoved(): 13 | global value 14 | value = value + 5; 15 | if (value > 255): 16 | value = 0; 17 | 18 | run() 19 | -------------------------------------------------------------------------------- /examples/reference/nocursor.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | # Press the mouse to hide the cursor 4 | 5 | def draw() : 6 | if mouse.pressed: 7 | noCursor() 8 | else: 9 | cursor(HAND) 10 | 11 | run() 12 | -------------------------------------------------------------------------------- /examples/reference/ortho.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill() 4 | camera(0,0,0,0,0,-1,0,1,0); 5 | ortho(0,width,0,height,-100,100) 6 | translate(50,50,0) 7 | rotateX(-PI/6); 8 | rotateY(PI/3); 9 | box(45) 10 | 11 | run() 12 | -------------------------------------------------------------------------------- /examples/reference/perspective.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill(); 4 | fov = PI/3.0; 5 | cameraZ = (height/2.0) / tan(fov/2.0); 6 | perspective(fov, float(width)/float(height), 7 | cameraZ/10.0, cameraZ*10.0); 8 | translate(50, 50, 0); 9 | rotateX(-PI/6); 10 | rotateY(PI/3); 11 | box(45); 12 | 13 | run() 14 | -------------------------------------------------------------------------------- /examples/reference/pimageset.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | img = loadImage("images/tower.jpg"); 4 | black = color(0, 0, 0); 5 | img.set(30, 20, black); 6 | img.set(85, 20, black); 7 | img.set(85, 75, black); 8 | img.set(30, 75, black); 9 | image(img, 0, 0); 10 | 11 | run() 12 | 13 | -------------------------------------------------------------------------------- /examples/reference/pmousex.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | # Move the mouse quickly to see the difference 5 | # between the current and previous position 6 | def draw() : 7 | background(204); 8 | line(mouse.x, 20, pmouse.x, 80); 9 | 10 | run() 11 | -------------------------------------------------------------------------------- /examples/reference/pointlight.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(100, 100); 4 | background(0); 5 | noStroke(); 6 | pointLight(51, 102, 126, 35, 40, 36); 7 | translate(80, 50, 0); 8 | sphere(30); 9 | 10 | run() 11 | -------------------------------------------------------------------------------- /examples/reference/popmatrix.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | rect(0, 0, 50, 50); #White rectangle 4 | pushMatrix(); 5 | translate(30, 20); 6 | fill(0); 7 | rect(0, 0, 50, 50); #Black rectangle 8 | popMatrix(); 9 | fill(102); 10 | rect(15, 10, 50, 50); #Gray rectangle 11 | 12 | run() 13 | -------------------------------------------------------------------------------- /examples/reference/rect.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | rect (10,10,80,80) 4 | 5 | run() 6 | -------------------------------------------------------------------------------- /examples/reference/redraw.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | x = 0 4 | 5 | def setup(): 6 | size(200, 200); 7 | noLoop(); 8 | 9 | def draw(): 10 | background(204); 11 | line(x, 0, x, height); 12 | 13 | def mousePressed(): 14 | global x 15 | x += 1; 16 | redraw(); 17 | 18 | run() 19 | 20 | -------------------------------------------------------------------------------- /examples/reference/resetmatrix.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noFill(); 4 | box(80); 5 | printMatrix(); 6 | # Processing prints 7 | # 01.0000 00.0000 00.0000 -50.0000 8 | # 00.0000 01.0000 00.0000 -50.0000 9 | # 00.0000 00.0000 01.0000 -86.6025 10 | # 00.0000 00.0000 00.0000 01.0000 11 | 12 | resetMatrix(); 13 | box(80); 14 | printMatrix(); 15 | # Prints: 16 | # 1.0000 0.0000 0.0000 0.0000 17 | # 0.0000 1.0000 0.0000 0.0000 18 | # 0.0000 0.0000 1.0000 0.0000 19 | # 0.0000 0.0000 0.0000 1.0000 20 | 21 | run() 22 | -------------------------------------------------------------------------------- /examples/reference/save.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | line(20, 20, 80, 80); 4 | # Saves a PNG file named "diagonal.png" 5 | save("diagonal.png"); 6 | # Saves a PNG file named "cross.png" 7 | line(80, 20, 20, 80); 8 | save("cross.png"); 9 | 10 | run() 11 | -------------------------------------------------------------------------------- /examples/reference/screen.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup(): 4 | size(screen.width, screen.height) 5 | 6 | def draw(): 7 | line(0, 0, screen.width, screen.height) 8 | 9 | run() 10 | -------------------------------------------------------------------------------- /examples/reference/screenx.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | def setup(): 4 | size(100, 100); 5 | 6 | 7 | def draw(): 8 | background(204); 9 | 10 | x = mouse.x; 11 | y = mouse.y; 12 | z = -100; 13 | 14 | # Draw "X" at z = -100 15 | stroke(255); 16 | line(x-10, y-10, z, x+10, y+10, z); 17 | line(x+10, y-10, z, x-10, y+10, z); 18 | 19 | # Draw line in 2D at same x value 20 | # Notice the parallax 21 | stroke(102); 22 | line(x, 0, 0, x, height, 0); 23 | 24 | # Draw 2D line to match the x value 25 | # element drawn at z = -100 26 | stroke(0); 27 | theX = screenX(x, y, z); 28 | line(theX, 0, 0, theX, height, 0); 29 | 30 | run() 31 | -------------------------------------------------------------------------------- /examples/reference/set.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | for i in range(30,width-15): 4 | for j in range(20,height-25): 5 | c = color(204-j, 153-i, 0); 6 | setScreen(i, j, c); 7 | 8 | 9 | run() 10 | 11 | -------------------------------------------------------------------------------- /examples/reference/shearx.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | size(100, 100) 5 | translate(width/4, height/4) 6 | shearX(PI/4.0) 7 | rect(0, 0, 30, 30) 8 | 9 | 10 | 11 | run() 12 | -------------------------------------------------------------------------------- /examples/reference/sheary.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | size(100, 100) 5 | translate(width/4, height/4) 6 | shearY(PI/4.0) 7 | rect(0, 0, 30, 30) 8 | 9 | 10 | run() 11 | -------------------------------------------------------------------------------- /examples/reference/shininess.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | background(0); 4 | noStroke(); 5 | background(0); 6 | fill(0, 51, 102); 7 | ambientLight(102, 102, 102); 8 | lightSpecular(204, 204, 204); 9 | directionalLight(102, 102, 102, 0, 0, -1); 10 | specular(255, 255, 255); 11 | translate(30, 50, 0); 12 | shininess(1.0); 13 | sphere(20); 14 | translate(40, 0, 0); 15 | shininess(5.0); 16 | sphere(20); 17 | 18 | run() 19 | -------------------------------------------------------------------------------- /examples/reference/specular.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(100, 100); 4 | background(0); 5 | noStroke(); 6 | background(0); 7 | fill(0, 51, 102); 8 | lightSpecular(255, 255, 255); 9 | directionalLight(204, 204, 204, 0, 0, -1); 10 | translate(20, 50, 0); 11 | specular(255, 255, 255); 12 | sphere(30); 13 | translate(60, 0, 0); 14 | specular(204, 102, 0); 15 | sphere(30); 16 | 17 | run() 18 | -------------------------------------------------------------------------------- /examples/reference/sphere.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | noStroke(); 4 | lights(); 5 | translate(58, 48, 0); 6 | sphere(28); 7 | 8 | run() 9 | -------------------------------------------------------------------------------- /examples/reference/spotlight.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | 4 | size(100, 100); 5 | background(0); 6 | noStroke(); 7 | spotLight(51, 102, 126, 80, 20, 40, -1, 0, 0, PI/2, 2); 8 | translate(20, 50, 0); 9 | sphere(30); 10 | 11 | run() 12 | -------------------------------------------------------------------------------- /examples/reference/text.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | font = createFont("Times New Roman", 24); 4 | textFont(font); 5 | text("word", 15, 30); 6 | fill(0, 102, 153); 7 | text("word", 15, 60); 8 | fill(0, 102, 153, 51); 9 | text("word", 15, 90); 10 | 11 | run() 12 | -------------------------------------------------------------------------------- /examples/reference/text2.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | font = createFont("times", 12); 4 | textFont(font); 5 | s = "The quick brown fox jumped over the lazy dog." 6 | text(s, 15, 20, 70, 70) 7 | 8 | run() 9 | -------------------------------------------------------------------------------- /examples/reference/text3.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | font = createFont("Times",32); 4 | textFont(font); 5 | text("word", 15, 60, -30); 6 | fill(0, 102, 153); 7 | text("word", 15, 60); 8 | 9 | run() 10 | -------------------------------------------------------------------------------- /examples/reference/textAscent.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | font = createFont("Helvetica"); 4 | textFont(font); 5 | 6 | textSize(32); 7 | ascent = textAscent(); 8 | text("dp", 0, 70); 9 | line(0, 70-ascent, 100, 70-ascent); 10 | 11 | textSize(64); 12 | ascent = textAscent(); 13 | text("dp", 35, 70); 14 | line(35, 70-ascent, 100, 70-ascent); 15 | 16 | run() 17 | -------------------------------------------------------------------------------- /examples/reference/textDescent.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | font = createFont("Helvetica"); 4 | textFont(font); 5 | 6 | textSize(32); 7 | descent = textDescent(); 8 | text("dp", 0, 70); 9 | line(0, 70+descent, 100, 70+descent); 10 | 11 | textSize(64); 12 | descent = textDescent(); 13 | text("dp", 35, 70); 14 | line(35, 70+descent, 100, 70+descent); 15 | 16 | run() 17 | -------------------------------------------------------------------------------- /examples/reference/texture.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | #TexturedCube 4 | #by Dave Bollinger. 5 | #Drag mouse to rotate cube. Demonstrates use of u/v coords in 6 | #vertex() and effect on texture(). 7 | 8 | rotx = PI/4; 9 | roty = PI/4; 10 | 11 | def setup(): 12 | global tex 13 | size(640, 360); 14 | tex = loadImage("images/tex.jpg"); 15 | textureMode(NORMALIZED); 16 | fill(255); 17 | stroke(color(44,48,32)); 18 | 19 | def draw(): 20 | background(0); 21 | noStroke(); 22 | translate(width/2.0, height/2.0, -100); 23 | rotateX(rotx); 24 | rotateY(roty); 25 | scale(90); 26 | TexturedCube(tex); 27 | 28 | def TexturedCube(tex): 29 | beginShape(QUADS); 30 | texture(tex); 31 | vertex(-1, -1, 1, 0, 0); 32 | vertex( 1, -1, 1, 1, 0); 33 | vertex( 1, 1, 1, 1, 1); 34 | vertex(-1, 1, 1, 0, 1); 35 | vertex( 1, -1, -1, 0, 0); 36 | vertex(-1, -1, -1, 1, 0); 37 | vertex(-1, 1, -1, 1, 1); 38 | vertex( 1, 1, -1, 0, 1); 39 | vertex(-1, 1, 1, 0, 0); 40 | vertex( 1, 1, 1, 1, 0); 41 | vertex( 1, 1, -1, 1, 1); 42 | vertex(-1, 1, -1, 0, 1); 43 | vertex(-1, -1, -1, 0, 0); 44 | vertex( 1, -1, -1, 1, 0); 45 | vertex( 1, -1, 1, 1, 1); 46 | vertex(-1, -1, 1, 0, 1); 47 | vertex( 1, -1, 1, 0, 0); 48 | vertex( 1, -1, -1, 1, 0); 49 | vertex( 1, 1, -1, 1, 1); 50 | vertex( 1, 1, 1, 0, 1); 51 | vertex(-1, -1, -1, 0, 0); 52 | vertex(-1, -1, 1, 1, 0); 53 | vertex(-1, 1, 1, 1, 1); 54 | vertex(-1, 1, -1, 0, 1); 55 | endShape(); 56 | 57 | def mouseDragged(): 58 | global rotx,roty 59 | rate = 0.01; 60 | rotx += (pmouse.y-mouse.y) * rate; 61 | roty += (mouse.x-pmouse.x) * rate; 62 | 63 | run() 64 | -------------------------------------------------------------------------------- /examples/reference/textwidth.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | font = createFont("Times"); 4 | textFont(font, 28); 5 | 6 | c = 'T'; 7 | cw = textWidth(c); 8 | text(c, 0, 40); 9 | line(cw, 0, cw, 50); 10 | 11 | s = "Tokyo"; 12 | sw = textWidth(s); 13 | text(s, 0, 85); 14 | line(sw, 50, sw, 100); 15 | 16 | run() 17 | -------------------------------------------------------------------------------- /examples/reference/tint.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | b = loadImage("images/arch.jpg"); 4 | image(b, 0, 0); 5 | # Tint blue 6 | tint(0, 153, 204, 126); 7 | image(b, 50, 0); 8 | 9 | run() 10 | 11 | -------------------------------------------------------------------------------- /examples/usage/animation.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | balls = [(20,20,2.5,3,10),(100,50,-3.5,-3,15)] 4 | 5 | def setup(): 6 | size(150,150) 7 | ellipseMode(CENTER) 8 | noStroke() 9 | 10 | def draw(): 11 | fill(200,50) 12 | rect(0,0,150,150) 13 | fill(0) 14 | for i in range(len(balls)): 15 | x,y,dx,dy,r = balls[i] 16 | x += dx 17 | if constrain(x,r,150-r) != x: dx = -dx 18 | y += dy 19 | if constrain(y,r,150-r) != y: dy = -dy 20 | balls[i] = x,y,dx,dy,r 21 | ellipse(x,y,r,r) 22 | 23 | run() 24 | -------------------------------------------------------------------------------- /examples/usage/basicusage.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | smooth() 4 | for i in range(10): 5 | line(i*5+5,20,i*5+50,80) 6 | 7 | run() 8 | -------------------------------------------------------------------------------- /examples/usage/interaction.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(200,200) 4 | 5 | def draw(): 6 | # scribble a line with the mouse 7 | if mouse.pressed: 8 | line (pmouse.x, pmouse.y, mouse.x, mouse.y) 9 | # typing 'C' clears the screen 10 | if key.pressed and key.char in 'cC': 11 | background(200) 12 | 13 | run() 14 | -------------------------------------------------------------------------------- /examples/usage/interactioncallback.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | 3 | size(200,200) 4 | 5 | def mouseDragged(): 6 | # scribble a line with the mouse 7 | line (pmouse.x, pmouse.y, mouse.x, mouse.y) 8 | 9 | def keyPressed(): 10 | # typing 'C' clears the screen 11 | if key.char in 'cC': 12 | background(200) 13 | 14 | run() 15 | -------------------------------------------------------------------------------- /ez_setup.py: -------------------------------------------------------------------------------- 1 | #!python 2 | """Bootstrap setuptools installation 3 | 4 | If you want to use setuptools in your package's setup.py, just include this 5 | file in the same directory with it, and add this to the top of your setup.py:: 6 | 7 | from ez_setup import use_setuptools 8 | use_setuptools() 9 | 10 | If you want to require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, you can do so by supplying 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import sys 17 | DEFAULT_VERSION = "0.6c11" 18 | DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] 19 | 20 | md5_data = { 21 | 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 22 | 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 23 | 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 24 | 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 25 | 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 26 | 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 27 | 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 28 | 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 29 | 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 30 | 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 31 | 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', 32 | 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', 33 | 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', 34 | 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', 35 | 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', 36 | 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', 37 | 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', 38 | 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', 39 | 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 40 | 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 41 | 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 42 | 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 43 | 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 44 | 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 45 | 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 46 | 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 47 | 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 48 | 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 49 | 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 50 | 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', 51 | 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', 52 | 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', 53 | 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', 54 | 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', 55 | 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', 56 | 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', 57 | 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', 58 | 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', 59 | 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', 60 | 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', 61 | 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', 62 | 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', 63 | } 64 | 65 | import sys, os 66 | try: from hashlib import md5 67 | except ImportError: from md5 import md5 68 | 69 | def _validate_md5(egg_name, data): 70 | if egg_name in md5_data: 71 | digest = md5(data).hexdigest() 72 | if digest != md5_data[egg_name]: 73 | print >>sys.stderr, ( 74 | "md5 validation of %s failed! (Possible download problem?)" 75 | % egg_name 76 | ) 77 | sys.exit(2) 78 | return data 79 | 80 | def use_setuptools( 81 | version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, 82 | download_delay=15 83 | ): 84 | """Automatically find/download setuptools and make it available on sys.path 85 | 86 | `version` should be a valid setuptools version number that is available 87 | as an egg for download under the `download_base` URL (which should end with 88 | a '/'). `to_dir` is the directory where setuptools will be downloaded, if 89 | it is not already available. If `download_delay` is specified, it should 90 | be the number of seconds that will be paused before initiating a download, 91 | should one be required. If an older version of setuptools is installed, 92 | this routine will print a message to ``sys.stderr`` and raise SystemExit in 93 | an attempt to abort the calling script. 94 | """ 95 | was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules 96 | def do_download(): 97 | egg = download_setuptools(version, download_base, to_dir, download_delay) 98 | sys.path.insert(0, egg) 99 | import setuptools; setuptools.bootstrap_install_from = egg 100 | try: 101 | import pkg_resources 102 | except ImportError: 103 | return do_download() 104 | try: 105 | pkg_resources.require("setuptools>="+version); return 106 | except pkg_resources.VersionConflict, e: 107 | if was_imported: 108 | print >>sys.stderr, ( 109 | "The required version of setuptools (>=%s) is not available, and\n" 110 | "can't be installed while this script is running. Please install\n" 111 | " a more recent version first, using 'easy_install -U setuptools'." 112 | "\n\n(Currently using %r)" 113 | ) % (version, e.args[0]) 114 | sys.exit(2) 115 | else: 116 | del pkg_resources, sys.modules['pkg_resources'] # reload ok 117 | return do_download() 118 | except pkg_resources.DistributionNotFound: 119 | return do_download() 120 | 121 | def download_setuptools( 122 | version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, 123 | delay = 15 124 | ): 125 | """Download setuptools from a specified location and return its filename 126 | 127 | `version` should be a valid setuptools version number that is available 128 | as an egg for download under the `download_base` URL (which should end 129 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 130 | `delay` is the number of seconds to pause before an actual download attempt. 131 | """ 132 | import urllib2, shutil 133 | egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) 134 | url = download_base + egg_name 135 | saveto = os.path.join(to_dir, egg_name) 136 | src = dst = None 137 | if not os.path.exists(saveto): # Avoid repeated downloads 138 | try: 139 | from distutils import log 140 | if delay: 141 | log.warn(""" 142 | --------------------------------------------------------------------------- 143 | This script requires setuptools version %s to run (even to display 144 | help). I will attempt to download it for you (from 145 | %s), but 146 | you may need to enable firewall access for this script first. 147 | I will start the download in %d seconds. 148 | 149 | (Note: if this machine does not have network access, please obtain the file 150 | 151 | %s 152 | 153 | and place it in this directory before rerunning this script.) 154 | ---------------------------------------------------------------------------""", 155 | version, download_base, delay, url 156 | ); from time import sleep; sleep(delay) 157 | log.warn("Downloading %s", url) 158 | src = urllib2.urlopen(url) 159 | # Read/write all in one block, so we don't create a corrupt file 160 | # if the download is interrupted. 161 | data = _validate_md5(egg_name, src.read()) 162 | dst = open(saveto,"wb"); dst.write(data) 163 | finally: 164 | if src: src.close() 165 | if dst: dst.close() 166 | return os.path.realpath(saveto) 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | def main(argv, version=DEFAULT_VERSION): 204 | """Install or upgrade setuptools and EasyInstall""" 205 | try: 206 | import setuptools 207 | except ImportError: 208 | egg = None 209 | try: 210 | egg = download_setuptools(version, delay=0) 211 | sys.path.insert(0,egg) 212 | from setuptools.command.easy_install import main 213 | return main(list(argv)+[egg]) # we're done here 214 | finally: 215 | if egg and os.path.exists(egg): 216 | os.unlink(egg) 217 | else: 218 | if setuptools.__version__ == '0.0.1': 219 | print >>sys.stderr, ( 220 | "You have an obsolete version of setuptools installed. Please\n" 221 | "remove it from your system entirely before rerunning this script." 222 | ) 223 | sys.exit(2) 224 | 225 | req = "setuptools>="+version 226 | import pkg_resources 227 | try: 228 | pkg_resources.require(req) 229 | except pkg_resources.VersionConflict: 230 | try: 231 | from setuptools.command.easy_install import main 232 | except ImportError: 233 | from easy_install import main 234 | main(list(argv)+[download_setuptools(delay=0)]) 235 | sys.exit(0) # try to force an exit 236 | else: 237 | if argv: 238 | from setuptools.command.easy_install import main 239 | main(argv) 240 | else: 241 | print "Setuptools version",version,"or greater has been installed." 242 | print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' 243 | 244 | def update_md5(filenames): 245 | """Update our built-in md5 registry""" 246 | 247 | import re 248 | 249 | for name in filenames: 250 | base = os.path.basename(name) 251 | f = open(name,'rb') 252 | md5_data[base] = md5(f.read()).hexdigest() 253 | f.close() 254 | 255 | data = [" %r: %r,\n" % it for it in md5_data.items()] 256 | data.sort() 257 | repl = "".join(data) 258 | 259 | import inspect 260 | srcfile = inspect.getsourcefile(sys.modules[__name__]) 261 | f = open(srcfile, 'rb'); src = f.read(); f.close() 262 | 263 | match = re.search("\nmd5_data = {\n([^}]+)}", src) 264 | if not match: 265 | print >>sys.stderr, "Internal error!" 266 | sys.exit(2) 267 | 268 | src = src[:match.start(1)] + repl + src[match.end(1):] 269 | f = open(srcfile,'w') 270 | f.write(src) 271 | f.close() 272 | 273 | 274 | if __name__=='__main__': 275 | if len(sys.argv)>2 and sys.argv[1]=='--md5update': 276 | update_md5(sys.argv[2:]) 277 | else: 278 | main(sys.argv[1:]) 279 | 280 | 281 | 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /pyprocessing/__init__.py: -------------------------------------------------------------------------------- 1 | #coding: utf-8 2 | # ---------------------------------------------------------------------------- 3 | # pyprocessing 4 | # Copyright (c) 2009 Claudio Esperança 5 | # All rights reserved. 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions 9 | # are met: 10 | # 11 | # * Redistributions of source code must retain the above copyright 12 | # notice, this list of conditions and the following disclaimer. 13 | # * Redistributions in binary form must reproduce the above copyright 14 | # notice, this list of conditions and the following disclaimer in 15 | # the documentation and/or other materials provided with the 16 | # distribution. 17 | # * Neither the name of pyprocessing nor the names of its 18 | # contributors may be used to endorse or promote products 19 | # derived from this software without specific prior written 20 | # permission. 21 | # 22 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 | # POSSIBILITY OF SUCH DAMAGE. 34 | # ---------------------------------------------------------------------------- 35 | """ 36 | A Processing-like environment for doing graphics with Python. 37 | 38 | Other than Python, the only requirement is pyglet, which in turn 39 | requires OpenGL. 40 | """ 41 | 42 | try: 43 | import pyglet 44 | except: 45 | print """The Pyglet package is not present in your Python 46 | installation. Please visit http://www.pyglet.org.""" 47 | exit(-1) 48 | 49 | import sys,math,ctypes,os,time,webbrowser 50 | from math import * 51 | from pyglet.gl import * 52 | 53 | # Sub-modules 54 | 55 | from pvector import * 56 | from pimage import * 57 | from constants import * 58 | from globs import * 59 | from colors import * 60 | from attribs import * 61 | from lights import * 62 | from materials import * 63 | from primitives import * 64 | from shapes import * 65 | from fonts import * 66 | from transformations import * 67 | from mathfunctions import * 68 | from flippolicy import * 69 | import config 70 | 71 | # We infringe good Python practice here by polluting the 72 | # __builtin__ namespace with global symbols width and height, 73 | # which are the two most commonly used "global" variables 74 | # in Processing. This is done in two places: the size() function 75 | # and the on_resize() callback. 76 | 77 | import __builtin__ 78 | 79 | __builtin__.width = __builtin__.height = 0 80 | 81 | starttime = time.time() 82 | 83 | #************************ 84 | # CALLBACK FUNCTIONS 85 | #************************ 86 | 87 | def __draw(*args): 88 | """Called for every frame.""" 89 | # reset the modelview transformation 90 | glMatrixMode (GL_MODELVIEW) 91 | camera() 92 | # reset the lighting 93 | noLights() 94 | # set last frame's mouse position in pmouse 95 | pmouse.x,pmouse.y = pmouse.savex, pmouse.savey 96 | # increment frame count and draw 97 | frame.count += 1 98 | frame.rate = pyglet.clock.get_fps() 99 | callback.draw() 100 | # save last mouse position 101 | pmouse.savex,pmouse.savey=mouse.x,mouse.y 102 | 103 | def on_close(): 104 | """Called when window is closed.""" 105 | pyglet.clock.unschedule(__draw) 106 | callback.exit() 107 | 108 | def on_mouse_press(x, y, button, modifiers): 109 | """Called when a mouse button is pressed.""" 110 | pmouse.x,pmouse.y = mouse.x,mouse.y 111 | mouse.x, mouse.y = x, height - y 112 | if button == 4: button = RIGHT 113 | elif button == 2: button = CENTER 114 | elif button == 1: button = LEFT 115 | else: button = None 116 | mouse.button = button 117 | mouse.pressed = True 118 | callback.mousePressed() 119 | 120 | def on_mouse_release(x, y, button, modifiers): 121 | """Called when a mouse button is released.""" 122 | pmouse.x,pmouse.y = mouse.x,mouse.y 123 | mouse.x, mouse.y = x, height - y 124 | mouse.pressed = False 125 | callback.mouseClicked() 126 | callback.mouseReleased() 127 | 128 | def on_key_press(symbol, modifiers): 129 | """Called when a key is pressed.""" 130 | key.pressed = True 131 | key.code = symbol 132 | key.modifiers = modifiers 133 | if 32 <= symbol <= 127: 134 | key.char = chr(symbol) 135 | else: 136 | key.char = CODED 137 | if key.modifiers == 1: 138 | key.char = key.char.upper() 139 | callback.keyPressed() 140 | 141 | def on_key_release(symbol, modifiers): 142 | """Called when a key is released.""" 143 | key.pressed = False 144 | key.code = symbol 145 | key.modifiers = modifiers 146 | if 32 <= symbol <= 127: 147 | key.char = chr(symbol) 148 | else: 149 | key.char = CODED 150 | callback.keyReleased() 151 | if key.char != CODED : callback.keyTyped() 152 | 153 | def on_mouse_drag(x, y, dx, dy, buttons, modifiers): 154 | """Called when mouse is moved with at least one button pressed.""" 155 | pmouse.x,pmouse.y = mouse.x,mouse.y 156 | mouse.x, mouse.y = x, height - y 157 | mouse.pressed = True 158 | callback.mouseDragged() 159 | 160 | def on_mouse_motion(x, y, dx, dy): 161 | """Called when mouse is moved with no buttons pressed.""" 162 | pmouse.x,pmouse.y = mouse.x,mouse.y 163 | mouse.x, mouse.y = x, height - y 164 | mouse.button = None 165 | mouse.pressed = False 166 | callback.mouseMoved() 167 | 168 | def on_resize(w, h): 169 | """Called whenever the window is resized.""" 170 | # beware of the margin! 171 | mx, my = canvas.margin 172 | if max(mx,my)>0 and w == width+mx and h == height+my: 173 | # This window has the same size as specified by 174 | # size(). keep the margin! 175 | pass 176 | else: 177 | # get rid of the margin 178 | canvas.margin = mx,my = 0,0 179 | __builtin__.width = w 180 | __builtin__.height = h 181 | # Remember window size if fullscreen 182 | if canvas.window.fullscreen: 183 | __builtin__.width,__builtin__.height=screen.width,screen.height 184 | # Set up a reasonable perspective view 185 | glViewport(mx/2, my/2, width, height) 186 | perspective() 187 | if callback.screenResized != callback.dummy: 188 | # User will handle the resize 189 | callback.screenResized() 190 | return pyglet.event.EVENT_HANDLED 191 | 192 | #************************ 193 | # ENVIRONMENT 194 | #************************ 195 | 196 | def cursor(*args): 197 | """Sets up the cursor type. Arguments: 198 | cursor() 199 | cursor(MODE) 200 | cursor(img,x,y) 201 | """ 202 | canvas.window.set_mouse_visible(True) 203 | if len(args)==0: 204 | pass 205 | elif len(args)==1: 206 | canvas.cursor = canvas.window.get_system_mouse_cursor(args[0]) 207 | canvas.window.set_mouse_cursor(canvas.cursor) 208 | elif len(args)==3: 209 | canvas.cursor = pyglet.window.ImageMouseCursor(args[0].img, args[1], args[2]) 210 | canvas.window.set_mouse_cursor(canvas.cursor) 211 | else: 212 | raise ValueError, "Wrong number of arguments" 213 | 214 | def noCursor(): 215 | """Hides the cursor.""" 216 | canvas.window.set_mouse_visible(False) 217 | 218 | def link(url, target = None): 219 | """Links to a webpage using the default browser.""" 220 | webbrowser.open(url) 221 | 222 | def delay(t): 223 | """Stops the program for t milliseconds.""" 224 | time.sleep(t/1000.0) 225 | 226 | def day(): 227 | """Returns the current day as a value from 1 - 31""" 228 | return int(time.strftime("%d",time.gmtime())) 229 | 230 | def hour(): 231 | """Returns the current hour as a value from 0 - 24""" 232 | gmt = int(time.strftime("%H",time.gmtime())) 233 | timezone = time.timezone/60/60 234 | if gmt < timezone: gmt+=24 235 | if gmt-timezone > 23: return (gmt-timezone)%24 236 | return gmt-timezone 237 | 238 | def millis(): 239 | """Returns the number of milliseconds since starting 240 | the application.""" 241 | return (time.time() - starttime)*1000 242 | 243 | def minute(): 244 | """Returns the current minute as a value from 0 - 59""" 245 | return int(time.strftime("%M",time.gmtime())) 246 | 247 | def month(): 248 | """Returns the current month as a value from 1 - 12""" 249 | return int(time.strftime("%m",time.gmtime())) 250 | 251 | def second(): 252 | """Returns the current second as a value from 0 - 61""" 253 | return int(time.strftime("%S",time.gmtime())) 254 | 255 | def year(): 256 | """Returns the current year (2005, 2006, etc)""" 257 | return int(time.strftime("%Y",time.gmtime())) 258 | 259 | def loop(): 260 | """Enables the periodical refresh of the screen.""" 261 | frame.loop = True 262 | pyglet.clock.unschedule(__draw) 263 | pyglet.clock.schedule_interval(__draw,1.0/frame.targetRate) 264 | 265 | def noLoop(): 266 | """Disables the periodical refresh of the screen.""" 267 | frame.loop = False 268 | pyglet.clock.unschedule(__draw) 269 | 270 | def redraw(): 271 | """Signals that the 'draw()' callback should be called.""" 272 | pyglet.clock.schedule_once(__draw,0) 273 | 274 | def frameRate(rate): 275 | """Sets the frame rate.""" 276 | frame.targetRate = rate 277 | if frame.loop: loop() 278 | 279 | def popStyle(): 280 | """Restores the prior drawing settings.""" 281 | glPopAttrib(GL_ALL_ATTRIB_BITS) 282 | 283 | def pushStyle(): 284 | """Saves the current drawing settings.""" 285 | glPushAttrib(GL_ALL_ATTRIB_BITS) 286 | 287 | def size(nx=100,ny=100,fullscreen=False,resizable=False,caption="pyprocessing", 288 | multisample=config.multisample): 289 | """Inits graphics screen with nx x ny pixels. 290 | Caption is the window title.""" 291 | # Set up canvas 292 | global canvas,screen 293 | if canvas.window != None: 294 | # get rid of window created on an earlier call to size 295 | canvas.window.close() 296 | canvas.window = None 297 | 298 | # Create a window. 299 | # 300 | # Note 1: It is created initially with visible=False so 301 | # that the default window may be silently destroyed and recreated. 302 | # After the run() function is called, the window is made visible. 303 | # 304 | # Note 2: A margin is defined for small windows. Apparently, 305 | # Pyglet under MS Windows does not cope well with windows with height 306 | # smaller than 120 pixels. 307 | # 308 | if fullscreen: 309 | sizex,sizey = None,None 310 | canvas.margin = (0,0) 311 | else: 312 | sizex = max(120,int(nx)) 313 | sizey = max(120,int(ny)) 314 | canvas.margin = (sizex-nx, sizey-ny) 315 | if multisample: 316 | canvas.config = Config(sample_buffers=1,samples=4,depth_size=24,double_buffer=True,alpha_size=8) 317 | else: 318 | canvas.config = Config(depth_size=24,double_buffer=True,apha_size=8) # a sane default, hopefully 319 | 320 | # select the proper window class depending on the flippolicy 321 | windowClass = { DOUBLE_FLIP_POLICY:PyprocessingWindow, 322 | SINGLE_FLIP_POLICY:SingleBufferWindow, 323 | FBO_FLIP_POLICY:FBOWindow, 324 | ACCUM_FLIP_POLICY:AccumWindow, 325 | BACKUP_FLIP_POLICY:BackupWindow}[config.flipPolicy] 326 | # 327 | # If single buffering is used, the window must be mapped onto 328 | # the screen immediately (visible = True). 329 | # 330 | isVisible = config.flipPolicy in (SINGLE_FLIP_POLICY,ACCUM_FLIP_POLICY,BACKUP_FLIP_POLICY) 331 | try: 332 | # Try and create a window with the requested config 333 | canvas.window = windowClass(sizex, sizey, resizable=resizable, 334 | fullscreen=fullscreen, 335 | config=canvas.config, caption=caption, visible = isVisible) 336 | #glEnable(GL_BLEND) 337 | #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 338 | 339 | except pyglet.window.NoSuchConfigException, msg: 340 | # Fall back to a minimalistic config for older hardware 341 | display = pyglet.window.get_platform().get_default_display() 342 | screen = display.get_screens()[0] 343 | canvas.config = None 344 | for template_config in [ 345 | Config(depth_size=24, double_buffer = True), 346 | Config(depth_size=16, double_buffer = True)]: 347 | try: 348 | canvas.config = screen.get_best_config(template_config) 349 | break 350 | except pyglet.window.NoSuchConfigException: 351 | pass 352 | if canvas.config == None: 353 | raise pyglet.window.NoSuchConfigException,\ 354 | "Sorry, but it seems your hardware does not support any usable OpenGL config" 355 | canvas.window = windowClass(sizex, sizey, resizable=resizable, caption=caption, 356 | fullscreen=fullscreen, config = canvas.config, 357 | visible = isVisible) 358 | # turn on the fix that prevents polygon antialiasing 359 | config.smoothFixHack = True 360 | 361 | canvas.window.clear() 362 | # set the width and height global variables 363 | __builtin__.width = nx 364 | __builtin__.height = ny 365 | 366 | # get the screen dimensions 367 | screen.width = canvas.window.screen.width 368 | screen.height = canvas.window.screen.height 369 | 370 | # some defaults: 371 | noSmooth() 372 | # bezier init 373 | bezierDetail(30) 374 | # set frame rate 375 | frameRate (frame.targetRate) 376 | # enable depth buffering by default 377 | hint(ENABLE_DEPTH_TEST) 378 | 379 | # set up default material and lighting parameters 380 | glEnable(GL_COLOR_MATERIAL) 381 | glEnable (GL_NORMALIZE) 382 | glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) 383 | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (ctypes.c_float * 4) (0,0,0,1)) 384 | specular(0) 385 | ambient(0.2*255) 386 | shininess(10) 387 | # set up colors 388 | fill(255) 389 | stroke(0) 390 | # clear canvas with medium gray 391 | background(200) 392 | # force a resize call 393 | on_resize(sizex,sizey) 394 | # setup the default camera 395 | camera() 396 | 397 | def run(): 398 | """Registers callbacks and starts event loop.""" 399 | import __main__ 400 | maindir = dir(__main__) 401 | 402 | # Import callbacks from main program 403 | if 'draw' in maindir: callback.draw = staticmethod(__main__.draw) 404 | if 'mousePressed' in maindir: callback.mousePressed = staticmethod(__main__.mousePressed) 405 | if 'mouseReleased' in maindir: callback.mouseReleased = staticmethod(__main__.mouseReleased) 406 | if 'mouseClicked' in maindir: callback.mouseClicked = staticmethod(__main__.mouseClicked) 407 | if 'mouseDragged' in maindir: callback.mouseDragged = staticmethod(__main__.mouseDragged) 408 | if 'mouseMoved' in maindir: callback.mouseMoved = staticmethod(__main__.mouseMoved) 409 | if 'keyPressed' in maindir: callback.keyPressed = staticmethod(__main__.keyPressed) 410 | if 'keyReleased' in maindir: callback.keyReleased = staticmethod(__main__.keyReleased) 411 | if 'keyTyped' in maindir: callback.keyTyped = staticmethod(__main__.keyTyped) 412 | if 'exit' in maindir: callback.exit = staticmethod(__main__.exit) 413 | if 'screenResized' in maindir: callback.screenResized = staticmethod(__main__.screenResized) 414 | 415 | # Automatically call setup if function was defined in the main program 416 | if 'setup' in maindir: 417 | __main__.setup() 418 | # Call draw at least once even if setup called noloop 419 | __draw() 420 | 421 | # set up other callbacks 422 | canvas.window.event(on_close) 423 | canvas.window.event(on_mouse_press) 424 | canvas.window.event(on_mouse_release) 425 | canvas.window.event(on_mouse_drag) 426 | canvas.window.event(on_mouse_motion) 427 | canvas.window.event(on_resize) 428 | canvas.window.event(on_key_press) 429 | canvas.window.event(on_key_release) 430 | 431 | # make window visible 432 | canvas.window.set_visible(True) 433 | 434 | # now for the main loop 435 | pyglet.app.run() 436 | 437 | # create a default window 438 | if canvas.window == None: size(100,100) 439 | 440 | #test program 441 | if __name__=="__main__": 442 | def draw(): 443 | background(200) 444 | smooth() 445 | textFont (createFont ("Times", size=24)) 446 | fill (0) 447 | text("Python Processing", 10, 42) 448 | fill (255) 449 | stroke(0) 450 | rect(width/2,height/2,50,50) 451 | if mouse.pressed: 452 | if mouse.button == LEFT: 453 | fill(255,0,0,100) 454 | noStroke() 455 | ellipse(mouse.x,mouse.y, 60, 60) 456 | elif mouse.button == RIGHT: 457 | fill(0,128,255,100) 458 | noStroke() 459 | rect (mouse.x, mouse.y, 60, 60) 460 | else: save("test.png") 461 | size(300,300) 462 | ellipseMode(CENTER) 463 | rectMode (CENTER) 464 | run() 465 | -------------------------------------------------------------------------------- /pyprocessing/attribs.py: -------------------------------------------------------------------------------- 1 | #************************ 2 | # ATTRIBUTES 3 | #************************ 4 | 5 | from globs import * 6 | from constants import * 7 | from pyglet.gl import * 8 | from colors import _getColor 9 | import config 10 | 11 | __all__=['stroke', 'noStroke', 'strokeWeight', 'fill', 'noFill', 'tint', 'noTint', 12 | 'smooth', 'noSmooth', 'ellipseMode', 'rectMode', 'imageMode', 'hint', 13 | 'texture', 'textureMode', 'strokeJoin', 'strokeCap'] 14 | 15 | def stroke(*color): 16 | """Sets color as color for drawing lines and shape borders.""" 17 | attrib.strokeColor = _getColor(*color) 18 | 19 | def noStroke(): 20 | """Omits line drawings""" 21 | attrib.strokeColor = None 22 | 23 | def strokeWeight (weight): 24 | """Sets line width for drawing outline objects""" 25 | if weight<=0: weight=0.001 26 | attrib.strokeWeight = weight 27 | 28 | def strokeCap(mode): 29 | attrib.strokeCap = mode 30 | 31 | def strokeJoin(mode): 32 | attrib.strokeJoin = mode 33 | 34 | def fill(*color): 35 | """Sets color as color for drawing filled shapes.""" 36 | attrib.fillColor = _getColor(*color) 37 | 38 | def tint(*color): 39 | """Sets color as a tint for drawing images.""" 40 | attrib.tintColor = _getColor(*color) 41 | 42 | def noTint(): 43 | """Undefines tint for drawing images.""" 44 | attrib.tintColor = None 45 | 46 | def noFill(): 47 | """Omits filled drawings""" 48 | attrib.fillColor = None 49 | 50 | def texture(filename): 51 | attrib.texture = filename 52 | 53 | def smooth(): 54 | """Sets state so that lines are rendered antialiased.""" 55 | attrib.smooth = True 56 | glEnable(GL_BLEND) 57 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 58 | glEnable(GL_LINE_SMOOTH) 59 | glEnable(GL_POINT_SMOOTH) 60 | glEnable(GL_POLYGON_SMOOTH) 61 | glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST) 62 | 63 | def noSmooth(): 64 | """Sets state so that lines are rendered quickly.""" 65 | attrib.smooth = False 66 | glEnable(GL_BLEND) 67 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 68 | glDisable(GL_LINE_SMOOTH) 69 | glDisable(GL_POINT_SMOOTH) 70 | glDisable(GL_POLYGON_SMOOTH) 71 | 72 | def textureMode(mode): 73 | """Alters the meaning of the arguments of the ellipse function""" 74 | attrib.textureMode = mode 75 | 76 | def ellipseMode(mode): 77 | """Alters the meaning of the arguments of the ellipse function""" 78 | attrib.ellipseMode = mode 79 | 80 | def rectMode(mode): 81 | """Alters the meaning of the arguments of the rectangle function""" 82 | attrib.rectMode = mode 83 | 84 | def imageMode(mode): 85 | """Alters the meaning of the arguments of the image function""" 86 | attrib.imageMode = mode 87 | 88 | def hint(hintconst): 89 | """Sets/unsets configuration settings. 90 | * Depth testing can be set or unset using constants DISABLE_DEPTH_TEST and 91 | ENABLE_DEPTH_TEST (default=ON). 92 | * Polygon antialiasing can be turned on or off using ENABLE_POLYGON_SMOOTH 93 | and DISABLE_POLYGON_SMOOTH (default=OFF). 94 | * Flip policy can be selected using the constants DOUBLE_FLIP_POLICY, 95 | SINGLE_FLIP_POLICY, FBO_FLIP_POLICY and ACCUM_FLIP_POLICY 96 | """ 97 | if hintconst==ENABLE_DEPTH_TEST: 98 | attrib.depthTest = True 99 | glDepthFunc(GL_LEQUAL) 100 | glEnable(GL_DEPTH_TEST) 101 | elif hintconst==DISABLE_DEPTH_TEST: 102 | attrib.depthTest = False 103 | glDisable(GL_DEPTH_TEST) 104 | elif hintconst in (DOUBLE_FLIP_POLICY,SINGLE_FLIP_POLICY, 105 | FBO_FLIP_POLICY, ACCUM_FLIP_POLICY,BACKUP_FLIP_POLICY): 106 | config.flipPolicy=hintconst 107 | else: 108 | raise ValueError,"Unknown hint" 109 | 110 | -------------------------------------------------------------------------------- /pyprocessing/colors.py: -------------------------------------------------------------------------------- 1 | #************************ 2 | # COLORS 3 | #************************ 4 | 5 | from globs import * 6 | from constants import * 7 | 8 | __all__=['_getColor','color','red','green','blue','alpha','hue','saturation','brightness', 9 | 'lerpColor', 'colorMode', 'blendColor'] 10 | 11 | def hsb_to_rgb (h,s,v,a): 12 | """Simple hsv to rgb conversion. Assumes components specified in range 0.0-1.0.""" 13 | tmp = h*5.9999 14 | hi = int (tmp) 15 | f = tmp-hi 16 | p = v * (1-s) 17 | q = v * (1-f*s) 18 | t = v * (1-(1-f)*s) 19 | if hi==0: 20 | r,g,b = v,t,p 21 | elif hi==1: 22 | r,g,b = q,v,p 23 | elif hi==2: 24 | r,g,b = p,v,t 25 | elif hi==3: 26 | r,g,b = p,q,v 27 | elif hi==4: 28 | r,g,b = t,p,v 29 | else: 30 | r,g,b = v,p,q 31 | return r,g,b,a 32 | 33 | def rgb_to_hsb(r,g,b,a): 34 | """Simple rgb to hsb conversion. Assumes components specified in range 0.0-1.0.""" 35 | maxval = max(r,g,b) 36 | minval = min(r,g,b) 37 | if maxval==minval: 38 | h = 0.0 39 | elif maxval==r: 40 | h = ((60 * (g-b)/(maxval-minval) + 360) % 360) / 360.0 41 | elif maxval==g: 42 | h = (60 * (b-r)/(maxval-minval) + 120) / 360.0 43 | else: 44 | h = (60 * (r-g)/(maxval-minval) + 240) / 360.0 45 | if maxval==0.0: 46 | s = 0.0 47 | else: 48 | s = (maxval-minval)/maxval 49 | v = maxval 50 | return (h,s,v,a) 51 | 52 | def _getColor(*color): 53 | """Analyzes the color arguments and returns a proper 4-float tuple or None""" 54 | 55 | if len(color) == 1 and type(color[0])==tuple: 56 | # a tuple, i.e., a value of type color, was passed rather than in-line values: 57 | # no transformation takes place 58 | assert (len(color[0]) == 4) 59 | return color[0] 60 | if len(color) == 1: 61 | # one value: This is tricky, because it could either convey a 62 | # gray code or an argb color. Processing has the same problem, and we 63 | # adopt the same solution, i.e., an integer with any high 8 bits set or 64 | # bigger than the allowed range for the first coordinate is viewed 65 | # as an argb color. Otherwise, it is regarded as a gray code 66 | n = color[0] 67 | if not isinstance(n,float) and (n & 0xff000000 != 0 or n>attrib.colorRange[0]): 68 | # argb color: just convert to tuple format and return 69 | color = ((n&0xff0000)>>16)/255.0, ((n&0xff00)>>8)/255.0, \ 70 | (n&0xff)/255.0, ((n&0xff000000)>>24)/255.0 71 | return color 72 | else: 73 | # a gray value. 74 | color = (color[0],color[0],color[0],attrib.colorRange[3]) 75 | elif len(color) == 2: 76 | # two values: Gray and Alpha 77 | color = (color[0],color[0],color[0],color[1]) 78 | elif len(color) == 3: 79 | # three values: RGB 80 | color = (color[0],color[1],color[2],attrib.colorRange[3]) 81 | else: 82 | assert(len(color)==4) 83 | color = tuple(float(x)/r for x,r in zip(color,attrib.colorRange)) 84 | if attrib.colorMode==HSB: color = hsb_to_rgb(*color) 85 | return color 86 | 87 | def color(*args): 88 | """This returns a color encoded as an unsigned int.""" 89 | r,g,b,a = _getColor(*args) 90 | return int(a*255)<<24 | int(r*255)<<16 | int(g*255)<<8 | int(b*255) 91 | 92 | def red(color): 93 | """Red component of the color.""" 94 | color = _getColor(color) 95 | return color[0]*attrib.colorRange[0] 96 | 97 | def green(color): 98 | """Green component of the color.""" 99 | color = _getColor(color) 100 | return color[1]*attrib.colorRange[1] 101 | 102 | def blue(color): 103 | """Blue component of the color.""" 104 | color = _getColor(color) 105 | return color[2]*attrib.colorRange[2] 106 | 107 | def alpha(color): 108 | """Alpha component of the color.""" 109 | color = _getColor(color) 110 | return color[3]*attrib.colorRange[3] 111 | 112 | def hue(color): 113 | """Hue component of the color.""" 114 | color = _getColor(color) 115 | color = rgb_to_hsb(*color) 116 | return color[0]*attrib.colorRange[0] 117 | 118 | def saturation(color): 119 | """Saturation component of the color.""" 120 | color = _getColor(color) 121 | color = rgb_to_hsb(*color) 122 | return color[1]*attrib.colorRange[1] 123 | 124 | def brightness(color): 125 | """Brightness component of the color.""" 126 | color = _getColor(color) 127 | color = rgb_to_hsb(*color) 128 | return color[2]*attrib.colorRange[2] 129 | 130 | def lerpColor(c1,c2,amt): 131 | """Returns the linear interpolation between two colors c1 and c2. 132 | amt is a value between 0.0 and 1.0.""" 133 | c1 = _getColor(c1) 134 | c2 = _getColor(c2) 135 | amtb = 1.0 - amt 136 | r,g,b,a = ([amtb*x+amt*y for x,y in zip(c1,c2)]) 137 | return int(a*255)<<24 | int(r*255)<<16 | int(g*255)<<8 | int(b*255) 138 | 139 | def colorMode(mode,*args): 140 | """Sets the color system used for specifying colors and the 141 | component ranges""" 142 | attrib.colorMode = mode 143 | if len(args)==0: 144 | pass 145 | elif len(args)==1: 146 | attrib.colorRange = args*4 147 | elif len(args)==3: 148 | attrib.colorRange = (args[0],args[1],args[2],attrib.colorRange[3]) 149 | else: 150 | assert(len(args)==4) 151 | attrib.colorRange = args 152 | 153 | # These are helper routines (grabbed from Processing's Pimage.java source) 154 | # They are used to define the various blending mode functions. They 155 | # assume 8-bit integer color coordinates 156 | 157 | def low(a, b): return min(a,b) 158 | 159 | def high(a, b): return max(a,b) 160 | 161 | def peg(a): return min(255,max(a,0)) 162 | 163 | def mix(a, b, f): return a + (((b - a) * f) >> 8); 164 | 165 | # bitwise masks 166 | 167 | ALPHA_MASK = 0xff000000 168 | RED_MASK = 0xff0000 169 | GREEN_MASK = 0xff00 170 | BLUE_MASK = 0xff 171 | 172 | # conversion from/to int/tuple 173 | 174 | def tuplecolor(i): 175 | return ((i & RED_MASK)>>16)/255.0,((i & GREEN_MASK)>>8)/255.0,\ 176 | (i & BLUE_MASK)/255.0,((i & ALPHA_MASK)>>24)/255.0 177 | 178 | def intcolor(r,g,b,a): 179 | return int(a*255)<<24 | int(r*255)<<16 | int(g*255)<<8 | int(b*255) 180 | 181 | # blend functions 182 | 183 | def blend_blend(a, b): 184 | """Combines a and b proportionally to b's alpha""" 185 | f = (b & ALPHA_MASK) >> 24; 186 | 187 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 188 | mix(a & RED_MASK, b & RED_MASK, f) & RED_MASK | 189 | mix(a & GREEN_MASK, b & GREEN_MASK, f) & GREEN_MASK | 190 | mix(a & BLUE_MASK, b & BLUE_MASK, f)); 191 | 192 | def blend_add_pin(a, b): 193 | """Adds b to a proportionally to b's alpha""" 194 | f = (b & ALPHA_MASK) >> 24; 195 | 196 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 197 | low(((a & RED_MASK) + 198 | ((b & RED_MASK) >> 8) * f), RED_MASK) & RED_MASK | 199 | low(((a & GREEN_MASK) + 200 | ((b & GREEN_MASK) >> 8) * f), GREEN_MASK) & GREEN_MASK | 201 | low((a & BLUE_MASK) + 202 | (((b & BLUE_MASK) * f) >> 8), BLUE_MASK)) 203 | 204 | def blend_sub_pin(a, b): 205 | """ Subtractive blend with clipping""" 206 | f = (b & ALPHA_MASK) >> 24; 207 | 208 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 209 | high(((a & RED_MASK) - ((b & RED_MASK) >> 8) * f), 210 | GREEN_MASK) & RED_MASK | 211 | high(((a & GREEN_MASK) - ((b & GREEN_MASK) >> 8) * f), 212 | BLUE_MASK) & GREEN_MASK | 213 | high((a & BLUE_MASK) - (((b & BLUE_MASK) * f) >> 8), 0)) 214 | 215 | def blend_lightest(a, b): 216 | """Only returns the blended lightest colour """ 217 | f = (b & ALPHA_MASK) >> 24; 218 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 219 | high(a & RED_MASK, ((b & RED_MASK) >> 8) * f) & RED_MASK | 220 | high(a & GREEN_MASK, ((b & GREEN_MASK) >> 8) * f) & GREEN_MASK | 221 | high(a & BLUE_MASK, ((b & BLUE_MASK) * f) >> 8)); 222 | 223 | def blend_darkest(a, b): 224 | """Only returns the blended darkest colour """ 225 | f = (b & ALPHA_MASK) >> 24; 226 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 227 | mix(a & RED_MASK, 228 | low(a & RED_MASK, 229 | ((b & RED_MASK) >> 8) * f), f) & RED_MASK | 230 | mix(a & GREEN_MASK, 231 | low(a & GREEN_MASK, 232 | ((b & GREEN_MASK) >> 8) * f), f) & GREEN_MASK | 233 | mix(a & BLUE_MASK, 234 | low(a & BLUE_MASK, 235 | ((b & BLUE_MASK) * f) >> 8), f)); 236 | 237 | def blend_difference(a, b): 238 | """ returns the absolute value of the difference of the input colors 239 | C = |A - B|""" 240 | # setup (this portion will always be the same) 241 | f = (b & ALPHA_MASK) >> 24; 242 | ar = (a & RED_MASK) >> 16; 243 | ag = (a & GREEN_MASK) >> 8; 244 | ab = (a & BLUE_MASK); 245 | br = (b & RED_MASK) >> 16; 246 | bg = (b & GREEN_MASK) >> 8; 247 | bb = (b & BLUE_MASK); 248 | # formula: 249 | cr = abs(ar-br) 250 | cg = abs(ag-bg) 251 | cb = abs(ab-bb) 252 | # alpha blend (this portion will always be the same) 253 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 254 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 255 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 256 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 257 | 258 | def blend_exclusion(a, b): 259 | """ Cousin of difference, algorithm used here is based on a Lingo version 260 | found here: http://www.mediamacros.com/item/item-1006687616/ 261 | (Not yet verified to be correct).""" 262 | # setup (this portion will always be the same) 263 | f = (b & ALPHA_MASK) >> 24; 264 | ar = (a & RED_MASK) >> 16; 265 | ag = (a & GREEN_MASK) >> 8; 266 | ab = (a & BLUE_MASK); 267 | br = (b & RED_MASK) >> 16; 268 | bg = (b & GREEN_MASK) >> 8; 269 | bb = (b & BLUE_MASK); 270 | # formula: 271 | cr = ar + br - ((ar * br) >> 7); 272 | cg = ag + bg - ((ag * bg) >> 7); 273 | cb = ab + bb - ((ab * bb) >> 7); 274 | 275 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 276 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 277 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 278 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 279 | 280 | def blend_multiply(a, b): 281 | """Returns the product of the input colors 282 | C = A * B """ 283 | # setup (this portion will always be the same) 284 | f = (b & ALPHA_MASK) >> 24; 285 | ar = (a & RED_MASK) >> 16; 286 | ag = (a & GREEN_MASK) >> 8; 287 | ab = (a & BLUE_MASK); 288 | br = (b & RED_MASK) >> 16; 289 | bg = (b & GREEN_MASK) >> 8; 290 | bb = (b & BLUE_MASK); 291 | # formula: 292 | cr = (ar * br) >> 8; 293 | cg = (ag * bg) >> 8; 294 | cb = (ab * bb) >> 8; 295 | # alpha blend (this portion will always be the same) 296 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 297 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 298 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 299 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 300 | 301 | def blend_screen(a, b): 302 | """Returns the inverse of the product of the inverses of the input colors 303 | (the inverse of multiply). C = 1 - (1-A) * (1-B) """ 304 | # setup (this portion will always be the same) 305 | f = (b & ALPHA_MASK) >> 24; 306 | ar = (a & RED_MASK) >> 16; 307 | ag = (a & GREEN_MASK) >> 8; 308 | ab = (a & BLUE_MASK); 309 | br = (b & RED_MASK) >> 16; 310 | bg = (b & GREEN_MASK) >> 8; 311 | bb = (b & BLUE_MASK); 312 | # formula: 313 | cr = 255 - (((255 - ar) * (255 - br)) >> 8); 314 | cg = 255 - (((255 - ag) * (255 - bg)) >> 8); 315 | cb = 255 - (((255 - ab) * (255 - bb)) >> 8); 316 | # alpha blend (this portion will always be the same) 317 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 318 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 319 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 320 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 321 | 322 | def blend_overlay(a, b): 323 | """Returns either multiply or screen for darker or lighter values of A 324 | (the inverse of hard light) 325 | C = 326 | A < 0.5 : 2 * A * B 327 | A >=0.5 : 1 - (2 * (255-A) * (255-B)) 328 | """ 329 | # setup (this portion will always be the same) 330 | f = (b & ALPHA_MASK) >> 24; 331 | ar = (a & RED_MASK) >> 16; 332 | ag = (a & GREEN_MASK) >> 8; 333 | ab = (a & BLUE_MASK); 334 | br = (b & RED_MASK) >> 16; 335 | bg = (b & GREEN_MASK) >> 8; 336 | bb = (b & BLUE_MASK); 337 | # formula: 338 | if (ar < 128): cr=((ar*br)>>7) 339 | else: cr = (255-(((255-ar)*(255-br))>>7)) 340 | if (ag < 128): cg=((ag*bg)>>7) 341 | else: cg = (255-(((255-ag)*(255-bg))>>7)) 342 | if (ab < 128): cb=((ab*bb)>>7) 343 | else: cb = (255-(((255-ab)*(255-bb))>>7)) 344 | # alpha blend (this portion will always be the same) 345 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 346 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 347 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 348 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 349 | 350 | def blend_hard_light(a, b): 351 | """Returns either multiply or screen for darker or lighter values of B 352 | (the inverse of overlay) 353 | C = 354 | B < 0.5 : 2 * A * B 355 | B >=0.5 : 1 - (2 * (255-A) * (255-B)) 356 | """ 357 | # setup (this portion will always be the same) 358 | f = (b & ALPHA_MASK) >> 24; 359 | ar = (a & RED_MASK) >> 16; 360 | ag = (a & GREEN_MASK) >> 8; 361 | ab = (a & BLUE_MASK); 362 | br = (b & RED_MASK) >> 16; 363 | bg = (b & GREEN_MASK) >> 8; 364 | bb = (b & BLUE_MASK); 365 | # formula: 366 | if (br < 128): cr=((ar*br)>>7) 367 | else: cr = (255-(((255-ar)*(255-br))>>7)) 368 | if (bg < 128): cg=((ag*bg)>>7) 369 | else: cg = (255-(((255-ag)*(255-bg))>>7)) 370 | if (bb < 128): cb=((ab*bb)>>7) 371 | else: cb = (255-(((255-ab)*(255-bb))>>7)) 372 | # alpha blend (this portion will always be the same) 373 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 374 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 375 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 376 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 377 | 378 | 379 | def blend_soft_light(a, b): 380 | """Returns the inverse multiply plus screen, which simplifies to 381 | C = 2AB + A^2 - 2A^2B 382 | """ 383 | # setup (this portion will always be the same) 384 | f = (b & ALPHA_MASK) >> 24; 385 | ar = (a & RED_MASK) >> 16; 386 | ag = (a & GREEN_MASK) >> 8; 387 | ab = (a & BLUE_MASK); 388 | br = (b & RED_MASK) >> 16; 389 | bg = (b & GREEN_MASK) >> 8; 390 | bb = (b & BLUE_MASK); 391 | # formula: 392 | cr = ((ar*br)>>7) + ((ar*ar)>>8) - ((ar*ar*br)>>15); 393 | cg = ((ag*bg)>>7) + ((ag*ag)>>8) - ((ag*ag*bg)>>15); 394 | cb = ((ab*bb)>>7) + ((ab*ab)>>8) - ((ab*ab*bb)>>15); 395 | # alpha blend (this portion will always be the same) 396 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 397 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 398 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 399 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 400 | 401 | 402 | def blend_dodge(a, b): 403 | """Returns the first (underlay) color divided by the inverse of 404 | the second (overlay) color. C = A / (255-B) 405 | """ 406 | # setup (this portion will always be the same) 407 | f = (b & ALPHA_MASK) >> 24; 408 | ar = (a & RED_MASK) >> 16; 409 | ag = (a & GREEN_MASK) >> 8; 410 | ab = (a & BLUE_MASK); 411 | br = (b & RED_MASK) >> 16; 412 | bg = (b & GREEN_MASK) >> 8; 413 | bb = (b & BLUE_MASK); 414 | # formula: 415 | if (br==255): cr = 255 416 | else: cr= peg((ar << 8) / (255 - br)) 417 | if (bg==255): cg =255 418 | else: cg= peg((ag << 8) / (255 - bg)) 419 | if (bb==255): cb = 255 420 | else: cb = peg((ab << 8) / (255 - bb)) 421 | # alpha blend (this portion will always be the same) 422 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 423 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 424 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 425 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 426 | 427 | def blend_burn(a, b): 428 | """Returns the inverse of the inverse of the first (underlay) color 429 | divided by the second (overlay) color. C = 255 - (255-A) / B 430 | """ 431 | # setup (this portion will always be the same) 432 | f = (b & ALPHA_MASK) >> 24; 433 | ar = (a & RED_MASK) >> 16; 434 | ag = (a & GREEN_MASK) >> 8; 435 | ab = (a & BLUE_MASK); 436 | br = (b & RED_MASK) >> 16; 437 | bg = (b & GREEN_MASK) >> 8; 438 | bb = (b & BLUE_MASK); 439 | # formula: 440 | if (br==0): cr = 0 441 | else: cr= 255 - peg(((255 - ar) << 8) / br); 442 | if (bg==0): cg = 0 443 | else: cg= 255 - peg(((255 - ag) << 8) / bg); 444 | if (bb==0): cb = 0 445 | else: cb = 255 - peg(((255 - ab) << 8) / bb); 446 | # alpha blend (this portion will always be the same) 447 | return (low(((a & ALPHA_MASK) >> 24) + f, 0xff) << 24 | 448 | (peg(ar + (((cr - ar) * f) >> 8)) << 16) | 449 | (peg(ag + (((cg - ag) * f) >> 8)) << 8) | 450 | (peg(ab + (((cb - ab) * f) >> 8)) ) ); 451 | 452 | # This array maps the blending modes to the proper color blending functions 453 | blendfunc = [blend_blend, blend_add_pin, blend_sub_pin, blend_darkest, blend_lightest, 454 | blend_difference, blend_exclusion, blend_multiply, blend_screen, blend_overlay, 455 | blend_hard_light, blend_soft_light, blend_dodge, blend_burn] 456 | 457 | def blendColor(c1, c2, MODE): 458 | """Implements the blending of two colors. MODE is one of the blend mode 459 | constants defined in pyprocessing (an integer between 0 and 13). This expects 460 | colors expressed as integers.""" 461 | return blendfunc[MODE](c1,c2) 462 | 463 | 464 | -------------------------------------------------------------------------------- /pyprocessing/config.py: -------------------------------------------------------------------------------- 1 | """ 2 | Holds system wide configuration options. 3 | """ 4 | 5 | from constants import * 6 | import os 7 | 8 | 9 | """"The preferences below are used as defaults if none of the configuration 10 | files exist. Being defaults, they have the lowest priority of the importing 11 | procedure.""" 12 | 13 | # Whether or not to try to obtain an OpenGL context supporting multisampling. 14 | # This usually produces nicer results but is unsupported in older hardware. 15 | # Even if this is set to false, however, pyprocessing will fallback to 16 | # a non-multisampled config if it is not supported. 17 | multisample = True 18 | 19 | # Whether or not to invert the y axis. This is required for strict conformity 20 | # with Processing. Beyond altering the modelview matrix, this also implies that 21 | # the drawing of some primitives such as arc or text be modified. 22 | coordInversionHack = True 23 | 24 | # Since OpenGL actually addresses lines between pixels, in some cases 25 | # shifting the drawing by half a pixel makes lines sharper. 26 | halfPixelShiftHack = False # off by default 27 | 28 | # try to get around the artifacts when drawing filled polygons in smooth mode 29 | smoothFixHack = False # off by default 30 | smoothTurnedOn = False # Used internally to tell whether smooth was on 31 | 32 | # flipping policy: uncomment only one of the assignments below 33 | # flipPolicy = DOUBLE_FLIP_POLICY # this should work for modern boards/drivers 34 | # flipPolicy = SINGLE_FLIP_POLICY # use this for Intel 945 under Windows or other cheap boards 35 | # flipPolicy = FBO_FLIP_POLICY # use this for modern boards/drivers where flip uses swap and not copy 36 | # flipPolicy = ACCUM_FLIP_POLICY # use this for cheap boards where 'SINGLE' produces too much flickering 37 | flipPolicy = BACKUP_FLIP_POLICY # this is the default and should work on all boards 38 | 39 | 40 | 41 | 42 | """Tries to import the global preferences from the globalconfig.txt file 43 | located inside the pyprocessing installation folder. These preferences 44 | have higher priority than defaults, but will be overriden by the user 45 | preferences if they exist.""" 46 | 47 | try: 48 | f = open(os.path.dirname(__file__)+"/globalconfig.txt","r") 49 | contents = f.read() 50 | contents = contents.split("\n") 51 | for i in contents: 52 | if i != "": vars()[i.split(":")[0]] = eval(i.split(":")[1]) 53 | except: 54 | None 55 | 56 | 57 | 58 | 59 | """Loads the user configuration preferences from the userconfig.txt file situated 60 | on the user's home path. Like the global preferences, they can be changed manually 61 | with a text editor. User preferences have the highest priority, meaning that if 62 | the import from userconfig.txt is successful, then the global preferencesill 63 | be overriden.""" 64 | 65 | try: 66 | f = open(os.path.expanduser("~/.pyprocessing/userconfig.txt"),"r") 67 | contents = f.read() 68 | contents = contents.split("\n") 69 | for i in contents: 70 | if i != "": vars()[i.split(":")[0]] = eval(i.split(":")[1]) 71 | except: 72 | None 73 | -------------------------------------------------------------------------------- /pyprocessing/constants.py: -------------------------------------------------------------------------------- 1 | import math 2 | import pyglet.gl as gl 3 | 4 | #************************ 5 | # CONSTANTS 6 | #************************ 7 | 8 | version = "0.1.3.23" # This version of pyprocessing 9 | 10 | #keycodes 11 | F1 = 65470 12 | F2 = 65471 13 | F3 = 65472 14 | F4 = 65473 15 | F5 = 65474 16 | F6 = 65475 17 | F7 = 65476 18 | F8 = 65477 19 | F9 = 65478 20 | F10 = 65479 21 | F11 = 65480 22 | F12 = 65481 23 | F13 = 65482 24 | F14 = 65483 25 | F15 = 65484 26 | F16 = 65485 27 | LSHIFT = SHIFT = 65505 28 | RSHIFT = 65506 29 | LCTRL = CTRL = 65507 30 | RCTRL = 65508 31 | CAPSLOCK = 65509 32 | LMETA = META = 65511 33 | RMETA = 65512 34 | LALT = ALT = 65513 35 | RALT = 65514 36 | LWINDOWS = WINDOWS = 65515 37 | RWINDOWS = 65516 38 | LCOMMAND = COMMAND = 65517 39 | RCOMMAND = 65518 40 | LOPTION = 65488 41 | ROPTION = 65489 42 | BACKSPACE = 65288 43 | TAB = 65289 44 | LINEFEED = 65290 45 | CLEAR = 65291 46 | RETURN = 65293 47 | ENTER = 65293 48 | PAUSE = 65299 49 | SCROLLLOCK = 65300 50 | SYSREQ = 65301 51 | ESCAPE = 65307 52 | HOME = 65360 53 | LEFT = 65361 54 | UP = 65362 55 | RIGHT = 65363 56 | DOWN = 65364 57 | PAGEUP = 65365 58 | PAGEDOWN = 65366 59 | END = 65367 60 | BEGIN = 65368 61 | DELETE = 65535 62 | SELECT = 65376 63 | PRINT = 65377 64 | EXECUTE = 65378 65 | INSERT = 65379 66 | UNDO = 65381 67 | REDO = 65382 68 | MENU = 65383 69 | FIND = 65384 70 | CANCEL = 65385 71 | HELP = 65386 72 | BREAK = 65387 73 | 74 | CODED = '\0' 75 | 76 | #rectmode/ellipsemode/mousebutton 77 | CORNER = 1 78 | CORNERS = 2 79 | CENTER = 3 80 | RADIUS = 4 81 | 82 | #textalign 83 | TOP = 7 84 | BOTTOM = 8 85 | BASELINE = 9 86 | 87 | # this maps Processing constants to strings used by pyglet's text 88 | # rendering subsystem 89 | textAlignConst = {LEFT:'left', RIGHT:'right', 90 | CENTER:'center', TOP:'top', 91 | BOTTOM:'bottom', BASELINE:'baseline'} 92 | 93 | # colorMode 94 | RGB=0 95 | HSB=1 96 | 97 | # math 98 | PI = math.pi 99 | TWO_PI = PI*2 100 | HALF_PI = PI/2 101 | 102 | # hints 103 | ENABLE_DEPTH_TEST = 'ENABLE_DEPTH_TEST' 104 | DISABLE_DEPTH_TEST = 'DISABLE_DEPTH_TEST' 105 | DISABLE_POLYGON_SMOOTH = 'DISABLE_POLYGON_SMOOTH' 106 | DOUBLE_FLIP_POLICY = 'DOUBLE_FLIP_POLICY' 107 | SINGLE_FLIP_POLICY = 'SINGLE_FLIP_POLICY' 108 | FBO_FLIP_POLICY = 'FBO_FLIP_POLICY' 109 | ACCUM_FLIP_POLICY = 'ACCUM_FLIP_POLICY' 110 | BACKUP_FLIP_POLICY = 'BACKUP_FLIP_POLICY' 111 | 112 | #filter modes 113 | THRESHOLD = 'THRESOLD' 114 | GRAY = 'GRAY' 115 | INVERT = 'INVERT' 116 | POSTERIZE = 'POSTERIZE' 117 | BLUR = 'BLUR' 118 | OPAQUE = 'OPAQUE' 119 | ERODE = 'ERODE' 120 | DILATE = 'DILATE' 121 | 122 | # shapes 123 | POINTS = gl.GL_POINTS 124 | LINES = gl.GL_LINES 125 | TRIANGLES = gl.GL_TRIANGLES 126 | TRIANGLE_FAN = gl.GL_TRIANGLE_FAN 127 | TRIANGLE_STRIP = gl.GL_TRIANGLE_STRIP 128 | QUADS = gl.GL_QUADS 129 | QUAD_STRIP = gl.GL_QUAD_STRIP 130 | CLOSE = 1 131 | 132 | #blend modes 133 | BLEND, ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, \ 134 | MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN = range(14) 135 | 136 | #texture modes 137 | NORMALIZED = 'NORMALIZED' 138 | IMAGE = 'IMAGE' 139 | 140 | # image formats 141 | RGB = 'RGB' 142 | ARGB = 'RGBA' 143 | ALPHA = 'A' 144 | 145 | #stroke join modes 146 | MITER = 'MITER' 147 | BEVEL = 'BEVEL' 148 | ROUND = 'ROUND' 149 | 150 | #strokecap modes 151 | SQUARE = 'SQUARE' 152 | PROJECT = 'PROJECT' 153 | 154 | # cursor types 155 | ARROW = None 156 | CROSS = 'crosshair' 157 | HAND = 'hand' 158 | MOVE = 'size' 159 | TEXT = 'text' 160 | WAIT = 'wait' 161 | 162 | #perlin noise table 163 | perlin = ( 164 | 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103, 165 | 30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197, 166 | 62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20, 167 | 125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231, 168 | 83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102, 169 | 143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200, 170 | 196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226, 171 | 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16, 172 | 58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70, 173 | 221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113, 174 | 224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144, 175 | 12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181, 176 | 199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236, 177 | 205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, 178 | 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103, 179 | 30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197, 180 | 62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20, 181 | 125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231, 182 | 83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102, 183 | 143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200, 184 | 196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226, 185 | 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16, 186 | 58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70, 187 | 221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113, 188 | 224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144, 189 | 12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181, 190 | 199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236, 191 | 205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180) 192 | -------------------------------------------------------------------------------- /pyprocessing/fbo.py: -------------------------------------------------------------------------------- 1 | import pyglet 2 | from pyglet.gl import * 3 | from ctypes import * 4 | 5 | class FBO(object): 6 | """Basic helper for using OpenGL's Frame Buffer Object (FBO)""" 7 | 8 | @staticmethod 9 | def supported(): 10 | """A static method that tells if FBOs are supported. 11 | If not sure, call this before creating an FBO instance.""" 12 | 13 | # Check if the board / driver supports FBO 14 | if not gl_info.have_extension("GL_EXT_framebuffer_object"): 15 | return False 16 | if not gl_info.have_extension("GL_ARB_draw_buffers"): 17 | return False 18 | 19 | return True 20 | 21 | def __init__(self, width=100, height=100): 22 | """Creates a Frame Buffer Object (FBO)""" 23 | 24 | # Must be supported... 25 | assert (FBO.supported()) 26 | 27 | self.width = width 28 | self.height = height 29 | 30 | # Setting it up 31 | self.framebuffer = c_uint(0) 32 | self.depthbuffer = c_uint(0) 33 | self.img = c_uint(0) 34 | 35 | glGenFramebuffersEXT(1, byref(self.framebuffer)) 36 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, self.framebuffer) 37 | 38 | # Adding a Depth Buffer 39 | glGenRenderbuffersEXT(1, byref(self.depthbuffer)) 40 | glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, self.depthbuffer) 41 | glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, self.width, self.height) 42 | glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 43 | GL_RENDERBUFFER_EXT, self.depthbuffer) 44 | 45 | # Adding a Texture To Render To 46 | glGenTextures(1, byref(self.img)) 47 | glBindTexture(GL_TEXTURE_2D, self.img) 48 | 49 | # Black magic (only works with these two lines) 50 | # (nearest works, as well as linear) 51 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 52 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR) 53 | 54 | # Add the texture to the frame buffer as a color buffer 55 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, self.width, self.height, 56 | 0, GL_RGBA, GL_UNSIGNED_BYTE, None) 57 | glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 58 | GL_TEXTURE_2D, self.img, 0) 59 | 60 | # Check if it worked so far 61 | status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) 62 | assert(status == GL_FRAMEBUFFER_COMPLETE_EXT) 63 | 64 | # Release framebuffer 65 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) 66 | 67 | def attach(self): 68 | """Call this before rendering to the FBO.""" 69 | 70 | # First we bind the FBO so we can render to it 71 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, self.framebuffer) 72 | 73 | # Save the view port and set it to the size of the texture 74 | glPushAttrib(GL_VIEWPORT_BIT) 75 | glViewport(0,0,self.width,self.height) 76 | 77 | def detach(self): 78 | """Call this after rendering to the FBO so that rendering now 79 | goes to the regular frame buffer.""" 80 | 81 | # Restore old view port and set rendering back to default frame buffer 82 | glPopAttrib() 83 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) 84 | 85 | def getTexture(self): 86 | """Returns a pyglet image with the contents of the FBO.""" 87 | self.data = (c_ubyte * (self.width*self.height*4))() 88 | 89 | glGetTexImage(GL_TEXTURE_2D, # target, 90 | 0, # level, 91 | GL_RGBA, # format, 92 | GL_UNSIGNED_BYTE , # type, 93 | self.data) # GLvoid * img 94 | 95 | return pyglet.image.ImageData (self.width, self.height, 'RGBA', self.data) 96 | 97 | def __del__(self): 98 | """Deallocates memory. Call this before discarding FBO.""" 99 | glDeleteFramebuffersEXT(1, byref(self.framebuffer)) 100 | glDeleteRenderbuffersEXT(1, byref(self.depthbuffer)) 101 | glDeleteTextures(1,byref(self.img)) 102 | 103 | 104 | -------------------------------------------------------------------------------- /pyprocessing/flippolicy.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module contains several window classes derived from pyglet's 3 | window classes. They implement variations on the standard way 4 | of handling the flip method. These are necessary because of the 5 | implementation-dependent way used by OpenGL to flip between the back and 6 | the front buffer. 7 | 8 | In most cases where a modern graphics board is supported 9 | by a recent driver, flipping works by copying the back to the front buffer, 10 | which is necessary whenever the screen is not completely redrawn from 11 | scratch between one frame and the next. If this is the case in your installation, 12 | the regular PyprocessingWindow, which is merely a pyglet.window.Window under 13 | another name, should be used and will give you the best performance. 14 | 15 | Some drivers, however, do not implement flip by copying, but merely makes the 16 | video controller address the other video memory buffer. This is what is called 17 | flipping by swapping. In such cases, programs which rely on a stable frame 18 | buffer will not work as expected. I spent a long time looking for portable 19 | ways of enforcing a copy flip, but it seems that there is no reliable way of 20 | doing that. 21 | 22 | One way of coping with the problem is to use single buffering, so that drawing 23 | is actually performed on the front buffer. This is not a good idea in 24 | general, because the drawing may result in flickering and other visual 25 | visual artifacts. Nevertheless, I found that the Intel 945 express chipset 26 | works fairly well in this mode under MS Windows. Other driver/board/OS 27 | combinations might also work well in this mode. If this is the case, 28 | instancing a SingleBufferWindow will solve the problem. 29 | 30 | Another way of providing a stable drawing buffer is to draw to a separate 31 | off-screen buffer. The most efficient way of doing this is to use a Frame 32 | Buffer Object, or FBO. The idea then is to copy the FBO to the back buffer 33 | just before the flip. The FBOWindow implements just this. 34 | 35 | Unfortunately the FBO extension is not common in old hardware. In this case, 36 | another type of buffer might be used to store a copy of the back buffer. The 37 | idea is to copy the back buffer to such an auxiliary buffer, flip and then 38 | copy it back. The simplest, but probably not the most efficient way of doing 39 | this is to use the accumulation buffer, which can be copied from/to with a 40 | single glAccum instruction. The AccumWindow implements this policy. 41 | 42 | The default flipping policy is governed by appropriate calls to the 43 | hint() function just before calling size(). You might wish to change the default 44 | by editting the config variable in the globs submodule. 45 | """ 46 | 47 | import pyglet 48 | from ctypes import * 49 | from pyglet.gl import * 50 | from fbo import FBO 51 | from pimage import * 52 | 53 | __all__=['PyprocessingWindow','FBOWindow','SingleBufferWindow','AccumWindow','BackupWindow'] 54 | 55 | 56 | class PyprocessingWindow (pyglet.window.Window): 57 | """This is just a wrapper for the pyglet window class. If any 58 | window method or attribute should be messed with for all of pyprocessing's 59 | window classes, it's best to do it here.""" 60 | pass 61 | 62 | class FBOWindow(PyprocessingWindow): 63 | """This is a pyglet window where drawing in fact occurs inside a FBO. 64 | The flip method is overridden so that instead of merely swapping the 65 | back and front buffers, the FBO is first blitted onto the back buffer. 66 | The idea is to provide a stable drawing canvas which is not erased or 67 | corrupted by the flip.""" 68 | 69 | def __init__(self, *args, **keyargs): 70 | """Constructor""" 71 | # construct the base class 72 | super(FBOWindow, self).__init__(*args, **keyargs) 73 | # construct the fbo and attach it 74 | self.fbo = FBO(self.width, self.height) 75 | self.fbo.attach() 76 | 77 | def flip(self): 78 | """Override the flip method.""" 79 | # cease using the FBO and start using the regular frame buffer 80 | self.fbo.detach() 81 | # save the OpenGL state 82 | glMatrixMode(GL_PROJECTION) 83 | glPushMatrix() 84 | glLoadIdentity() 85 | glMatrixMode(GL_MODELVIEW) 86 | glPushMatrix() 87 | glLoadIdentity() 88 | glViewport(0,0,self.width,self.height) 89 | # prepares and blits the FBO buffer onto the back buffer. 90 | glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, self.fbo.framebuffer) 91 | glReadBuffer(GL_COLOR_ATTACHMENT0_EXT) 92 | glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0) 93 | glDrawBuffer(GL_BACK) 94 | glBlitFramebufferEXT(0, 0, self.width, self.height, 0, 0, self.width, self.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); 95 | glMatrixMode(GL_PROJECTION) 96 | glPopMatrix() 97 | glMatrixMode(GL_MODELVIEW) 98 | glPopMatrix() 99 | # do the actual flip 100 | super (FBOWindow, self).flip() 101 | # reattach the fbo for further drawing 102 | self.fbo.attach() 103 | 104 | def on_resize(self,w,h): 105 | super (FBOWindow, self).on_resize(w,h) 106 | self.fbo.detach() 107 | self.fbo = FBO(w,h) 108 | self.fbo.attach() 109 | 110 | class SingleBufferWindow(PyprocessingWindow): 111 | """This is a pyglet window with a single buffer config.""" 112 | 113 | def __init__(self, *args, **keyargs): 114 | """Constructor""" 115 | # construct the base class 116 | if 'config' in keyargs: 117 | config = keyargs['config'] 118 | else: 119 | config = Config(depth_size=24) 120 | config.double_buffer = False 121 | keyargs['config'] = config 122 | super(SingleBufferWindow, self).__init__(*args, **keyargs) 123 | glDrawBuffer(GL_FRONT) 124 | 125 | def flip(self): pass 126 | 127 | class BackupWindow(PyprocessingWindow): 128 | """This is a pyglet window for which an array is used to keep the back 129 | buffer contents consistent. The flip method is overridden so that 130 | instead of merely swapping the back and front buffers, the back buffer 131 | contents are copied to an array inside the CPU's memory, and after the flip 132 | the contents are copied back to the back buffer.""" 133 | 134 | def __init__(self, *args, **keyargs): 135 | """Constructor""" 136 | # construct the base class 137 | if 'config' in keyargs: 138 | config = keyargs['config'] 139 | else: 140 | config = Config(double_buffer=True,depth_size=24) 141 | keyargs['config'] = config 142 | super(BackupWindow, self).__init__(*args, **keyargs) 143 | self.buffer = ( GLubyte * (4*self.width*self.height) )() 144 | self.currentpos = (c_int*2)() 145 | 146 | def flip(self): 147 | """Override the flip method.""" 148 | glReadPixels(0, 0, self.width, self.height, GL_RGBA, GL_UNSIGNED_BYTE, self.buffer) 149 | super (BackupWindow, self).flip() 150 | glGetIntegerv(GL_CURRENT_RASTER_POSITION, self.currentpos) 151 | glMatrixMode (GL_MODELVIEW) 152 | glPushMatrix() 153 | glLoadIdentity() 154 | glMatrixMode (GL_PROJECTION) 155 | glPushMatrix() 156 | glLoadIdentity() 157 | glWindowPos2i(0,0) 158 | glDisable(GL_DEPTH_TEST) 159 | glDrawPixels(self.width, self.height, GL_RGBA, GL_UNSIGNED_BYTE, self.buffer) 160 | glEnable(GL_DEPTH_TEST) 161 | glPopMatrix() 162 | glMatrixMode (GL_MODELVIEW) 163 | glPopMatrix() 164 | glRasterPos2i(self.currentpos[0],self.currentpos[1]) 165 | 166 | def on_resize(self,w,h): 167 | """Window changed size. Must reallocate backing buffer.""" 168 | super (FBOWindow, self).on_resize(w,h) 169 | self.buffer = ( GLubyte * (4*w*h) )(0) 170 | 171 | class AccumWindow(PyprocessingWindow): 172 | """This is a pyglet window for which an accumulation buffer is defined. 173 | The flip method is overridden so that instead of merely swapping the 174 | back and front buffers, a copy of the back buffer is blitted onto the accum 175 | buffer, and after the flip the accum buffer is copied back. 176 | The idea is to provide a stable drawing canvas which is not erased or 177 | corrupted by the flip.""" 178 | 179 | def __init__(self, *args, **keyargs): 180 | """Constructor""" 181 | # construct the base class 182 | if 'config' in keyargs: 183 | config = keyargs['config'] 184 | else: 185 | config = Config(double_buffer=True,depth_size=24) 186 | config.accum_alpha_size = 8 187 | config.accum_red_size = 8 188 | config.accum_green_size = 8 189 | config.accum_blue_size = 8 190 | keyargs['config'] = config 191 | super(AccumWindow, self).__init__(*args, **keyargs) 192 | 193 | def flip(self): 194 | """Override the flip method.""" 195 | # copy from the the back buffer to the accumulation buffer 196 | glAccum(GL_LOAD, 1.0) 197 | # do the actual flip 198 | super (AccumWindow, self).flip() 199 | # copy the accum buffer to the back buffer 200 | glAccum(GL_RETURN, 1) 201 | -------------------------------------------------------------------------------- /pyprocessing/fonts.py: -------------------------------------------------------------------------------- 1 | #************************ 2 | # FONT/TEXT STUFF 3 | #************************ 4 | 5 | import pyglet 6 | from pyglet.gl import * 7 | from globs import * 8 | from constants import * 9 | import config 10 | 11 | __all__=['textAlign', 'createFont', 'textFont', 'htmlText', 'text', 12 | 'textSize', 'textWidth', 'textAscent', 'textDescent'] 13 | 14 | def textAlign (align,yalign=BASELINE): 15 | """Set the text alignment attributes.""" 16 | attrib.textAlign = (align, yalign) 17 | 18 | def createFont(family = None, size = 16, bold=False, italic=False): 19 | """Creates a font for subsequent use""" 20 | return {"font_name":family, "font_size":size, "bold":bold, "italic":italic } 21 | 22 | def textSize(size): 23 | """Changes the size of the current font to 'size' (in pixels)""" 24 | attrib.font['font_size'] = size 25 | 26 | def textFont (font, size=None): 27 | """Set font as current font. Should be object created with createFont""" 28 | attrib.font = font 29 | if size!=None: attrib.font['font_size'] = size 30 | 31 | def textWidth (data): 32 | """Returns the estimated width in pixels of the string 'data' rendered 33 | in the current font""" 34 | label = pyglet.text.Label(data, 35 | x=0, y=0, 36 | anchor_x=textAlignConst[attrib.textAlign[0]], 37 | anchor_y=textAlignConst[attrib.textAlign[1]], 38 | **attrib.font) 39 | return label.content_width 40 | 41 | def textAscent (): 42 | """Returns the ascent of the current font, i.e., the height starting 43 | from the baseline.""" 44 | fontspec = {'name':attrib.font.get('font_name', None), 45 | 'size':attrib.font.get('font_size', None), 46 | 'italic':attrib.font.get('italic', False), 47 | 'bold':attrib.font.get('bold', False)} 48 | font = pyglet.font.load(**fontspec) 49 | return font.ascent 50 | 51 | def textDescent (): 52 | """Returns the descent of the current font, i.e., the vertical size 53 | below the baseline.""" 54 | fontspec = {'name':attrib.font.get('font_name', None), 55 | 'size':attrib.font.get('font_size', None), 56 | 'italic':attrib.font.get('italic', False), 57 | 'bold':attrib.font.get('bold', False)} 58 | font = pyglet.font.load(**fontspec) 59 | return -font.descent 60 | 61 | def htmlText(string, x, y, z = 0): 62 | """Draws the html text at x,y,z""" 63 | if attrib.fillColor != None: 64 | r,g,b,a=[int (c*255) for c in attrib.fillColor] 65 | label = pyglet.text.HTMLLabel(string, location=attrib.location, 66 | x=x, y=y, width=width, 67 | anchor_x=textAlignConst[attrib.textAlign[0]], 68 | anchor_y=textAlignConst[attrib.textAlign[1]], 69 | multiline=True) 70 | label.color=(r,g,b,a) 71 | if config.coordInversionHack: 72 | glPushMatrix() 73 | glTranslatef(0,y*2,0) 74 | glScalef(1,-1,1) 75 | label.draw() 76 | glPopMatrix() 77 | else: 78 | label.draw() 79 | 80 | def text(string, x, y, *args): 81 | """Draws text at x,y. Argument list is of the form: 82 | text(string,x,y) 83 | text(string,x,y,z) 84 | text(string,x,y,width,height) 85 | text(string,x,y,width,height,z) 86 | """ 87 | # Do nothing if no fill color is defined 88 | if attrib.fillColor == None: return 89 | # get color 90 | r,g,b,a=[int (c*255) for c in attrib.fillColor] 91 | # Obtain z coordinate 92 | if len(args) == 1: 93 | z = args[0] 94 | elif len(args)== 3: 95 | z = args[2] 96 | else: 97 | z = 0 98 | # create a label object 99 | label = pyglet.text.Label(string, 100 | x=x, y=y, color=(r,g,b,a), 101 | anchor_x=textAlignConst[attrib.textAlign[0]], 102 | anchor_y=textAlignConst[attrib.textAlign[1]], 103 | **attrib.font) 104 | # Obtain width and height 105 | if len(args)>1: 106 | label.width, label.height = args[0],args[1] 107 | label.multiline = True 108 | else: 109 | # see if the string has newlines 110 | s = string.split('\n') 111 | if len(s)>1: 112 | # Now follows a horribly inadequate way of figuring out 113 | # a reasonable value for the width property of the label 114 | w = 0 115 | for line in s: 116 | w = max(w,textWidth(line)) 117 | label.width = w 118 | print w 119 | label.multiline=True 120 | 121 | glPushMatrix() 122 | glTranslatef(0,0,z) 123 | if config.coordInversionHack: 124 | glPushMatrix() 125 | glTranslatef(0,y*2,0) 126 | glScalef(1,-1,1) 127 | label.draw() 128 | glPopMatrix() 129 | else: 130 | label.draw() 131 | glPopMatrix() 132 | -------------------------------------------------------------------------------- /pyprocessing/globalconfig.txt: -------------------------------------------------------------------------------- 1 | multisample:True 2 | coordInversionHack:True 3 | halfPixelShiftHack:False 4 | smoothFixHack:False 5 | flipPolicy:BACKUP_FLIP_POLICY 6 | 7 | -------------------------------------------------------------------------------- /pyprocessing/globs.py: -------------------------------------------------------------------------------- 1 | from constants import * 2 | import pyglet,os 3 | 4 | __all__ = ['mouse', 'pmouse', 'attrib', 'frame', 'key', 'canvas', 'shape', 5 | 'screen', 'callback'] 6 | 7 | #************************ 8 | # GLOBALS 9 | #************************ 10 | 11 | class mouse: 12 | """Stores mouse state""" 13 | pressed = False # Tells if any mouse button is pressed 14 | x = 0 # x coordinate of mouse 15 | y = 0 # y coordinate of mouse 16 | button = None # state of mouse buttons 17 | 18 | class pmouse: 19 | """Store previous position of mouse""" 20 | pressed = False # Tells if any mouse button is pressed 21 | x = 0 # x coordinate of mouse 22 | y = 0 # y coordinate of mouse 23 | savex = 0 # saved x from the previous frame 24 | savey = 0 # saved y from the previous frame 25 | button = None # state of mouse buttons 26 | 27 | class key: 28 | """Stores keyboard state""" 29 | char = "" 30 | code = 0 31 | modifiers = None 32 | pressed = False 33 | 34 | class canvas: 35 | """Stores the drawing window attributes""" 36 | window = None 37 | # These two symbols were relocated to the __builtin__ namespace 38 | #width = 100 39 | #height = 100 40 | 41 | class screen: 42 | """Current window properties.""" 43 | co = 2 44 | pixels = [] 45 | width = None 46 | height = None 47 | 48 | class attrib: 49 | """Drawing attributes""" 50 | strokeJoin = MITER 51 | strokeCap = SQUARE 52 | textureMode = IMAGE 53 | strokeColor = (0,0,0,1) 54 | fillColor = (1,1,1,1) 55 | tintColor = None 56 | strokeWeight = 1 57 | font = {} 58 | location = pyglet.resource.FileLocation(os.path.dirname(__file__)) 59 | rectMode = CORNER 60 | ellipseMode = CENTER 61 | imageMode = CORNER 62 | textAlign = (LEFT,BASELINE) 63 | # color attribs 64 | colorMode = RGB 65 | colorRange = (255.0,255.0,255.0,255.0) 66 | # light attribs 67 | lights = False 68 | lightCount = 0 69 | lightSpecular = (0,0,0,1) 70 | lightFalloff = (1, 0, 0) # constant, linear, quadratic 71 | # depth testing 72 | depthTest = True 73 | texture = False 74 | 75 | class frame: 76 | """Frame rate and the like.""" 77 | loop=True 78 | rate=10 # estimated frame rate 79 | targetRate = 60 # the target frame rate 80 | count=0 # number of frames displayed since the application started 81 | 82 | class shape: 83 | """Attributes for shapes.""" 84 | quadric = None # Stores a gluQuadricObject 85 | tess = None # Stores a gluTesselatorObject 86 | ellipseFillDL = None # Stores a display list for a filled ellipse 87 | ellipseStrokeDL = None # Stores a display list for an outline ellipse 88 | cubeFillVL = None # Stores a vertex list for drawing a cube with quads 89 | cubeStrokeVL = None # Stores a vertex list for drawing a cube with line segments 90 | type = None # stores the type of the shape as passed to function beginShape 91 | sphereDetail = (20,10) 92 | bezierDetail = 40 93 | curveDetail = 20 94 | ellipseDetail = 100 95 | tension = 0.5 96 | bezierBlend = [] 97 | vtx = [] 98 | nrm = [] 99 | 100 | 101 | class callback: 102 | """Call back functions.""" 103 | 104 | @staticmethod 105 | def dummy(*args): 106 | """A callback function that does nothing.""" 107 | pass 108 | 109 | """All of these are imported from the user space 110 | by the 'run' function or else fall back to dummy""" 111 | draw = mousePressed = mouseReleased = mouseClicked = mouseDragged = \ 112 | mouseMoved = keyPressed = keyReleased = keyTyped = exit = \ 113 | screenResized = dummy 114 | 115 | -------------------------------------------------------------------------------- /pyprocessing/lights.py: -------------------------------------------------------------------------------- 1 | #************************ 2 | # Lights 3 | #************************ 4 | 5 | import ctypes 6 | from pyglet.gl import * 7 | from globs import * 8 | from constants import * 9 | from colors import _getColor 10 | 11 | __all__=['directionalLight', 'pointLight', 'ambientLight', 'spotLight', 12 | 'lightFalloff', 'lightSpecular', 'lights', 'noLights'] 13 | 14 | def _lightsOn(): 15 | """Turns on the lighting if not set earlier.""" 16 | if attrib.lights: return 17 | glEnable(GL_LIGHTING) 18 | attrib.lights = True 19 | for i in range(attrib.lightCount): glDisable (GL_LIGHT0+i) 20 | attrib.lightCount = 0 21 | 22 | def directionalLight(v1,v2,v3,nx,ny,nz): 23 | """Adds a directional light (diffuse/specular) with the given color and direction.""" 24 | _lightsOn() 25 | color = _getColor(v1,v2,v3) 26 | n = GL_LIGHT0 + attrib.lightCount 27 | attrib.lightCount += 1 28 | glLightfv(n, GL_DIFFUSE, (ctypes.c_float * 4)(*color)) 29 | glLightfv(n, GL_AMBIENT, (ctypes.c_float * 3)(0,0,0)) 30 | glLightfv(n, GL_SPECULAR, (ctypes.c_float * 4)(*attrib.lightSpecular)) 31 | glLightfv(n, GL_POSITION, (ctypes.c_float * 4)(-nx,-ny,-nz,0)) 32 | glLightfv(n, GL_SPOT_DIRECTION, (ctypes.c_float * 3)(0,0,-1)) 33 | glLightf(n, GL_SPOT_EXPONENT, 0) 34 | glLightf(n, GL_SPOT_CUTOFF, 180) 35 | constant, linear, quadratic = 1, 0, 0 36 | glLightf(n, GL_LINEAR_ATTENUATION, linear) 37 | glLightf(n, GL_QUADRATIC_ATTENUATION, quadratic) 38 | glLightf(n, GL_CONSTANT_ATTENUATION, constant) 39 | glEnable(n) 40 | 41 | def pointLight(v1,v2,v3,x,y,z): 42 | """Adds a point light (diffuse/specular) with the given color and position.""" 43 | _lightsOn() 44 | color = _getColor(v1,v2,v3) 45 | n = GL_LIGHT0 + attrib.lightCount 46 | attrib.lightCount += 1 47 | glLightfv(n, GL_DIFFUSE, (ctypes.c_float * 4)(*color)) 48 | glLightfv(n, GL_AMBIENT, (ctypes.c_float * 3)(0,0,0)) 49 | glLightfv(n, GL_SPECULAR, (ctypes.c_float * 4)(*attrib.lightSpecular)) 50 | glLightfv(n, GL_POSITION, (ctypes.c_float * 4)(x,y,z,1)) 51 | glLightfv(n, GL_SPOT_DIRECTION, (ctypes.c_float * 3)(0,0,-1)) 52 | glLightf(n, GL_SPOT_EXPONENT, 0) 53 | glLightf(n, GL_SPOT_CUTOFF, 180) 54 | constant, linear, quadratic = attrib.lightFalloff 55 | glLightf(n, GL_LINEAR_ATTENUATION, linear) 56 | glLightf(n, GL_QUADRATIC_ATTENUATION, quadratic) 57 | glLightf(n, GL_CONSTANT_ATTENUATION, constant) 58 | glEnable(n) 59 | 60 | def ambientLight(v1,v2,v3,x=0,y=0,z=0): 61 | """Adds an ambient light.""" 62 | _lightsOn() 63 | color = _getColor(v1,v2,v3) 64 | n = GL_LIGHT0 + attrib.lightCount 65 | attrib.lightCount += 1 66 | glLightfv(n, GL_DIFFUSE, (ctypes.c_float * 3)(0,0,0)) 67 | glLightfv(n, GL_AMBIENT, (ctypes.c_float * 4)(*color)) 68 | glLightfv(n, GL_SPECULAR, (ctypes.c_float * 3)(0,0,0)) 69 | glLightfv(n, GL_POSITION, (ctypes.c_float * 4)(x,y,z,0)) 70 | constant, linear, quadratic = attrib.lightFalloff 71 | glLightf(n, GL_LINEAR_ATTENUATION, linear) 72 | glLightf(n, GL_QUADRATIC_ATTENUATION, quadratic) 73 | glLightf(n, GL_CONSTANT_ATTENUATION, constant) 74 | glEnable(n) 75 | 76 | def spotLight(v1, v2, v3, x, y, z, nx, ny, nz, angle, concentration): 77 | """Adds a spot light source.""" 78 | _lightsOn() 79 | color = _getColor(v1,v2,v3) 80 | n = GL_LIGHT0 + attrib.lightCount 81 | attrib.lightCount += 1 82 | glLightfv(n, GL_DIFFUSE, (ctypes.c_float * 4)(*color)) 83 | glLightfv(n, GL_AMBIENT, (ctypes.c_float * 3)(0,0,0)) 84 | glLightfv(n, GL_SPECULAR, (ctypes.c_float * 3)(0,0,0)) 85 | glLightfv(n, GL_POSITION, (ctypes.c_float * 4)(x,y,z,1)) 86 | glLightfv(n, GL_SPOT_DIRECTION, (ctypes.c_float * 3)(nx,ny,nz)) 87 | glLightf(n, GL_SPOT_EXPONENT, concentration) 88 | glLightf(n, GL_SPOT_CUTOFF, math.degrees(angle)) 89 | constant, linear, quadratic = attrib.lightFalloff 90 | glLightf(n, GL_LINEAR_ATTENUATION, linear) 91 | glLightf(n, GL_QUADRATIC_ATTENUATION, quadratic) 92 | glLightf(n, GL_CONSTANT_ATTENUATION, constant) 93 | glEnable(n) 94 | 95 | 96 | def lightSpecular (v1,v2,v3): 97 | """Sets the specular coefficients for light sources defined afterwards.""" 98 | attrib.lightSpecular = _getColor(v1,v2,v3) 99 | 100 | def lightFalloff(constant, linear, quadratic): 101 | """Sets the attenuation coefficients for light sources defined afterwards.""" 102 | attrib.lightFalloff = (constant, linear, quadratic) 103 | 104 | def lights(): 105 | """Turns on the illumination model.""" 106 | _lightsOn() 107 | lightSpecular(0,0,0) 108 | directionalLight(128, 128, 128, 0, 0, -1) 109 | ambientLight(128, 128, 128) 110 | 111 | def noLights(): 112 | """Turns off the illumination model.""" 113 | glDisable(GL_LIGHTING) 114 | for i in range(attrib.lightCount): glDisable (GL_LIGHT0+i) 115 | attrib.lights = False 116 | attrib.lightCount = 0 117 | attrib.lightFalloff = (1,0,0) 118 | attrib.lightSpecular = (0,0,0,1) 119 | 120 | -------------------------------------------------------------------------------- /pyprocessing/materials.py: -------------------------------------------------------------------------------- 1 | #************************ 2 | # MATERIAL PROPERTIES 3 | #************************ 4 | 5 | import ctypes 6 | from pyglet.gl import * 7 | from globs import * 8 | from constants import * 9 | from colors import _getColor 10 | 11 | __all__=['emissive', 'shininess', 'specular', 'ambient'] 12 | 13 | def emissive(*args): 14 | """Emission material Properties""" 15 | color = _getColor(*args) 16 | glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION, (ctypes.c_float * 4)(*color)) 17 | 18 | def shininess(shine): 19 | """Specular reflection material properties.""" 20 | glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine) 21 | 22 | def specular(*args): 23 | """Specular reflection material properties.""" 24 | color = _getColor(*args) 25 | glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, (ctypes.c_float * 4)(*color)) 26 | 27 | def ambient(*args): 28 | """Ambient reflection material properties.""" 29 | color = _getColor(*args) 30 | glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, (ctypes.c_float * 4)(*color)) 31 | 32 | -------------------------------------------------------------------------------- /pyprocessing/mathfunctions.py: -------------------------------------------------------------------------------- 1 | #===================== 2 | # SOME MATH FUNCTIONS (not in python's math) 3 | #===================== 4 | 5 | import math 6 | from constants import perlin 7 | 8 | def noise(*args): 9 | """Returns the Perlin noise value at specified coordinates.""" 10 | x = args[0] 11 | if len(args) == 3: y, z = args[1], args[2] 12 | elif len(args) == 2: y, z = args[1], 0 13 | else: y = z = 0 14 | X = int(math.floor(x)) & 255 15 | Y = int(math.floor(y)) & 255 16 | Z = int(math.floor(z)) & 255 17 | x -= math.floor(x) 18 | y -= math.floor(y) 19 | z -= math.floor(z) 20 | u = __fade(x) 21 | v = __fade(y) 22 | w = __fade(z) 23 | A = perlin[X]+Y 24 | AA = perlin[A]+Z 25 | AB = perlin[A+1]+Z 26 | B = perlin[X+1]+Y 27 | BA = perlin[B]+Z 28 | BB = perlin[B+1]+Z 29 | return __plerp(w, __plerp(v, __plerp(u, __grad(perlin[AA ], x , y , z ), __grad(perlin[BA ], x-1, y , z )),__plerp(u, __grad(perlin[AB ], x , y-1, z ),__grad(perlin[BB ], x-1, y-1, z ))),__plerp(v, __plerp(u, __grad(perlin[AA+1], x , y , z-1 ),__grad(perlin[BA+1], x-1, y , z-1 )),__plerp(u, __grad(perlin[AB+1], x , y-1, z-1 ),__grad(perlin[BB+1], x-1, y-1, z-1 )))) 30 | 31 | def __fade(t): 32 | """Used internally by noise().""" 33 | return t*t*t*(t*(t*6-15)+10) 34 | 35 | def __plerp(t,a,b): 36 | """Used internally by noise().""" 37 | return a+t*(b-a) 38 | 39 | def __grad(ha,x,y,z): 40 | """Used internally by noise().""" 41 | h = ha & 15 42 | if h < 8: u = x 43 | else: u = y 44 | if h < 4: v = y 45 | elif h == 12 or h == 14: v = x 46 | else: v = z 47 | if h & 1 != 0: u = -u 48 | if h & 2 != 0: v = -v 49 | return u + v 50 | 51 | def binary(*args): 52 | """Converts a char or int to a string containing the equivalent binary notation.""" 53 | if isinstance(args[0],str): number = bin(ord(args[0]))[2:] 54 | else: number = bin(args[0])[2:] 55 | if len(args) == 1: return number 56 | st = len(number) - args[1] 57 | return number[st:] 58 | 59 | def hex(*args): 60 | """Converts a char or int to a string containing the equivalent hexadecimal notation.""" 61 | if isinstance(args[0],str): number = "%X"%ord(args[0]) 62 | else: number = "%X"%args[0] 63 | if len(args) == 1: return number 64 | return number[(len(number)-args[1]):] 65 | 66 | def unbinary(value): 67 | """Converts a string representation of a binary number to its equivalent integer value.""" 68 | return int(value,2) 69 | 70 | def unhex(value): 71 | """Converts a string representation of a hexadecimal number to its equivalent integer value.""" 72 | return int(value,16) 73 | 74 | def byte(value): 75 | """Converts a char or int to its byte representation.""" 76 | if isinstance(value,str) and len(value) == 1: return ord(value) 77 | elif isinstance(value,int): 78 | if value > 127: return byte(value-256) 79 | if value < -128: return byte(256+value) 80 | return value 81 | 82 | def constrain (value, minv, maxv): 83 | """Returns the constrained value so that it falls between minv and maxv.""" 84 | return min(max(value,minv),maxv) 85 | 86 | def dist(*args): 87 | """Calculates the Euclidean distance between two points. Arguments are of the form 88 | dist(x1,y1,x2,y2) 89 | dist(x1,y1,z1,x2,y2,z2)""" 90 | if len(args)==4: 91 | return math.sqrt(sum([(a-b)**2 for a,b in zip(args[:2],args[2:])])) 92 | else: 93 | assert(len(args)==6) 94 | return math.sqrt(sum([(a-b)**2 for a,b in zip(args[:3],args[3:])])) 95 | 96 | def map(value,low1,high1,low2,high2): 97 | """Re-maps a number from one range to another. 98 | CAUTION: this function overwrites Python's map builtin. 99 | """ 100 | return float(value-low1)/(high1-low1)*(high2-low2)+low2 101 | 102 | def norm(value,low,high): 103 | """Normalizes a number from another range into a value between 0 and 1. 104 | Identical to map(value, low, high, 0, 1).""" 105 | return float(value-low)/(high-low) 106 | 107 | def mag(*args): 108 | """Calculates the magnitude (or length) of a vector. Arguments are of the form 109 | mag(x,y) 110 | mag(x,y,z) 111 | """ 112 | return math.sqrt(sum([a*a for a in args])) 113 | 114 | def lerp(value1,value2,amt): 115 | """Calculates a number between two numbers at a specific increment. 116 | The amt parameter is the amount to interpolate between the two values 117 | where 0.0 equal to the first point, 0.1 is very near the first point, 118 | 0.5 is half-way in between, etc""" 119 | return value1+amt*(value2-value1) 120 | 121 | def sq(value): 122 | """Returns the square of value.""" 123 | return value*value 124 | 125 | # test program 126 | if __name__=='__main__': 127 | print dist(1,1,1,2,2,2) 128 | print constrain(0.1,0,1),constrain(-0.1,0,1),constrain(10,0,1) 129 | print map(25,0,100,100,300) 130 | print norm(25,0,100) 131 | print mag(1,1,1) 132 | 133 | -------------------------------------------------------------------------------- /pyprocessing/primitives.py: -------------------------------------------------------------------------------- 1 | #************************ 2 | # PRIMITIVE DRAWING 3 | #************************ 4 | 5 | import ctypes 6 | from pyglet.gl import * 7 | from globs import * 8 | from constants import * 9 | from attribs import * 10 | from colors import _getColor 11 | import config 12 | from pimage import * 13 | 14 | __all__=['_smoothFixHackBegin', '_smoothFixHackEnd', 15 | 'background', 'ellipse', 'arc', 'rect', 'quad', 16 | 'triangle', 'point', 'line', 'box', 'sphere'] 17 | 18 | def _smoothFixHackBegin(): 19 | """Try to cope with OpenGL's faulty antialiasing of polygons by turning 20 | off smooth rendering temporarily.""" 21 | if config.smoothFixHack: 22 | config.smoothTurnedOn = attrib.smooth 23 | if config.smoothTurnedOn: noSmooth() 24 | 25 | def _smoothFixHackEnd(): 26 | """Restore the smooth setting if it was temporarily turned off.""" 27 | if config.smoothFixHack and config.smoothTurnedOn: smooth() 28 | 29 | def background(*color): 30 | """Clears the screen with color. 31 | Color may be an (r,g,b) tuple or a single gray value. If depth testing is 32 | turned on, also clears the depth buffer.""" 33 | if len(color) == 1 and isinstance(color[0],PImage): 34 | image(color[0],0,0) 35 | else: 36 | color = _getColor(*color) 37 | glClearColor (*color) 38 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 39 | 40 | def ellipse(x,y,width,height): 41 | """Draws an ellipse with center at (x,y) and size (width,height)""" 42 | if shape.quadric == None: 43 | shape.quadric = gl.gluNewQuadric() 44 | if shape.ellipseFillDL==None: 45 | # Create display lists for ellipse in case none was created before 46 | shape.ellipseFillDL = glGenLists (1) 47 | glNewList(shape.ellipseFillDL, GL_COMPILE) 48 | gluDisk(shape.quadric,0,0.5,shape.ellipseDetail,1) 49 | glEndList(); 50 | shape.ellipseStrokeDL = glGenLists (1) 51 | glNewList(shape.ellipseStrokeDL, GL_COMPILE) 52 | gluDisk(shape.quadric,0.5,0.5,shape.ellipseDetail,1) 53 | glEndList(); 54 | if attrib.ellipseMode==CENTER: 55 | x -= width/2 56 | y -= height/2 57 | elif attrib.ellipseMode==RADIUS: 58 | x -= width 59 | y -= height 60 | width *= 2 61 | height *= 2 62 | elif attrib.ellipseMode==CORNERS: 63 | width = width-x 64 | height = height-y 65 | glMatrixMode(GL_MODELVIEW) 66 | glPushMatrix() 67 | glTranslatef(x,y,0) 68 | glScalef(width,height,1) 69 | glTranslatef(0.5,0.5,0) 70 | if attrib.fillColor != None: 71 | glColor4f(*attrib.fillColor) 72 | _smoothFixHackBegin() 73 | glCallList(shape.ellipseFillDL) 74 | _smoothFixHackEnd() 75 | glPushAttrib(GL_POLYGON_BIT) 76 | glPolygonMode(GL_FRONT_AND_BACK,GL_LINE) 77 | glLineWidth (attrib.strokeWeight) 78 | if attrib.strokeColor != None: 79 | glColor4f(*attrib.strokeColor) 80 | glCallList(shape.ellipseStrokeDL) 81 | glPopAttrib() 82 | glPopMatrix() 83 | 84 | def arc(x,y,width,height, start, stop): 85 | """Draws an ellipse arc with lower left corner at (x,y) and size (width,height)""" 86 | if attrib.ellipseMode==CENTER: 87 | x -= width/2 88 | y -= height/2 89 | elif attrib.ellipseMode==RADIUS: 90 | x -= width 91 | y -= height 92 | width *= 2 93 | height *= 2 94 | elif attrib.ellipseMode==CORNERS: 95 | width = width-x 96 | height = height-y 97 | glMatrixMode(GL_MODELVIEW) 98 | glPushMatrix() 99 | if config.coordInversionHack: 100 | glTranslatef(0,y*2+height,0) 101 | glScalef(1,-1,1) 102 | glTranslatef(x,y,0) 103 | glScalef(width,height,1) 104 | glTranslatef(0.5,0.5,0) 105 | if stop0) 46 | # remember the index where the bezier control points will be stored 47 | shape.bez.append(len(shape.vtx)) 48 | if len(coords) == 6: 49 | shape.vtx += [coords[:2]+(0,),coords[2:4]+(0,),coords[4:6]+(0,)] 50 | else: 51 | shape.vtx += [coords[:3],coords[3:6],coords[6:9]] 52 | 53 | def endShape(close=False): 54 | """Does the actual drawing of the shape.""" 55 | 56 | def computeNormal(p0,p1,p2): 57 | """Computes a normal for triangle p0-p1-p2.""" 58 | return (PVector(p1)-PVector(p0)).cross(PVector(p2)-PVector(p1)) 59 | 60 | if attrib.texture: 61 | glEnable(GL_TEXTURE_2D) 62 | if type(attrib.texture) == str: 63 | image = pyglet.image.load(attrib.texture) 64 | texture = image.get_texture() 65 | else: 66 | texture = attrib.texture.img.get_texture() 67 | t = texture.tex_coords 68 | glBindTexture(GL_TEXTURE_2D,texture.id) 69 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 70 | glMatrixMode(GL_TEXTURE); 71 | glLoadIdentity(); 72 | glTranslatef(0.0,t[7],0.0); 73 | glMatrixMode(GL_MODELVIEW); 74 | if attrib.textureMode == IMAGE: 75 | normx = image.width 76 | normy = image.height 77 | elif attrib.textureMode == NORMALIZED: 78 | normx = normy = 1.0 79 | if shape.type: glBegin(shape.type) 80 | else: glBegin(GL_POLYGON) 81 | for v in shape.vtx: 82 | glTexCoord2f(v[3]*t[6]/normx,-v[4]*t[7]/normy) 83 | glVertex3f(*v[:3]) 84 | glEnd() 85 | attrib.texture = None 86 | # Draw the interior of the shape 87 | elif attrib.fillColor != None: 88 | glColor4f(*attrib.fillColor) 89 | # establish an initial normal vector 90 | if shape.nrm != []: 91 | inormal, normal = shape.nrm[0] 92 | else: 93 | inormal = len(shape.vtx) 94 | if len(shape.vtx)>=3: 95 | normal = computeNormal(shape.vtx[0],shape.vtx[1],shape.vtx[2]) 96 | else: 97 | normal = [0,0,1] 98 | glNormal3f(*normal) 99 | # Draw filled shape 100 | if shape.type==None: 101 | _smoothFixHackBegin() 102 | # first create a tesselator object if none was defined yet 103 | if shape.tess == None: shape.tess = gl.gluNewTess() 104 | # set up the tesselator callbacks 105 | gluTessCallback(shape.tess, GLU_TESS_VERTEX, ctypes.cast(glVertex3dv,ctypes.CFUNCTYPE(None))) 106 | gluTessCallback(shape.tess, GLU_TESS_BEGIN, ctypes.cast(glBegin,ctypes.CFUNCTYPE(None))) 107 | gluTessCallback(shape.tess, GLU_TESS_END, ctypes.cast(glEnd,ctypes.CFUNCTYPE(None))) 108 | gluTessBeginPolygon(shape.tess, None) 109 | gluTessBeginContour(shape.tess) 110 | i = 0 111 | n = len(shape.vtx) 112 | shape.bez += [n] 113 | b = 0 114 | a = [] 115 | while i1 or \ 156 | shape.type==TRIANGLE_STRIP and i>1: 157 | normal = computeNormal(shape.vtx[i],shape.vtx[i+1],shape.vtx[i+2]) 158 | glNormal3f (*normal) 159 | glVertex3f(*v) 160 | glEnd() 161 | 162 | 163 | 164 | # Draw the outline of the shape 165 | if attrib.strokeColor != None: 166 | glColor4f(*attrib.strokeColor) 167 | glPushAttrib(GL_POLYGON_BIT) 168 | glPolygonMode(GL_FRONT_AND_BACK,GL_LINE) 169 | glLineWidth (attrib.strokeWeight) 170 | if shape.type==None: 171 | if close: glBegin(GL_LINE_LOOP) 172 | else: glBegin(GL_LINE_STRIP) 173 | i = 0 174 | n = len(shape.vtx) 175 | shape.bez += [n] 176 | nextbez = shape.bez.pop(0) 177 | while i4: shape.crv = shape.crv[-4:] 298 | if len(shape.crv)==4: 299 | blend = CatmullRomBlend(shape.tension) 300 | npts = shape.curveDetail 301 | for i in range(npts+1): 302 | p = blend.blendPoint(float(i)/npts, *shape.crv) 303 | vertex(*p) 304 | 305 | def curve (*coords): 306 | """Generates a catmull-rom curve given 4 points. Takes either 8 numbers 307 | for coordinates of 4 points in 2D or 12 numbers for 4 points in 3D""" 308 | if len(coords)==8: 309 | p0,p1,p2,p3 = coords[0:2],coords[2:4],coords[4:6],coords[6:8] 310 | else: 311 | assert (len(coords)==12) 312 | p0,p1,p2,p3 = coords[0:3],coords[3:6],coords[6:9],coords[9:12] 313 | blend = CatmullRomBlend(shape.tension) 314 | beginShape() 315 | npts = shape.curveDetail 316 | for i in range(npts+1): 317 | p = blend.blendPoint(float(i)/npts, p0,p1,p2,p3) 318 | vertex(*p) 319 | endShape() 320 | 321 | def curvePoint (a,b,c,d,t): 322 | """Evaluates the n'th coordinate of a cubic Catmull-Rom curve at parameter 323 | t for control points having their n'th coordinate equal to a, b, c and d, respectively. 324 | """ 325 | blend = CatmullRomBlend(shape.tension) 326 | return blend.blendPoint(t,(a,),(b,),(c,),(d,)) [0] 327 | 328 | def curveTangent (a,b,c,d,t): 329 | """Evaluates the n'th coordinate of the tangent at the point on a cubic Catmull-Rom 330 | curve at parameter t for control points having their n'th coordinate equal to 331 | a, b, c and d, respectively. 332 | """ 333 | blend = CatmullRomBlend(shape.tension) 334 | return blend.blendTangent(t,(a,),(b,),(c,),(d,)) [0] 335 | 336 | def curveDetail(npts=shape.curveDetail): 337 | """Controls the number of samples per curve arc.""" 338 | shape.curveDetail = npts 339 | 340 | def sphereDetail(*args): 341 | """Controls the how many segments are used per circle revolution while drawing a 342 | sphere. The first and second parameters determine the number of segments used 343 | longitudinally and latitudinally, respectively. If only one parameter is used, it 344 | determines the total number of segments used per full circle revolution.""" 345 | if len(args)==1: 346 | shape.sphereDetail = (args[0], args[0]) 347 | elif len(args)==2: 348 | shape.sphereDetail = (args[0], args[1]) 349 | -------------------------------------------------------------------------------- /pyprocessing/transformations.py: -------------------------------------------------------------------------------- 1 | #************************ 2 | # TRANSFORMATIONS STUFF 3 | #************************ 4 | 5 | import ctypes 6 | from pyglet.gl import * 7 | from globs import * 8 | from constants import * 9 | from math import * 10 | import config 11 | 12 | __all__=['pushMatrix', 'popMatrix', 'resetMatrix', 'applyMatrix', 'getMatrix', 13 | 'printMatrix', 'getProjection', 'printProjection', 14 | 'translate', 'rotate', 'rotateX', 'rotateY', 'rotateZ', 15 | 'scale', 'camera', 'perspective', 'ortho', 16 | 'screenXYZ', 'screenX', 'screenY', 'screenZ', 17 | 'modelXYZ','modelX', 'modelY', 'modelZ', 'shearX', 'shearY'] 18 | 19 | def pushMatrix(): 20 | """Saves current transformation""" 21 | glPushMatrix() 22 | 23 | def popMatrix(): 24 | """Restores previous transformation""" 25 | glPopMatrix() 26 | 27 | def resetMatrix(): 28 | """Loads an identity matrix""" 29 | glLoadIdentity() 30 | 31 | def applyMatrix(n00, n01, n02, n03, 32 | n04, n05, n06, n07, 33 | n08, n09, n10, n11, 34 | n12, n13, n14, n15): 35 | """Applies matrix.""" 36 | # notice that processing uses a transposed matrix 37 | glMultMatrixf((ctypes.c_float * 16)(n00, n04, n08, n12, 38 | n01, n05, n09, n13, 39 | n02, n06, n10, n14, 40 | n03, n07, n11, n15)) 41 | 42 | def shearX(angle): 43 | """Shears a shape around the x-axis the amount specified by the angle 44 | parameter""" 45 | # notice that processing uses a transposed matrix 46 | glMultMatrixf((ctypes.c_float * 16)(1, 0, 0, 0, 47 | angle, 1, 0, 0, 48 | 0, 0, 1, 0, 49 | 0, 0, 0, 1)) 50 | 51 | def shearY(angle): 52 | """ Shears a shape around the y-axis the amount specified by the angle 53 | parameter.""" 54 | # notice that processing uses a transposed matrix 55 | glMultMatrixf((ctypes.c_float * 16)(1, angle, 0, 0, 56 | 0, 1, 0, 0, 57 | 0, 0, 1, 0, 58 | 0, 0, 0, 1)) 59 | 60 | def getMatrix(): 61 | """Returns the MODELVIEW matrix as a tuple.""" 62 | matrix = (ctypes.c_double*16)() 63 | glGetDoublev (GL_MODELVIEW_MATRIX, matrix) 64 | return tuple([matrix [i] for i in range(16)]) 65 | 66 | def getProjection(): 67 | """Returns the PROJECTION matrix as a tuple.""" 68 | matrix = (ctypes.c_double*16)() 69 | glGetDoublev (GL_PROJECTION_MATRIX, matrix) 70 | return tuple([matrix [i] for i in range(16)]) 71 | 72 | def printMatrix(): 73 | """Prints the MODELVIEW matrix.""" 74 | print getMatrix() 75 | 76 | def printProjection(): 77 | """Prints the PROJECTION matrix.""" 78 | print getProjection() 79 | 80 | def translate(x,y,z=0): 81 | """Translation transformation""" 82 | glTranslatef(x,y,z) 83 | 84 | def rotate(*args): 85 | """Rotation transformation. Angles in radians""" 86 | if len(args) == 1: glRotatef(math.degrees(args[0]), 0,0,1) 87 | else: glRotatef(math.degrees(args[0]),args[1],args[2],args[3]) 88 | 89 | rotateZ = rotate 90 | 91 | def rotateX(angle): 92 | """Rotation around the X axis""" 93 | rotate (angle, 1, 0, 0) 94 | 95 | def rotateY(angle): 96 | """Rotation around the Y axis""" 97 | rotate (angle, 0, 1, 0) 98 | 99 | def scale(*args): 100 | """Scale transformation""" 101 | if len(args) == 1: glScalef(args[0],args[0],args[0]) 102 | elif len(args)==2: glScalef(args[0],args[1],1) 103 | else: glScalef(*args) 104 | 105 | def camera (*args): 106 | """Args should either be empty or be of the form 107 | (eyex,eyey,eyez,centerx, centery, centerz, upx, upy, upz). 108 | Creates a viewing transformation given the camera position 109 | (eyex,eyey,eyez), the center of the scene (centerx, centery, centerz) and 110 | a vector to be used as the up direction (upx, upy, upz). If no args 111 | are passed, the standard camera is created.""" 112 | glLoadIdentity() 113 | 114 | if len(args)==0: 115 | # default camera 116 | if config.halfPixelShiftHack: 117 | # Add a half-pixel shift in order to obtain sharper lines 118 | glTranslatef(0.5,0.5,0) 119 | gluLookAt (width/2.0, height/2.0, (height/2.0) / tan(PI*60.0 / 360.0), 120 | width/2.0, height/2.0, 0, 0, 1, 0) 121 | else: 122 | assert (len(args)==9) 123 | gluLookAt (*args) 124 | 125 | def perspective(*args): 126 | """Args should either be empty or be of the form 127 | (fov,aspect,znear,zfar). Loads a perspective projection matrix, where 128 | fov is the field-of-view angle (in radians) for vertical direction, aspect 129 | is the ratio of width to height, znear is the z-position of nearest clipping 130 | plane and zfar is the z-position of nearest farthest plane. If no args are 131 | passed, the standard projection is created, i.e, equivalent to 132 | perspective(PI/3.0, width/height, cameraZ/10.0, cameraZ*10.0) 133 | where cameraZ is ((height/2.0) / tan(PI*60.0/360.0)).""" 134 | glMatrixMode(GL_PROJECTION) 135 | glLoadIdentity() 136 | if len(args)==0: 137 | cameraZ = height/2.0 / math.tan(math.pi*60/360) 138 | gluPerspective(60, width*1.0/height, cameraZ/100.0, cameraZ*10.0) 139 | else: 140 | assert(len(args)==4) 141 | fov,aspect,znear,zfar = args 142 | gluPerspective(degrees(fov),aspect,znear,zfar) 143 | # invert the y axis 144 | if config.coordInversionHack: glScalef(1,-1,1) 145 | glMatrixMode(GL_MODELVIEW) 146 | 147 | def ortho(*args): 148 | """Args should either be empty or be of the form 149 | (left, right, bottom, top, near, far). Loads an orthogonal projection matrix. 150 | The clipping volume in this case is an axes-aligned parallelepiped, where 151 | left and right are the minimum and maximum x values, top and bottom are 152 | the minimum and maximum y values, and near and far are the minimum and 153 | maximum z values. If no parameters are given, the default is used: 154 | ortho(0, width, 0, height, -10, 10).""" 155 | glMatrixMode(GL_PROJECTION) 156 | glLoadIdentity() 157 | if len(args)==0: 158 | left, right = 0, width 159 | bottom, top = 0, height 160 | near, far = -height*2, height*2 # a saner default than Processing's 161 | else: 162 | assert(len(args)==6) 163 | left, right, bottom, top, near, far = args 164 | # invert the y axis 165 | if config.coordInversionHack: bottom, top = top, bottom 166 | glOrtho(left, right, bottom, top, near, far) 167 | glMatrixMode(GL_MODELVIEW) 168 | 169 | def screenXYZ (ox,oy,oz): 170 | """Returns the projected space coordinates of object coordinates ox,oy,oz""" 171 | # variables for calling gluUnProject 172 | viewport = (ctypes.c_int*4)() 173 | projmatrix = (ctypes.c_double*16)() 174 | mviewmatrix = (ctypes.c_double*16)() 175 | sx,sy,sz = (ctypes.c_double)(),(ctypes.c_double)(),(ctypes.c_double)() 176 | # get current transformation state 177 | glGetIntegerv(GL_VIEWPORT, viewport) 178 | glGetDoublev(GL_MODELVIEW_MATRIX, mviewmatrix) 179 | glGetDoublev(GL_PROJECTION_MATRIX, projmatrix) 180 | # call gluUnProject 181 | gluProject(ox,oy,oz, 182 | mviewmatrix,projmatrix,viewport, 183 | ctypes.byref(sx),ctypes.byref(sy),ctypes.byref(sz)) 184 | if config.coordInversionHack: 185 | return sx.value, height-sy.value, sz.value 186 | else: 187 | return sx.value, sy.value, sz.value 188 | 189 | def screenX (ox,oy,oz): 190 | """Returns the x coordinate of screenXYZ(ox,oy,oz)""" 191 | return screenXYZ(ox,oy,oz)[0] 192 | 193 | def screenY (ox,oy,oz): 194 | """Returns the y coordinate of screenXYZ(ox,oy,oz)""" 195 | return screenXYZ(ox,oy,oz)[1] 196 | 197 | def screenZ (ox,oy,oz): 198 | """Returns the Z coordinate of screenXYZ(ox,oy,oz)""" 199 | return screenXYZ(ox,oy,oz)[2] 200 | 201 | # As far as I can understand, modelX, modelY and modelZ are synonyms of 202 | # screenX, screenY and screenZ 203 | modelX, modelY, modelZ, modelXYZ = screenX, screenY, screenZ, screenXYZ 204 | 205 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding:utf-8 3 | 4 | from distutils.core import setup 5 | 6 | def get_version(): 7 | from os.path import dirname, join 8 | for line in open(join(dirname(__file__), 'pyprocessing/constants.py')): 9 | if 'version' in line: 10 | version = line.split('"')[1] 11 | return version 12 | 13 | long_description = ''' 14 | This Python package provides an environment for graphics applications that 15 | closely resembles that of the Processing system. 16 | 17 | The project mission is to implement Processing's friendly graphics 18 | functions and interaction model in Python. Not all of Processing is ported, 19 | though, since Python itself already provides alternatives for many features 20 | of Processing. 21 | 22 | The pyprocessing backend is built upon OpenGL and Pyglet, 23 | which provide the actual graphics rendering. Since these are multiplatform, 24 | so is pyprocessing. 25 | ''' 26 | 27 | # MAKE SURE THE VERSION BELOW IS THE SAME AS THAT IN CONSTANTS.PY! 28 | 29 | setup(name='pyprocessing', 30 | version=get_version(), 31 | description='A Processing-like environment for Python', 32 | long_description=long_description, 33 | author='Claudio Esperanca', 34 | author_email='claudio.esperanca@gmail.com', 35 | url='http://code.google.com/p/pyprocessing/', 36 | license='BSD', 37 | packages=['pyprocessing'], 38 | install_requires = ["pyglet>=1.1.4"], 39 | ) 40 | 41 | -------------------------------------------------------------------------------- /tools/accumfliptest.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a simple application intended to test the accumulation buffer flip 3 | policy of pyprocessing. If everything works as intended, you should see 4 | a rotating square... 5 | """ 6 | 7 | def usage(): 8 | print "Usage:", sys.argv[0], "--accum | --fbo | --single | --double" 9 | print "where --accum tests the accumulation flip policy (default)," 10 | print " --fbo tests the frame buffer object flip policy," 11 | print " --single tests the single buffer flip policy" 12 | print " --double tests the double buffer flip policy" 13 | 14 | import pyglet,sys 15 | from pyglet.gl import * 16 | from flippolicy import * 17 | fps_display = pyglet.clock.ClockDisplay(color=(1, 1, 1, 1),) 18 | 19 | if len(sys.argv)==1 or sys.argv[1]=="--accum": 20 | win = AccumWindow(200,200) 21 | elif sys.argv[1]=="--double": 22 | win = PyprocessingWindow(200,200) 23 | elif sys.argv[1]=="--fbo": 24 | win = FBOWindow(200,200) 25 | elif sys.argv[1]=="--single": 26 | win = SingleBufferWindow(200,200) 27 | else: 28 | print "Unrecognized argument:",sys.argv[1] 29 | usage() 30 | sys.exit(-1) 31 | 32 | ang = 0 33 | 34 | @win.event 35 | def on_draw(): 36 | glEnable(GL_BLEND) 37 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 38 | glMatrixMode(GL_PROJECTION) 39 | glLoadIdentity() 40 | glMatrixMode(GL_MODELVIEW) 41 | glLoadIdentity() 42 | glColor4f(0,0,0,0.05) 43 | glRectf(-1,-1,1,1) 44 | global ang 45 | ang += 1 46 | glRotatef(ang,0,0,1) 47 | glEnable(GL_POLYGON_SMOOTH) 48 | glEnable(GL_LINE_SMOOTH) 49 | glEnable(GL_POINT_SMOOTH) 50 | glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST) 51 | pt = [(-0.5,-0.5,0),(0.5,-0.5,0),(0.5,0.5,0),(-0.5,0.5,0)] 52 | glColor4f(1,1,1,0.5) 53 | glBegin(GL_QUADS) 54 | for p in pt: glVertex3f(*p) 55 | glEnd() 56 | glColor4f(0,1,1,0.8) 57 | glPointSize(10) 58 | glBegin(GL_POINTS) 59 | for p in pt: glVertex3f(*p) 60 | glEnd() 61 | 62 | def dummy(t): pass 63 | 64 | pyglet.clock.schedule_interval(dummy,1.0/30) 65 | pyglet.app.run() 66 | -------------------------------------------------------------------------------- /tools/fbo.py: -------------------------------------------------------------------------------- 1 | import pyglet 2 | from pyglet.gl import * 3 | from ctypes import * 4 | 5 | class FBO(object): 6 | """Basic helper for using OpenGL's Frame Buffer Object (FBO)""" 7 | 8 | @staticmethod 9 | def supported(): 10 | """A static method that tells if FBOs are supported. 11 | If not sure, call this before creating an FBO instance.""" 12 | 13 | # Check if the board / driver supports FBO 14 | if not gl_info.have_extension("GL_EXT_framebuffer_object"): 15 | return False 16 | if not gl_info.have_extension("GL_ARB_draw_buffers"): 17 | return False 18 | 19 | return True 20 | 21 | def __init__(self, width=100, height=100): 22 | """Creates a Frame Buffer Object (FBO)""" 23 | 24 | # Must be supported... 25 | assert (FBO.supported()) 26 | 27 | self.width = width 28 | self.height = height 29 | 30 | # Setting it up 31 | self.framebuffer = c_uint(0) 32 | self.depthbuffer = c_uint(0) 33 | self.img = c_uint(0) 34 | 35 | glGenFramebuffersEXT(1, byref(self.framebuffer)) 36 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, self.framebuffer) 37 | 38 | # Adding a Depth Buffer 39 | glGenRenderbuffersEXT(1, byref(self.depthbuffer)) 40 | glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, self.depthbuffer) 41 | glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, self.width, self.height) 42 | glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 43 | GL_RENDERBUFFER_EXT, self.depthbuffer) 44 | 45 | # Adding a Texture To Render To 46 | glGenTextures(1, byref(self.img)) 47 | glBindTexture(GL_TEXTURE_2D, self.img) 48 | 49 | # Black magic (only works with these two lines) 50 | # (nearest works, as well as linear) 51 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 52 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR) 53 | 54 | # Add the texture ot the frame buffer as a color buffer 55 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, self.width, self.height, 56 | 0, GL_RGBA, GL_UNSIGNED_BYTE, None) 57 | glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, 58 | GL_TEXTURE_2D, self.img, 0) 59 | 60 | # Check if it worked so far 61 | status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) 62 | assert(status == GL_FRAMEBUFFER_COMPLETE_EXT) 63 | 64 | def attach(self): 65 | """Call this before rendering to the FBO.""" 66 | 67 | # First we bind the FBO so we can render to it 68 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, self.framebuffer) 69 | 70 | # Save the view port and set it to the size of the texture 71 | glPushAttrib(GL_VIEWPORT_BIT) 72 | glViewport(0,0,self.width,self.height) 73 | 74 | def detach(self): 75 | """Call this after rendering to the FBO so that rendering now 76 | goes to the regular frame buffer.""" 77 | 78 | # Restore old view port and set rendering back to default frame buffer 79 | glPopAttrib() 80 | glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) 81 | 82 | def getTexture(self): 83 | """Returns a pyglet image with the contents of the FBO.""" 84 | self.data = (c_ubyte * (self.width*self.height*4))() 85 | 86 | glGetTexImage(GL_TEXTURE_2D, # target, 87 | 0, # level, 88 | GL_RGBA, # format, 89 | GL_UNSIGNED_BYTE , # type, 90 | self.data) # GLvoid * img 91 | 92 | return pyglet.image.ImageData (self.width, self.height, 'RGBA', self.data) 93 | 94 | def __del__(self): 95 | """Deallocates memory. Call this before discarding FBO.""" 96 | glDeleteFramebuffersEXT(1, byref(self.framebuffer)) 97 | glDeleteRenderbuffersEXT(1, byref(self.depthbuffer)) 98 | glDeleteTextures(1,byref(self.img)) 99 | 100 | 101 | -------------------------------------------------------------------------------- /tools/flip_setup.py: -------------------------------------------------------------------------------- 1 | from pyprocessing import * 2 | from random import random 3 | import sys 4 | import os 5 | 6 | nballs = 100 7 | balls = [] 8 | 9 | 10 | """This script is aimed at users who don't know which Flip Policy is 11 | best suited for their hardware setup. It will automatically display a 12 | simple pyprocessing example and give the user options to say if the 13 | graphics are displayed correctly: if not, then the setup will change 14 | the Flip Policy automatically and run itself again.""" 15 | 16 | 17 | 18 | 19 | def setup(): 20 | global policy 21 | if '-nodouble' not in sys.argv: 22 | hint(DOUBLE_FLIP_POLICY) 23 | policy = DOUBLE_FLIP_POLICY 24 | size(400,400) 25 | smooth() 26 | noStroke() 27 | colorMode(HSB,1.0) 28 | ellipseMode(CENTER) 29 | for i in range(nballs): 30 | x = int(random()*width) 31 | y = int(random()*height) 32 | vel = random()*4+2 33 | ang = random()*TWO_PI 34 | dx = vel*cos(ang) 35 | dy = vel*sin(ang) 36 | r = random()*20+4 37 | c = color(random(),random()*0.5+0.5,random()*0.5+0.5) 38 | balls.append([x,y,dx,dy,r,c]) 39 | colorMode(RGB,256) 40 | 41 | def draw(): 42 | fill(255,50) 43 | rect(0,0,width,height-100) 44 | for i,(x,y,dx,dy,r,c) in enumerate(balls): 45 | fill(c) 46 | x += dx 47 | newx = constrain(x,r,width-r) 48 | if newx != x: dx,x = -dx,newx 49 | y += dy 50 | newy = constrain(y,r,height-r-100) 51 | if newy != y: dy,y = -dy,newy 52 | balls[i][0:4] = x,y,dx,dy 53 | ellipse(x,y,r,r) 54 | fill(10,200,10) 55 | rect(0,height-100,width/2,100) 56 | fill(200,10,10) 57 | rect(width/2,height-100,width/2,100) 58 | fill(0) 59 | text("Yes, this config is ok",width/30,height-50) 60 | text("I'm seeing glitches",5*width/9,height-50) 61 | text("%3d"%frame.rate,0,20) 62 | 63 | def mouseClicked(): 64 | global contents, policy 65 | if (height - 100 < mouse.y < height): 66 | for i in range(len(contents)-1,-1,-1): 67 | if contents[i].find("flip") != -1 or contents[i] == "": 68 | del contents[i] 69 | if (mouse.x > width/2): 70 | if fbo.FBO.supported(): policy = FBO_FLIP_POLICY 71 | else: policy = BACKUP_FLIP_POLICY 72 | f = open(os.path.expanduser("~/.pyprocessing/userconfig.txt"),"w") 73 | contents.append("flipPolicy:"+policy) 74 | contents = '\n'.join(contents) 75 | f.write(contents) 76 | f.close() 77 | os.system('python %s -nodouble'%sys.argv[0]) 78 | sys.exit() 79 | else: 80 | if '-nodouble' in sys.argv: sys.exit() 81 | f = open(os.path.expanduser("~/.pyprocessing/userconfig.txt"),"w") 82 | contents.append("flipPolicy:"+policy) 83 | contents = '\n'.join(contents) 84 | f.write(contents) 85 | f.close() 86 | sys.exit() 87 | 88 | try: 89 | f = open(os.path.expanduser("~/.pyprocessing/userconfig.txt"),"r") 90 | contents = f.read() 91 | f.close() 92 | contents = contents.split('\n') 93 | except IOError: 94 | try: 95 | os.mkdir(os.path.expanduser("~/.pyprocessing")) 96 | except OSError: None 97 | contents = [] 98 | 99 | 100 | 101 | 102 | 103 | 104 | run() 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /tools/flippolicy.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module contains several window classes derived from pyglet's 3 | window classes. They implement variations on the standard way 4 | of handling the flip method. These are necessary because of the 5 | implementation-dependent way used by OpenGL to flip between the back and 6 | the front buffer. 7 | 8 | In most cases where a modern graphics board is supported 9 | by a recent driver, flipping works by copying the back to the front buffer, 10 | which is necessary whenever the screen is not completely redrawn from 11 | scratch between one frame and the next. If this is the case in your installation, 12 | the regular PyprocessingWindow, which is merely a pyglet.window.Window under 13 | another name, should be used and will give you the best performance. 14 | 15 | Some drivers, however, do not implement flip by copying, but merely makes the 16 | video controller address the other video memory buffer. This is what is called 17 | flipping by swapping. In such cases, programs which rely on a stable frame 18 | buffer will not work as expected. I spent a long time looking for portable 19 | ways of enforcing a copy flip, but it seems that there is no reliable way of 20 | doing that. 21 | 22 | One way of coping with the problem is to use single buffering, so that drawing 23 | is actually performed on the front buffer. This is not a good idea in 24 | general, because the drawing may result in flickering and other visual 25 | visual artifacts. Nevertheless, I found that the Intel 945 express chipset 26 | works fairly well in this mode under MS Windows. Other driver/board/OS 27 | combinations might also work well in this mode. If this is the case, 28 | instancing a SingleBufferWindow will solve the problem. 29 | 30 | Another way of providing a stable drawing buffer is to draw to a separate 31 | off-screen buffer. The most efficient way of doing this is to use a Frame 32 | Buffer Object, or FBO. The idea then is to copy the FBO to the back buffer 33 | just before the flip. The FBOWindow implements just this. 34 | 35 | Unfortunately the FBO extension is not common in old hardware. In this case, 36 | another type of buffer might be used to store a copy of the back buffer. The 37 | idea is to copy the back buffer to such an auxiliary buffer, flip and then 38 | copy it back. The simplest, but probably not the most efficient way of doing 39 | this is to use the accumulation buffer, which can be copied from/to with a 40 | single glAccum instruction. The AccumWindow implements this policy. 41 | 42 | The default flipping policy is governed by appropriate calls to the 43 | hint() function just before calling size(). You might wish to change the default 44 | by editting the config variable in the globs submodule. 45 | """ 46 | 47 | import pyglet 48 | from pyglet.gl import * 49 | from fbo import FBO 50 | 51 | __all__=['PyprocessingWindow','FBOWindow','SingleBufferWindow','AccumWindow'] 52 | 53 | 54 | class PyprocessingWindow (pyglet.window.Window): 55 | """This is just a wrapper for the pyglet window class. If any 56 | window method or attribute should be messed with for all of pyprocessing's 57 | window classes, it's best to do it here.""" 58 | pass 59 | 60 | class FBOWindow(PyprocessingWindow): 61 | """This is a pyglet window where drawing in fact occurs inside an FBO. 62 | The flip method is overridden so that instead of merely swapping the 63 | back and front buffers, the FBO is first blitted onto the back buffer. 64 | The idea is to provide a stable drawing canvas which is not erased or 65 | corrupted by the flip.""" 66 | 67 | def __init__(self, *args, **keyargs): 68 | """Constructor""" 69 | # construct the base class 70 | super(FBOWindow, self).__init__(*args, **keyargs) 71 | # construct the fbo and attach it 72 | self.fbo = FBO(self.width, self.height) 73 | self.fbo.attach() 74 | 75 | def flip(self): 76 | """Override the flip method.""" 77 | # cease using the FBO and start using the regular frame buffer 78 | self.fbo.detach() 79 | # save the OpenGL state 80 | glMatrixMode(GL_PROJECTION) 81 | glPushMatrix() 82 | glLoadIdentity() 83 | glMatrixMode(GL_MODELVIEW) 84 | glPushMatrix() 85 | glLoadIdentity() 86 | glPushAttrib(GL_ALL_ATTRIB_BITS) 87 | glViewport(0,0,self.width,self.height) 88 | # Draws a quad with the fbo as a texture 89 | glDisable(GL_BLEND) 90 | glDisable(GL_DEPTH_TEST) 91 | glDisable(GL_LIGHTING) 92 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) 93 | glEnable(GL_TEXTURE_2D) 94 | glColor3f(1,1,1) 95 | glBindTexture(GL_TEXTURE_2D, self.fbo.img) 96 | glBegin(GL_QUADS) 97 | for v,t in [((-1,-1,0),(0,0)), 98 | ((-1,1,0),(0,1)), 99 | ((1,1,0),(1,1)), 100 | ((1,-1,0),(1,0))]: 101 | glTexCoord2f(*t) 102 | glVertex3f(*v) 103 | glEnd() 104 | # restore the state 105 | glMatrixMode(GL_PROJECTION) 106 | glPopMatrix() 107 | glMatrixMode(GL_MODELVIEW) 108 | glPopMatrix() 109 | glPopAttrib() 110 | 111 | # do the actual flip 112 | super (FBOWindow, self).flip() 113 | # reattach the fbo for further drawing 114 | self.fbo.attach() 115 | 116 | def on_resize(self,w,h): 117 | super (FBOWindow, self).on_resize(w,h) 118 | self.fbo.detach() 119 | self.fbo = FBO(w,h) 120 | self.fbo.attach() 121 | 122 | class SingleBufferWindow(PyprocessingWindow): 123 | """This is a pyglet window with a single buffer config.""" 124 | 125 | def __init__(self, *args, **keyargs): 126 | """Constructor""" 127 | # construct the base class 128 | if 'config' in keyargs: 129 | config = keyargs['config'] 130 | else: 131 | config = Config(depth_size=24) 132 | config.double_buffer = False 133 | keyargs['config'] = config 134 | super(SingleBufferWindow, self).__init__(*args, **keyargs) 135 | 136 | 137 | class AccumWindow(PyprocessingWindow): 138 | """This is a pyglet window for which an accumulation buffer is defined. 139 | The flip method is overridden so that instead of merely swapping the 140 | back and front buffers, a copy of the back buffer is blitted onto the accum 141 | buffer, and after the flip the accum buffer is copied back. 142 | The idea is to provide a stable drawing canvas which is not erased or 143 | corrupted by the flip.""" 144 | 145 | def __init__(self, *args, **keyargs): 146 | """Constructor""" 147 | # construct the base class 148 | if 'config' in keyargs: 149 | config = keyargs['config'] 150 | else: 151 | config = Config(double_buffer=True,depth_size=24) 152 | config.accum_alpha_size = 8 153 | config.accum_red_size = 8 154 | config.accum_green_size = 8 155 | config.accum_blue_size = 8 156 | keyargs['config'] = config 157 | super(AccumWindow, self).__init__(*args, **keyargs) 158 | 159 | def flip(self): 160 | """Override the flip method.""" 161 | # copy from the the back buffer to the accumulation buffer 162 | glAccum(GL_LOAD, 1.0) 163 | # do the actual flip 164 | super (AccumWindow, self).flip() 165 | # copy the accum buffer to the back buffer 166 | glAccum(GL_RETURN, 1) 167 | 168 | -------------------------------------------------------------------------------- /tools/takesnapshot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Usage: takesnapshot.py [options] script.py 4 | 5 | This program is used to take snapshots of a pyprocessing 6 | application called script.py. 7 | 8 | Essentially, it runs a modified version of the given script which 9 | includes a call to save(). Command line arguments select one 10 | of the two supported modes of operation: 11 | 12 | --single=