"""
volrender.py

Autor: Mahesh Venkitachalam

Renderer objętościowy ray casting dla wizualizacji danych medycznych.

"""

import sys, argparse, os
from slicerender import *
from raycast import *
import glfw

class RenderWin:
    """Klasa okna renderowania GLFW"""
    def __init__(self, imageDir):
        
        # zapisanie bieżącego katalogu roboczego
        cwd = os.getcwd()

        # inicjowanie glfw — to zmienia cwd
        glfw.glfwInit()
        
        # przywrócenie cwd
        os.chdir(cwd)

        # wskazówki wersji
        glfw.glfwWindowHint(glfw.GLFW_CONTEXT_VERSION_MAJOR, 3)
        glfw.glfwWindowHint(glfw.GLFW_CONTEXT_VERSION_MINOR, 3)
        glfw.glfwWindowHint(glfw.GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE)
        glfw.glfwWindowHint(glfw.GLFW_OPENGL_PROFILE, glfw.GLFW_OPENGL_CORE_PROFILE)

        # utworzenie okna
        self.width, self.height = 512, 512
        self.aspect = self.width/float(self.height)
        self.win = glfw.glfwCreateWindow(self.width, self.height, b"volrender")
        # utworzenie bieżącego kontekstu
        glfw.glfwMakeContextCurrent(self.win)
        
        # inicjowanie GL
        glViewport(0, 0, self.width, self.height)
        glEnable(GL_DEPTH_TEST)
        glClearColor(0.0, 0.0, 0.0, 0.0)

        # ustawienie wywołań zwrotnych okna
        glfw.glfwSetMouseButtonCallback(self.win, self.onMouseButton)
        glfw.glfwSetKeyCallback(self.win, self.onKeyboard)
        glfw.glfwSetWindowSizeCallback(self.win, self.onSize)

        # ładowanie danych wolumenu
        self.volume =  volreader.loadVolume(imageDir)
        # tworzenie renderera
        self.renderer = RayCastRender(self.width, self.height, self.volume)

        # flaga wyjścia
        self.exitNow = False
        
    def onMouseButton(self, win, button, action, mods):
        # print 'przycisk myszy: ', win, button, action, mods
        pass

    def onKeyboard(self, win, key, scancode, action, mods):
        # print 'klawiatura: ', win, key, scancode, action, mods
        # ESC, aby zakończyć 
        if key is glfw.GLFW_KEY_ESCAPE:
            self.renderer.close()
            self.exitNow = True
        else:
            if action is glfw.GLFW_PRESS or action is glfw.GLFW_REPEAT:
                if key == glfw.GLFW_KEY_V:
                    # przełączanie trybu renderowania
                    if isinstance(self.renderer, RayCastRender):
                        self.renderer = SliceRender(self.width, self.height, 
                                                    self.volume)
                    else:
                        self.renderer = RayCastRender(self.width, self.height, 
                                                      self.volume)
                    # wywołanie reshape na rendererze
                    self.renderer.reshape(self.width, self.height)
                else:
                    # wysłanie wciśniętego przycisku do renderera
                    keyDict = {glfw.GLFW_KEY_X : 'x', glfw.GLFW_KEY_Y: 'y', 
                               glfw.GLFW_KEY_Z: 'z', 
                               glfw.GLFW_KEY_LEFT: 'l', glfw.GLFW_KEY_RIGHT: 'r'}
                    try:
                        self.renderer.keyPressed(keyDict[key])
                    except:
                        pass

    def onSize(self, win, width, height):
        # print 'onsize: ', win, width, height
        self.width = width
        self.height = height
        self.aspect = width/float(height)
        glViewport(0, 0, self.width, self.height)
        self.renderer.reshape(width, height)

    def run(self):
        # rozpoczęcie pętli
        while not glfw.glfwWindowShouldClose(self.win) and not self.exitNow:
            # renderowanie
            self.renderer.draw()
            # zamiana buforów
            glfw.glfwSwapBuffers(self.win)
            # oczekiwanie na zdarzenia
            glfw.glfwWaitEvents()
        # koniec
        glfw.glfwTerminate()

# funkcja main()
def main():
  print('rozpoczęcie programu volrender...')
  # tworzenie parsera
  parser = argparse.ArgumentParser(description="Rendering objętościowy...")
  # dodanie oczekiwanych argumentów
  parser.add_argument('--dir', dest='imageDir', required=True)
  # parsowanie args
  args = parser.parse_args()

  # tworzenie okna renderowania
  rwin = RenderWin(args.imageDir)
  rwin.run()

# wywołanie main
if __name__ == '__main__':
  main()
