Mirra
2D OpenGL graphics Python framework by www.ixi-software.net
version alpha 0.3.5 - May 08.

Contribute : If you want to contribute drop us a mail. Current plans are to port some modules to C as a extension to Python, we would need some help here from people with experience developing Python extensions in C.

Download page : http://www.ixi-software.net/mirra

 

Contents of documentation:
- Description
- License
- System requirements
- Mailing list
- Installation
- Changes
- Short tutorial (how to use, built-in classes description, tips about Mirra, event system description, etc...)
- API, command reference
- OpenSoundControl module description
- Creating executables and apps under windows and macintosh
- Extending Mirra
- To do
- Contents of Mirra
- Aknowledgements
- Feedback

 

Description:


Mirra is a 2D OpenGL graphics library based on Python. Mirra allows for the creation of 2D interfaces, games or applications. It defines a set of classes to render primitive shapes (Text, Pixel, Line, Circle, Rect, Bitmap, BitmapPolygon), it manages rendering and user input (mouse and keyboard). Mirra focuses on interaction and implements an event managing system and classes that capture mouse events (in a way like Macromedia Director or Flash do).

Mirra can send and receive OpenSoundControl messages via the OSC module. It allows to easily create exe and apps out of your scripts and also offers some basic sound features.

Mirra can be run with the following window systems : wxPython, Pygame-SDL (by default).
Using either Pygame or WxPython gives you access to various different features from those libraries such as import menus, drag&drop, basic sound features, etc... Check their websites for more info about what can be done with them --> www.pygame.org | www.wxpython.org

Mirra has been also thought to be used to teach basics of programming to students by manipulating graphics.

 

License :


This library is free software; you can redistribute it and/or modify it under the terms of the Lesser GNU, Lesser General Public License as published by the Free Software Foundation.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Mirra contains small parts by others such as OSC.py by Daniel Holth under Lesser GPL. Licence and credits are included on those parts from others.

 

System requirements:


Mirra works under any platform where Python runs (OS X, GNU/Linux, Windows, etc...).
You will need to have Python plus some Python libraries (PyOpenGL and Pygame(SDL)) installed on your machine. You might need as well wxPython (if you choose to use wxPython to handle the application's window instead of Pygame). If you want to export your scripts as exe (windows) or app (Mac) you will need py2exe (windows users) or pyapp (mac users).
- Must be there:
Python - www.python.org
Pygame - www.pygame.org
PyOpenGL - pyopengl.sourceforge.net
- Optional :
WxPython - www.wxpython.org
Py2exe (win) - www.py2exe.org
Py2app (mac) - www.pythonmac.org/wiki/py2app

OS X users http://pythonmac.org/packages/

(*) Under some versions of Windows you might need to install as well GLUT32.dll to get OpenGL running. This can be downloaded from http://www.xmission.com/%7Enate/glut.html . Just copy the glut32.dll into your c:\windows\system32 folder

Mailing list

For questions, info about updates, etc.... subscribe to Mirra mailing list here :
http://lists.goto10.org/cgi-bin/mailman/listinfo/mirra

 

Installation

Uncompress the zip cd to the mirra folder and on the terminal type : 'python setup.py install'. Windows users can use the exe installer provided.

 

Changes:

0.3.5 :
- Engine class from graphics.py converted to module engine.py with functions this allows to avoid having to pass the reference to engine on each render. Drawing functions are now accesed by importing engine. (First step towards moving this part of code into C)
- removed visible property

0.3.2 :
- killMe() renamed to end()
- implement properties for the Base class like rect or quad that update on the fly when you change location, etc...
- added preferences system (check example provided)
- removed pygame from main,py and events.py this disables self.env and should slightly improve performance on event handling
- added end() function to App

0.3.1 :
- fullscreen overwrites pos and size properties to fit display's size
- added self.width and self.height to main app. they return same as self.size[0] and self.size[1]
- fixed data folder problem on export.py for windows. need to be checked yet on mac

0.3 :
- (finally!) Fixed basic integration with wxPython
- fixed error in some linux system with sound from externals sound engines colliding with pygame audio. From now on audio needs to be initalised manually with self.initAudio()
- tested ChucK and SuperCollider as external sound engines.
- fixed mayor errors with wxpython
- fixed export.py module errors under windows
- added startup preferences system. Check example 16 and prefs.txt files

0.2.8.2 (Piksel):
- added rect class as property of graphical objects. This allows to have x,y,loc properties connected to a rect left,top,right,bottom, quad properties.
- trying experimental 3D mode
- added draw styles to Circles, Arcs, Lines, Rects and Polygons
- changes on rendering stack system
- added Arc drawing primitive class
- added end() method to primitive classes
- massive changes on render engine to optimise performance: reduced amount of code executed on the render loop, optimised loops, optimised drawing methods
- improving documentation files to include a better API description
- improving documentation and comments on the code

0.2.8.1 :
- fixed errors on setup.py installer script, exe installer provided for windows users - fixed bugs on Bitmap instances when calling tile() and setImage() - Implemented support for images with transparencies - graphics.py cleaned, there where some old lines of code not used anymore.

0.2.8 :
- Using py2exe / py2app now it can easily be created self executables (mac and win, linux users dont need this) non dependent from Python interpreter or library dependencies. Check 15export.py example.
- added mouseVisible property to App. self.mouseVisible = 0 will hide the mouse (but itwill keep active!)
- end() happends now just before quiting pygame and not after
- Bitmap and tmapPolygon images can be changed on the fly with setImage(pathtoimage) method, check examples related to textures
- several changes to optimise performance
- more extendingclasses examples added
- modified opengl setup suggested by tom betts to get rid of unnecesary coordinate and angle translations.
- finally fixed wx problems with refresh thanks to tip from robin dunn. Currently reconstructing wx support and creating examples. gui.py added back.
- fixed bug on mouse click that caused some mouse clicks not to be recognised properly.
- top app's mouseLoc implemented as a python property on pygame
- small changes on events.py to add mouseLoc to wx

0.2.7 :
- added pong.py to examples
- changed resources importing method to allow mirra to work as a proper python library
- added start method to Base class to avoid having to extend __init__ always when extending bult-in classes
- solved bug with start() on main.App class - added more examples

0.2.6.1 :
- changed tabs to spaces in all files to avoid problems in some editors.
- bug fixed, property blend was not active.
- bug fixed, killMe() method was not working properly. Thanks to Dan Law.
- bug fixed, instances where added twice to rendering stack because of new z property system. Thanks to Dan Law.
- bug fixed, setting the loc now work on Line class. Thanks to Dan Law.

0.2.6 :
- removed setters and getters for a more pythonic Mirra. This causes mayor changes on the API, check 'Short tutorial' section for more details.
- added visible property to all shapes
- small optimisation changes and code clean up
- license changed to LGPL to allow for commercial use of Mirra

0.2.5.7 :
- wxPython frames (with menus, status bars etc..) can be defined in a custom module. Before it was hard wired (just for testing) inside the mirra package. Check example6wxPython.py for usage
- render stack performance improved. Before it was a bidimensional array a 'bucket' for each Z depth(and they where 1000!), every time it rendered it had to go through each bucket rendering its shapes. Now it is one dimensional array where objects are shorted depending on their Z when created. The work is done on creation time and not every time it renders! . We are tying to improve...
- small changes to improve performance here and there ...
- joystick support added (only under pygame at the moment). Example provided.
- added keyUp() event to event manager. Modified KeyDown() now it only receives an argument with the pressed key code. (many thanks to Peter Goode for pointing this out)
- added render() method to MirraApp. This feature has been added just for completenes, it is handy to test drawing methods. Check example11directdrawing.py
- added end() method to MirraApp. It is called just before the application is closed. Good place to kill processes, write preferences to disk, etc...

0.2.5.6 :
- added basic audio functionality using pygame (to be extended and improved over next releases).
- fixed bug on setColor(). Alpha was default to 0 instead of 1 causing shapes to disapear if no alpha was passed.
- fixed bug on intersection with rotated Rects.
- hard-coded wxPython dependency removed and coded proper system exits if PyOpenGL or Pygame are not found.
- improved documentation and examples
- circles diameter argument is now called width.

0.2.5.5 :
- GLUT dropped in favor of Pygame. This way dependency from PIL library has been removed.
- support for more image file types added thanks to pygame
- mayor changes on graphics.py module to make class structure more clear and simple trying to avoid using multiple inheritance too much.
- added constrain to dragged shapes --> self.setConstrainRect(left, top, right, bottom). To reset do self.setConstrainRect(0,0,0,0)
- All shapes have now (inherited from Base) a built it self.getMouseLoc() method
- Base class keeps now a reference to the main App instance so that all objects inheriting from Base can comunicate back. This makes for example the access to mouseLoc more easy and clear to implement. Because main App knows about the mouseLoc it can be asked for its value using that reference. A class called Test could do Test.app.getMouseLoc() and would get a tupple containing x and y of current mouseloc. The previous system was more obscure than this one.

0.2.5.4 :
- bug fixed : eventhandler instance didnt receive the MirraApp instance so it couldnt pass back events to it.
- small changes in documentation and examples
- added to MirraApp class a method to access the mouse location --> getMouseLoc()

0.2.5 :
- optimised bitmap handling system (images are stored as static property of graphics engine class)
- WxPython and Pygame support added.
- new examples added and documentation improved
- small changes on rendering method to improve performance and some z location errors.
- bug fixed : when shape.setInteractiveState(1) and draggged there was a weird behavior
- Text class implements now setText(string) and getText()
- Text class implements default GLUT fonts
- Rects have now height and width allowing to create rectangles as well as squares
- small changes and cleanup on utilities.py module
- Base object implents :
self.mouseLoc --> gives access to mouse location
self.blend = float --> sets alpha component of instance's color
self.blend --> returns alpha component of instance's color

0.2.2 : solved flickering when two shapes are in the same z location
0.2.1 : solved bug with flipH() and flipV() in Rects

 

Short tutorial :

:: How to use it? ::

The mirratemplate.py module provides a template for your application. The simplest way to start working is to code using this template as a base. Basically you need to create a .py module where there is a class that extends main.App (like MirraApp does). Check examples 1 to 4

By intialising this app class, the main window and rendering system will be initialised according to the parameters you pass to the MirraApp during setUp() (environment, caption, size, position, framerate, fullscreen).

You will be able to use several methods inherited from main.App where you can place code such as start(), step() and several mouse and joystick events. By extending those methods you can create complex applications. There are several system properties that can be set or checked on the fly such as trails, mouseVisible and bgColor. Primitive drawing classes can be used to draw shapes that can be moved, clicked and dragged. By extending those classes you will be able to create complex graphics and behaviors.

It is a good idea to place images, sounds, etc... in the 'data' folder as they get automatically packed when you export you script as exe or app. Mirra supports for many image file types, SDL is used to load media.

To run your code just run with the Python interpreter the file you are working on. On windows just double click your .py file. Under unix systems (GNU/linux, OSX ..) you would type on the console something like 'python mirratemplate.py' (windows users can also run it from command line, this will actually give better feedback about errors as the console wont quit after the end of the script).

Several other examples are available in the main folder for you to learn using the basics of this framework. They are named '01example.py', '02example_events.py', 'example_osc.py' and so on.

Mirra allows to create self executables non dependent from Python interpreter and dependencies by using the py2app and py2exe, check example 15export_app.py or the section of this file 'Creating executables for windows or mac

 

:: Some tips about Mirra ::

- About MirraApp:
MirraApp is the application class, lets say it is the place where everything lives. It can set and get few properties of the main window (described above) like :
self.trails --> boolean  
self.bgColor --> r,g,b      

About all graphical classes :
All graphical classes (Rect, Circle, ...) are subclass of Base class. This means that they inherit few handy methods and properties from it, like loc, z, color or app (which is a reference to the top application instance, this allows to comunicate back to the application for example to ask for the mouse location or the background color and size of the window). Check the description of Base class above to see the methods available for all graphical classes.

- Instanciating built-in classes in MirraApp:
Built-in classes' instances are automagically added to the rendering stack as soon as you instanciate them. This means that the rendering is done under the hood and that you should not, in principle, worry about it too much. This is why just by calling Text('hi there', 100, 100) renders that text without us having to save a reference to the instance of the Text class initialised. A reference to that particular object has been added to the rendering stack, under the hood, as soon as it has been created. The graphic engine uses this reference to render the instance in the right place and order. Iif you want to know more about this check the render() function in engine.py module.

So, what if we want to manipulate the location or some other property of the instance? We should keep as well a reference to that instance. To do this we should save it, for example, as a property of the MirraApp or some other class where this instance should live. For example in start() we would create a property self.label = Text('number 5', 100, 100). The reference would allow us to change the loc of the instance from mainApp's step() method by calling the instance's internal method self.label.loc = x,y. Check the examples provided. We could as well save it as a global variable in our working module.

- Extending built-in classes:
Check example 7 to 8, and others like snow.py, orbit.py etc...
If you want to make something more complex that just displaying some basic shapes, like for example you want to have objects that move and bounce agains window limits, you will need to extend the basic classes to define methods that calculate movement and collision against walls.

- Event system description :
Events are controlled by the window system(wxPython or Pygame(SDL)) and binded to functions in the eventListener instance (in events.py) whose instance lives in the main App. The event listener asks the graphics engine for intersections between mouse and some clickable/draggable graphical object on the graphical stack of the engine. If intersection is true then it passes the event to the intersected object, if none is intersected it tries to pass the event up to the main App you are working in (usually MirraApp). In case you dont define those events on the main app then it just skips the event.

Mouse location can be accessed from the main App as property self.mouseLoc. It is a tuple containing the current x and y loc of the mouse. Because all graphical objects extend Base they can access the mouse location by calling self.app.mouseLoc

questions or suggestions are welcome to info@ixi-software.net or to the Mirra mailing list

 

API - command reference:

This API reference describes the main public commands you can use to manipulate Mirra. It is structured in three main areas (main app class, graphic primitive classes and utilities).

:: Main app class (defined in main.py)::

Here there is a complete description of your MirraApp class where most of your code will live

> General system functions. Check mirratemplate.py

start(self) # just when starting the app. Good place to initialise variables, objects or general stuff
step(self) # called every frame, frequency depends on frameRate set on setUp()
end(self) # called just before killing the application
setUp(self) # In setUp we initialise the whole application and set the main application's parameters
*Note*: fullScreen=1 overwrites size and pos
render()

# we can extend this method to draw directly by using the engine's module drawing functions or by coding directly OpenGL. For example
render(self) : engine.drawLine( (100,100), (20,35), color=(1,0,0,0.5))
Check example 11directdraw.py . Note that Z position does not work in this case

   
  > Environment properties that are defined during setUp()
 
self.caption # sets window's caption name - string .
self.size # window's size. width and height.
self.pos # sets window's top-left corner's location -- x, y
self.fullScreen # sets window fullscreen / non fullscreen -- boolean
self.frameRate # sets graphics refresh framerate -- integer
   
   
 
self.wxFrameClass # pass frame class to Mirra so that it can create it inside the main window - reference to a class like for example gui.MyFrame. Remember you have to import whatever module your wx frame is defined on before (only if you want a wxframe of course)

 

> Mouse and keyboard events functions- Read 'Event system description' paragraph in this file for more info. Check 03.events.py

mouseDown(self, x,y) # x and y is the mouse coordinates at the moment when the event is triggered
mouseUp(self, x,y)   
mouseDragged(self, x,y)   
rightMouseDown(self, x,y)   
rightMouseUp(self, x,y)  
keyDown(self, key) # key arg is the key being pressed : Check key reference for more details
keyUp(self, key) # key arg is the key being released : Check key reference for more details

> Joystick events, (not working if using wxPython on OSX, otherwise is runs fine). Check 12joystick.py

(more joystick/gamepad events to be implemented)
joyAxisMotion(self, joystick, index, value)  
joyBallMotion(self, joystick, index, value)  
joyHatMotion(self, joystick, index, value)  
joyButtonDown(self, joystick, button)  
joyButtonUp(self, joystick, button)  

> General properties of the sytem that cab be get and/or set at any point

# can only be get :  
self.width # returns windows width, same as size[0] --> int
self.height # returns windows height, same as size[1] --> int
# can be set and get :  
self.mouseVisible = 1 # mouse visibility on/off --> boolean
self.bgColor = r,g,b,a # window's background color --> rgba tuple like (0.1, 0, 0, 0.04)
self.trails = b   # trails on or off --> boolean

> General SDL audio system functions that can be called. Check example 09audio.py

Audio methods :  
self.initAudio() # starts SDL audio
self.playSound(self, path, volume=1.0, pan=0.5, channel=0, loop=0, maxtime=-1) # plays a sound
self.findFreeChannel(self) # returns a free channel in the mixer
setVolume(self,channel, volume=1, pan=0.5 # sets volume and pan of given chanel
self.preLoadSound(self, path) # preload a sound file
self.getVolume(self,channel) # get channel volume
self.stopSound(self,channel) # stop channel
self.pauseAll(self) # pause all channels
self.unpauseAll(self) # resume all channels
self.stopAll(self) # stop all channels

> Preferences related functions. Check example 16preferences.py and prefs.txt

self.readSetUpPrefs(self, aprefsfile) # executes lines in file UNTIL 'others' keyword
self.readOtherPrefs(self, aprefsfile) # executes lines in file AFTER 'others' keyword

The basic idea is that there is a txt file with python commands. Those commands are executed by python
when readSetUpPrefs() or readOtherPrefs() are called. We need to keep setUp preferences separated from other
preferences by a comment line with 'others' keyword on it. Check prefs.txt for format example. Each of the functions will read its part of the file. SetUp prefs need to be executed from setUp() function and others can be executed and any time after setUp, for example start() is a good moment.

This system can be used to set an initial state for your application, this only makes sense if you have created a exe or app with py2exe and py2app or if you dont want to edit the initial values for your variables in the source. Otherwise you would do the same result by editing the source. This was developed for situations where source can not be edited.

 


::: Description of graphic primitive classes defined by Mirra (defined in graphics.py module) :::

Primitive graphic classes available currently are: Text, Pixel, Line, Rect, Polygon, Circle, Bitmap, BitmapPolygon

> Primitive classes details (defined in graphics.py). Check 01allclasses.py and 01allclasses2.py

Text:
Draws a text given x,y,z, font family, font size, and color.
args : string, x, y, z, font, size, color
example : Text("hello world", 10, 100, 1, 'helvetica', 10, (0.1, 1, 0.3, 0.8))
NOTE - available fonts ans sizes are:
> typewriter 13 and 15
> timesroman 10 and 24
> helvetica 10, 12 and 18
other values would cause an error.
Text class also implements :
text = string # to update displayed string on the fly
example: myLabel.text = 'bye world'

Pixel:
Pixel(x, y, z, color)
Draws a pixel given x,y,z and color.
example : self.pixel = Pixel(x=12, y=100, z=900, color=(1,0,0,0.5))

Line:
Line(a, b, z, color, stroke, rotation)
example : self.line = Line( a=(1,1), b=(100,100), z=20, color=(0.2,0,0,1), stroke=10, rotation=45, style=0)
Draws a line given the begining and end point (as tupples with x,y), color (tupple) and stroke (thickness of line) and rotation. style is a value like 0xF0F0 (dashed line), 0xF00F (long dashed line) or 0x8888 (dotted lines)

Polygon:
Polygon(vertexarray, z, color, stroke, rotation)
Polygon described with an array that contains tuple points of each vertex.
example : self.poly = Polygon(vertexarray=[(0, 0), (29, 100), (30, 200)], z=100, color=(0,0.3,0.1,1), stroke=0, rotation=23, style=0)
style is a value like 0xF0F0 (dashed line), 0xF00F (long dashed line) or 0x8888 (dotted lines)

Rect:
Rect(x, y, z, width, height, color, stroke, rotation)
example : self.rect = Rect(x=10, y=100, z=1, width=40, height=60, color=(0.5,0.5,0.5,1), stroke=0, rotation=90, style=0)
style is a value like 0xF0F0 (dashed line), 0xF00F (long dashed line) or 0x8888 (dotted lines)

Circle:
Circle(x, y, z, width, color, stroke, rotation)
example : self.circle = Circle(x=20, y=100, z=1, width=300, color=(1,1,0,0.3), stroke=5, rotation=0, style=GLU_FILL)
style choices are : GLU_LINE, GLU_FILL, GLU_SILHOUETTE, GLU_POINT)

Arc:
Arc(x, y, z, width, color, stroke, rotation)
example : self.arc = Arc(x=10, y=10, z=0, radius=1, start=0, sweep=1, color=(0,0,0,1), stroke=0, rotation=0.0, style=GLU_FILL)
start is an angle, sweep is arc lenght in angles *anticlockwise*
style choices are : GLU_LINE, GLU_FILL, GLU_SILHOUETTE, GLU_POINT)

Bitmap:
Bitmap(file, x, y, z, width, height, rotation)
example : self.bmp = Bitmap(file='data/pict.bmp', x=300, y=500, z=3, width=300, height=250, rotation=45)
Bitmaps respond as well to these methods:
flipH()
flipV()
Both flip commands cause the image of the image of the shape to be flipped (*but not the shape itself!!*)
tile(int)
example : mybitmap.tile(10)
This modifies property called 'texCoord' which defines the way the image is mapped into the rect or polygon. Check the example2textures.py and example2textures2.pymodule.
setImage(self, path)
example : mybitmap.setIMage("data/image.bmp")
changes the image of the shape for a new one, path is relative

BitmapPolygon:
BitmapPolygon(file, vertexarray, z, rotation)
Described with an array that contains tuple points of each vertex.
args : file, vertexarray, z, rotation
example : self.bmpoly = BitmapPolygon(file='data/pict.bmp', vertexarray=[(0, 0), (29, 100), (30, 200)], z=2, rotation=0)
BitmapPolygon also implements :
tile(self, int)
example : mybitmap.tile(10)
This modifies property called 'texCoord' which defines the way the image is mapped into the rect or polygon. Check the tiled() example at the sometests.py module.
setImage(self, path)
example :  mybitmap.setImage("data/image.bmp")
changes the image of the shape for a new one, path is relative

* Note for Bitmaps and BitmapPolygon *
Both can receive an extra argument texCoord which is an array of tupples that defines how the image is mapped into the shape and it can be used to cause the image to be twisted. It is defaulted to [(0, 1), (1, 1), (1, 0), (0, 0)] . Check out some tutorial about OpenGL textures if you want to learn about this.

 

> ALL of primitive graphic classes inherit from Base class the following PROPERTIES:

# can be get :  
app # reference to the top app (MirraApp or whatever you name it). It can be used to access variables from mirraApp such as mouseLoc, trails, bgcolor or any other that you might define.
mouseLoc # returns current mouse location --> x,y
# can be set and get :  
z # z depth buffer position. Below 0 shapes are not visible - integer
loc # loc of instance - x,y
color # color of shape (alpha is default to 1) - r,g,b,a all must be float between 0 to 1
blend # alpha component of color - float between 0 to 1 value
rotation # instances rotation clockwise in degrees - integer or float
stroke # instances drawing thinkness, 0 for filled shapes. Bitmap and BitmapPolygon dont use it. - integer
interactiveState # instance's interaction level to be : 2 (draggable), 1 (clickable) or 0 (no interactive).
constrainRect # constrains an object being dragged within the given rect. Check example10constrain.py - left,top,right,bottom
clicked # am i clicked by the mouse? - boolean
textID # Only Bitmap and BitmatPolygon.
rect # left, top, right, bottom position. Connected to x,y and loc. You can do self.square.rect.left +=100
Does not work ok when rotation is on - To be changed soon
-- to be added soon:
left, top,right, bottom
quad # lefttop, righttop, bottomright, bottomleft locations of rect

For more details check Base class at graphics.py

 

> ALL of primitive graphic classes inherit from Base class the following METHODS:

start(self)      # just after __init__
intersects(self, x,y) # check intersection of shape with given x,y. Used for mouse events --> boolean
step(self)    # called every frame, depends on fps set on main app setup.
end(self) # removes the instance from rendering stack.
mouseDown(self, x,y) # clicked by mouse
mouseUp(self, x,y)   # unclicked by mouse
rightMouseDown(self, x,y) ...
rightMouseUp(self, x,y)   ...
mouseDragged(self, x,y) ...
render() # render method called from engine following the right rendering order. Each shape has a different render method which can be extended (using render drawing methods from engine module or pure OpenGL) to allow for more complex shapes to be drawn.

For more details check Base class at graphics.py

 


::: Utilities (defined in utilities.py) :::

path(res = '') returns the absolute path to a file or folder passed as argument -> string
   
Some random utilities :  
randint(min, max) returns random integer between min and max -> int
random() returns random float between 0 and 1 -> float between 0 and 1
randRGB() returns random RGB tuple color -> tuple r,g,b
randRGBA() returns random RGBA tuple color -> tuple r,g,b,a
randPoint(l, t, r, b) returns a random point within a given a rect or four limits-> x, y
It can receive four limits (left, top, right, bottom)
choice(seq) choose one in a list with few items -> whatever the choosen item is
receives a sequence of items
   
Some rect and quad utilities :  
calcPolygonRect(pointArray) receives a point list and returns the rect that contains them as a tupple -> tuple left, top, right, bottom
calcRectCenter(l,t,r,b) returns rect center point -> x,y
receives left, top, right and bottom of a rect
calcRectRect(x, y, width, height) calcs surrounding rect of a rectangular shape -> tuple left, top, right, bottom
receives x, y , width, height
calcRectQuad(x, y, width, height) returns a list containing the vertex points of a rect providing its
x,y, width and height -> list [lefttop, righttop, rightbottom, leftbottom]
receives x, y , width, height
constrainToRect(x,y, r) constrains a given x,y location to a given rect -> tupple x,y
receives x, y , rect as a tupple
   
Some intersection utilities :  
pointInLine(p, linePoints) TO BE DONE -> returns false
pointInRect(p, r) returns true if a point is inside a rect. rect is (left, top, right, bottom) -> Boolean
receives a tuple (x,y) and a tuple(left,top,right,bottom)
pointInCircle(p, p2, r) if distance from point to circle center is smaller than radius then it must be inside -> Boolean
receives two tuples (x,y) and the radius of the circle
pointInPoly(point, pointsList) Return True if point is contained in polygon (defined by given list of points.) -> Boolean
receives a tuple (x,y) and a sequence of tuple locations ((x,y),(x,y),(x,y).(x,y))
distance(p1, p2) Return the distance between two points, which may be given as (x,y) tuples or as complex numbers. -> float
receives two tuples (x,y)
rotPoint(point, axis, ang) Orbit. calcs the new loc for a point that rotates a given num of degrees around an axis point, +clockwise, -anticlockwise -> tuple x,y
receives a tuple (x,y), tuple (x,y), and ang in degrees
reverseAng(ang) converts angles from OpenGL anticlockwise to clockwise and the other way around -> int ang in degrees
receives ang in degrees
getAng(p1, p2)

returns the ang in degrees between two points *clockwise!* -> int ang in degrees
receives two tuple locs (x,y)

 

::: Drawing methods from engine class (graphics.py) :::
Check example 11directdrawing.py, 04extendingclasses4.py and 04extendingclasses5.py

drawPixel(self, x=1, y=1, z=0, color=(0,0,0,1))
Draws a pixel at a given x and y with given color .
Color = 3 or 4 arg tuple. RGB values from 0 to 1 being 1 max value (1, 1, 1) would be white

drawLine(self, p1, p2, z=0, color=(0,0,0,1), stroke=0, rotation=0.0, style=0)
p1, p2 are two tuple points and color is tuple rgb, values range 0 to 1
Rotation in degrees. clockwise.
style is a value like 0xF0F0 (dashed line), 0xF00F (long dashed line) or 0x8888 (dotted lines)

drawPolygon(self, v=[], z=0, color=(0,0,0,1), stroke=0, rotation=0.0, texID=None, texCoord=[], style=0)
v is an array with tuple points like [(x, y), (x2, y2), (x3, y3)]
min vertex number to draw a polygon is 3
stroke=0 to fill with color the inside of the shape or stroke=integer just to draw N-px thick outline.
style is a value like 0xF0F0 (dashed line), 0xF00F (long dashed line) or 0x8888 (dotted lines)
Note. It doesnt work with non covex polygons, need to implement tesselation yet

drawRect(self, x=1, y=1, z=0, width=10, height=10, color=(0,0,0,1), stroke=0, rotation=0.0, texID=None, texCoord=[], style=0)
draws a rect
style is a value like 0xF0F0 (dashed line), 0xF00F (long dashed line) or 0x8888 (dotted lines)

drawCircle(self, x=1, y=1, z=0, radius=5, color=(0,0,0,1), stroke=0, rotation=0.0, style=GLU_FILL)
x, y, z, width in pixel, rotation, color and line width in px
style choices are : GLU_LINE, GLU_FILL, GLU_SILHOUETTE, GLU_POINT)
TO DO : textured circles

drawArc(self, x, y, z=0, radius=1, start=0, sweep=1, color=(0,0,0,1), stroke = 0, rotation=0.0, style=GLU_FILL)
start angle, sweep is arc lenght in angles *anticlockwise*
style choices are : GLU_LINE, GLU_FILL, GLU_SILHOUETTE, GLU_POINT

This methods can be used to extend the render method of Mirra's built in graphic primitives or to draw directly from the render method of our mainApp. For example you could extend the drawing method or a Rect to draw a circle around it, lets see how it would look:

class myCustomRect(Rect): # extends mirra.graphics.Rect class
         def render() :
                super(myCustomRect, self).render() # call superclass method
                e.drawCircle(self.x, self.y, z, self.width, self.color) # calling engine instance drawing methods

Key Reference :

To check wxPython key reference

def keyDown(self, k):
            print k # this just prints the key number



Open Sound Control module :

the OSC module within Mirra allows to send and receive OSC messages. OSC is a very handy network protocol, read more about it at http://www.cnmat.berkeley.edu/OpenSoundControl/

There is a exampleosc.py module where you are provided with a template of a Mirra file that sends and receives OpenSoundControl messages. A PureData (http://pd.iem.org) patch called osc.pd explains how to communicate Mirra with other software able to communicate via OSC.
It can be as simple as doing this:
import osc
osc.init() # defaults to  ip 127.1.1.1 port 9000
osc.sendMsg(/hello, [666])
Check the exampleosc.py file for more details


Creating executables/apps for windows or mac :

Mirra allows to create self executables non dependent from Python interpreter and dependencies by using the py2app (http://undefined.org/python/#py2app) module on OSX and py2exe (http://www.py2exe.org) under windows. So you MUST have either of those libraries installed. On linux does not make much sense to do this so you have to install the libraries requiered.

**Note that currently (November 07) if you use PyOpenGL 3 under windows there are some issues with the way py2exe handles python eggs. This has to be solved by the py2exe developers. On the mean time you have to manually copy the pyOpenGL and setuptools eggs to your dist/lib folder after you pack your app with mirra. Check the example provided for details. The rest of this help is correct.

To make our lives easier, we created a crossplatform module inside Mirra that takes care off all this automatically. So all you need to do it to place this three lines in your setup()

import sys
from mirra import export
export.pack('myscript.py')

Next time you run your script, the export.pack() function will perform all steps required and after that it will quit. The process imports all the libraries and packages your app needs, it also imports all the files inside a folder called data next to your main script. So if you are importing images or audio you might want to place them there. After your script has quited you should find an folder called dist with the app (on mac) or with few files and folders (on windows) with the yourscript.exe file included. Copying the dist folder and to any machine should be enough to run it despite of that machine not having python or any libray installed. Note that the script might raise some error at some point, check the console output to see if everything went right.

In general you wont really need to change the command and the three lines above should be enough. But in case you want to do extra things like specify an icon, extra folders containing files (not included in data folder) or extra Python packages you can specify parameters to the command.

Note that on MAC the script deletes the previous dist during the process.

This the API for export.pack
pack(mainFile=, extraPackages=[], extraFiles=[], iconPath='')

Extra packages :
export.pack('myscript.py', extraPackages = [mypackage])

Custom icons :
export.pack('myscript.py', iconPath = 'myicon.ico') # OR myicon.icns on mac

Specifying extraFiles is a bit more complex, this is an example of how to specify extra files and folders to be added to the application:
files = [ ("stuff", ["stuff/slicer_pd.pd", "stuff/sampler.pd"]) ]
export.pack('myscript.py', extraFiles = files)

So a full complex example of the use would be:
import sys
from mirra import export
files = [ ("stuff", ["stuff/slicer_pd.pd", "stuff/sampler.pd"]), ("anotherfolder", ["anotherfolder/blah.txt"]) ]
export.pack('myscript.py', extraPackages = [mypackage], extraFiles = files, iconPath = "data\\icon\\myicon.ico" )

More advanced users can create their own setup.py file for py2app or py2exe, just remember to add mirra to the packages included and to manually copy the site-packages/OpenGL folder to the dist folder on windows But you probably just want to stick to the simple use which should be enough for most of us.

Extending Mirra :

Because currently Mirra is just 100% Python plus some widely used libraries (PyOpenGL, Pygame) you can easily use any part of the Python standard library and other Python library to extend Mirra for you needs, please let us know if you add something that would be of interest for all Mirra users.

TO DO:

- wx : Joystick events implement (check if wxpython supports joysticks on OSX)
- wx : update wx key reference example 03eventskey.py
- exceptions sometimes come from not the actual error, this is confussing for debugging
- textured circles
- drop pygame to use only wx?
- add center button event
- delete textures from opengl memory when textured objects are deleted
- when trials is set to True it forces background to white color, need to find a way to do this if possible.
- explore possibility to use Polygon library
- include pyode physics engine support
- posibility to use opengl scale. This would require to update with, height, vertex etc... on the fly for the intersections and also to implement intersection between point and elipse.
- more mouse events on objects like mouseUpOutSide, mouseOver, etc...
- optimise rendering:
explore possibility to delegate to C some rendering loops
# explore display lists # done: no much improvement
render by object types to call glBegin(GL_LINES) etc... only once rendering all similar shapes in the same call
- support antialias
- tesselation on polygons
- try to create hierarchy systems (glPopMatrix and glPushMatrix) and allow for relative locations.
- event driven (pop and not push) OSC system, maybe using Twisted?
- SuperCollider, OSW and Chuck sound examples with OSC
- implement some kind of object subgrouping system like in Flash. Maybe the easiest way to do this is the user to use own lists to store objects instances in groups?
- MIDI support
- video (Myron for webcams?)
- try nested ifs --> hash tables
- pygame : extend sound functionality
- wx : drag and drop
- wx : right/control click menu
- wx : other widgets? to be able to draw openGL window within a defined boxer in the window

 ...
email us with your request or ideas to info@ixi-software.net or to the Mirra mailing list

 

Contents of Mirra:

> /documentation
documentation.html
license.txt
> /examples
mirratemplate.py --> Application example
exampleosc.py --> OpenSoundControl example
examples 1 to N --> some examples using and extending the built-in classes
wxgui.py --> (for wxpython only) example description of own menus, dialogues and their functionality.
osc.pd --> PureData patch sending and receiving OSC to exampleosc.py
+ other examples ...
> /mirra package folder:
main.py --> main application class
graphics.py --> main drawing classes and graphicsStack instance
events.py --> event handling classes
export.py --> py2exe / py2app setup script
utilities.py --> a handy bunch of functions (collisions, random nums and colors, rotations, some triginometry and maths) and utility classes such as the Stack class.
export.py --> py2exe and py2app functionality
> /mirra/OSC package folder:
OSC.py --> Open Sound Control library by daniel Holth
oscAPI.py --> simple interface to OSC.py by ixi

 

Aknowledgements :

Currently Mirra is made thanks to the support and help of:
- The Digital Research Unit / Center for Excelence on Digital Design at the University of Huddersfield. http://www.druh.co.uk
- Goto10 collective www.goto10.org

Thanks to Goto10 collective www.goto10.org for thir SVN hosting and mailing list.

Some parts of the development of Mirra were developed with the support from different institutions :
- The Digital Research Unit at the University of Huddersfield. http://www.druh.co.uk
- The Lansdown Center for Electronic Arts at Middlesex University who helped providing expertise and support for developing the early versions of Mirra. http://www.cea.mdx.ac.uk/
- Bizkaiko Diputazioa, Basque Country.
- Buchsenhausen Kunstlerhaus, Innsbruck, Austria.

Tom Schoulten, John Cox, Daniel Holth and Tom Betts for the technical help.



Feedback:

We would more than happy to hear your comments, suggestions or to incorporte any improvement you might do to our code. Contact us on www.ixi-software.net , Mirra's mailing list (http://lists.goto10.org/cgi-bin/mailman/listinfo/mirra) or info@ixi-software.net
enjoy.