| 1 | # PySoy's atoms.Face class |
|---|
| 2 | # |
|---|
| 3 | # Copyright (C) 2006,2007,2008 PySoy Group |
|---|
| 4 | # |
|---|
| 5 | # This program is free software; you can redistribute it and/or modify |
|---|
| 6 | # it under the terms of the GNU Affero General Public License as published |
|---|
| 7 | # by the Free Software Foundation, either version 3 of the License, or |
|---|
| 8 | # (at your option) any later version. |
|---|
| 9 | # |
|---|
| 10 | # This program is distributed in the hope that it will be useful, |
|---|
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | # GNU Affero General Public License for more details. |
|---|
| 14 | # |
|---|
| 15 | # You should have received a copy of the GNU Affero General Public License |
|---|
| 16 | # along with this program; if not, see http://www.gnu.org/licenses |
|---|
| 17 | # |
|---|
| 18 | # $Id: Face.pym 1278 2008-05-19 22:57:46Z ArcRiley $ |
|---|
| 19 | |
|---|
| 20 | cdef class Face : |
|---|
| 21 | '''PySoy Face |
|---|
| 22 | |
|---|
| 23 | An element of FaceList with .verts property |
|---|
| 24 | ''' |
|---|
| 25 | |
|---|
| 26 | ############################################################################ |
|---|
| 27 | # |
|---|
| 28 | # Python functions |
|---|
| 29 | # |
|---|
| 30 | |
|---|
| 31 | def __cinit__(self, soy.models.Mesh mesh, |
|---|
| 32 | verts=None, material=None, |
|---|
| 33 | index=-1, *args, **keywords) : |
|---|
| 34 | cdef int i, _mindex |
|---|
| 35 | self._index = -1 |
|---|
| 36 | self._list = mesh._faces |
|---|
| 37 | self._mutex = mesh._mutex |
|---|
| 38 | |
|---|
| 39 | if index >= 0 : |
|---|
| 40 | # For an instance of an existing face |
|---|
| 41 | if index >= self._list._arraySize : |
|---|
| 42 | raise ValueError('index out of range') |
|---|
| 43 | self._list._children._append(<void*> self) |
|---|
| 44 | self._index = index |
|---|
| 45 | else : |
|---|
| 46 | # For a brand new face |
|---|
| 47 | if not (verts and material) : |
|---|
| 48 | raise TypeError('must provide verticies and material for a new Face') |
|---|
| 49 | if not isinstance(material, soy.materials.Material) : |
|---|
| 50 | raise TypeError('material must be of type soy.materials.Material') |
|---|
| 51 | py.PyThread_acquire_lock(self._mutex, 1) |
|---|
| 52 | self._list._children._append(<void*> self) |
|---|
| 53 | self._list._allocArray(self._list._arraySize + 1) |
|---|
| 54 | _mindex = mesh._mates._children._index(<void*> material) |
|---|
| 55 | if _mindex == -1 : |
|---|
| 56 | # |
|---|
| 57 | # New material, add face to end of array |
|---|
| 58 | self._index = self._list._arraySize |
|---|
| 59 | _mindex = mesh._mates._children._current |
|---|
| 60 | mesh._mates._children._append(<void*> material) |
|---|
| 61 | if (<soy.materials.Material> material)._needsTSLVs() : |
|---|
| 62 | mesh._mates._hasBumps = mesh._mates._hasBumps + 1 |
|---|
| 63 | py.Py_INCREF(material) |
|---|
| 64 | mesh._mates._allocRanges(mesh._mates._children._current) |
|---|
| 65 | mesh._mates._ranges[_mindex].offset = self._index |
|---|
| 66 | mesh._mates._ranges[_mindex].length = 1 |
|---|
| 67 | self._list._arraySize = self._list._arraySize + 1 |
|---|
| 68 | self._list._flagUpdated(self._index, 1) |
|---|
| 69 | # |
|---|
| 70 | else : |
|---|
| 71 | # |
|---|
| 72 | # Existing material, insert face into center of array |
|---|
| 73 | self._index = mesh._mates._ranges[_mindex].offset + \ |
|---|
| 74 | mesh._mates._ranges[_mindex].length |
|---|
| 75 | mesh._mates._ranges[_mindex].length = \ |
|---|
| 76 | mesh._mates._ranges[_mindex].length + 1 |
|---|
| 77 | for i from self._list._arraySize > i >= self._index : |
|---|
| 78 | self._list._array[i+1] = self._list._array[i] |
|---|
| 79 | for i from _mindex < i < mesh._mates._children._current : |
|---|
| 80 | mesh._mates._ranges[i].offset = mesh._mates._ranges[i].offset + 1 |
|---|
| 81 | self._list._arraySize = self._list._arraySize + 1 |
|---|
| 82 | self._list._flagUpdated(self._index, self._list._arraySize-self._index) |
|---|
| 83 | # |
|---|
| 84 | py.PyThread_release_lock(self._mutex) |
|---|
| 85 | self.verts = verts |
|---|
| 86 | |
|---|
| 87 | |
|---|
| 88 | def __dealloc__(self) : |
|---|
| 89 | if self._index >= 0 : |
|---|
| 90 | self._list._children._remove(<void*> self) |
|---|
| 91 | |
|---|
| 92 | |
|---|
| 93 | def __repr__(self) : |
|---|
| 94 | return '<%s>' % self.__class__.__name__ |
|---|
| 95 | |
|---|
| 96 | |
|---|
| 97 | ############################################################################ |
|---|
| 98 | # |
|---|
| 99 | # Properties |
|---|
| 100 | # |
|---|
| 101 | |
|---|
| 102 | property verts : |
|---|
| 103 | def __get__(self) : |
|---|
| 104 | cdef float a, b, c |
|---|
| 105 | cdef object t |
|---|
| 106 | cdef soy._datatypes.VertexList _verts |
|---|
| 107 | _verts = (<soy.models.Mesh> self._list._mesh)._verts |
|---|
| 108 | py.PyThread_acquire_lock(self._mutex, 1) |
|---|
| 109 | t = (_verts[self._list._array[self._index].a], |
|---|
| 110 | _verts[self._list._array[self._index].b], |
|---|
| 111 | _verts[self._list._array[self._index].c]) |
|---|
| 112 | py.PyThread_release_lock(self._mutex) |
|---|
| 113 | return t |
|---|
| 114 | |
|---|
| 115 | def __set__(self, value) : |
|---|
| 116 | cdef int i |
|---|
| 117 | if type(value) != tuple and type(value) != list : |
|---|
| 118 | raise TypeError('Must provide a tuple or list') |
|---|
| 119 | if len(value) != 3 : |
|---|
| 120 | raise TypeError('Must provide (x,y,z)') |
|---|
| 121 | for i from 0 <= i < 3 : |
|---|
| 122 | if type(value[i]) != Vertex : |
|---|
| 123 | raise TypeError('All three elements must be of type Vertex') |
|---|
| 124 | py.PyThread_acquire_lock(self._mutex, 1) |
|---|
| 125 | self._list._array[self._index].a = (<Vertex> value[0])._index |
|---|
| 126 | self._list._array[self._index].b = (<Vertex> value[1])._index |
|---|
| 127 | self._list._array[self._index].c = (<Vertex> value[2])._index |
|---|
| 128 | self._list._flagUpdated(self._index, 1) |
|---|
| 129 | py.PyThread_release_lock(self._mutex) |
|---|
| 130 | |
|---|
| 131 | |
|---|
| 132 | property material : |
|---|
| 133 | def __get__(self) : |
|---|
| 134 | cdef int i |
|---|
| 135 | cdef soy.materials.Material material |
|---|
| 136 | cdef soy._datatypes.MaterialList mlist |
|---|
| 137 | cdef soy._datatypes.Face _face |
|---|
| 138 | mlist = (<soy.models.Mesh> self._list._mesh)._mates |
|---|
| 139 | py.PyThread_acquire_lock(self._mutex, 1) |
|---|
| 140 | for i from 0 <= i < mlist._children._current : |
|---|
| 141 | if self._index >= mlist._ranges[i].offset and \ |
|---|
| 142 | self._index < mlist._ranges[i].offset + mlist._ranges[i].length : |
|---|
| 143 | material = <soy.materials.Material> mlist._children._list[i] |
|---|
| 144 | break |
|---|
| 145 | py.PyThread_release_lock(self._mutex) |
|---|
| 146 | if material : |
|---|
| 147 | return material |
|---|
| 148 | else : |
|---|
| 149 | return None |
|---|
| 150 | |
|---|
| 151 | def __set__(self, soy.materials.Material material) : |
|---|
| 152 | cdef int i, _mindex, _oldindex |
|---|
| 153 | cdef soy._datatypes.Face _face |
|---|
| 154 | cdef soy._datatypes.MaterialList mlist |
|---|
| 155 | mlist = (<soy.models.Mesh> self._list._mesh)._mates |
|---|
| 156 | py.PyThread_acquire_lock(self._mutex, 1) |
|---|
| 157 | _mindex = -1 |
|---|
| 158 | _oldindex = self._index |
|---|
| 159 | _face = self._list._array[self._index] |
|---|
| 160 | for i from 0 <= i < mlist._children._current : |
|---|
| 161 | if self._index >= mlist._ranges[i].offset and \ |
|---|
| 162 | self._index < mlist._ranges[i].offset + mlist._ranges[i].length : |
|---|
| 163 | _mindex = i |
|---|
| 164 | break |
|---|
| 165 | if _mindex == -1 : |
|---|
| 166 | py.PyThread_release_lock(self._mutex) |
|---|
| 167 | raise RuntimeError('This error should never happen. ' + \ |
|---|
| 168 | 'Please file a ticket on www.pysoy.org') |
|---|
| 169 | # |
|---|
| 170 | # First we're going to tackle the MaterialList since it will determine |
|---|
| 171 | # where in FaceList we need to be. We start by removing ourselves from |
|---|
| 172 | # our current location. |
|---|
| 173 | mlist._ranges[_mindex].length = mlist._ranges[_mindex].length - 1 |
|---|
| 174 | for i from _mindex < i < mlist._children._current : |
|---|
| 175 | mlist._ranges[i].offset = mlist._ranges[i].offset - 1 |
|---|
| 176 | if mlist._ranges[_mindex].offset == self._index : |
|---|
| 177 | if mlist._ranges[_mindex].length == 0 : |
|---|
| 178 | # If this was the only face using that material, remove it |
|---|
| 179 | for i from _mindex < i < mlist._children._current : |
|---|
| 180 | mlist._ranges[i-1] = mlist._ranges[i] |
|---|
| 181 | if (<soy.materials.Material> material)._needsTSLVs() : |
|---|
| 182 | mesh._mates._hasBumps = mesh._mates._hasBumps - 1 |
|---|
| 183 | py.Py_DECREF(<object> mlist._children._list[_mindex]) |
|---|
| 184 | mlist._children._remove(mlist._children._list[_mindex]) |
|---|
| 185 | #else : |
|---|
| 186 | # mlist._ranges[_mindex].offset = mlist._ranges[_mindex].offset + 1 |
|---|
| 187 | _mindex = -1 |
|---|
| 188 | # |
|---|
| 189 | # Now to see if the material we're setting is already in MaterialList |
|---|
| 190 | for i from 0 <= i < mlist._children._current : |
|---|
| 191 | if <soy.materials.Material> mlist._children._list[i] == material : |
|---|
| 192 | _mindex = i |
|---|
| 193 | break |
|---|
| 194 | if _mindex == -1 : |
|---|
| 195 | # |
|---|
| 196 | # New material, add face to end of array (look familiar? see __cinit__) |
|---|
| 197 | self._index = self._list._arraySize - 1 |
|---|
| 198 | _mindex = mlist._children._current |
|---|
| 199 | mlist._children._append(<void*> material) |
|---|
| 200 | if (<soy.materials.Material> material)._needsTSLVs() : |
|---|
| 201 | mesh._mates._hasBumps = mesh._mates._hasBumps + 1 |
|---|
| 202 | py.Py_INCREF(material) |
|---|
| 203 | mlist._allocRanges(mlist._children._current) |
|---|
| 204 | mlist._ranges[_mindex].offset = self._index |
|---|
| 205 | mlist._ranges[_mindex].length = 1 |
|---|
| 206 | else : |
|---|
| 207 | # |
|---|
| 208 | # Existing material, make room for ourselves and slide into that group |
|---|
| 209 | self._index = mlist._ranges[_mindex].offset + \ |
|---|
| 210 | mlist._ranges[_mindex].length |
|---|
| 211 | mlist._ranges[_mindex].length = mlist._ranges[_mindex].length + 1 |
|---|
| 212 | for i from _mindex < i < mlist._children._current : |
|---|
| 213 | mlist._ranges[i].offset = mlist._ranges[i].offset + 1 |
|---|
| 214 | # |
|---|
| 215 | # Now that we know where we're going, shift the face array in the |
|---|
| 216 | # correct direction and flag the array for update. Oh, and if for some |
|---|
| 217 | # reason we ended up with the same index, we don't need to do anything |
|---|
| 218 | if _oldindex < self._index : |
|---|
| 219 | # We've moved to a later position in the array |
|---|
| 220 | for i from _oldindex < i <= self._index : |
|---|
| 221 | self._list._array[i-1] = self._list._array[i] |
|---|
| 222 | self._list._array[self._index] = _face |
|---|
| 223 | self._list._flagUpdated(_oldindex, self._index - _oldindex + 1) |
|---|
| 224 | elif _oldindex > self._index : |
|---|
| 225 | # We've moved to an earlier position in the array |
|---|
| 226 | for i from _oldindex > i >= self._index : |
|---|
| 227 | self._list._array[i+1] = self._list._array[i] |
|---|
| 228 | self._list._array[self._index] = _face |
|---|
| 229 | self._list._flagUpdated(self._index, _oldindex - self._index + 1) |
|---|
| 230 | py.PyThread_release_lock(self._mutex) |
|---|