#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
QDSpy module - routines to generate graphical objects as vertex lists

This module is a graphics API independent.
  
Copyright (c) 2013-2019 Thomas Euler
All rights reserved.
"""
# ---------------------------------------------------------------------
__author__ 	= "code@eulerlab.de"

import numpy as np
import QDSpy_stim as stm
import QDSpy_stim_support as spp
import Graphics.renderer_opengl as rdr

# ---------------------------------------------------------------------
def box2vert (_ob, _iob, _sc, _Stage, _stim, _nextiV):
  # Generate vertices for a box object from the description in _ob
  #
  (dx, dy)  = _ob[stm.SO_field_size]
  (mx, my)  = _sc[stm.SC_field_magXY][_iob]
  dx2       = dx *mx /2.0
  dy2       = dy *my /2.0
  rot_deg   = _sc[stm.SC_field_rot][_iob]
  pxy       = _sc[stm.SC_field_posXY][_iob]
  rect      = [-dx2, -dy2, dx2, dy2]
  newVert   = [rect[0], rect[1], rect[2], rect[1],
               rect[2], rect[3], rect[0], rect[3]]
  newVert   = spp.rotateTranslate(newVert, rot_deg, pxy)
  newVert   = spp.toInt(newVert)
  newiVTr   = [_nextiV, _nextiV+1, _nextiV+2, _nextiV, _nextiV+2, _nextiV+3]
  if _ob[stm.SO_field_doRGBAByVert]:
    newRGBA = spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][0][0:4]) +\
              spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][1][0:4]) +\
              spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][2][0:4]) +\
              spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][3][0:4])
    newRGBA2= spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][0][4:8]) +\
              spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][1][4:8]) +\
              spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][2][4:8]) +\
              spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][3][4:8])
  else:
    tmpRGBA = _ob[stm.SO_field_fgRGB][0:3] +(_ob[stm.SO_field_alpha],) 
    newRGBA = len(newVert)//2 *spp.scaleRGB(_stim, tmpRGBA)
    tmpRGBA = _ob[stm.SO_field_fgRGB][3:6] +(_ob[stm.SO_field_alpha],)
    newRGBA2= len(newVert)//2 *spp.scaleRGB(_stim, tmpRGBA)

  hList     = [stm.StimObjType.box, dy,dy, mx,my, rot_deg, pxy]
  hStr      = spp.getHashStr(hList.__str__())

  return (newVert, newiVTr, newRGBA, newRGBA2, hStr, pxy, rot_deg)

# ---------------------------------------------------------------------
def ell2vert (_ob, _iob, _sc, _Stage, _stim, _nextiV):
  # Generate vertices for an ellipse object from the description in _ob
  #
  (dx, dy)   = _ob[stm.SO_field_size]
  (mx, my)   = _sc[stm.SC_field_magXY][_iob]
  rot_deg    = _sc[stm.SC_field_rot][_iob]
  pxy        = _sc[stm.SC_field_posXY][_iob]

  # Determine center and radii, then calculate number of triangles
  # and vertices
  #
  rx         = dx *mx /2.0
  ry         = dy *my /2.0
  rm         = (rx+ry) /2.0
  nTri       = int(min(max(10, round(rm/1.5)), stm.Ellipse_maxTr))
  nPnts      = nTri +1
  dAng       = 2*np.pi/nTri

  # Center vertex, then points on perimeter
  #
  ang        = 0
  newVert    = [0, 0]
  for i in range(1, nPnts):
    newVert.append(round(rx*np.sin(ang)))
    newVert.append(round(ry*np.cos(ang)))
    ang      += dAng
  newVert    = spp.rotateTranslate(newVert, rot_deg, pxy)
  newVert    = spp.toInt(newVert)

  newiVTr    = []
  for i in range(nTri):
    newiVTr  += [_nextiV, _nextiV+i+1, _nextiV+i+2]
  newiVTr[len(newiVTr)-1] = newiVTr[1]

  if _ob[stm.SO_field_doRGBAByVert]:
    # *************
    # *************    
    # TODO: Currently uses only the first RGBA for the center and the
    #       second RGBA for the circumfence. It would be better, if RGBA[1:]
    #       were interpolated and arranged arround the circumfence ...
    # *************
    # *************
    RGBA0    = _ob[stm.SO_field_fgRGB][0][0:4]
    RGBA1    = _ob[stm.SO_field_fgRGB][1][0:4]
    newRGBA  = spp.scaleRGB(_stim, RGBA0)
    tmpRGBA  = (len(newVert)-1)//2 *spp.scaleRGB(_stim, RGBA1)
    newRGBA  += tmpRGBA
    RGBA0    = _ob[stm.SO_field_fgRGB][0][4:8]
    RGBA1    = _ob[stm.SO_field_fgRGB][1][4:8]
    newRGBA2 = spp.scaleRGB(_stim, RGBA0)
    tmpRGBA  = (len(newVert)-1)//2 *spp.scaleRGB(_stim, RGBA1)
    newRGBA2 += tmpRGBA
    
  else:
    tmpRGBA  = _ob[stm.SO_field_fgRGB][0:3] +(_ob[stm.SO_field_alpha],)
    newRGBA  = len(newVert)//2 *spp.scaleRGB(_stim, tmpRGBA)
    tmpRGBA  = _ob[stm.SO_field_fgRGB][3:6] +(_ob[stm.SO_field_alpha],)
    newRGBA2 = len(newVert)//2 *spp.scaleRGB(_stim, tmpRGBA)

  hList      = [stm.StimObjType.ellipse, dy,dy, mx,my, rot_deg, pxy]
  hStr       = spp.getHashStr(hList.__str__())

  return (newVert, newiVTr, newRGBA, newRGBA2, hStr, pxy, rot_deg)

# ---------------------------------------------------------------------
def sct2vert (_ob, _iob, _sc, _Stage, _stim, _nextiV):
  # Generate vertices for a sector object from the description in _ob
  #
  (r,offs,acenter,awidth,astep) = _ob[stm.SO_field_size]
  (mx, my)  = _sc[stm.SC_field_magXY][_iob]
  rot_deg   = _sc[stm.SC_field_rot][_iob]
  pxy       = _sc[stm.SC_field_posXY][_iob]

  if astep == None:
    # If astep is not given, choose the best one
    #
    if awidth == 360:
      # It's a full circle
      #
      astep = stm.Sector_maxStep
      
    else:
      # Try to minimize the number of triangles needed while
      # preserving the precission
      #
      for astep in range(stm.Sector_maxStep, 0, -1):
        if (int(awidth) % astep) == 0:
          break

  nSteps    = int(min(max(1, awidth/astep), stm.Sector_maxTr))
  '''
  spp.Log.write("DEBUG", "sct2vert: # steps={0}, angle={1}°, step angle={2}°"
                .format(nSteps, awidth, astep))
  '''
  acenter   = -2*np.pi *acenter/360.0 +np.pi
  awidth    = 2*np.pi *awidth/360.0
  astep     = 2*np.pi *astep/360.0

  if offs > 0:
    # Is arc ...
    #
    nPnts   = 2*nSteps +2
    ang     = acenter -awidth/2.0
    i       = 0
    newVert = []
    while i < (nPnts-1):
      newVert.append(r *np.sin(ang))
      newVert.append(-r *np.cos(ang))
      i     += 1
      newVert.append(offs *np.sin(ang))
      newVert.append(-offs *np.cos(ang))
      i     += 1
      ang   += astep

    newiVTr = []
    for i in range(nSteps*2):
      newiVTr  += [_nextiV+i, _nextiV+i+1, _nextiV+i+2]

    if _ob[stm.SO_field_doRGBAByVert]:
      RGBAout  = spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][0][0:4])
      RGBAin   = spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][1][0:4])
      RGBAout2 = spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][0][4:8])
      RGBAin2  = spp.scaleRGB(_stim, _ob[stm.SO_field_fgRGB][1][4:8])
      newRGBA  = []
      newRGBA2 = []
      for i in range(len(newVert)//4):
        newRGBA  += RGBAout
        newRGBA  += RGBAin
        newRGBA2 += RGBAout2
        newRGBA2 += RGBAin2
        
    else:
      tmpRGBA  = _ob[stm.SO_field_fgRGB][0:3] +(_ob[stm.SO_field_alpha],)
      newRGBA  = len(newVert)//2 *spp.scaleRGB(_stim, tmpRGBA)
      tmpRGBA  = _ob[stm.SO_field_fgRGB][3:6] +(_ob[stm.SO_field_alpha],)
      newRGBA2 = len(newVert)//2 *spp.scaleRGB(_stim, tmpRGBA)

  else:
    # Is sector ...
    #
    nPnts   = nSteps +2
    ang     = acenter -awidth/2.0
    newVert = [0, 0]
    for i in range(1, nPnts):
      newVert.append(r *np.sin(ang))
      newVert.append(-r *np.cos(ang))
      ang   += astep

    newiVTr   = []
    for i in range(nSteps +1):
      newiVTr += [_nextiV, _nextiV+i+1, _nextiV+i+2]
      #newiVTr[len(newiVTr)-1] = newiVTr[1]

    if _ob[stm.SO_field_doRGBAByVert]:
      RGBA0    = _ob[stm.SO_field_fgRGB][0][0:4]
      RGBA1    = _ob[stm.SO_field_fgRGB][1][0:4]
      newRGBA  = spp.scaleRGB(_stim, RGBA0)
      tmpRGBA  = (len(newVert)-1)//2 *spp.scaleRGB(_stim, RGBA1)
      newRGBA  += tmpRGBA
      RGBA0    = _ob[stm.SO_field_fgRGB][0][4:8]
      RGBA1    = _ob[stm.SO_field_fgRGB][1][4:8]
      newRGBA  = spp.scaleRGB(_stim, RGBA0)
      tmpRGBA  = (len(newVert)-1)//2 *spp.scaleRGB(_stim, RGBA1)
      newRGBA2 += tmpRGBA
      
    else:
      tmpRGBA  = _ob[stm.SO_field_fgRGB][0:3] +(_ob[stm.SO_field_alpha],)
      newRGBA  = len(newVert)//2 *spp.scaleRGB(_stim, tmpRGBA)
      tmpRGBA  = _ob[stm.SO_field_fgRGB][3:6] +(_ob[stm.SO_field_alpha],)
      newRGBA2 = len(newVert)//2 *spp.scaleRGB(_stim, tmpRGBA)

  newVert   = spp.rotateTranslate(newVert, rot_deg, pxy)
  newVert   = spp.toInt(newVert)

  hList     = [stm.StimObjType.sector, r,offs,acenter,awidth,astep, mx,my,
               rot_deg, pxy]
  hStr      = spp.getHashStr(hList.__str__())

  return (newVert, newiVTr, newRGBA, newRGBA2, hStr, pxy, rot_deg)

# ---------------------------------------------------------------------
def marker2vert (_Stage, _Conf):
  # Generate vertices for the trigger marker
  #
  if _Stage.useScrOvl:
    dx2 = _Stage.dxScr12 /_Conf.markScrWidthFract/4
    pxy = (_Stage.dxScr12//4, -_Stage.dyScr12//2)
  else:
    dx2 = _Stage.dxScr /_Conf.markScrWidthFract/2
    pxy = (_Stage.dxScr//2-dx2, -_Stage.dyScr//2+dx2)
  
  '''
  return rdr.vertFromRect([-dx2, -dx2, dx2, dx2], pxy, _Conf.markRGBA)
  '''
  return rdr.vertFromRect([-dx2, -dx2, dx2, dx2], pxy, _Conf.markRGBA),\
         rdr.vertFromRect([-dx2, -dx2, dx2, dx2], pxy, _Conf.antiMarkRGBA)

# ---------------------------------------------------------------------
