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