docs: def paintGL(self):
          '''GL function called each time a frame is drawn'''
  
          if self.post_processing:
              # Render to the first framebuffer
              glBindFramebuffer(GL_FRAMEBUFFER, self.fb0)
              glViewport(0, 0, self.width(), self.height())
  
              status = glCheckFramebufferStatus(GL_FRAMEBUFFER)
              if (status != GL_FRAMEBUFFER_COMPLETE):
                  reason = dict(GL_FRAMEBUFFER_UNDEFINED='UNDEFINED',
                                GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT='INCOMPLETE_ATTACHMENT',
                                GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT='INCOMPLETE_MISSING_ATTACHMENT',
                                GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER='INCOMPLETE_DRAW_BUFFER',
                                GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER='INCOMPLETE_READ_BUFFER',
                                GL_FRAMEBUFFER_UNSUPPORTED='UNSUPPORTED',
                            )[status]
  
                  raise Exception('Framebuffer is not complete: {}'.format(reason))
          else:
              glBindFramebuffer(GL_FRAMEBUFFER, DEFAULT_FRAMEBUFFER)
  
  
          # Clear color take floats
          bg_r, bg_g, bg_b, bg_a = self.background_color
          glClearColor(bg_r/255, bg_g/255, bg_b/255, bg_a/255)
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
  
          proj = self.camera.projection
          cam = self.camera.matrix
  
          self.mvproj = np.dot(proj, cam)
  
          self.ldir = cam[:3, :3].T.dot(self.light_dir)
  
  
  
          # Draw World
          self.on_draw_world()
  
          # Iterate over all of the post processing effects
          if self.post_processing:
              if len(self.post_processing) > 1:
                  newarg = self.textures.copy()
  
                  # Ping-pong framebuffer rendering
                  for i, pp in enumerate(self.post_processing[:-1]):
                      if i % 2:
                          outfb = self.fb1
                          outtex = self._extra_textures['fb1']
                      else:
                          outfb = self.fb2
                          outtex = self._extra_textures['fb2']
  
                      pp.render(outfb, newarg)
  
                      newarg['color'] = outtex
  
                  self.post_processing[-1].render(DEFAULT_FRAMEBUFFER, newarg)
  
              else:
                  self.post_processing[0].render(DEFAULT_FRAMEBUFFER, self.textures)
  
          # Draw the UI at the very last step
          self.on_draw_ui()