chiark / gitweb /
39b435c25e1744ea46ba830bbe3d58ff2e63e95a
[cura.git] / Cura / gui / util / opengl.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2
3 import math
4 import numpy
5 import wx
6 import time
7
8 from Cura.util.resources import getPathForImage
9
10 import OpenGL
11
12 #OpenGL.ERROR_CHECKING = False
13 from OpenGL.GLUT import *
14 from OpenGL.GLU import *
15 from OpenGL.GL import *
16 from OpenGL.GL import shaders
17 glutInit()
18
19 platformMesh = None
20
21 class GLReferenceCounter(object):
22         def __init__(self):
23                 self._refCounter = 1
24
25         def incRef(self):
26                 self._refCounter += 1
27
28         def decRef(self):
29                 self._refCounter -= 1
30                 return self._refCounter <= 0
31
32 def hasShaderSupport():
33         if bool(glCreateShader):
34                 return True
35         return False
36
37 class GLShader(GLReferenceCounter):
38         def __init__(self, vertexProgram, fragmentProgram):
39                 super(GLShader, self).__init__()
40                 self._vertexString = vertexProgram
41                 self._fragmentString = fragmentProgram
42                 try:
43                         vertexShader = shaders.compileShader(vertexProgram, GL_VERTEX_SHADER)
44                         fragmentShader = shaders.compileShader(fragmentProgram, GL_FRAGMENT_SHADER)
45
46                         #shader.compileProgram tries to return the shader program as a overloaded int. But the return value of a shader does not always fit in a int (needs to be a long). So we do raw OpenGL calls.
47                         # self._program = shaders.compileProgram(self._vertexProgram, self._fragmentProgram)
48                         self._program = glCreateProgram()
49                         glAttachShader(self._program, vertexShader)
50                         glAttachShader(self._program, fragmentShader)
51                         glLinkProgram(self._program)
52                         # Validation has to occur *after* linking
53                         glValidateProgram(self._program)
54                         if glGetProgramiv(self._program, GL_VALIDATE_STATUS) == GL_FALSE:
55                                 raise RuntimeError("Validation failure: %s"%(glGetProgramInfoLog(self._program)))
56                         if glGetProgramiv(self._program, GL_LINK_STATUS) == GL_FALSE:
57                                 raise RuntimeError("Link failure: %s" % (glGetProgramInfoLog(self._program)))
58                         glDeleteShader(vertexShader)
59                         glDeleteShader(fragmentShader)
60                 except RuntimeError, e:
61                         print str(e)
62                         self._program = None
63
64         def bind(self):
65                 if self._program is not None:
66                         shaders.glUseProgram(self._program)
67
68         def unbind(self):
69                 shaders.glUseProgram(0)
70
71         def release(self):
72                 if self._program is not None:
73                         glDeleteProgram(self._program)
74                         self._program = None
75
76         def setUniform(self, name, value):
77                 if self._program is not None:
78                         if type(value) is float:
79                                 glUniform1f(glGetUniformLocation(self._program, name), value)
80                         elif type(value) is numpy.matrix:
81                                 glUniformMatrix3fv(glGetUniformLocation(self._program, name), 1, False, value.getA().astype(numpy.float32))
82                         else:
83                                 print 'Unknown type for setUniform: %s' % (str(type(value)))
84
85         def isValid(self):
86                 return self._program is not None
87
88         def getVertexShader(self):
89                 return self._vertexString
90
91         def getFragmentShader(self):
92                 return self._fragmentString
93
94         def __del__(self):
95                 if self._program is not None and bool(glDeleteProgram):
96                         print "Shader was not properly released!"
97
98 #A Class that acts as an OpenGL shader, but in reality is not none.
99 class GLFakeShader(GLReferenceCounter):
100         def __init__(self):
101                 super(GLFakeShader, self).__init__()
102
103         def bind(self):
104                 glEnable(GL_LIGHTING)
105                 glEnable(GL_LIGHT0)
106                 glEnable(GL_COLOR_MATERIAL)
107                 glLightfv(GL_LIGHT0, GL_DIFFUSE, [1,1,1,1])
108                 glLightfv(GL_LIGHT0, GL_AMBIENT, [0,0,0,0])
109                 glLightfv(GL_LIGHT0, GL_SPECULAR, [0,0,0,0])
110
111         def unbind(self):
112                 glDisable(GL_LIGHTING)
113
114         def release(self):
115                 pass
116
117         def setUniform(self, name, value):
118                 pass
119
120         def isValid(self):
121                 return True
122
123         def getVertexShader(self):
124                 return ''
125
126         def getFragmentShader(self):
127                 return ''
128
129 class GLVBO(GLReferenceCounter):
130         def __init__(self, renderType, vertexArray, normalArray = None, indicesArray = None):
131                 super(GLVBO, self).__init__()
132                 self._renderType = renderType
133                 if not bool(glGenBuffers):
134                         self._vertexArray = vertexArray
135                         self._normalArray = normalArray
136                         self._indicesArray = indicesArray
137                         self._size = len(vertexArray)
138                         self._buffer = None
139                         self._hasNormals = self._normalArray is not None
140                         self._hasIndices = self._indicesArray is not None
141                 else:
142                         self._buffer = glGenBuffers(1)
143                         self._size = len(vertexArray)
144                         self._hasNormals = normalArray is not None
145                         self._hasIndices = indicesArray is not None
146                         glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
147                         if self._hasNormals:
148                                 glBufferData(GL_ARRAY_BUFFER, numpy.concatenate((vertexArray, normalArray), 1), GL_STATIC_DRAW)
149                         else:
150                                 glBufferData(GL_ARRAY_BUFFER, vertexArray, GL_STATIC_DRAW)
151                         glBindBuffer(GL_ARRAY_BUFFER, 0)
152                         if self._hasIndices:
153                                 self._size = len(indicesArray)
154                                 self._bufferIndices = glGenBuffers(1)
155                                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
156                                 glBufferData(GL_ELEMENT_ARRAY_BUFFER, numpy.array(indicesArray, numpy.uint32), GL_STATIC_DRAW)
157
158         def render(self):
159                 glEnableClientState(GL_VERTEX_ARRAY)
160                 if self._buffer is None:
161                         glVertexPointer(3, GL_FLOAT, 0, self._vertexArray)
162                         if self._hasNormals:
163                                 glEnableClientState(GL_NORMAL_ARRAY)
164                                 glNormalPointer(GL_FLOAT, 0, self._normalArray)
165                 else:
166                         glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
167                         if self._hasNormals:
168                                 glEnableClientState(GL_NORMAL_ARRAY)
169                                 glVertexPointer(3, GL_FLOAT, 2*3*4, c_void_p(0))
170                                 glNormalPointer(GL_FLOAT, 2*3*4, c_void_p(3 * 4))
171                         else:
172                                 glVertexPointer(3, GL_FLOAT, 3*4, c_void_p(0))
173                         if self._hasIndices:
174                                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._bufferIndices)
175
176                 if self._hasIndices:
177                         glDrawElements(self._renderType, self._size, GL_UNSIGNED_INT, c_void_p(0))
178                 else:
179                         batchSize = 996    #Warning, batchSize needs to be dividable by 4, 3 and 2
180                         extraStartPos = int(self._size / batchSize) * batchSize
181                         extraCount = self._size - extraStartPos
182                         for i in xrange(0, int(self._size / batchSize)):
183                                 glDrawArrays(self._renderType, i * batchSize, batchSize)
184                         glDrawArrays(self._renderType, extraStartPos, extraCount)
185
186                 if self._buffer is not None:
187                         glBindBuffer(GL_ARRAY_BUFFER, 0)
188                 if self._hasIndices:
189                         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
190
191                 glDisableClientState(GL_VERTEX_ARRAY)
192                 if self._hasNormals:
193                         glDisableClientState(GL_NORMAL_ARRAY)
194
195         def release(self):
196                 if self._buffer is not None:
197                         glBindBuffer(GL_ARRAY_BUFFER, self._buffer)
198                         glBufferData(GL_ARRAY_BUFFER, None, GL_STATIC_DRAW)
199                         glBindBuffer(GL_ARRAY_BUFFER, 0)
200                         glDeleteBuffers(1, [self._buffer])
201                         self._buffer = None
202                 self._vertexArray = None
203                 self._normalArray = None
204
205         def __del__(self):
206                 if self._buffer is not None and bool(glDeleteBuffers):
207                         print "VBO was not properly released!"
208
209 def glDrawStringCenter(s):
210         glRasterPos2f(0, 0)
211         glBitmap(0,0,0,0, -glGetStringSize(s)[0]/2, 0, None)
212         for c in s:
213                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
214
215 def glGetStringSize(s):
216         width = 0
217         for c in s:
218                 width += glutBitmapWidth(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
219         height = 18
220         return width, height
221
222 def glDrawStringLeft(s):
223         glRasterPos2f(0, 0)
224         n = 1
225         for c in s:
226                 if c == '\n':
227                         glPushMatrix()
228                         glTranslate(0, 18 * n, 0)
229                         n += 1
230                         glRasterPos2f(0, 0)
231                         glPopMatrix()
232                 else:
233                         glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
234
235 def glDrawStringRight(s):
236         glRasterPos2f(0, 0)
237         glBitmap(0,0,0,0, -glGetStringSize(s)[0], 0, None)
238         for c in s:
239                 glutBitmapCharacter(OpenGL.GLUT.GLUT_BITMAP_HELVETICA_18, ord(c))
240
241 def glDrawQuad(x, y, w, h):
242         glPushMatrix()
243         glTranslatef(x, y, 0)
244         glDisable(GL_TEXTURE_2D)
245         glBegin(GL_QUADS)
246         glVertex2f(w, 0)
247         glVertex2f(0, 0)
248         glVertex2f(0, h)
249         glVertex2f(w, h)
250         glEnd()
251         glPopMatrix()
252
253 def glDrawTexturedQuad(x, y, w, h, texID, mirror = 0):
254         tx = float(texID % 4) / 4
255         ty = float(int(texID / 4)) / 8
256         tsx = 0.25
257         tsy = 0.125
258         if mirror & 1:
259                 tx += tsx
260                 tsx = -tsx
261         if mirror & 2:
262                 ty += tsy
263                 tsy = -tsy
264         glPushMatrix()
265         glTranslatef(x, y, 0)
266         glEnable(GL_TEXTURE_2D)
267         glBegin(GL_QUADS)
268         glTexCoord2f(tx+tsx, ty)
269         glVertex2f(w, 0)
270         glTexCoord2f(tx, ty)
271         glVertex2f(0, 0)
272         glTexCoord2f(tx, ty+tsy)
273         glVertex2f(0, h)
274         glTexCoord2f(tx+tsx, ty+tsy)
275         glVertex2f(w, h)
276         glEnd()
277         glPopMatrix()
278
279 def glDrawStretchedQuad(x, y, w, h, cornerSize, texID):
280         tx0 = float(texID % 4) / 4
281         ty0 = float(int(texID / 4)) / 8
282         tx1 = tx0 + 0.25 / 2.0
283         ty1 = ty0 + 0.125 / 2.0
284         tx2 = tx0 + 0.25
285         ty2 = ty0 + 0.125
286
287         glPushMatrix()
288         glTranslatef(x, y, 0)
289         glEnable(GL_TEXTURE_2D)
290         glBegin(GL_QUADS)
291         #TopLeft
292         glTexCoord2f(tx1, ty0)
293         glVertex2f( cornerSize, 0)
294         glTexCoord2f(tx0, ty0)
295         glVertex2f( 0, 0)
296         glTexCoord2f(tx0, ty1)
297         glVertex2f( 0, cornerSize)
298         glTexCoord2f(tx1, ty1)
299         glVertex2f( cornerSize, cornerSize)
300         #TopRight
301         glTexCoord2f(tx2, ty0)
302         glVertex2f( w, 0)
303         glTexCoord2f(tx1, ty0)
304         glVertex2f( w - cornerSize, 0)
305         glTexCoord2f(tx1, ty1)
306         glVertex2f( w - cornerSize, cornerSize)
307         glTexCoord2f(tx2, ty1)
308         glVertex2f( w, cornerSize)
309         #BottomLeft
310         glTexCoord2f(tx1, ty1)
311         glVertex2f( cornerSize, h - cornerSize)
312         glTexCoord2f(tx0, ty1)
313         glVertex2f( 0, h - cornerSize)
314         glTexCoord2f(tx0, ty2)
315         glVertex2f( 0, h)
316         glTexCoord2f(tx1, ty2)
317         glVertex2f( cornerSize, h)
318         #BottomRight
319         glTexCoord2f(tx2, ty1)
320         glVertex2f( w, h - cornerSize)
321         glTexCoord2f(tx1, ty1)
322         glVertex2f( w - cornerSize, h - cornerSize)
323         glTexCoord2f(tx1, ty2)
324         glVertex2f( w - cornerSize, h)
325         glTexCoord2f(tx2, ty2)
326         glVertex2f( w, h)
327
328         #Center
329         glTexCoord2f(tx1, ty1)
330         glVertex2f( w-cornerSize, cornerSize)
331         glTexCoord2f(tx1, ty1)
332         glVertex2f( cornerSize, cornerSize)
333         glTexCoord2f(tx1, ty1)
334         glVertex2f( cornerSize, h-cornerSize)
335         glTexCoord2f(tx1, ty1)
336         glVertex2f( w-cornerSize, h-cornerSize)
337
338         #Right
339         glTexCoord2f(tx2, ty1)
340         glVertex2f( w, cornerSize)
341         glTexCoord2f(tx1, ty1)
342         glVertex2f( w-cornerSize, cornerSize)
343         glTexCoord2f(tx1, ty1)
344         glVertex2f( w-cornerSize, h-cornerSize)
345         glTexCoord2f(tx2, ty1)
346         glVertex2f( w, h-cornerSize)
347
348         #Left
349         glTexCoord2f(tx1, ty1)
350         glVertex2f( cornerSize, cornerSize)
351         glTexCoord2f(tx0, ty1)
352         glVertex2f( 0, cornerSize)
353         glTexCoord2f(tx0, ty1)
354         glVertex2f( 0, h-cornerSize)
355         glTexCoord2f(tx1, ty1)
356         glVertex2f( cornerSize, h-cornerSize)
357
358         #Top
359         glTexCoord2f(tx1, ty0)
360         glVertex2f( w-cornerSize, 0)
361         glTexCoord2f(tx1, ty0)
362         glVertex2f( cornerSize, 0)
363         glTexCoord2f(tx1, ty1)
364         glVertex2f( cornerSize, cornerSize)
365         glTexCoord2f(tx1, ty1)
366         glVertex2f( w-cornerSize, cornerSize)
367
368         #Bottom
369         glTexCoord2f(tx1, ty1)
370         glVertex2f( w-cornerSize, h-cornerSize)
371         glTexCoord2f(tx1, ty1)
372         glVertex2f( cornerSize, h-cornerSize)
373         glTexCoord2f(tx1, ty2)
374         glVertex2f( cornerSize, h)
375         glTexCoord2f(tx1, ty2)
376         glVertex2f( w-cornerSize, h)
377
378         glEnd()
379         glDisable(GL_TEXTURE_2D)
380         glPopMatrix()
381
382 def unproject(winx, winy, winz, modelMatrix, projMatrix, viewport):
383         npModelMatrix = numpy.matrix(numpy.array(modelMatrix, numpy.float64).reshape((4,4)))
384         npProjMatrix = numpy.matrix(numpy.array(projMatrix, numpy.float64).reshape((4,4)))
385         finalMatrix = npModelMatrix * npProjMatrix
386         finalMatrix = numpy.linalg.inv(finalMatrix)
387
388         viewport = map(float, viewport)
389         vector = numpy.array([(winx - viewport[0]) / viewport[2] * 2.0 - 1.0, (winy - viewport[1]) / viewport[3] * 2.0 - 1.0, winz * 2.0 - 1.0, 1]).reshape((1,4))
390         vector = (numpy.matrix(vector) * finalMatrix).getA().flatten()
391         ret = list(vector)[0:3] / vector[3]
392         return ret
393
394 def convert3x3MatrixTo4x4(matrix):
395         return list(matrix.getA()[0]) + [0] + list(matrix.getA()[1]) + [0] + list(matrix.getA()[2]) + [0, 0,0,0,1]
396
397 def loadGLTexture(filename):
398         tex = glGenTextures(1)
399         glBindTexture(GL_TEXTURE_2D, tex)
400         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
401         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
402         img = wx.ImageFromBitmap(wx.Bitmap(getPathForImage(filename)))
403         rgbData = img.GetData()
404         alphaData = img.GetAlphaData()
405         if alphaData is not None:
406                 data = ''
407                 for i in xrange(0, len(alphaData)):
408                         data += rgbData[i*3:i*3+3] + alphaData[i]
409                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
410         else:
411                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.GetWidth(), img.GetHeight(), 0, GL_RGB, GL_UNSIGNED_BYTE, rgbData)
412         return tex
413
414 def ResetMatrixRotationAndScale():
415         matrix = glGetFloatv(GL_MODELVIEW_MATRIX)
416         noZ = False
417         if matrix[3][2] > 0:
418                 return False
419         scale2D = matrix[0][0]
420         matrix[0][0] = 1.0
421         matrix[1][0] = 0.0
422         matrix[2][0] = 0.0
423         matrix[0][1] = 0.0
424         matrix[1][1] = 1.0
425         matrix[2][1] = 0.0
426         matrix[0][2] = 0.0
427         matrix[1][2] = 0.0
428         matrix[2][2] = 1.0
429
430         if matrix[3][2] != 0.0:
431                 matrix[3][0] = matrix[3][0] / (-matrix[3][2] / 100)
432                 matrix[3][1] = matrix[3][1] / (-matrix[3][2] / 100)
433                 matrix[3][2] = -100
434         else:
435                 matrix[0][0] = scale2D
436                 matrix[1][1] = scale2D
437                 matrix[2][2] = scale2D
438                 matrix[3][2] = -100
439                 noZ = True
440
441         glLoadMatrixf(matrix)
442         return noZ
443
444
445 def DrawBox(vMin, vMax):
446         glBegin(GL_LINE_LOOP)
447         glVertex3f(vMin[0], vMin[1], vMin[2])
448         glVertex3f(vMax[0], vMin[1], vMin[2])
449         glVertex3f(vMax[0], vMax[1], vMin[2])
450         glVertex3f(vMin[0], vMax[1], vMin[2])
451         glEnd()
452
453         glBegin(GL_LINE_LOOP)
454         glVertex3f(vMin[0], vMin[1], vMax[2])
455         glVertex3f(vMax[0], vMin[1], vMax[2])
456         glVertex3f(vMax[0], vMax[1], vMax[2])
457         glVertex3f(vMin[0], vMax[1], vMax[2])
458         glEnd()
459         glBegin(GL_LINES)
460         glVertex3f(vMin[0], vMin[1], vMin[2])
461         glVertex3f(vMin[0], vMin[1], vMax[2])
462         glVertex3f(vMax[0], vMin[1], vMin[2])
463         glVertex3f(vMax[0], vMin[1], vMax[2])
464         glVertex3f(vMax[0], vMax[1], vMin[2])
465         glVertex3f(vMax[0], vMax[1], vMax[2])
466         glVertex3f(vMin[0], vMax[1], vMin[2])
467         glVertex3f(vMin[0], vMax[1], vMax[2])
468         glEnd()
469
470
471 def DrawMeshOutline(mesh):
472         glEnable(GL_CULL_FACE)
473         glEnableClientState(GL_VERTEX_ARRAY);
474         glVertexPointer(3, GL_FLOAT, 0, mesh.vertexes)
475
476         glCullFace(GL_FRONT)
477         glLineWidth(3)
478         glPolygonMode(GL_BACK, GL_LINE)
479         glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount)
480         glPolygonMode(GL_BACK, GL_FILL)
481         glCullFace(GL_BACK)
482
483         glDisableClientState(GL_VERTEX_ARRAY)
484
485
486 def DrawMesh(mesh, insideOut = False):
487         glEnable(GL_CULL_FACE)
488         glEnableClientState(GL_VERTEX_ARRAY)
489         glEnableClientState(GL_NORMAL_ARRAY)
490         for m in mesh._meshList:
491                 glVertexPointer(3, GL_FLOAT, 0, m.vertexes)
492                 if insideOut:
493                         glNormalPointer(GL_FLOAT, 0, m.invNormal)
494                 else:
495                         glNormalPointer(GL_FLOAT, 0, m.normal)
496
497                 #Odd, drawing in batchs is a LOT faster then drawing it all at once.
498                 batchSize = 999    #Warning, batchSize needs to be dividable by 3
499                 extraStartPos = int(m.vertexCount / batchSize) * batchSize
500                 extraCount = m.vertexCount - extraStartPos
501
502                 glCullFace(GL_BACK)
503                 for i in xrange(0, int(m.vertexCount / batchSize)):
504                         glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
505                 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
506
507                 glCullFace(GL_FRONT)
508                 if insideOut:
509                         glNormalPointer(GL_FLOAT, 0, m.normal)
510                 else:
511                         glNormalPointer(GL_FLOAT, 0, m.invNormal)
512                 for i in xrange(0, int(m.vertexCount / batchSize)):
513                         glDrawArrays(GL_TRIANGLES, i * batchSize, batchSize)
514                 extraStartPos = int(m.vertexCount / batchSize) * batchSize
515                 extraCount = m.vertexCount - extraStartPos
516                 glDrawArrays(GL_TRIANGLES, extraStartPos, extraCount)
517                 glCullFace(GL_BACK)
518
519         glDisableClientState(GL_VERTEX_ARRAY)
520         glDisableClientState(GL_NORMAL_ARRAY)
521
522
523 def DrawMeshSteep(mesh, matrix, angle):
524         cosAngle = math.sin(angle / 180.0 * math.pi)
525         glDisable(GL_LIGHTING)
526         glDepthFunc(GL_EQUAL)
527         normals = (numpy.matrix(mesh.normal, copy = False) * matrix).getA()
528         for i in xrange(0, int(mesh.vertexCount), 3):
529                 if normals[i][2] < -0.999999:
530                         if mesh.vertexes[i + 0][2] > 0.01:
531                                 glColor3f(0.5, 0, 0)
532                                 glBegin(GL_TRIANGLES)
533                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
534                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
535                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
536                                 glEnd()
537                 elif normals[i][2] < -cosAngle:
538                         glColor3f(-normals[i][2], 0, 0)
539                         glBegin(GL_TRIANGLES)
540                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
541                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
542                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
543                         glEnd()
544                 elif normals[i][2] > 0.999999:
545                         if mesh.vertexes[i + 0][2] > 0.01:
546                                 glColor3f(0.5, 0, 0)
547                                 glBegin(GL_TRIANGLES)
548                                 glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
549                                 glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
550                                 glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
551                                 glEnd()
552                 elif normals[i][2] > cosAngle:
553                         glColor3f(normals[i][2], 0, 0)
554                         glBegin(GL_TRIANGLES)
555                         glVertex3f(mesh.vertexes[i + 0][0], mesh.vertexes[i + 0][1], mesh.vertexes[i + 0][2])
556                         glVertex3f(mesh.vertexes[i + 2][0], mesh.vertexes[i + 2][1], mesh.vertexes[i + 2][2])
557                         glVertex3f(mesh.vertexes[i + 1][0], mesh.vertexes[i + 1][1], mesh.vertexes[i + 1][2])
558                         glEnd()
559         glDepthFunc(GL_LESS)