Author: JaroslawTworek
Date: 2008-01-30 19:40:48 +0000 (Wed, 30 Jan 2008)
New Revision: 807

Added:
   trunk/pysoy/examples/bumpmap_example.py
   trunk/pysoy/examples/media/decal.png
   trunk/pysoy/examples/media/decal.soy
   trunk/pysoy/examples/media/normal_map.png
   trunk/pysoy/examples/media/normal_map.soy
   trunk/pysoy/src/textures/NormalisationCubeMap.pxi
Modified:
   trunk/pysoy/include/gl.pxd
   trunk/pysoy/include/stdlib.pxd
   trunk/pysoy/setup.py
   trunk/pysoy/src/_datatypes/FaceList.pxi
   trunk/pysoy/src/_datatypes/MaterialList.pxi
   trunk/pysoy/src/_datatypes/VertexList.pxi
   trunk/pysoy/src/_datatypes/soy._datatypes.pxd
   trunk/pysoy/src/atoms/Vertex.pxi
   trunk/pysoy/src/bodies._bodies/Body.pxi
   trunk/pysoy/src/bodies._bodies/soy.bodies._bodies.pxd
   trunk/pysoy/src/materials/Material.pxi
   trunk/pysoy/src/materials/soy.materials.pxd
   trunk/pysoy/src/meshes/Mesh.pxi
   trunk/pysoy/src/textures/soy.textures.pxd
   trunk/pysoy/src/textures/soy.textures.pyx
Log:
Added support for bump mapping


Added: trunk/pysoy/examples/bumpmap_example.py
===================================================================
--- trunk/pysoy/examples/bumpmap_example.py                             (rev 0)
+++ trunk/pysoy/examples/bumpmap_example.py     2008-01-30 19:40:48 UTC (rev 
807)
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+
+import soy
+import cmath
+from time import sleep, time
+
+V = soy.atoms.Vertex
+F = soy.atoms.Face
+
+def calculate_trig_normal(v1,v2,v3):
+    v_1 = (v2[0]-v1[0], v2[1]-v1[1], v2[2]-v1[2])
+    v_2 = (v3[0]-v1[0], v3[1]-v1[1], v3[2]-v1[2])
+    cross_a = (v_1[1] * v_2[2] - v_1[2] * v_2[1],
+               v_1[2] * v_2[0] - v_1[0] * v_2[2],
+               v_1[0] * v_2[1] - v_1[1] * v_2[0])
+    lgt = abs( cmath.sqrt( cross_a[0]**2 + cross_a[1]**2 + cross_a[2]**2))
+    return (cross_a[0] / lgt, cross_a[1]  / lgt, cross_a[2] / lgt)
+
+def create_quad_mesh(mat):
+    mesh = soy.meshes.Mesh(material=mat)
+
+    quad_vertices = [
+            ( 1, 1, 0),
+            ( 1,-1, 0),
+            (-1,-1, 0),
+            (-1, 1, 0)
+            ]
+    quad_faces = [
+            (0,1,2),
+            (2,3,0)
+            ]
+
+    V1 = lambda x,y : V(mesh, position=x, normal=y, texcoord=x, 
tangent=(0,1,0))
+    F1 = lambda x : F(mesh, verts=x, material=mat)
+
+    for f in quad_faces:
+        v1 = quad_vertices[ f[0] ]
+        v2 = quad_vertices[ f[1] ]
+        v3 = quad_vertices[ f[2] ]
+        n = calculate_trig_normal(v1,v2,v3)
+
+        vv1 = V1(v1,n)
+        vv2 = V1(v2,n)
+        vv3 = V1(v3,n)
+
+        face = F1([vv1,vv3,vv2])
+
+    return mesh
+    
+
+def main():
+    sce = soy.Scene()
+
+    cam = soy.bodies.Camera(sce)
+    cam.position = (0,0,10)
+    
+    lig = soy.bodies.lights.Light(sce)
+    lig.position = (-10, 1, -2)
+
+    decal_tex = soy.transports.File('media/decal.soy')['gimp']
+    normal_tex = soy.transports.File('media/normal_map.soy')['gimp']
+
+    normalisation_cube = soy.textures.NormalisationCubeMap()
+    normalisation_cube.generate(32,32)
+
+    decal_mat = soy.materials.Material(decal_tex)
+    decal_mat.normal = normal_tex
+    decal_mat.normalisation_cube_map = normalisation_cube
+
+    test_mesh = create_quad_mesh(decal_mat)
+    test_mesh_b = soy.bodies.Body(sce, mesh=test_mesh)
+
+    scr = soy.Screen()
+    win = soy.Window(scr, 'Bumpmap example', background=soy.colors.Black(),
+            size = (1024,768))
+
+    pro = soy.widgets.Projector(win, camera=cam)
+
+    key = soy.controllers.Keyboard(win)
+    key[ 1 ] = soy.actions.Quit()
+
+    wcn = soy.controllers.Window(win)
+    wcn['close'] = soy.actions.Quit()
+
+    while True:
+        sleep(0.3)
+        lig.position = (20*abs(cmath.sin(time())) - 10, 1, -2)
+        #test_mesh_b.position = (10*abs(cmath.sin( time()))- 6, 
10*abs(cmath.sin( time()))- 6, 2)
+
+if __name__=='__main__':
+    main()
+


Property changes on: trunk/pysoy/examples/bumpmap_example.py
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/pysoy/examples/media/decal.png
===================================================================
(Binary files differ)


Property changes on: trunk/pysoy/examples/media/decal.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/pysoy/examples/media/decal.soy
===================================================================
(Binary files differ)


Property changes on: trunk/pysoy/examples/media/decal.soy
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/pysoy/examples/media/normal_map.png
===================================================================
(Binary files differ)


Property changes on: trunk/pysoy/examples/media/normal_map.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/pysoy/examples/media/normal_map.soy
===================================================================
(Binary files differ)


Property changes on: trunk/pysoy/examples/media/normal_map.soy
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: trunk/pysoy/include/gl.pxd
===================================================================
--- trunk/pysoy/include/gl.pxd  2008-01-30 01:24:05 UTC (rev 806)
+++ trunk/pysoy/include/gl.pxd  2008-01-30 19:40:48 UTC (rev 807)
@@ -1121,6 +1121,11 @@
                                  GLsizei, GLsizei )
   cdef void glCopyTexSubImage3D( GLenum, GLint, GLint, GLint, GLint, GLint,
                                  GLint, GLsizei, GLsizei )
+  cdef void glTexEnvi(GLenum, GLenum, GLint)
+  # Multitexturing
+  cdef void glActiveTexture(GLenum texture)
+  cdef void glClientActiveTexture(GLenum texture)
+
   #Fog calculations
   cdef void glFogi(GLenum, GLint)
   cdef void glFogf(GLenum, GLfloat)

Modified: trunk/pysoy/include/stdlib.pxd
===================================================================
--- trunk/pysoy/include/stdlib.pxd      2008-01-30 01:24:05 UTC (rev 806)
+++ trunk/pysoy/include/stdlib.pxd      2008-01-30 19:40:48 UTC (rev 807)
@@ -2,6 +2,7 @@
 cdef extern from "math.h" :
     cdef float sinf(float)
     cdef float cosf(float)
+    cdef float sqrtf(float)
 
 cdef extern from "stdlib.h" :
     ctypedef unsigned int size_t

Modified: trunk/pysoy/setup.py
===================================================================
--- trunk/pysoy/setup.py        2008-01-30 01:24:05 UTC (rev 806)
+++ trunk/pysoy/setup.py        2008-01-30 19:40:48 UTC (rev 807)
@@ -26,7 +26,7 @@
 
 version = 'Trunk'
 modules = {
-  '_datatypes'       : ['GLEW','GL','glib-2.0'],
+  '_datatypes'       : ['GLEW','GL','glib-2.0','ode'],
   '_internals'       : [],
   'actions'          : ['ode'],
   'atoms'            : [],
@@ -36,7 +36,7 @@
   'colors'           : ['GL'],  
   'controllers'      : [],
   'joints'           : ['GL','ode'],
-  'materials'        : ['GL'],
+  'materials'        : ['GL','GLEW'],
   'meshes'           : ['GLEW','GL','GLU','ode'],
   'textures'         : ['GLEW','GL', 'ogg', 'theora', 'cairo'],
   'shapes'           : ['ode'],

Modified: trunk/pysoy/src/_datatypes/FaceList.pxi
===================================================================
--- trunk/pysoy/src/_datatypes/FaceList.pxi     2008-01-30 01:24:05 UTC (rev 
806)
+++ trunk/pysoy/src/_datatypes/FaceList.pxi     2008-01-30 19:40:48 UTC (rev 
807)
@@ -78,7 +78,13 @@
     gl.glDrawElements (gl.GL_TRIANGLES, _length*3,
                        gl.GL_UNSIGNED_SHORT, (<Face *> 0) + _offset)
 
+  cdef void _renderArrayBumpPass  (self, int a, int b):
+      pass
 
+  cdef void _renderBufferBumpPass (self, int a , int b):
+      pass
+
+
   cdef void _createBuffer(self) :
     self._children.lock()
     self._bufferAlloc = self._arrayAlloc

Modified: trunk/pysoy/src/_datatypes/MaterialList.pxi
===================================================================
--- trunk/pysoy/src/_datatypes/MaterialList.pxi 2008-01-30 01:24:05 UTC (rev 
806)
+++ trunk/pysoy/src/_datatypes/MaterialList.pxi 2008-01-30 19:40:48 UTC (rev 
807)
@@ -75,10 +75,21 @@
     return _mat
 
 
-  cdef void _renderArray(self) :
+  cdef void _renderArray(self, void* body) :
     cdef int i
     cdef soy.meshes.Mesh _mesh
+
     _mesh = <soy.meshes.Mesh> self._mesh
+    _mesh._verts._calculateTSLV(body)
+
+    _mesh._verts._renderArrayBumpPass()
+    self._children.lock()
+    for i from 0 <= i < self._children.current :
+      (<soy.materials.Material> self._children.list[i])._bind()
+      _mesh._faces._renderArray(self._ranges[i].offset, self._ranges[i].length)
+      (<soy.materials.Material> self._children.list[i])._unbind()
+    self._children.unlock()
+
     _mesh._verts._renderArray()
     self._children.lock()
     for i from 0 <= i < self._children.current :
@@ -88,16 +99,30 @@
     self._children.unlock()
 
 
-  cdef void _renderBuffer(self) :
+  cdef void _renderBuffer(self, void* body) :
     cdef int i
     cdef soy.meshes.Mesh _mesh
     if self._children.current == 0 :
       return
     _mesh = <soy.meshes.Mesh> self._mesh
+    _mesh._verts._calculateTSLV(body)
+
     if _mesh._faces._buffer == 0 :
       _mesh._faces._createBuffer()
       _mesh._verts._createBuffer()
+
     _mesh._faces._sendUpdated()
+
+    _mesh._verts._renderBufferBumpPass()
+
+    self._children.lock()
+    for i from 0 <= i < self._children.current :
+        if (<soy.materials.Material> self._children.list[i])._has_bumpmap():
+          (<soy.materials.Material> self._children.list[i])._bindBumpPass()
+          _mesh._faces._renderBuffer(self._ranges[i].offset, 
self._ranges[i].length)
+          (<soy.materials.Material> self._children.list[i])._unbindBumpPass()
+    self._children.unlock()
+
     _mesh._verts._renderBuffer()
     self._children.lock()
     for i from 0 <= i < self._children.current :

Modified: trunk/pysoy/src/_datatypes/VertexList.pxi
===================================================================
--- trunk/pysoy/src/_datatypes/VertexList.pxi   2008-01-30 01:24:05 UTC (rev 
806)
+++ trunk/pysoy/src/_datatypes/VertexList.pxi   2008-01-30 19:40:48 UTC (rev 
807)
@@ -22,6 +22,9 @@
 # it's parent holds the data this class works on.
 
 cimport stdlib
+cimport soy._core
+cimport soy.bodies._bodies
+cimport soy.bodies.lights
 
 cdef class VertexList (Datatype) :
   '''PySoy VertexList
@@ -93,27 +96,57 @@
 
 
   cdef void _renderArray(self) :
-    gl.glVertexPointer  (3,  gl.GL_FLOAT, 36, &self._array[0].px)
-    gl.glNormalPointer  (    gl.GL_FLOAT, 36, &self._array[0].nx)
-    gl.glTexCoordPointer(3,  gl.GL_FLOAT, 36, &self._array[0].tx)
+    gl.glVertexPointer  (3,  gl.GL_FLOAT, sizeof(Vert), &self._array[0].px)
+    gl.glNormalPointer  (    gl.GL_FLOAT, sizeof(Vert), &self._array[0].nx)
+    gl.glTexCoordPointer(3,  gl.GL_FLOAT, sizeof(Vert), &self._array[0].tx)
     gl.glFogCoordPointerEXT( gl.GL_FLOAT,  0, self._fogArray)
 
 
   cdef void _renderBuffer(self) :
+    gl.glClientActiveTexture(gl.GL_TEXTURE1)
+    gl.glDisableClientState(gl.GL_TEXTURE_COORD_ARRAY)
+    gl.glClientActiveTexture(gl.GL_TEXTURE0)
+
     gl.glBindBufferARB  (gl.GL_ARRAY_BUFFER_ARB, self._buffer)
     self._sendUpdated()
-    gl.glTexCoordPointer(3,  gl.GL_FLOAT, 36, <float*> 24)
-    gl.glNormalPointer  (    gl.GL_FLOAT, 36, <float*> 12)
-    gl.glVertexPointer  (3,  gl.GL_FLOAT, 36, <float*>  0)
-    gl.glFogCoordPointerEXT( gl.GL_FLOAT,  0, <float*> (36 * 
self._bufferAlloc))
 
+    gl.glTexCoordPointer(3,  gl.GL_FLOAT, sizeof(Vert), <float*> 24)
+    gl.glNormalPointer  (    gl.GL_FLOAT, sizeof(Vert), <float*> 12)
+    gl.glVertexPointer  (3,  gl.GL_FLOAT, sizeof(Vert), <float*>  0)
+    gl.glFogCoordPointerEXT( gl.GL_FLOAT,  0, <float*> (sizeof(Vert) * 
self._bufferAlloc))
 
+  cdef void _renderArrayBumpPass  (self):
+    gl.glVertexPointer  (3,  gl.GL_FLOAT, sizeof(Vert), &self._array[0].px)
+    gl.glNormalPointer  (    gl.GL_FLOAT, sizeof(Vert), &self._array[0].nx)
+    gl.glTexCoordPointer(3,  gl.GL_FLOAT, sizeof(Vert), &self._array[0].tx)
+    gl.glFogCoordPointerEXT( gl.GL_FLOAT,  0, self._fogArray)
+
+    gl.glClientActiveTexture(gl.GL_TEXTURE1)
+    gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY)
+    gl.glTexCoordPointer(3, gl.GL_FLOAT, 0, self._tslvArray)
+    gl.glClientActiveTexture(gl.GL_TEXTURE0)
+
+  cdef void _renderBufferBumpPass (self):
+    gl.glBindBufferARB  (gl.GL_ARRAY_BUFFER_ARB, self._buffer)
+    self._sendUpdated()
+
+    gl.glNormalPointer  (    gl.GL_FLOAT, sizeof(Vert), <float*> 12)
+    gl.glVertexPointer  (3,  gl.GL_FLOAT, sizeof(Vert), <float*>  0)
+    gl.glFogCoordPointerEXT( gl.GL_FLOAT,  0, <float*> (sizeof(Vert) * 
self._bufferAlloc))
+    gl.glTexCoordPointer(3,  gl.GL_FLOAT, sizeof(Vert), <float*> 24)
+
+    gl.glClientActiveTexture(gl.GL_TEXTURE1)
+    gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY)
+    gl.glTexCoordPointer(3, gl.GL_FLOAT, 0, <float*> ( 
(sizeof(Vert)+sizeof(float)) * self._bufferAlloc))
+    gl.glClientActiveTexture(gl.GL_TEXTURE0)
+
+
   cdef void _createBuffer(self) :
     self._bufferAlloc = self._arrayAlloc
     self._updateRange.offset = -1
     gl.glGenBuffersARB(1, &self._buffer)
     gl.glBindBufferARB(gl.GL_ARRAY_BUFFER_ARB, self._buffer)
-    gl.glBufferDataARB(gl.GL_ARRAY_BUFFER_ARB, (36+4)*self._bufferAlloc, 
#+FOGCOORDS
+    gl.glBufferDataARB(gl.GL_ARRAY_BUFFER_ARB, 
(sizeof(Vert)+4+12)*self._bufferAlloc, #+FOGCOORDS+TSLV
                        self._array, gl.GL_STATIC_DRAW_ARB)
 
 
@@ -133,12 +166,12 @@
     # If the range to be updated is larger than the existing buffer
     if self._updateRange.offset+self._updateRange.length > self._bufferAlloc :
       self._bufferAlloc = self._arrayAlloc
-      gl.glBufferDataARB(gl.GL_ARRAY_BUFFER_ARB, (36+4)*self._bufferAlloc, 
#+FOGCOORDS
+      gl.glBufferDataARB(gl.GL_ARRAY_BUFFER_ARB, 
(sizeof(Vert)+4+12)*self._bufferAlloc, #+FOGCOORDS+TSLV
                          self._array, gl.GL_STATIC_DRAW_ARB)
     else :
       gl.glBufferSubDataARB(gl.GL_ARRAY_BUFFER_ARB,
-                            36 * self._updateRange.offset,
-                            36 * (self._updateRange.length+1),
+                            sizeof(Vert) * self._updateRange.offset,
+                            sizeof(Vert) * (self._updateRange.length+1),
                             &self._array[self._updateRange.offset])
     self._updateRange.offset = -1
     self._updateRange.length = 0
@@ -150,9 +183,13 @@
     _mesh = <soy.meshes.Mesh> self._mesh
     self._array = <Vert *> self._alloc(num, &self._arrayAlloc, 
                                        self._array, sizeof(Vert))
+
     self._fogArray = <float*> self._alloc(num, &self._fogSize,
             self._fogArray, sizeof(float))
 
+    self._tslvArray = <float*> self._alloc(num, &self._tslvSize,
+            self._tslvArray, 3*sizeof(float))
+
   cdef void _uploadFogCoord(self, float y_coord):
       cdef int i
       #cdef float* fog_coord_array
@@ -163,10 +200,75 @@
       
       if self._bufferAlloc:
           gl.glBindBufferARB  (gl.GL_ARRAY_BUFFER_ARB, self._buffer)
-          gl.glBufferSubDataARB(gl.GL_ARRAY_BUFFER_ARB, 36 * self._bufferAlloc,
+          gl.glBufferSubDataARB(gl.GL_ARRAY_BUFFER_ARB, sizeof(Vert) * 
self._bufferAlloc,
                   4*self._bufferAlloc, self._fogArray )
 
       #stdlib.free( fog_coord_array)
 
+  cdef void _calculateTSLV(self, void* body):
+      cdef soy.bodies._bodies.Body _body
+      cdef soy._core.Scene         _scene
+      cdef soy.bodies.lights.Light _light
+      cdef ode.dVector3            _light_pos
+      cdef float                   _inv_mm[16]
+      cdef float                   _model_light_pos[3]
+      cdef float                   _binormal[3]
+      cdef int                     i
 
+      _body = <soy.bodies._bodies.Body> body
+      _scene = _body._scene
 
+      if _scene._lights.current > 0:
+          _light = <soy.bodies.lights.Light> _scene._lights.list[0]
+          ode.dBodyCopyPosition(<ode.dBodyID> _light._bodyID, _light_pos)
+          _body._get_inv_modelview(_inv_mm)
+
+          #vector by matrix multiplication by hand
+          _model_light_pos[0] = _inv_mm[0]  * _light_pos[0] + \
+                                _inv_mm[4]  * _light_pos[1] + \
+                                _inv_mm[8]  * _light_pos[2] + \
+                                _inv_mm[12] 
+
+          _model_light_pos[1] = _inv_mm[1]  * _light_pos[0] + \
+                                _inv_mm[5]  * _light_pos[1] + \
+                                _inv_mm[9]  * _light_pos[2] + \
+                                _inv_mm[13] 
+
+          _model_light_pos[2] = _inv_mm[2]  * _light_pos[0] + \
+                                _inv_mm[6]  * _light_pos[1] + \
+                                _inv_mm[10] * _light_pos[2] + \
+                                _inv_mm[14]
+
+          for i from 0 <= i < self._arraySize:
+              _binormal[0] = self._array[i].tan_y * self._array[i].nz - \
+                             self._array[i].tan_z * self._array[i].ny
+
+              _binormal[1] = self._array[i].tan_z * self._array[i].nx - \
+                             self._array[i].tan_x * self._array[i].nz
+
+              _binormal[2] = self._array[i].tan_x * self._array[i].ny - \
+                             self._array[i].tan_y * self._array[i].nx
+              
+              self._tslvArray[3*i + 0] = _model_light_pos[0] * 
self._array[i].tan_x + \
+                                         _model_light_pos[1] * 
self._array[i].tan_y + \
+                                         _model_light_pos[2] * 
self._array[i].tan_z
+
+              self._tslvArray[3*i + 1] = _model_light_pos[0] * _binormal[0] + \
+                                         _model_light_pos[1] * _binormal[1] + \
+                                         _model_light_pos[2] * _binormal[2]
+
+              self._tslvArray[3*i + 2] = _model_light_pos[0] * 
self._array[i].nx + \
+                                         _model_light_pos[1] * 
self._array[i].ny + \
+                                         _model_light_pos[2] * 
self._array[i].nz
+              if self._bufferAlloc:
+                  gl.glBindBufferARB  (gl.GL_ARRAY_BUFFER_ARB, self._buffer)
+                  gl.glBufferSubDataARB(gl.GL_ARRAY_BUFFER_ARB, 
(sizeof(Vert)+4) * self._bufferAlloc,
+                          12*self._bufferAlloc, self._tslvArray )
+
+      else:
+          return
+
+
+
+
+

Modified: trunk/pysoy/src/_datatypes/soy._datatypes.pxd
===================================================================
--- trunk/pysoy/src/_datatypes/soy._datatypes.pxd       2008-01-30 01:24:05 UTC 
(rev 806)
+++ trunk/pysoy/src/_datatypes/soy._datatypes.pxd       2008-01-30 19:40:48 UTC 
(rev 807)
@@ -22,8 +22,10 @@
 cimport glib
 cimport stdio
 cimport soy._internals
+cimport ode
 
 
+
 cdef struct Face :
   unsigned short a
   unsigned short b
@@ -40,6 +42,9 @@
   float tx
   float ty
   float tz
+  float tan_x
+  float tan_y
+  float tan_z
 
 
 cdef struct Range :
@@ -76,8 +81,8 @@
   cdef Range                     *_ranges
   cdef int                        _rangesAlloc
   cdef void                       _allocRanges  (self, int)
-  cdef void                       _renderArray  (self)
-  cdef void                       _renderBuffer (self)
+  cdef void                       _renderArray  (self, void*)
+  cdef void                       _renderBuffer (self, void*)
 
 
 cdef class FaceList (Datatype) :
@@ -93,6 +98,8 @@
   cdef void                       _allocArray   (self, int)
   cdef void                       _renderArray  (self, int, int)
   cdef void                       _renderBuffer (self, int, int)
+  cdef void                       _renderArrayBumpPass  (self, int, int)
+  cdef void                       _renderBufferBumpPass (self, int, int)
   cdef void                       _createBuffer (self)
   cdef void                       _sendUpdated  (self)
   cdef void                       _flagUpdated  (self, int, int)
@@ -104,6 +111,8 @@
   cdef Vert                      *_array
   cdef float                     *_fogArray
   cdef int                        _fogSize
+  cdef float                     *_tslvArray
+  cdef int                        _tslvSize
   cdef unsigned short             _arraySize
   cdef int                        _arrayAlloc
   cdef gl.GLuint                  _buffer
@@ -112,7 +121,11 @@
   cdef void                       _allocArray   (self, int)
   cdef void                       _renderArray  (self)
   cdef void                       _renderBuffer (self)
+  cdef void                       _renderArrayBumpPass  (self)
+  cdef void                       _renderBufferBumpPass (self)
   cdef void                       _createBuffer (self)
   cdef void                       _sendUpdated  (self)
   cdef void                       _flagUpdated  (self, int)
   cdef void                       _uploadFogCoord(self, float)
+  cdef void                       _calculateTSLV(self, void* body) #Tangent 
Space Light Vector
+

Modified: trunk/pysoy/src/atoms/Vertex.pxi
===================================================================
--- trunk/pysoy/src/atoms/Vertex.pxi    2008-01-30 01:24:05 UTC (rev 806)
+++ trunk/pysoy/src/atoms/Vertex.pxi    2008-01-30 19:40:48 UTC (rev 807)
@@ -23,7 +23,7 @@
      An element of VertexList with .position .normal and .texcoord properties
   '''
   def __cinit__(self, soy.meshes.Mesh mesh,
-              position=None, normal=None, texcoord=None,
+              position=None, normal=None, texcoord=None, tangent=None,
               index=-1, *args, **keywords) :
     self._index = -1
     self._list = mesh._verts
@@ -50,6 +50,8 @@
       self.normal   = normal
     if texcoord :   
       self.texcoord = texcoord
+    if tangent:
+        self.tangent = tangent
 
 
   def __dealloc__(self) :
@@ -136,3 +138,26 @@
       self._list._array[self._index].tz = value[2]
       self._list._flagUpdated(self._index)
       self._list._children.unlock()
+
+  property tangent:
+      def __get__(self):
+          cdef object t
+          self._list._children.lock()
+          t = (self._list._array[self._index].tan_x, 
+               self._list._array[self._index].tan_y, 
+               self._list._array[self._index].tan_z)
+          self._list._children.unlock()
+          return t
+      def __set__(self,value):
+          if type(value)!=tuple and type(value)!=list :
+            raise TypeError('Must provide a tuple or list')
+          if len(value)!=3 :
+            raise TypeError('Must provide (x,y,z)')
+
+          self._list._children.lock()
+          self._list._array[self._index].tan_x = value[0]
+          self._list._array[self._index].tan_y = value[1]
+          self._list._array[self._index].tan_z = value[2]
+          self._list._flagUpdated(self._index)
+          self._list._children.unlock()
+

Modified: trunk/pysoy/src/bodies._bodies/Body.pxi
===================================================================
--- trunk/pysoy/src/bodies._bodies/Body.pxi     2008-01-30 01:24:05 UTC (rev 
806)
+++ trunk/pysoy/src/bodies._bodies/Body.pxi     2008-01-30 19:40:48 UTC (rev 
807)
@@ -304,9 +304,32 @@
   cdef void _render(self) :
     if not self._mesh :
       return
+
+    cdef gl.GLfloat  mtx[16]
+
+    self._get_modelview(mtx)
+
+    gl.glPushMatrix()
+    gl.glMultMatrixf(mtx)
+
+    (<soy.meshes.Mesh> self._mesh)._render(<void *> self)
+
+    gl.glPopMatrix()
+
+  cdef void _createVerticalFogCoords(self):
     cdef ode.dReal  *pos
+    cdef soy._datatypes.VertexList _verts
+
+    pos = <ode.dReal *> ode.dBodyGetPosition(self._bodyID)
+
+    if self._mesh:
+        _verts = (<soy.meshes.Mesh> self._mesh)._verts
+        _verts._uploadFogCoord( <float>pos[1] )
+      
+  cdef void                     _get_modelview(self, float* mtx):
+    cdef ode.dReal  *pos
     cdef ode.dReal  *rot
-    cdef gl.GLfloat  mtx[16]
+
     pos = <ode.dReal *> ode.dBodyGetPosition(self._bodyID)
     rot = <ode.dReal *> ode.dBodyGetRotation(self._bodyID)
     mtx[0]  = rot[0]
@@ -325,19 +348,28 @@
     mtx[13] = pos[1]
     mtx[14] = pos[2]
     mtx[15] = 1.0
-    gl.glPushMatrix()
-    gl.glMultMatrixf(mtx)
-    (<soy.meshes.Mesh> self._mesh)._render(<void *> self)
-    gl.glPopMatrix()
 
-  cdef void _createVerticalFogCoords(self):
+  cdef void                     _get_inv_modelview(self, float* mtx):
     cdef ode.dReal  *pos
-    cdef soy._datatypes.VertexList _verts
+    cdef ode.dReal  *rot
 
     pos = <ode.dReal *> ode.dBodyGetPosition(self._bodyID)
+    rot = <ode.dReal *> ode.dBodyGetRotation(self._bodyID)
+    mtx[0]  = rot[0]
+    mtx[4]  = rot[4]
+    mtx[8]  = rot[8]
+    mtx[3]  = 0.0
+    mtx[1]  = rot[1]
+    mtx[5]  = rot[5]
+    mtx[9]  = rot[9]
+    mtx[7]  = 0.0
+    mtx[2]  = rot[2]
+    mtx[6]  = rot[6]
+    mtx[10] = rot[10]
+    mtx[11] = 0.0
+    mtx[12] = -pos[0]
+    mtx[13] = -pos[1]
+    mtx[14] = -pos[2]
+    mtx[15] = 1.0
 
-    if self._mesh:
-        _verts = (<soy.meshes.Mesh> self._mesh)._verts
-        _verts._uploadFogCoord( <float>pos[1] )
-      
 

Modified: trunk/pysoy/src/bodies._bodies/soy.bodies._bodies.pxd
===================================================================
--- trunk/pysoy/src/bodies._bodies/soy.bodies._bodies.pxd       2008-01-30 
01:24:05 UTC (rev 806)
+++ trunk/pysoy/src/bodies._bodies/soy.bodies._bodies.pxd       2008-01-30 
19:40:48 UTC (rev 807)
@@ -45,6 +45,8 @@
   cdef void                     _render(self)
   cdef void                     _createVerticalFogCoords(self)
   cdef void                    poke(self, vector)
+  cdef void                     _get_modelview    (self, float*)
+  cdef void                     _get_inv_modelview(self, float*)
 
 
 cdef class Camera (Body) :

Modified: trunk/pysoy/src/materials/Material.pxi
===================================================================
--- trunk/pysoy/src/materials/Material.pxi      2008-01-30 01:24:05 UTC (rev 
806)
+++ trunk/pysoy/src/materials/Material.pxi      2008-01-30 19:40:48 UTC (rev 
807)
@@ -22,13 +22,16 @@
 
      shared material for many visible objects
   '''
-  def __cinit__(self, color=None, ambient=None, diffuse=None, specular=None) :
+  def __cinit__(self, color=None, ambient=None, diffuse=None, specular=None, 
normal=None, normalisation_cube_map=None) :
 
     if color :
-      self.color = color
+      self._color = color
     else :
       self._color = None
 
+    self._normal = normal
+    self._normalisation_cube_map = normalisation_cube_map
+
     if ambient :
       self._ambient = ambient
     else :
@@ -79,6 +82,11 @@
               return 1
           return 0
 
+  cdef int _has_bumpmap(self):
+      if self._normal and self._normalisation_cube_map:
+          return 1
+      return 0
+
   cdef void _bind(self) :
     cdef gl.GLfloat _ambient[4]
     cdef gl.GLfloat _diffuse[4]
@@ -109,18 +117,60 @@
     if self._color :
       (<soy.textures.Texture> self._color)._bind()
 
-    if self._is_transparent():
+    if self._has_bumpmap():
         gl.glEnable(gl.GL_BLEND)
+        gl.glBlendFunc(gl.GL_DST_COLOR, gl.GL_ZERO)
+        gl.glEnable(gl.GL_POLYGON_OFFSET_FILL)
+        gl.glPolygonOffset(0,-2)
+    elif self._is_transparent():
+        gl.glEnable(gl.GL_BLEND)
         gl.glBlendFunc(self._blend_func_src, self._blend_func_dst)
 
   cdef void _unbind(self) :
     if self._color :
       (<soy.textures.Texture> self._color)._unbind()
-    if self._is_transparent():
+
+    if self._has_bumpmap():
         gl.glDisable(gl.GL_BLEND)
+        gl.glDisable(gl.GL_POLYGON_OFFSET_FILL)
+        gl.glPolygonOffset(0,0)
+    elif self._is_transparent():
+        gl.glDisable(gl.GL_BLEND)
+
     if self._shadeless:
         gl.glEnable(gl.GL_LIGHTING)
 
+  cdef void _bindBumpPass(self) :
+      if self._has_bumpmap():
+
+        gl.glActiveTexture(gl.GL_TEXTURE0)
+        (<soy.textures.Texture> self._normal)._bind()
+
+        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_COMBINE);
+        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_SOURCE0_RGB,  gl.GL_TEXTURE);
+        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_COMBINE_RGB,  gl.GL_REPLACE);
+
+        gl.glActiveTexture(gl.GL_TEXTURE1)
+        (<soy.textures.NormalisationCubeMap> 
self._normalisation_cube_map)._bind()
+
+        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_COMBINE);
+        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_SOURCE0_RGB,  gl.GL_TEXTURE);
+        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_COMBINE_RGB,  gl.GL_DOT3_RGB);
+        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_SOURCE1_RGB,  gl.GL_PREVIOUS);
+
+        gl.glActiveTexture(gl.GL_TEXTURE0)
+
+  cdef void _unbindBumpPass(self) :
+      if self._has_bumpmap():
+        gl.glActiveTexture(gl.GL_TEXTURE0)
+        (<soy.textures.Texture> self._normal)._unbind()
+        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_MODULATE)
+
+        gl.glActiveTexture(gl.GL_TEXTURE1)
+        (<soy.textures.NormalisationCubeMap> 
self._normalisation_cube_map)._unbind()
+
+        gl.glActiveTexture(gl.GL_TEXTURE0)
+
   property color :
     def __get__(self) :
       return self._color
@@ -128,8 +178,24 @@
       self._color = value
     def __del__(self) :
       self._color = None
+  
+  property normal:
+      def __get__(self):
+          return self._normal
+      def __set__(self, soy.textures.Texture val):
+          self._normal = val
+      def __del__(self):
+          self._normal = None
 
+  property normalisation_cube_map:
+      def __get__(self):
+          return self._normalisation_cube_map
+      def __set__(self, soy.textures.NormalisationCubeMap val):
+          self._normalisation_cube_map = val
+      def __del__(self):
+          self._normal = None
 
+
   property ambient :
     def __get__(self) :
       return self._ambient
@@ -219,6 +285,10 @@
       def __get__(self):
           return self._is_transparent()
 
+  property has_bumpmap:
+      def __get__(self):
+          return self._has_bumpmap()
+
   property shadeless:
       def __get__(self):
           return self._shadeless

Modified: trunk/pysoy/src/materials/soy.materials.pxd
===================================================================
--- trunk/pysoy/src/materials/soy.materials.pxd 2008-01-30 01:24:05 UTC (rev 
806)
+++ trunk/pysoy/src/materials/soy.materials.pxd 2008-01-30 19:40:48 UTC (rev 
807)
@@ -24,6 +24,8 @@
 
 cdef class Material :
   cdef object           _color
+  cdef object           _normal
+  cdef object           _normalisation_cube_map
 
   cdef soy.colors.Color _ambient
   cdef soy.colors.Color _diffuse
@@ -40,4 +42,7 @@
   # C Functions
   cdef void   _bind(self)
   cdef void   _unbind(self)
+  cdef void   _bindBumpPass(self)
+  cdef void   _unbindBumpPass(self)
   cdef int    _is_transparent(self)
+  cdef int    _has_bumpmap(self)

Modified: trunk/pysoy/src/meshes/Mesh.pxi
===================================================================
--- trunk/pysoy/src/meshes/Mesh.pxi     2008-01-30 01:24:05 UTC (rev 806)
+++ trunk/pysoy/src/meshes/Mesh.pxi     2008-01-30 19:40:48 UTC (rev 807)
@@ -87,6 +87,6 @@
 
   cdef void _render(self, void* _body) :
     if gl.GLEW_ARB_vertex_buffer_object :
-      self._mates._renderBuffer()
+      self._mates._renderBuffer(_body)
     else :
-      self._mates._renderArray()
+      self._mates._renderArray(_body)

Added: trunk/pysoy/src/textures/NormalisationCubeMap.pxi
===================================================================
--- trunk/pysoy/src/textures/NormalisationCubeMap.pxi                           
(rev 0)
+++ trunk/pysoy/src/textures/NormalisationCubeMap.pxi   2008-01-30 19:40:48 UTC 
(rev 807)
@@ -0,0 +1,208 @@
+cimport stdlib
+
+cdef class NormalisationCubeMap(Texture):
+    def __cinit__(self):
+        self._mutex = py.PyThread_allocate_lock()
+
+    def generate(self,x,y):
+        self._generate(x,y)
+        
+
+    cdef void _generate(self, int x_size, int y_size):
+        self._textureTarget = gl.GL_TEXTURE_CUBE_MAP
+        self._chans = 3
+        gl.glGenTextures(1, &self._textureID)
+        gl.glBindTexture(self._textureTarget, self._textureID)
+
+       #cdef int   size     = 32
+        cdef float offset
+        cdef float halfSizeX
+        cdef unsigned char* data
+        cdef unsigned char* bytePtr
+        cdef int i,j
+        cdef float temp_vector[3]
+        cdef float length
+
+        data = <unsigned char*>stdlib.malloc(x_size*x_size*3)
+        halfSizeX = <float>x_size / 2.0
+        offset = 0.5
+
+        #+X
+        bytePtr = data
+        for j from 0 < j <= x_size:
+            for i from 0 < i <= x_size:
+                temp_vector[0] = (halfSizeX)
+                temp_vector[1] = (-(j+offset-halfSizeX))
+                temp_vector[2] = (-(i+offset-halfSizeX))
+
+                length = stdlib.sqrtf(temp_vector[0]*temp_vector[0] + 
temp_vector[1] * temp_vector[1] + temp_vector[2]*temp_vector[2])
+
+                temp_vector[0] = temp_vector[0] / length
+                temp_vector[1] = temp_vector[1] / length
+                temp_vector[2] = temp_vector[2] / length
+
+                temp_vector[0] = 0.5 * temp_vector[0] + 0.5
+                temp_vector[1] = 0.5 * temp_vector[1] + 0.5
+                temp_vector[2] = 0.5 * temp_vector[2] + 0.5
+
+                bytePtr[0] = <unsigned char>(temp_vector[0]*255);
+                bytePtr[1] = <unsigned char>(temp_vector[1]*255);
+                bytePtr[2] = <unsigned char>(temp_vector[2]*255);
+                bytePtr = bytePtr + 3;
+
+        gl.glTexImage2D(gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, gl.GL_RGBA8, 
x_size, x_size,
+                0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, data)
+
+        #-X
+        bytePtr = data
+        for j from 0 < j <= x_size:
+            for i from 0 < i <= x_size:
+                temp_vector[0] = (-halfSizeX)
+                temp_vector[1] = (-(j+offset-halfSizeX))
+                temp_vector[2] = ((i+offset-halfSizeX))
+
+                length = stdlib.sqrtf(temp_vector[0]*temp_vector[0] + 
temp_vector[1] * temp_vector[1] + temp_vector[2]*temp_vector[2])
+
+                temp_vector[0] = temp_vector[0] / length
+                temp_vector[1] = temp_vector[1] / length
+                temp_vector[2] = temp_vector[2] / length
+
+                temp_vector[0] = 0.5 * temp_vector[0] + 0.5
+                temp_vector[1] = 0.5 * temp_vector[1] + 0.5
+                temp_vector[2] = 0.5 * temp_vector[2] + 0.5
+
+                bytePtr[0] = <unsigned char>(temp_vector[0]*255);
+                bytePtr[1] = <unsigned char>(temp_vector[1]*255);
+                bytePtr[2] = <unsigned char>(temp_vector[2]*255);
+                bytePtr = bytePtr + 3;
+        
+        gl.glTexImage2D(gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, gl.GL_RGBA8, 
x_size, x_size,
+                0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, data)
+
+        #+Y
+        bytePtr = data
+        for j from 0 < j <= x_size:
+            for i from 0 < i <= x_size:
+                temp_vector[0] = i+offset-halfSizeX
+                temp_vector[1] = halfSizeX
+                temp_vector[2] = j+offset - halfSizeX
+
+                length = stdlib.sqrtf(temp_vector[0]*temp_vector[0] + 
temp_vector[1] * temp_vector[1] + temp_vector[2]*temp_vector[2])
+
+                temp_vector[0] = temp_vector[0] / length
+                temp_vector[1] = temp_vector[1] / length
+                temp_vector[2] = temp_vector[2] / length
+
+                temp_vector[0] = 0.5 * temp_vector[0] + 0.5
+                temp_vector[1] = 0.5 * temp_vector[1] + 0.5
+                temp_vector[2] = 0.5 * temp_vector[2] + 0.5
+
+                bytePtr[0] = <unsigned char>(temp_vector[0]*255);
+                bytePtr[1] = <unsigned char>(temp_vector[1]*255);
+                bytePtr[2] = <unsigned char>(temp_vector[2]*255);
+                bytePtr = bytePtr + 3;
+        
+        gl.glTexImage2D(gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, gl.GL_RGBA8, 
x_size, x_size,
+                0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, data)
+
+        #-Y
+        bytePtr = data
+        for j from 0 < j <= x_size:
+            for i from 0 < i <= x_size:
+                temp_vector[0] = (i+offset-halfSizeX)
+                temp_vector[1] =-(halfSizeX)
+                temp_vector[2] =-(j+offset - halfSizeX)
+
+                length = stdlib.sqrtf(temp_vector[0]*temp_vector[0] + 
temp_vector[1] * temp_vector[1] + temp_vector[2]*temp_vector[2])
+
+                temp_vector[0] = temp_vector[0] / length
+                temp_vector[1] = temp_vector[1] / length
+                temp_vector[2] = temp_vector[2] / length
+
+                temp_vector[0] = 0.5 * temp_vector[0] + 0.5
+                temp_vector[1] = 0.5 * temp_vector[1] + 0.5
+                temp_vector[2] = 0.5 * temp_vector[2] + 0.5
+
+                bytePtr[0] = <unsigned char>(temp_vector[0]*255);
+                bytePtr[1] = <unsigned char>(temp_vector[1]*255);
+                bytePtr[2] = <unsigned char>(temp_vector[2]*255);
+                bytePtr = bytePtr + 3;
+        
+        gl.glTexImage2D(gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, gl.GL_RGBA8, 
x_size, x_size,
+                0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, data)
+
+        #+Z
+        bytePtr = data
+        for j from 0 < j <= x_size:
+            for i from 0 < i <= x_size:
+                temp_vector[0] = (i+offset-halfSizeX)
+                temp_vector[1] = (j+offset-halfSizeX)
+                temp_vector[2] = (halfSizeX)
+
+                length = stdlib.sqrtf(temp_vector[0]*temp_vector[0] + 
temp_vector[1] * temp_vector[1] + temp_vector[2]*temp_vector[2])
+
+                temp_vector[0] = temp_vector[0] / length
+                temp_vector[1] = temp_vector[1] / length
+                temp_vector[2] = temp_vector[2] / length
+
+                temp_vector[0] = 0.5 * temp_vector[0] + 0.5
+                temp_vector[1] = 0.5 * temp_vector[1] + 0.5
+                temp_vector[2] = 0.5 * temp_vector[2] + 0.5
+
+                bytePtr[0] = <unsigned char>(temp_vector[0]*255);
+                bytePtr[1] = <unsigned char>(temp_vector[1]*255);
+                bytePtr[2] = <unsigned char>(temp_vector[2]*255);
+                bytePtr = bytePtr + 3;
+        
+        gl.glTexImage2D(gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, gl.GL_RGBA8, 
x_size, x_size,
+                0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, data)
+
+
+        #-Z
+        bytePtr = data
+        for j from 0 < j <= x_size:
+            for i from 0 < i <= x_size:
+                temp_vector[0] = (i+offset-halfSizeX)
+                temp_vector[1] =-(j+offset-halfSizeX)
+                temp_vector[2] =-(halfSizeX)
+
+                length = stdlib.sqrtf(temp_vector[0]*temp_vector[0] + 
temp_vector[1] * temp_vector[1] + temp_vector[2]*temp_vector[2])
+
+                temp_vector[0] = temp_vector[0] / length
+                temp_vector[1] = temp_vector[1] / length
+                temp_vector[2] = temp_vector[2] / length
+
+                temp_vector[0] = 0.5 * temp_vector[0] + 0.5
+                temp_vector[1] = 0.5 * temp_vector[1] + 0.5
+                temp_vector[2] = 0.5 * temp_vector[2] + 0.5
+
+                bytePtr[0] = <unsigned char>(temp_vector[0]*255);
+                bytePtr[1] = <unsigned char>(temp_vector[1]*255);
+                bytePtr[2] = <unsigned char>(temp_vector[2]*255);
+                bytePtr = bytePtr + 3;
+        
+        gl.glTexImage2D(gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, gl.GL_RGBA8, 
x_size, x_size,
+                0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, data)
+
+        stdlib.free(data)
+
+        gl.glTexParameteri(self._textureTarget, gl.GL_TEXTURE_MAG_FILTER, 
gl.GL_LINEAR);
+        gl.glTexParameteri(self._textureTarget, gl.GL_TEXTURE_MIN_FILTER, 
gl.GL_LINEAR);
+        gl.glTexParameteri(self._textureTarget, gl.GL_TEXTURE_WRAP_S    , 
gl.GL_CLAMP_TO_EDGE);
+        gl.glTexParameteri(self._textureTarget, gl.GL_TEXTURE_WRAP_T    , 
gl.GL_CLAMP_TO_EDGE);
+        gl.glTexParameteri(self._textureTarget, gl.GL_TEXTURE_WRAP_R    , 
gl.GL_CLAMP_TO_EDGE);
+
+
+
+    cdef void _bind(self):
+        py.PyThread_acquire_lock(self._mutex,1)
+
+        gl.glEnable(self._textureTarget)
+        gl.glBindTexture(self._textureTarget, self._textureID)
+
+    cdef void _unbind(self):
+        gl.glDisable(self._textureTarget)
+        gl.glBindTexture(self._textureTarget, 0)
+
+        py.PyThread_release_lock(self._mutex)
+

Modified: trunk/pysoy/src/textures/soy.textures.pxd
===================================================================
--- trunk/pysoy/src/textures/soy.textures.pxd   2008-01-30 01:24:05 UTC (rev 
806)
+++ trunk/pysoy/src/textures/soy.textures.pxd   2008-01-30 19:40:48 UTC (rev 
807)
@@ -72,3 +72,9 @@
   cdef ogg.theora_state       _decode
   cdef double                 _startTime
   cdef double                 _frameTime
+
+cdef class NormalisationCubeMap(Texture):
+  cdef void                   _generate(self,int,int)
+  cdef void                   _bind(self)
+  cdef void                   _unbind(self)
+

Modified: trunk/pysoy/src/textures/soy.textures.pyx
===================================================================
--- trunk/pysoy/src/textures/soy.textures.pyx   2008-01-30 01:24:05 UTC (rev 
806)
+++ trunk/pysoy/src/textures/soy.textures.pyx   2008-01-30 19:40:48 UTC (rev 
807)
@@ -31,3 +31,5 @@
 include "Image.pxi"
 include "Video.pxi"
 include "Print.pxi"
+include "NormalisationCubeMap.pxi"
+

_______________________________________________
PySoy-SVN mailing list
[email protected]
http://www.pysoy.org/mailman/listinfo/pysoy-svn

Reply via email to