# PySoy's models.Mesh class # # Copyright (C) 2006,2007,2008 PySoy Group # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program; if not, see http://www.gnu.org/licenses # # $Id$ cdef class Mesh (Model) : '''soy.models.Mesh This is a collection of verticies and faces we call a "mesh". Faces and verticies are added to a Mesh by passing the Mesh instance to a new soy.atoms.Vertex or soy.atoms.Face object. Materials are added to a Mesh by using it in one of its faces and is automatically removed from a Mesh when no longer used by any Face. Math and comparison is planned for the future, allowing two Mesh objects to be combined, the area of one subtracted from another, etc. An example of using a Mesh: {{{ >>> pyramid = soy.models.Mesh() >>> pyrskin = soy.materials.darkWood >>> [[ Add verticies/faces ]] >>> pyrbody = soy.bodies.Body(scene) }}} Mesh objects have three main properties, .faces .verts and .materials. These are instances of soy._datatypes.FaceList, soy._datatypes.VertexList, and soy._datatypes.MaterialList respectively. Each of these emulate a Python list plus some additional functionality, see the help() on each for more information. ''' # # A Mesh is mostly a placeholder class, it stores no actual data. # The reason for this is alternatives to Mesh inherit it and sometimes # use these datatypes in other ways, or don't use them at all. # # MaterialList (self._mates) stores a Children of Material objects and # an array of Face ranges which use that Material. This is to speed up # rendering, to minimize the number of texture/etc changes during rendering. # # FaceList (self._faces) stores a Children of Face objects and the actual # face data, each having three intices to a Vertex in that array/buffer. # # VertexList (self._verts) stores a Children of Vertex objects and the # vertex array/buffer. # # It should be noted that the Children of _faces and _verts is only for # Face and Vertex objects created by Python. These need not exist to be # rendered and hold only pointers to the data stored in the FaceList or # VertexList. They may be __dealloc__'ed, forgotten by Python, and still # be rendered. # # The Children of each of these exists to manage update their offsets when # internal order is changed (Face/Vertex removed, Face changes its Material, # various order-based optimization routines run, etc). ############################################################################ # # Python functions # def __cinit__(self, *args, **keywords) : self._mutex = py.PyThread_allocate_lock() self._mates = soy._datatypes.MaterialList(self) self._faces = soy._datatypes.FaceList(self) self._verts = soy._datatypes.VertexList(self) def __dealloc__(self) : py.PyThread_free_lock(self._mutex) def __repr__(self) : return '' % ( len(self._verts), len(self._faces), len(self._mates)) ############################################################################ # # Properties # property faces : '''Mesh.faces This is a list-like object for manipulating the faces of a Mesh. ''' def __get__(self) : return self._faces property verts : '''Mesh.verts This is a list-like object for manipulating the verticies of a Mesh. ''' def __get__(self) : return self._verts property materials : '''Mesh.materials This is a list-like object for manipulating the materials of a Mesh. ''' def __get__(self) : return self._mates ############################################################################ # # WindowLoop Functions # cdef void _render(self, soy.bodies.Body _body) : cdef gl.GLfloat _mtx[16] # ###################################### # # save current matrix # gl.glPushMatrix() # ###################################### # # set model's matrix # _mtx[0] = _body._rotation[0] _mtx[1] = _body._rotation[4] _mtx[2] = _body._rotation[8] _mtx[3] = 0.0 _mtx[4] = _body._rotation[1] _mtx[5] = _body._rotation[5] _mtx[6] = _body._rotation[9] _mtx[7] = 0.0 _mtx[8] = _body._rotation[2] _mtx[9] = _body._rotation[6] _mtx[10] = _body._rotation[10] _mtx[11] = 0.0 _mtx[12] = _body._position[0] _mtx[13] = _body._position[1] _mtx[14] = _body._position[2] _mtx[15] = 1.0 gl.glMultMatrixf(_mtx) # ###################################### # # render materials - insert new code here # py.PyThread_acquire_lock(self._mutex, 1) self._mates._render( _body) py.PyThread_release_lock(self._mutex) # ###################################### # # restore previous matrix # gl.glPopMatrix() # ###################################### # # Rendering Pipeline : # # We start with the "original" vertex array. # # The next step is applying morph targets. The product of this must be # saved because, often, morph will change infrequently. When no morphs are # in use the "original" is simply copied here and updated whenever needed. # # After morphs we need to do bone transformations. Bone transformations # from resting to current within the coordinate system of the Mesh's Body # is aquired and a comparison of transformation from the last frame (ie, # how much that bone has moved since last calculated) is made. # # Once all the bone transformations are calculated each vertex tests against # the bones that it's attached to. First step of this is to multiply it's # weight (0.0 - 1.0) against the amount of transformation and test to see if # it's greater than the culling value (if it's changed enough to recalc). # If so, calculate that vertex's transformation based on weights for each # bone it's attached to and then apply the product of this. # # These are placed, one by one, into the final array with the appropriate # VBO update array calculated. If VBO, the updated subarray range is sent, # and in both VA and VBO this is transformed to the body's location and # then rendered. # ############################################################################ cdef void _calcFogCoords(self, float _depth) nogil : cdef int _i #cdef float* fog_coord_array #fog_coord_array = ( stdlib.malloc(4 * self._bufferAlloc) ) # for _i from 0 <= _i < self._verts._fogSize : self._verts._fogArray[_i] = _depth + self._verts._array[_i].py # if self._verts._bufferAlloc : gl.glBindBufferARB (gl.GL_ARRAY_BUFFER_ARB, self._verts._buffer) gl.glBufferSubDataARB(gl.GL_ARRAY_BUFFER_ARB, 48 * self._verts._bufferAlloc, 4 * self._verts._bufferAlloc, self._verts._fogArray) #stdlib.free( fog_coord_array)