Completed
Push — master ( 308305...c45d91 )
by Matthew
01:08
created

ed2d.MeshBase.render()   A

Complexity

Conditions 3

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 3
dl 0
loc 19
rs 9.4285
1
from gem import matrix
2
from gem import vector
3
from ed2d.opengl import gl, pgl
4
from ed2d.assets import objloader
5
6
7
def buffer_object(data, typeM):
8
    if data or 0:
9
        vbo = pgl.glGenBuffers(1)
10
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
11
        pgl.glBufferData(gl.GL_ARRAY_BUFFER, data, typeM, gl.GL_STATIC_DRAW)
12
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
13
        return vbo
14
    else:
15
        return None
16
17
18
def index_buffer_object(data, typeM):
19
    if data or 0:
20
        ibo = pgl.glGenBuffers(1)
21
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, ibo)
22
        pgl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, data, typeM,
23
                         gl.GL_STATIC_DRAW)
24
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
25
        return ibo
26
    else:
27
        return None
28
29
30
def bind_object(dataLoc, vbo, size):
31
    if (dataLoc is not None) and (vbo is not None):
32
        gl.glEnableVertexAttribArray(dataLoc)
33
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
34
        pgl.glVertexAttribPointer(dataLoc, size, gl.GL_FLOAT, gl.GL_FALSE, 0,
35
                                  None)
36
    else:
37
        pass
38
39
40
def unbind_object(dataLoc):
41
    if dataLoc is not None:
42
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
43
        gl.glDisableVertexAttribArray(dataLoc)
44
    else:
45
        pass
46
47
def calc_face_normal(vertex1, vertex2, vertex3):
48
    ''' Calculate a face normal from 3 vertices. 3D Vector inputs. '''
49
    vertex11 = vertex2 - vertex1
50
    vertex22 = vertex3 - vertex1
51
    normal = vertex11.cross(vertex22)
52
    normal.i_normalize()
53
    return normal
54
55
# Conver matrix 4x4 to 3x3
56
def convertM4to3(mat):
57
    ''' Convert a 4x4 Matrix to 3x3. '''
58
    temp = [[0.0, 0.0, 0.0],
59
            [0.0, 0.0, 0.0],
60
            [0.0, 0.0, 0.0]]
61
62
    for i in range(3):
63
        for j in range(3):
64
            temp[i][j] = mat[i][j]
65
66
    out = matrix.Matrix(3)
67
    out.matrix = temp
68
    return out
69
70
71
class Indexer(object):
72
    ''' This is needed for CSG.'''
73
    def __init__(self):
74
        self.unique = []
75
        self.indices = []
76
        self.map = {}
77
78
    def add(self, obj):
79
        key = repr(obj)
80
81
        if not (key in self.map):
82
            self.map[key] = len(self.unique)
83
            self.unique.append(obj)
84
85
        return self.map[key]
86
87
88
class MeshBase(object):
89
    def __init__(self):
90
        self.program = None
91
        self.vertLoc = None
92
        self.UVLoc = None
93
        self.colorLoc = None
94
        self.normLoc = None
95
        self.modelID = None
96
        self.texture = None
97
        self.obj2world = matrix.Matrix(4)
98
        self.matrix = matrix.Matrix(4) # Model matrix
99
        self.modelInverseTranspose = matrix.Matrix(4)
100
101
        self.vbos = []
102
        self.cbos = []
103
        self.nbos = []
104
105
    def addProgram(self, program):
106
        self.program = program
107
        self.vertLoc = self.program.get_attribute(b'vertexPosition_modelspace')
108
        self.normLoc = self.program.get_attribute(b'normal_modelspace')
109
        #self.UVLoc = self.program.get_attribute(b'vertexUV')
110
        self.colorLoc = self.program.get_attribute(b'vertexColor')
111
        self.modelID = self.program.new_uniform(b'model_matrix')
112
        self.invModelLoc = self.program.new_uniform(b'gMdVw')
113
114
115
    def render(self):
116
        self.program.set_uniform_matrix(self.modelID, self.matrix)
117
        self.program.set_uniform_matrix(self.invModelLoc, self.modelInverseTranspose)
118
119
        i = 0
120
        for key in self.materials:
121
            try:
122
                bind_object(self.vertLoc, self.vbos[i], 3)
123
                bind_object(self.normLoc, self.nbos[i], 3)
124
                bind_object(self.colorLoc, self.cbos[i], 3)
125
126
                gl.glDrawArrays(gl.GL_TRIANGLES, 0, len(self.verData[key]))
127
128
                unbind_object(self.colorLoc)
129
                unbind_object(self.normLoc)
130
                unbind_object(self.vertLoc)
131
                i += 1
132
            except KeyError:
133
                pass
134
135
    def buffer_objects(self):
136
        if self.importedModel:
137
            for key in self.materials:
138
                try:
139
                    self.vbos.append(buffer_object(self.verData[key], gl.GLfloat))
140
                    self.nbos.append(buffer_object(self.norData[key], gl.GLfloat))
141
                    self.cbos.append(buffer_object(self.colData[key], gl.GLfloat))
142
                except KeyError:
143
                    pass
144
        else:
145
            self.vbo = buffer_object(self.vertices, gl.GLfloat)
146
            self.uvbo = buffer_object(self.texCoord, gl.GLfloat)
147
            self.ibo = index_buffer_object(self.triangles, gl.GLuint)
148
149
class Mesh(MeshBase):
150
    def __init__(self):
151
        super(Mesh, self).__init__()
152
153
        self.xPos = 0
154
        self.yPos = 0
155
        self.zPos = 0
156
        self.xPosDelta = 0
157
        self.yPosDelta = 0
158
        self.zPosDelta = 0
159
160
        self._scale = 1
161
        self.scaleDelta = 0
162
163
        self.verData = {}
164
        self.norData = {}
165
        self.colData = {}
166
        self.rect = None
167
        self.nverts = 0
168
        self.ntris = 0
169
170
        self.vertices = []
171
        self.texCoord = []
172
        self.normals = []
173
        self.colors = []
174
        self.triangles = []
175
        self.materials = {}
176
177
        self.physObj = None
178
        self.importedModel = False
179
180
    def setColorAll(self, r, g, b):
181
        '''
182
        This will populate the colors array with same color for every vertex.
183
        '''
184
        if not self.colors:
185
            for i in range(self.nverts):
186
                self.colors.append([r, g, b])
187
        else:
188
            for i in range(self.nverts):
189
                self.colors[i] = [r, g, b]
190
191
    def addMaterial(self, name, material):
192
        # Add a material to the mesh
193
        self.materials[name] = material
194
195
    def fromData(self, data, normals=None, texCoord=None):
196
        '''
197
        This will take in any set of vertices, uv coordinates and colors arrays
198
        '''
199
200
        if isinstance(data, objloader.OBJ):
201
            self.importedModel = True
202
            self.materials = data.mtlfile.data
203
204
            for key, value in data.fmvnig.items():
205
                # Vertices
206
                self.verData[key] = value[0]
207
                # Normals
208
                self.norData[key] = value[2]
209
210
            for key, value in self.materials.items():
211
                try:
212
                    self.colData[key] = []
213
                    for i in range(len(self.verData[key])):
214
                            self.colData[key].append(value.diffuse)
215
                except KeyError:
216
                    pass
217
        else:
218
            self.importedModel = False
219
            self.vertices = data
220
            self.nverts = len(self.vertices)
221
222
            if normals is not None:
223
                self.normals = normals
224
225
            if texCoord is not None:
226
                self.texCoord = texCoord
227
            else:
228
                self.texCoord = self.vertices
229
230
        self.buffer_objects()
231
232
    def fromCSG(self, csg):
233
        '''
234
        This will take in a CSG object and convert it to mesh for
235
        rendering and simulation purposes.
236
        '''
237
        indexer = Indexer()
238
        polygons = csg.toPolygons()
239
240
        for i in range(len(polygons)):
241
            polygon = polygons[i]
242
            indices = []
243
            for j in range(len(polygon.vertices)):
244
                vertex = polygon.vertices[j]
245
                vertex.color = polygon.shared or [1.0, 1.0, 1.0]
246
                index = indexer.add(vertex)
247
                indices.append(index)
248
            for k in range(2, len(indices), 1):
249
                self.triangles.append([indices[0], indices[k - 1], indices[k]])
250
251
        for i in range(len(indexer.unique)):
252
            v = indexer.unique[i]
253
            self.vertices.append(v.pos.vector)
254
            self.normals.append(v.normal.vector)
255
            self.colors.append(v.color)
256
257
        # print("Indexer Unique Count: ", len(indexer.unique))
258
        # print("Polygon Count: ", len(polygons))
259
        # print("Triangles Count: ", len(self.triangles))
260
        # print("Vertices Count: ", len(self.vertices))
261
262
        self.nverts = len(self.vertices)
263
        self.ntris = len(self.triangles)
264
265
        self.buffer_objects()
266
267
    def addPhysicsObject(self, physObj):
268
        '''This will attach a physics object to the mesh.'''
269
        self.physObj = physObj
270
        self.rect = physObj.getCollisionModel().getModel()
271
        self.vertices = self.rect.getVertices()
272
        self.texCoord = self.rect.getVertices()
273
        self.matrix = self.rect.getModelMatrix()
274
275
    def scale(self, value):
276
        self.scaleDelta = value / self._scale
277
        self._scale = value
278
279
    def translate(self, x, y, z):
280
        self.xPosDelta += x - self.xPos
281
        self.yPosDelta += y - self.yPos
282
        self.zPosDelta += z - self.yPos
283
        self.xPos = x
284
        self.yPos = y
285
        self.zPos = z
286
287
    # TODO - Needs to be checked
288
    def rotate(self, axis, angle):
289
        self.rotationMatrix = matrix.Matrix().rotate(axis, angle)
290
        self.matrix *= self.rotationMatrix
291
292
    def update(self):
293
294
        if self.physObj is None:
295
            pass
296
        else:
297
            self.rect = self.physObj.getCollisionModel().getModel()
298
            self.matrix = self.rect.getModelMatrix()
299
300
        if self.scaleDelta:
301
            vecScale = vector.Vector(
302
                3,
303
                data=[self.scaleDelta, self.scaleDelta, 0.0])
304
305
            self.matrix.i_scale(vecScale)
306
            self.scaleDelta = 0
307
308
        if self.xPosDelta or self.yPosDelta or self.zPosDelta:
309
            vecTrans = vector.Vector(
310
                3,
311
                data=[self.xPosDelta, self.yPosDelta, self.zPosDelta])
312
313
            #self.matrix.i_translate(vecTrans)
314
            self.matrix.i_translate(vecTrans)
315
            self.xPosDelta = 0
316
            self.yPosDelta = 0
317
            self.zPosDelta = 0
318
319
        temp4x4 = self.matrix.inverse().transpose()
320
        self.modelInverseTranspose = convertM4to3(temp4x4.matrix)