"""
     pygl/displayobject.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2005 University of York, CCLRC

     This library is free software: you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public License
     version 3, modified in accordance with the provisions of the 
     license to address the requirements of UK law.
 
     You should have received a copy of the modified GNU Lesser General 
     Public License along with this library.  If not, copies may be 
     downloaded from http://www.ccp4.ac.uk/ccp4license.php
 
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU Lesser General Public License for more details.
"""


#import Quat
import pygl_coord
import Lighting
from point_funcs import *
from opengl import *

class displayobject:
      """
      Class which contains all the information about a given
      display object. A display object is a collection of primitives
      with a given position and orientation. The class also contains
      information out the material properties of the primitives. The
      same properties are applied to all primitives in an object to
      enable the speed up the colouring.
      """

      def ApplyTranslation(self):
         glTranslatef(self.origin[0],self.origin[1],self.origin[2])

      def ApplyRotation(self):
          M = self.quat.getMatrix()
          cmat = doublea(16)
          cmat[0] = M[0][0]
          cmat[1] = M[1][0]
          cmat[2] = M[2][0]
          cmat[3] = M[3][0]
          cmat[4] = M[0][1]
          cmat[5] = M[1][1]
          cmat[6] = M[2][1]
          cmat[7] = M[3][1]
          cmat[8] = M[0][2]
          cmat[9] = M[1][2]
          cmat[10] = M[2][2]
          cmat[11] = M[3][2]
          cmat[12] = M[0][3]
          cmat[13] = M[1][3]
          cmat[14] = M[2][3]
          cmat[15] = M[3][3]
          M = dptomat(4,4,cmat)
          glrotmat_c = buildrotmatrix_from_c(M)
          glMultMatrixf(glrotmat_c)

      def __init__(self):
         self.init()

      def get_selected_prims(self,volume):
        import util
        self.set_primitive_origins()
        M = self.quat.getMatrix()
        rotmat = util.buildmatrix(M,4,4)
        selected_prims = []
        primid = -1
        for prim in self.prims[:]:
          primid = primid + 1
          origin4 = []
          origin4.append(prim.origin[0])
          origin4.append(prim.origin[1])
          origin4.append(prim.origin[2])
          origin4.append(0)
          primoriginrot = util.matrixXvector(M,origin4)
          primorigin = []
          primorigin.append(primoriginrot[0]+self.origin[0])
          primorigin.append(primoriginrot[1]+self.origin[1])
          primorigin.append(primoriginrot[2]+self.origin[2])
          """
          Now determine if primitive is above each plane:
          """
          prim_in_box = 1
          for plane in volume:
            v0 = []
            v0.append(plane[0][0]-plane[1][0])
            v0.append(plane[0][1]-plane[1][1])
            v0.append(plane[0][2]-plane[1][2])
            v1 = []
            v1.append(plane[1][0]-plane[2][0])
            v1.append(plane[1][1]-plane[2][1])
            v1.append(plane[1][2]-plane[2][2])
            n = util.vcross(v0,v1)
            n = util.normalize(n)
            p2prim = []
            p2prim.append(plane[0][0]-primorigin[0])
            p2prim.append(plane[0][1]-primorigin[1])
            p2prim.append(plane[0][2]-primorigin[2])
            p2prim = util.normalize(p2prim)
            if util.vdot(n, p2prim) < 0.0:
              prim_in_box = 0
          if prim_in_box > 0:
             selected_prims.append(primid)

        return selected_prims

      def clear_labels(self):
         prims = []
         print "Clear labels"
         for prim in self.prims:
	   if dir(prim).count("text") == 0:
	      prims.append(prim)

         self.prims = prims

      def clear_prims(self):
         self.prims = []

      def GetNumSymmetryMatrices(self):
         return 0; # HACKERY.

      def ApplySymmetryMatrix(self,i):
         pass # HACKERY.

      def GetSymmetryMatrix(self,i):
         pass # HACKERY.

      def DrawUnitCell(self):
         pass # HACKERY.

      def SetSymmetryMatrices(self,symm_mat):
         self.symm_mat = symm_mat

      def init(self):
         """
         Create null object with zero primitives and positioned
         at origin. Default lighting behaviour.
         """
         self.prims = []
         self.origin = (0.0,0.0,0.0)
         self.com = (0.0,0.0,0.0)
         self.visible = 1
         self.rot = (0.0,0.0,0.0)
         self.drot = (0.0,0.0,0.0)
         self.dx = 0.0
         self.dy = 0.0
         self.dz = 0.0
         self.quat = pygl_coord.Quat(self.rot[0],self.rot[1],self.rot[2],0)
         self.lighting = Lighting.Lighting()
         self.do_rebuild = 0
         self.symm_mat = None
         self.build_list = 1

      def get_rebuild(self,doit=1):
         return self.do_rebuild

      def rebuild(self,doit=1):
         self.do_rebuild = doit

      def changevis(self):
         if self.visible == 1:
            self.visible = 0
         else:
            self.visible = 1

      def set_prim_lighting(self,prim):
         prim.lighting.copy(self.lighting)

      def delete_primitive(self,delprim):
         i = 0
         for prim in self.prims:
           if prim == delprim:
             self.prims.pop(i)
           i = i + 1

      def add_primitive(self,prim):
         """
         Add primitive to self.prims and set its colouring.
         The colouring needs to be made into its own nice class.
         """
         self.set_prim_lighting(prim)
         self.prims.append(prim)

      def increase_shininess(self,shininess):
         """
         Set shininess.
         """
         self.lighting.shininess = self.lighting.shininess + shininess
         if self.lighting.shininess < 0.0:
           self.lighting.shininess = 0.0
         if self.lighting.shininess > 128.0:
           self.lighting.shininess = 128.0
         for prim in self.prims:
           self.set_prim_lighting(prim)

         self.do_rebuild = 1

      def increase_specular(self,specular):
         """
         Set specular lighting property.
         """

         self.lighting.specular[0] = self.lighting.specular[0] + specular[0]
         self.lighting.specular[1] = self.lighting.specular[1] + specular[1]
         self.lighting.specular[2] = self.lighting.specular[2] + specular[2]

         if self.lighting.specular[0] < 0.0:
           self.lighting.specular[0] = 0.0
         if self.lighting.specular[0] > 1.0:
           self.lighting.specular[0] = 1.0

         if self.lighting.specular[1] < 0.0:
           self.lighting.specular[1] = 0.0
         if self.lighting.specular[1] > 1.0:
           self.lighting.specular[1] = 1.0

         if self.lighting.specular[2] < 0.0:
           self.lighting.specular[2] = 0.0
         if self.lighting.specular[2] > 1.0:
           self.lighting.specular[2] = 1.0

         for prim in self.prims:
           self.set_prim_lighting(prim)

         self.do_rebuild = 1

      def increase_ambient(self,ambient):
         """
         Set ambient lighting property.
         """

         self.lighting.ambient[0] = self.lighting.ambient[0] + ambient[0]
         self.lighting.ambient[1] = self.lighting.ambient[1] + ambient[1]
         self.lighting.ambient[2] = self.lighting.ambient[2] + ambient[2]

         if self.lighting.ambient[0] < 0.0:
           self.lighting.ambient[0] = 0.0
         if self.lighting.ambient[0] > 1.0:
           self.lighting.ambient[0] = 1.0

         if self.lighting.ambient[1] < 0.0:
           self.lighting.ambient[1] = 0.0
         if self.lighting.ambient[1] > 1.0:
           self.lighting.ambient[1] = 1.0

         if self.lighting.ambient[2] < 0.0:
           self.lighting.ambient[2] = 0.0
         if self.lighting.ambient[2] > 1.0:
           self.lighting.ambient[2] = 1.0

         for prim in self.prims:
           self.set_prim_lighting(prim)

         self.do_rebuild = 1

      def increase_diffuse(self,diffuse):
         """
         Set diffuse lighting property.
         """

         self.lighting.diffuse[0] = self.lighting.diffuse[0] + diffuse[0]
         self.lighting.diffuse[1] = self.lighting.diffuse[1] + diffuse[1]
         self.lighting.diffuse[2] = self.lighting.diffuse[2] + diffuse[2]

         if self.lighting.diffuse[0] < 0.0:
           self.lighting.diffuse[0] = 0.0
         if self.lighting.diffuse[0] > 1.0:
           self.lighting.diffuse[0] = 1.0

         if self.lighting.diffuse[1] < 0.0:
           self.lighting.diffuse[1] = 0.0
         if self.lighting.diffuse[1] > 1.0:
           self.lighting.diffuse[1] = 1.0

         if self.lighting.diffuse[2] < 0.0:
           self.lighting.diffuse[2] = 0.0
         if self.lighting.diffuse[2] > 1.0:
           self.lighting.diffuse[2] = 1.0

         for prim in self.prims:
           self.set_prim_lighting(prim)

         self.do_rebuild = 1

      def increase_emission(self,emission):
         """
         Set emission lighting property.
         """

         self.lighting.emission[0] = self.lighting.emission[0] + emission[0]
         self.lighting.emission[1] = self.lighting.emission[1] + emission[1]
         self.lighting.emission[2] = self.lighting.emission[2] + emission[2]

         if self.lighting.emission[0] < 0.0:
           self.lighting.emission[0] = 0.0
         if self.lighting.emission[0] > 1.0:
           self.lighting.emission[0] = 1.0

         if self.lighting.emission[1] < 0.0:
           self.lighting.emission[1] = 0.0
         if self.lighting.emission[1] > 1.0:
           self.lighting.emission[1] = 1.0

         if self.lighting.emission[2] < 0.0:
           self.lighting.emission[2] = 0.0
         if self.lighting.emission[2] > 1.0:
           self.lighting.emission[2] = 1.0

         for prim in self.prims:
           self.set_prim_lighting(prim)

         self.do_rebuild = 1

      def move(self,dx,dy,dz):
          self.dx = self.dx + dx
          self.dy = self.dy + dy
          self.dz = self.dz + dz
          
      def findprimitive(self,xyzmpc,xyzmmc,xyzpmc,xyzppc,near,far):
          self.set_primitive_origins()
          rotmat = self.quat.getInvMatrix()
          nearprim = findprimc(xyzmpc,xyzmmc,xyzpmc,xyzppc,self.primorigin,len(self.prims),self.origin[0],self.origin[1],self.origin[2],rotmat)
          return nearprim

      def set_primitive_origins(self):
         self.primorigin = doublea(3*len(self.prims))
         for i in range(len(self.prims)):
             prim = self.prims[i]
             self.primorigin[i] = prim.origin[0]
             self.primorigin[i+len(self.prims)] = prim.origin[1]
             self.primorigin[i+2*len(self.prims)] = prim.origin[2]

      def rotate(self,dphi,dchi,dpsi):
          self.drot = dphi,dchi,dpsi

      def move_origin(self,origin):
          o0 = self.origin[0]+origin[0]
          o1 = self.origin[1]+origin[1]
          o2 = self.origin[2]+origin[2]

          self.origin = (o0, o1, o2)
          self.dx,self.dy,self.dz = 0.0, 0.0, 0.0

      def draw_text(self):
          pass

      def draw(self,white=0,transparent=0):
          for prim in self.prims:
            if white > 1:
              prim.set_draw_colour_white()
            else:
              prim.set_draw_colour()
            if prim.transparent == transparent:
              prim.draw()

      def get_origin(self):
          return self.origin

      def get_primitive(self,i):
          return self.prims[i]

      def set_origin(self,o1,o2,o3):
          self.origin = o1, o2, o3

      def get_drot(self):
          return self.drot

      def apply_rotation_about_axes(self,xaxis,yaxis,zaxis):
          self.quat.rotate_about_axes(xaxis,yaxis,zaxis,self.drot)  
          self.drot = (0.0,0.0,0.0)
            
      def get_rotation_matrix(self):
          return self.quat.getMatrix()

      def get_rotation_matrix_c(self):
          return self.quat.getMatrix_c()

      def get_primorigin(self,i):
        prim = self.prims[i]
        origin4 = []
        origin4.append(prim.origin[0])
        origin4.append(prim.origin[1])
        origin4.append(prim.origin[2])
        origin4.append(0)
        return origin4

      def rotate_point(self,x,y,z):
        M = self.get_rotation_matrix()
        origin4 = []
        origin4.append(x)
        origin4.append(y)
        origin4.append(z)
        origin4.append(0)
        primoriginrot = util.matrixXvector(M,origin4) 
        return primoriginrot
        
      def SetBuildDisplayList(self,build_list):
        self.build_list = build_list

      def BuildDisplayList(self):
        return build_list;

      def get_primoriginrot(self,i):
        import util
        prim = self.prims[i]
        M = self.get_rotation_matrix()
        origin4 = []
        origin4.append(prim.origin[0])
        origin4.append(prim.origin[1])
        origin4.append(prim.origin[2])
        origin4.append(0)
        primoriginrot = util.matrixXvector(M,origin4) 
        return primoriginrot

class mapdisplayobject(displayobject):
      def __init__(self):
          self.init()

      def BuildDisplayList(self):
        return 0;

      def move_origin(self,origin):
          print self.dx,self.dy,self.dz

          if abs(origin[0]) > 0.0 or abs(origin[1]) > 0.0 or abs(origin[2]) > 0.0:
            self.prims[0].mapcom =  \
              (self.prims[0].mapcom[0]+origin[0],self.prims[0].mapcom[1]+origin[1],self.prims[0].mapcom[2]+origin[2])
            self.prims[0].rebuild = 1
          self.dx,self.dy,self.dz = 0.0, 0.0, 0.0
