Completed
Push — master ( 43f138...ce3314 )
by
unknown
59s
created

ed2d.calc_face_normal()   A

Complexity

Conditions 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 7
rs 9.4286
1
from gem import matrix
2
from gem import vector
3
from ed2d.opengl import gl, pgl
4
5
6
def buffer_object(data, typeM):
7
    if data or 0:
8
        vbo = pgl.glGenBuffers(1)
9
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
10
        pgl.glBufferData(gl.GL_ARRAY_BUFFER, data, typeM, gl.GL_STATIC_DRAW)
11
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
12
        return vbo
13
    else:
14
        return None
15
16
17
def index_buffer_object(data, typeM):
18
    if data or 0:
19
        ibo = pgl.glGenBuffers(1)
20
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, ibo)
21
        pgl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, data, typeM,
22
                         gl.GL_STATIC_DRAW)
23
        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
24
        return ibo
25
    else:
26
        return None
27
28
29
def bind_object(dataLoc, vbo, size):
30
    if (dataLoc is not None) and (vbo is not None):
31
        gl.glEnableVertexAttribArray(dataLoc)
32
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)
33
        pgl.glVertexAttribPointer(dataLoc, size, gl.GL_FLOAT, gl.GL_FALSE, 0,
34
                                  None)
35
    else:
36
        pass
37
38
39
def unbind_object(dataLoc):
40
    if dataLoc is not None:
41
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
42
        gl.glDisableVertexAttribArray(dataLoc)
43
    else:
44
        pass
45
46
def calc_face_normal(vertex1, vertex2, vertex3):
47
    ''' Calculate a face normal from 3 vertices. 3D Vector inputs. '''
48
    vertex11 = vertex2 - vertex1
49
    vertex22 = vertex3 - vertex1
50
    normal = vertex11.cross(vertex22)
51
    normal.i_normalize()
52
    return normal
53
54
55
class Indexer(object):
56
    ''' This is needed for CSG.'''
57
    def __init__(self):
58
        self.unique = []
59
        self.indices = []
60
        self.map = {}
61
62
    def add(self, obj):
63
        key = repr(obj)
64
65
        if not (key in self.map):
66
            self.map[key] = len(self.unique)
67
            self.unique.append(obj)
68
69
        return self.map[key]
70
71
72
class MeshBase(object):
73
    def __init__(self):
74
        self.program = None
75
        self.vertLoc = None
76
        self.UVLoc = None
77
        self.colorLoc = None
78
        self.modelID = None
79
        self.matrix = matrix.Matrix(4) # Model matrix
80
81
    def addProgram(self, program):
82
        self.program = program
83
        self.vertLoc = self.program.get_attribute(b'position')
84
        self.UVLoc = self.program.get_attribute(b'vertexUV')
85
        self.colorLoc = self.program.get_attribute(b'color')
86
        self.modelID = self.program.new_uniform(b'model')
87
88
    def addTexture(self, texture):
89
        self.texture = texture
90
91
    def render(self):
92
93
        self.program.set_uniform_matrix(self.modelID, self.matrix)
94
95
        if self.texture is not None:
96
            self.texture.bind()
97
        else:
98
            gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
99
100
        self.cbo = buffer_object(self.colors, gl.GLfloat)
101
102
        bind_object(self.vertLoc, self.vbo, 3)
103
        bind_object(self.UVLoc, self.uvbo, 3)
104
        bind_object(self.colorLoc, self.cbo, 3)
105
106
        if self.ibo:
107
            gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.ibo)
108
109
            gl.glDrawElements(gl.GL_TRIANGLES, self.ntris * 3,
110
                              gl.GL_UNSIGNED_INT, 0)
111
112
            gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, 0)
113
        else:
114
            gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, self.nverts)
115
116
        unbind_object(self.colorLoc)
117
        unbind_object(self.UVLoc)
118
        unbind_object(self.vertLoc)
119
120
    def buffer_objects(self):
121
        self.vbo = buffer_object(self.data, gl.GLfloat)
122
        self.uvbo = buffer_object(self.texCoord, gl.GLfloat)
123
        self.ibo = index_buffer_object(self.triangles, gl.GLuint)
124
125
126
class Mesh(MeshBase):
127
    def __init__(self):
128
        super(Mesh, self).__init__()
129
130
        self.xPos = 0
131
        self.yPos = 0
132
        self.xPosDelta = 0
133
        self.yPosDelta = 0
134
135
        self._scale = 1
136
        self.scaleDelta = 0
137
138
        self.rect = None
139
        self.nverts = 0
140
        self.ntris = 0
141
        self.data = []
142
        self.texCoord = []
143
144
        self.normals = []
145
        self.colors = []
146
        self.triangles = []
147
148
        self.physObj = None
149
150
    def setColorAll(self, r, g, b):
151
        '''
152
        This will populate the colors array with same color for every vertex.
153
        '''
154
155
        if not self.colors:
156
            for i in range(self.nverts):
157
                self.colors.append([r, g, b])
158
        else:
159
            for i in range(self.nverts):
160
                self.colors[i] = [r, g, b]
161
162
    def fromData(self, data, texCoord=None, colors=None):
163
        '''
164
        This will take in any set of vertices, uv coordinates and colors arrays
165
        '''
166
        self.data = data
167
        self.nverts = len(self.data)
168
169
        if texCoord is not None:
170
            self.texCoord = texCoord
171
        else:
172
            self.texCoord = self.data
173
174
        if colors is not None:
175
            self.colors = colors
176
        else:
177
            self.colors = []
178
179
        self.buffer_objects()
180
181
    def fromCSG(self, csg):
182
        '''
183
        This will take in a CSG object and convert it to mesh for
184
        rendering and simulation purposes.
185
        '''
186
        indexer = Indexer()
187
        polygons = csg.toPolygons()
188
189
        for i in range(len(polygons)):
190
            polygon = polygons[i]
191
            indices = []
192
            for j in range(len(polygon.vertices)):
193
                vertex = polygon.vertices[j]
194
                vertex.color = polygon.shared or [1.0, 1.0, 1.0]
195
                index = indexer.add(vertex)
196
                indices.append(index)
197
            for k in range(2, len(indices), 1):
198
                self.triangles.append([indices[0], indices[k - 1], indices[k]])
199
200
        for i in range(len(indexer.unique)):
201
            v = indexer.unique[i]
202
            self.data.append(v.pos.vector)
203
            self.normals.append(v.normal.vector)
204
            self.colors.append(v.color)
205
206
        # print("Indexer Unique Count: ", len(indexer.unique))
207
        # print("Polygon Count: ", len(polygons))
208
        # print("Triangles Count: ", len(self.triangles))
209
        # print("Vertices Count: ", len(self.data))
210
211
        self.nverts = len(self.data)
212
        self.ntris = len(self.triangles)
213
214
        self.buffer_objects()
215
216
    def addPhysicsObject(self, physObj):
217
        '''This will attach a physics object to the mesh.'''
218
        self.physObj = physObj
219
        self.rect = physObj.getCollisionModel().getModel()
220
        self.data = self.rect.getVertices()
221
        self.texCoord = self.rect.getVertices()
222
        self.matrix = self.rect.getModelMatrix()
223
224
    def scale(self, value):
225
        self.scaleDelta = value / self._scale
226
        self._scale = value
227
228
    def translate(self, x, y):
229
        self.xPosDelta += x - self.xPos
230
        self.yPosDelta += y - self.yPos
231
        self.xPos = x
232
        self.yPos = y
233
234
    # TODO - Implement rotation..
235
236
    def update(self):
237
238
        if self.physObj is None:
239
            pass
240
        else:
241
            self.rect = self.physObj.getCollisionModel().getModel()
242
            self.matrix = self.rect.getModelMatrix()
243
244
        if self.scaleDelta:
245
            vecScale = vector.Vector(
246
                3,
247
                data=[self.scaleDelta, self.scaleDelta, 0.0])
248
249
            self.matrix.i_scale(vecScale)
250
            self.scaleDelta = 0
251
252
        if self.xPosDelta or self.yPosDelta:
253
            vecTrans = vector.Vector(
254
                3,
255
                data=[self.xPosDelta, self.yPosDelta, 0.0])
256
257
            self.matrix.i_translate(vecTrans)
258
            self.xPosDelta = 0
259
            self.yPosDelta = 0
260