#####################################################################
# -*- coding: iso-8859-1 -*-                                        #
#                                                                   #
# Frets on Fire                                                     #
# Copyright (C) 2009 Team FoFiX                                     #
#               2009 Blazingamer(n_hydock@comcast.net)              #
#                                                                   #
# This program is free software; you can redistribute it and/or     #
# modify it under the terms of the GNU General Public License       #
# as published by the Free Software Foundation; either version 2    #
# of the License, or (at your option) any later version.            #
#                                                                   #
# 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 General Public License for more details.                      #
#                                                                   #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software       #
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,        #
# MA  02110-1301, USA.                                              #
#####################################################################


import Player
from Song import Tempo, Bars
import Theme
import random
from copy import deepcopy
from Shader import shaders, mixColors

from OpenGL.GL import *
from numpy import array, float32

#myfingershurt: needed for multi-OS file fetching
import os
import Log
import Song   #need the base song defines as well

class Neck:
  def __init__(self, engine, instrument, playerObj):

    self.engine         = engine
    self.player         = instrument.player
    self.instrument     = instrument

    self.isDrum       = self.instrument.isDrum
    self.isBassGuitar = self.instrument.isBassGuitar
    self.isVocal      = self.instrument.isVocal

    self.oNeckovr = None    #MFH - needs to be here to prevent crashes!    

    self.staticStrings  = self.engine.config.get("performance", "static_strings")

    self.indexFps       = self.engine.config.get("video", "fps") #QQstarS
    
    self.neckAlpha=[] # necks transparency
    self.neckAlpha.append( self.engine.config.get("game", "necks_alpha") ) # all necks
    self.neckAlpha.append( self.neckAlpha[0] * self.engine.config.get("game", "neck_alpha") ) # normal neck
    self.neckAlpha.append( self.neckAlpha[0] * self.engine.config.get("game", "solo_neck_alpha") ) # solo neck
    self.neckAlpha.append( self.neckAlpha[0] * self.engine.config.get("game", "bg_neck_alpha") ) # bass groove neck
    self.neckAlpha.append( self.neckAlpha[0] * self.engine.config.get("game", "overlay_neck_alpha") ) # overlay neck
    self.neckAlpha.append( self.neckAlpha[0] * self.engine.config.get("game", "fail_neck_alpha") ) # fail neck

    self.boardWidth     = Theme.neckWidth
    self.boardLength    = Theme.neckLength
    #death_au: fixed neck size
    
    if self.isDrum and self.engine.config.get("game", "large_drum_neck"):
      self.boardWidth     = 4.0
      self.boardLength    = 12.0
    #elif Theme.twoDnote == False or Theme.twoDkeys == False:
      #self.boardWidth     = 3.6
      #self.boardLength    = 9.0  

    self.beatsPerBoard  = 5.0
    self.beatsPerUnit   = self.beatsPerBoard / self.boardLength


    color = (1,1,1)
    self.vis = 1

    # evilynux - Neck color
    self.board_col  = array([[color[0],color[1],color[2], 0],
                             [color[0],color[1],color[2], 0],
                             [color[0],color[1],color[2], self.vis],
                             [color[0],color[1],color[2], self.vis],
                             [color[0],color[1],color[2], self.vis],
                             [color[0],color[1],color[2], self.vis],
                             [color[0],color[1],color[2], 0],
                             [color[0],color[1],color[2], 0]], dtype=float32)

    w            = self.boardWidth
    l            = self.boardLength

    # evilynux - Neck vertices
    self.board_vtx = array([[-w / 2, 0, -2],
                            [w / 2, 0, -2],
                            [-w/ 2, 0, -1],
                            [w / 2, 0, -1],
                            [-w / 2, 0, l * .7],
                            [w / 2, 0, l * .7],
                            [-w / 2, 0, l],
                            [w / 2, 0, l]], dtype=float32)
    # evilynux - Sidebars vertices
    w += 0.15
    self.sidebars_vtx = array([[-w / 2, 0, -2],
                               [w / 2, 0, -2],
                               [-w/ 2, 0, -1],
                               [w / 2, 0, -1],
                               [-w / 2, 0, l * .7],
                               [w / 2, 0, l * .7],
                               [-w / 2, 0, l],
                               [w / 2, 0, l]], dtype=float32)

    # evilynux - Just in case the type has became double, convert to float32
    self.board_col = self.board_col.astype(float32)
    self.board_vtx = self.board_vtx.astype(float32)
    self.sidebars_vtx = self.sidebars_vtx.astype(float32)

    self.neckType = playerObj.neckType
    if self.neckType == 0:
      self.neck = engine.mainMenu.chosenNeck
    else:
      self.neck = str(playerObj.neck)
    playerObj  = None
    #Get theme
    themename = self.engine.data.themeLabel
    #now theme determination logic is only in data.py:
    self.theme = self.engine.data.theme

    self.incomingNeckMode = self.engine.config.get("game", "incoming_neck_mode")

    #blazingamer

    self.failcount = 0
    self.failcount2 = False
    self.spcount = 0
    self.spcount2 = 0
    self.bgcount = 0
    self.ovrneckoverlay = self.engine.config.get("fretboard", "ovrneckoverlay")
    self.ocount = 0
    
    self.currentPeriod  = 60000.0 / self.instrument.currentBpm
    self.lastBpmChange  = -1.0
    self.baseBeat       = 0.0

    #myfingershurt:
    self.bassGrooveNeckMode = self.engine.config.get("game", "bass_groove_neck")
    self.guitarSoloNeckMode = self.engine.config.get("game", "guitar_solo_neck")


    self.useMidiSoloMarkers = False
    self.markSolos = 0
    
    neckFind = True
    themeNeckPath = os.path.join(self.engine.resource.fileName("themes", themename, "necks"))
    if self.neckType == 1 and os.path.exists(themeNeckPath):
      themeNeck = []
      for i in os.listdir(themeNeckPath):
        if str(i)[-4:] == ".png":
          themeNeck.append(str(i))
      if len(themeNeck) > 0:
        i = random.randint(1,len(themeNeck))
        engine.loadImgDrawing(self, "neckDrawing", os.path.join("themes", themename, "necks", themeNeck[i-1]), textureSize = (256, 256))
        neckFind = False
    if neckFind:
      if not engine.data.fileExists(os.path.join("necks", self.neck + ".png")) and not engine.data.fileExists(os.path.join("necks", "Neck_" + self.neck + ".png")):
        self.neck = str(engine.mainMenu.chosenNeck) #this neck is safe!
      # evilynux - Fixed random neck -- MFH: further fixing random neck
      if self.neck == "0" or self.neck == "Neck_0" or self.neck == "randomneck":
        self.neck = []
        # evilynux - improved loading logic to support arbitrary filenames
        for i in os.listdir(self.engine.resource.fileName("necks")):
          # evilynux - Special cases, ignore these...
          if( str(i) == "overdriveneck.png" or str(i) == "randomneck.png"  or str(i) == "Neck_0.png" or str(i)[-4:] != ".png" ):
            continue
          else:
            self.neck.append(str(i)[:-4]) # evilynux - filename w/o extension
        i = random.randint(1,len(self.neck))
        engine.loadImgDrawing(self, "neckDrawing", os.path.join("necks",self.neck[i]+".png"),  textureSize = (256, 256))
        Log.debug("Random neck chosen: " + self.neck[i])
      else:
        try:
          # evilynux - first assume the self.neck contains the full filename
          engine.loadImgDrawing(self, "neckDrawing", os.path.join("necks",self.neck+".png"),  textureSize = (256, 256))
        except IOError:
          engine.loadImgDrawing(self, "neckDrawing", os.path.join("necks","Neck_"+self.neck+".png"),  textureSize = (256, 256))



    if self.theme == 2:
      if self.isDrum == True:
        try:
          engine.loadImgDrawing(self, "oSideBars", os.path.join("themes",themename,"drum_overdrive_side_bars.png"),  textureSize = (256, 256))
        except IOError:
          self.oSideBars = None
  
        try:
          engine.loadImgDrawing(self, "oCenterLines", os.path.join("themes",themename,"drum_overdrive_center_lines.png"), textureSize = (256, 256))
        except IOError:
          #engine.loadImgDrawing(self, "centerLines", os.path.join("themes",themename,"center_lines.png"))
          self.oCenterLines = None

      
        #myfingershurt: the overdrive neck file should be in the theme folder... and also not required:
        try:
          engine.loadImgDrawing(self, "oNeck", os.path.join("themes",themename,"overdriveneck_drum.png"),  textureSize = (256, 256))
        except IOError:
          try:
            engine.loadImgDrawing(self, "oNeck", os.path.join("themes",themename,"overdriveneck.png"),  textureSize = (256, 256))
          except IOError:
            self.oNeck = None

      else:
        try:
          engine.loadImgDrawing(self, "oSideBars", os.path.join("themes",themename,"overdrive side_bars.png"),  textureSize = (256, 256))
        except IOError:
          self.oSideBars = None
        try:
          engine.loadImgDrawing(self, "oCenterLines", os.path.join("themes",themename,"overdrive center_lines.png"),  textureSize = (256, 256))
        except IOError:
          self.oCenterLines = None
        if self.isBassGuitar == True:
          try:
            engine.loadImgDrawing(self, "oNeck", os.path.join("themes",themename,"overdriveneck_bass.png"),  textureSize = (256, 256))
          except IOError:
            try:
              engine.loadImgDrawing(self, "oNeck", os.path.join("themes",themename,"overdriveneck.png"),  textureSize = (256, 256))
            except IOError:
              self.oNeckBass = None
        else:
          try:
            engine.loadImgDrawing(self, "oNeck", os.path.join("themes",themename,"overdriveneck.png"),  textureSize = (256, 256))
          except IOError:
            self.oNeck = None
          
      try:
        engine.loadImgDrawing(self, "oNeckovr", os.path.join("themes",themename,"overdriveneckovr.png"),  textureSize = (256, 256))
      except IOError:
        self.oNeckovr = None

      if self.isDrum == True:
        try:
          engine.loadImgDrawing(self, "oFlash", os.path.join("themes",themename,"drum_overdrive_string_flash.png"),  textureSize = (256, 256))
        except IOError:
          self.oFlash = None
      else:
        try:
          engine.loadImgDrawing(self, "oFlash", os.path.join("themes",themename,"overdrive_string_flash.png"),  textureSize = (256, 256))
        except IOError:
          self.oFlash = None

    if self.isDrum == True:
      try:
        engine.loadImgDrawing(self, "centerLines", os.path.join("themes",themename,"drumcenterlines.png"),  textureSize = (256, 256))
      except IOError:
        #engine.loadImgDrawing(self, "centerLines", os.path.join("themes",themename,"center_lines.png"))
        self.centerLines = None
    else:
      engine.loadImgDrawing(self, "centerLines", os.path.join("themes",themename,"center_lines.png"),  textureSize = (256, 256))

    engine.loadImgDrawing(self, "sideBars", os.path.join("themes",themename,"side_bars.png"))
    engine.loadImgDrawing(self, "bpm_halfbeat", os.path.join("themes",themename,"bpm_halfbeat.png"))
    engine.loadImgDrawing(self, "bpm_beat", os.path.join("themes",themename,"bpm_beat.png"))
    engine.loadImgDrawing(self, "bpm_measure", os.path.join("themes",themename,"bpm_measure.png"))

    if self.theme == 0 or self.theme == 1:

      self.oNeckovr = None #fixes GH theme crash

      if self.isDrum == True:
        #myfingershurt: the starpower neck file should be in the theme folder... and also not required:
        try:
          engine.loadImgDrawing(self, "oNeck", os.path.join("themes",themename,"starpowerneck_drum.png"),  textureSize = (256, 256))
        except IOError:
          try:
            engine.loadImgDrawing(self, "oNeck", os.path.join("themes",themename,"starpowerneck.png"),  textureSize = (256, 256))
          except IOError:
            self.oNeck = None
      else:
        #myfingershurt: the starpower neck file should be in the theme folder... and also not required:
        try:
          engine.loadImgDrawing(self, "oNeck", os.path.join("themes",themename,"starpowerneck.png"),  textureSize = (256, 256))
        except IOError:
          self.oNeck = None
        try:
          engine.loadImgDrawing(self, "oNeckBass", os.path.join("themes",themename,"starpowerneck_bass.png"),  textureSize = (256, 256))
        except IOError:
          try:
            engine.loadImgDrawing(self, "oNeckBass", os.path.join("themes",themename,"starpowerneck.png"),  textureSize = (256, 256))
          except IOError:
            self.oNeckBass = None


    #myfingershurt: Bass Groove neck:
    if self.isBassGuitar == True:
      if self.bassGrooveNeckMode > 0:
        if self.bassGrooveNeckMode == 1:  #replace neck
          try:
            engine.loadImgDrawing(self, "bassGrooveNeck", os.path.join("themes",themename,"bassgrooveneck.png"),  textureSize = (256, 256))
          except IOError:
            self.bassGrooveNeck = None
        elif self.bassGrooveNeckMode == 2:  #overlay neck
          try:
            engine.loadImgDrawing(self, "bassGrooveNeck", os.path.join("themes",themename,"bassgrooveneckovr.png"),  textureSize = (256, 256))
          except IOError:
            self.bassGrooveNeck = None
      else:
        self.bassGrooveNeck = None
    else:
      self.bassGrooveNeck = None



    #myfingershurt: Guitar Solo neck:
    if self.isVocal == False:
      if self.guitarSoloNeckMode > 0:
        if self.guitarSoloNeckMode == 1:  #replace neck
          if self.isBassGuitar:
            try:
              engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"basssoloneck.png"),  textureSize = (256, 256))
            except IOError:
              try:
                engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"guitarsoloneck.png"),  textureSize = (256, 256))
              except IOError:
                self.guitarSoloNeck = None
          elif self.isDrum:
            try:
              engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"drumsoloneck.png"),  textureSize = (256, 256))
            except IOError:
              try:
                engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"guitarsoloneck.png"),  textureSize = (256, 256))
              except IOError:
                self.guitarSoloNeck = None
          else:
            try:
              engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"guitarsoloneck.png"),  textureSize = (256, 256))
            except IOError:
              self.guitarSoloNeck = None
        elif self.guitarSoloNeckMode == 2:  #overlay neck
          if self.isBassGuitar:
            try:
              engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"basssoloneckovr.png"),  textureSize = (256, 256))
            except IOError:
              try:
                engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"guitarsoloneckovr.png"),  textureSize = (256, 256))
              except IOError:
                self.guitarSoloNeck = None
          elif self.isDrum:
            try:
              engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"drumsoloneckovr.png"),  textureSize = (256, 256))
            except IOError:
              try:
                engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"guitarsoloneckovr.png"),  textureSize = (256, 256))
              except IOError:
                self.guitarSoloNeck = None
          else:
            try:
              engine.loadImgDrawing(self, "guitarSoloNeck", os.path.join("themes",themename,"guitarsoloneckovr.png"),  textureSize = (256, 256))
            except IOError:
              self.guitarSoloNeck = None
      else:
        self.guitarSoloNeck = None
    else:
      self.guitarSoloNeck = None

    try:
      engine.loadImgDrawing(self, "failNeck", os.path.join("themes",themename,"failneck.png"))
    except IOError:
      engine.loadImgDrawing(self, "failNeck", os.path.join("failneck.png"))


    self.isFailing = False
    self.canGuitarSolo = self.instrument.canGuitarSolo
    self.guitarSolo = False
    self.scoreMultiplier = 1
    self.overdriveFlashCounts = self.indexFps/4   #how many cycles to display the oFlash: self.indexFps/2 = 1/2 second
    self.overdriveFlashCount = self.overdriveFlashCounts
    self.ocount = 0
    self.paused = False

  def renderIncomingNeck(self, visibility, song, pos, time, neckTexture):   #MFH - attempt to "scroll" an incoming guitar solo neck towards the player
    if not song:
      return
    if not song.readyToGo:
      return
    
    def project(beat):
      return 0.125 * beat / self.beatsPerUnit    # glorandwarf: was 0.12

    v            = visibility
    w            = self.boardWidth
    l            = self.boardLength

    #offset       = (pos - self.lastBpmChange) / self.currentPeriod + self.baseBeat 
    offset = 0

    z  = ((time - pos) / self.currentPeriod) / self.beatsPerUnit

    color = (1,1,1)

    glEnable(GL_TEXTURE_2D)
    if neckTexture:
      neckTexture.texture.bind()


    glBegin(GL_TRIANGLE_STRIP)
    glColor4f(color[0],color[1],color[2], 0)
    glTexCoord2f(0.0, project(offset - 2 * self.beatsPerUnit))
    #glVertex3f(-w / 2, 0, -2)
    glVertex3f(-w / 2, 0, z)   #point A
    glTexCoord2f(1.0, project(offset - 2 * self.beatsPerUnit))
    #glVertex3f( w / 2, 0, -2)
    glVertex3f( w / 2, 0, z)   #point B

    
    glColor4f(color[0],color[1],color[2], v)
    glTexCoord2f(0.0, project(offset - 1 * self.beatsPerUnit))
    #glVertex3f(-w / 2, 0, -1)
    glVertex3f(-w / 2, 0, z+1)   #point C
    glTexCoord2f(1.0, project(offset - 1 * self.beatsPerUnit))
    #glVertex3f( w / 2, 0, -1)
    glVertex3f( w / 2, 0, z+1)   #point D
    
    glTexCoord2f(0.0, project(offset + l * self.beatsPerUnit * .7))
    #glVertex3f(-w / 2, 0, l * .7)
    glVertex3f(-w / 2, 0, z+2+l * .7) #point E
    glTexCoord2f(1.0, project(offset + l * self.beatsPerUnit * .7))
    #glVertex3f( w / 2, 0, l * .7)
    glVertex3f( w / 2, 0, z+2+l * .7) #point F
    
    glColor4f(color[0],color[1],color[2], 0)
    glTexCoord2f(0.0, project(offset + l * self.beatsPerUnit))
    #glVertex3f(-w / 2, 0, l)
    glVertex3f(-w / 2, 0, z+2+l)    #point G
    glTexCoord2f(1.0, project(offset + l * self.beatsPerUnit))
    #glVertex3f( w / 2, 0, l)
    glVertex3f( w / 2, 0, z+2+l)    #point H
    glEnd()
    
    glDisable(GL_TEXTURE_2D)


  def renderIncomingNecks(self, visibility, song, pos):
    if not song:
      return
    if not song.readyToGo:
      return

    boardWindowMin = pos - self.currentPeriod * 2
    boardWindowMax = pos + self.currentPeriod * self.beatsPerBoard
    track = song.midiEventTrack[self.player]


    if self.incomingNeckMode > 0:   #if enabled


      #if self.song.hasStarpowerPaths and self.song.midiStyle == Song.MIDI_TYPE_RB:  
      if self.useMidiSoloMarkers:
        for time, event in track.getEvents(boardWindowMin, boardWindowMax):
          if isinstance(event, Song.MarkerNote):
            if event.number == Song.starPowerMarkingNote:
              if self.guitarSoloNeck:
                if event.endMarker:   #solo end
                  if self.incomingNeckMode == 2:    #render both start and end incoming necks
                    if self.guitarSolo:   #only until the end of the guitar solo!
                      if self.instrument.starPowerActive and self.oNeck and self.ovrneckoverlay == False:
                        neckImg = self.oNeck
                        alpha   = self.neckAlpha[4]
                      elif self.scoreMultiplier > 4 and self.bassGrooveNeck != None and self.bassGrooveNeckMode == 1:
                        neckImg = self.bassGrooveNeck
                        alpha   = self.neckAlpha[3]
                      else:
                        neckImg = self.neckDrawing
                        alpha   = self.neckAlpha[1]
                      self.renderIncomingNeck(visibility*alpha, song, pos, time, neckImg)
                        
                else:   #solo start
                  if not self.guitarSolo:   #only until guitar solo starts!
                    neckImg = self.guitarSoloNeck
                    alpha   = self.neckAlpha[2]
                    self.renderIncomingNeck(visibility*alpha, song, pos, time, neckImg)
                    if self.spcount2 != 0 and self.spcount < 1.2 and self.oNeck:
                      alpha = self.neckAlpha[4]
                      if self.oNeckovr != None and (self.scoreMultiplier > 4 or self.guitarSolo or self.ovrneckoverlay == True):
                        neck = self.oNeckovr
                      else:
                        neck = self.oNeck
                      self.renderIncomingNeck(visibility*alpha, song, pos, time, neckImg)

      elif self.markSolos == 1:   #fall back on text-based guitar solo marking track
        for time, event in song.eventTracks[Song.TK_GUITAR_SOLOS].getEvents(boardWindowMin, boardWindowMax):
          if self.canGuitarSolo and self.guitarSoloNeck:
            if event.text.find("ON") >= 0:
              if not self.guitarSolo:   #only until guitar solo starts!
                neckImg = self.guitarSoloNeck
                self.renderIncomingNeck(visibility, song, pos, time, neckImg)
            #else: #event.text.find("OFF"):
            elif self.incomingNeckMode == 2:    #render both start and end incoming necks
              if self.guitarSolo:   #only until the end of the guitar solo!
                if self.instrument.starPowerActive and self.oNeck:
                  neckImg = self.oNeck
                elif self.scoreMultiplier > 4 and self.bassGrooveNeck != None and self.bassGrooveNeckMode == 1:
                  neckImg = self.bassGrooveNeck
                else:
                  neckImg = self.neckDrawing
                self.renderIncomingNeck(visibility, song, pos, time, neckImg)


  def renderNeckMethod(self, visibility, offset, neck, alpha = False): #blazingamer: New neck rendering method
    
    def project(beat):
      return 0.125 * beat / self.beatsPerUnit    # glorandwarf: was 0.12
      
    if self.instrument.starPowerActive and self.theme == 0:#8bit
      color = Theme.fretColors[5] #self.spColor #(.3,.7,.9)
    elif self.instrument.starPowerActive and self.theme == 1:
      color = Theme.fretColors[5] #self.spColor #(.3,.7,.9)
    else:
      color = (1,1,1)

    v            = visibility
    l            = self.boardLength

    glEnable(GL_TEXTURE_2D)

    board_tex  = array([[0.0, project(offset - 2 * self.beatsPerUnit)],
                         [1.0, project(offset - 2 * self.beatsPerUnit)],
                         [0.0, project(offset - 1 * self.beatsPerUnit)],
                         [1.0, project(offset - 1 * self.beatsPerUnit)],
                         [0.0, project(offset + l * self.beatsPerUnit * .7)],
                         [1.0, project(offset + l * self.beatsPerUnit * .7)],
                         [0.0, project(offset + l * self.beatsPerUnit)],
                         [1.0, project(offset + l * self.beatsPerUnit)]], dtype=float32)
    
    #must be seperate for neck flashing.
    board_col  = array([[color[0],color[1],color[2], 0],
                             [color[0],color[1],color[2], 0],
                             [color[0],color[1],color[2], v],
                             [color[0],color[1],color[2], v],
                             [color[0],color[1],color[2], v],
                             [color[0],color[1],color[2], v],
                             [color[0],color[1],color[2], 0],
                             [color[0],color[1],color[2], 0]], dtype=float32)

    if alpha == True:
      glBlendFunc(GL_ONE, GL_ONE)
    neck.texture.bind()
    glEnableClientState(GL_VERTEX_ARRAY)
    glEnableClientState(GL_COLOR_ARRAY)
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glVertexPointerf(self.board_vtx)
    glColorPointerf(board_col)
    glTexCoordPointerf(board_tex)
    glDrawArrays(GL_TRIANGLE_STRIP, 0, self.board_vtx.shape[0])
    glDisableClientState(GL_VERTEX_ARRAY)
    glDisableClientState(GL_COLOR_ARRAY)
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    if alpha == True:
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
      
    glDisable(GL_TEXTURE_2D)
    
  def renderNeck(self, visibility, song, pos):     
    if not song:
      return
    if not song.readyToGo:
      return
    
    v            = visibility
    w            = self.boardWidth
    l            = self.boardLength

    offset       = (pos - self.lastBpmChange) / self.currentPeriod + self.baseBeat 

    #myfingershurt: every theme can have oNeck:

    if self.guitarSolo and self.guitarSoloNeck != None and self.guitarSoloNeckMode == 1:
      neck = self.guitarSoloNeck
    elif self.scoreMultiplier > 4 and self.bassGrooveNeck != None and self.bassGrooveNeckMode == 1:
      neck = self.bassGrooveNeck
    elif self.instrument.starPowerActive and not (self.spcount2 != 0 and self.spcount < 1.2) and self.oNeck and self.scoreMultiplier <= 4 and self.ovrneckoverlay == False:
      neck = self.oNeck
    else:
      neck = self.neckDrawing

    
    self.renderNeckMethod(v*self.neckAlpha[1], offset, neck)
    
    if self.guitarSolo and self.guitarSoloNeck != None and self.guitarSoloNeckMode == 2:   #static overlay
      self.renderNeckMethod(v*self.neckAlpha[2], 0, self.guitarSoloNeck)
      
    elif self.bgcount > 0 and self.bassGrooveNeck != None and self.bassGrooveNeckMode == 2:   #static bass groove overlay
      self.renderNeckMethod(v*self.bgcount*self.neckAlpha[3], 0, self.bassGrooveNeck)
      
    if self.spcount2 != 0 and self.spcount < 1.2 and self.oNeck:   #static overlay
      if self.oNeckovr != None and (self.scoreMultiplier > 4 or self.guitarSolo or self.ovrneckoverlay == True):
        neck = self.oNeckovr
        alpha = False
      else:
        neck = self.oNeck
        alpha = True          

      self.renderNeckMethod(v*self.spcount*self.neckAlpha[4], offset, neck, alpha)
      
    
      
    if self.instrument.starPowerActive and not (self.spcount2 != 0 and self.spcount < 1.2) and self.oNeck and (self.scoreMultiplier > 4 or self.guitarSolo or self.ovrneckoverlay == True):   #static overlay
      if self.oNeckovr != None:
        neck = self.oNeckovr
        alpha = False
      else:
        neck = self.oNeck
        alpha = True

      self.renderNeckMethod(v*self.neckAlpha[4], offset, neck, alpha)

    if shaders.enabled:
      shaders.globals["basspos"] = shaders.var["fret"][self.player][0]
      shaders.globals["notepos"] = shaders.var["fret"][self.player][1:]
      shaders.globals["bpm"] = self.instrument.currentBpm
      shaders.globals["songpos"] = pos
      shaders.globals["spEnabled"] = self.instrument.starPowerActive
      shaders.globals["isFailing"] = self.isFailing
      shaders.globals["isMultChanged"] = (shaders.var["scoreMult"][self.player] != self.scoreMultiplier)
      if shaders.globals["isMultChanged"]:
        shaders.var["multChangePos"][self.player] = pos
      shaders.globals["scoreMult"] = self.scoreMultiplier
      shaders.var["scoreMult"][self.player] = self.scoreMultiplier
      shaders.globals["isDrum"] = self.isDrum
      shaders.globals["soloActive"] = self.guitarSolo
      
      posx = shaders.time()
      fret = []
      neckcol = (0,0,0)
      
      notecolors = list(Theme.fretColors)
      if self.isDrum:
        notecolors[4] = notecolors[0]
        notecolors[0] = Theme.opencolor
        
        
      for i in range(5):
        blend = max(shaders.var["fret"][self.player][i] - posx + 1.5,0.01)
        neckcol = mixColors(neckcol, notecolors[i], blend)

      shaders.var["color"][self.player]=neckcol
      
    if shaders.enable("neck"):
      shaders.setVar("fretcol",neckcol)
      shaders.update()
      glBegin(GL_TRIANGLE_STRIP)
      glVertex3f(-w / 2, 0.1, -2)
      glVertex3f(w / 2, 0.1, -2)
      glVertex3f(-w / 2, 0.1, l)
      glVertex3f(w / 2, 0.1, l)
      glEnd()
      shaders.disable()
    else:
      if self.isFailing:
        self.renderNeckMethod(self.failcount, 0, self.failNeck)
        
    if (self.guitarSolo or self.instrument.starPowerActive) and self.theme == 1:
      shaders.var["solocolor"]=(0.3,0.7,0.9,0.6)
    else:
      shaders.var["solocolor"]=(0.0,)*4


  def drawTrack(self, visibility, song, pos):
    if not song:
      return
    if not song.readyToGo:
      return

    def project(beat):
      return 0.125 * beat / self.beatsPerUnit    # glorandwarf: was 0.12

    if self.theme == 0 or self.theme == 1:
      size = 2
    else:
      size = 0

    v            = visibility
    w            = self.boardWidth
    l            = self.boardLength

    if self.staticStrings:
      offset       = 0
    else:
      offset       = (pos - self.lastBpmChange) / self.currentPeriod + self.baseBeat 

    track_tex  = array([[0.0, project(offset - 2 * self.beatsPerUnit)],
                         [1.0, project(offset - 2 * self.beatsPerUnit)],
                         [0.0, project(offset - 1 * self.beatsPerUnit)],
                         [1.0, project(offset - 1 * self.beatsPerUnit)],
                         [0.0, project(offset + l * self.beatsPerUnit * .7)],
                         [1.0, project(offset + l * self.beatsPerUnit * .7)],
                         [0.0, project(offset + l * self.beatsPerUnit)],
                         [1.0, project(offset + l * self.beatsPerUnit)]], dtype=float32)


    glEnable(GL_TEXTURE_2D)
    
    #MFH - logic to briefly display oFlash
    if self.theme == 2 and self.overdriveFlashCount < self.overdriveFlashCounts and self.oFlash:
      self.oFlash.texture.bind()
    elif self.theme == 2 and self.instrument.starPowerActive and self.oCenterLines:
      self.oCenterLines.texture.bind()
    else:
      self.centerLines.texture.bind()

      
    track_vtx       = array([[-w / 2, 0, -2+size],
                           [w / 2, 0, -2+size],
                           [-w / 2, 0, -1+size],
                           [w / 2, 0, -1+size],
                           [-w / 2, 0, l * .7],
                           [w / 2, 0, l * .7],
                           [-w / 2, 0, l],
                           [w / 2, 0, l]], dtype=float32)
    
    if self.staticStrings:    #MFH
      color = (1,1,1)
      track_col  = array([[color[0],color[1],color[2], v],
                         [color[0],color[1],color[2], v],
                         [color[0],color[1],color[2], v],
                         [color[0],color[1],color[2], v],
                         [color[0],color[1],color[2], v],
                         [color[0],color[1],color[2], v],
                         [color[0],color[1],color[2], 0],
                         [color[0],color[1],color[2], 0]], dtype=float32)
      glEnableClientState(GL_VERTEX_ARRAY)
      glEnableClientState(GL_COLOR_ARRAY)
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glVertexPointerf(track_vtx)
      glColorPointerf(track_col)
      glTexCoordPointerf(track_tex)
      glDrawArrays(GL_TRIANGLE_STRIP, 0, track_vtx.shape[0])
      glDisableClientState(GL_VERTEX_ARRAY)
      glDisableClientState(GL_COLOR_ARRAY)
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    else:   #MFH: original moving strings

      glEnableClientState(GL_VERTEX_ARRAY)
      glEnableClientState(GL_COLOR_ARRAY)
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glVertexPointerf(track_vtx)
      glColorPointerf(self.board_col)
      glTexCoordPointerf(track_tex)
      glDrawArrays(GL_TRIANGLE_STRIP, 0, track_vtx.shape[0])
      glDisableClientState(GL_VERTEX_ARRAY)
      glDisableClientState(GL_COLOR_ARRAY)
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glDisable(GL_TEXTURE_2D)

  def drawSideBars(self, visibility, song, pos):
    if not song:
      return
    if not song.readyToGo:
      return

    def project(beat):
      return 0.125 * beat / self.beatsPerUnit  # glorandwarf: was 0.12

    v            = visibility
    w            = self.boardWidth + 0.15
    l            = self.boardLength

    offset       = (pos - self.lastBpmChange) / self.currentPeriod + self.baseBeat 

    c = (1,1,1)

    board_tex  = array([[0.0, project(offset - 2 * self.beatsPerUnit)],
                         [1.0, project(offset - 2 * self.beatsPerUnit)],
                         [0.0, project(offset - 1 * self.beatsPerUnit)],
                         [1.0, project(offset - 1 * self.beatsPerUnit)],
                         [0.0, project(offset + l * self.beatsPerUnit * .7)],
                         [1.0, project(offset + l * self.beatsPerUnit * .7)],
                         [0.0, project(offset + l * self.beatsPerUnit)],
                         [1.0, project(offset + l * self.beatsPerUnit)]], dtype=float32)

    glEnable(GL_TEXTURE_2D)
    if self.theme == 2 and self.instrument.starPowerActive and self.oSideBars:
      self.oSideBars.texture.bind()
    else:
      self.sideBars.texture.bind()

    glEnableClientState(GL_VERTEX_ARRAY)
    glEnableClientState(GL_COLOR_ARRAY)
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glVertexPointerf(self.sidebars_vtx)
    glColorPointerf(self.board_col)
    glTexCoordPointerf(board_tex)
    glDrawArrays(GL_TRIANGLE_STRIP, 0, self.sidebars_vtx.shape[0])
    glDisableClientState(GL_VERTEX_ARRAY)
    glDisableClientState(GL_COLOR_ARRAY)
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    
    glDisable(GL_TEXTURE_2D)
    
    if self.theme == 1:   
      if shaders.enable("sololight"):
        shaders.modVar("color",shaders.var["solocolor"])
        shaders.setVar("offset",(-3.5,-w/2))
        glBegin(GL_TRIANGLE_STRIP)
        glVertex3f(w / 2-1.0, 0.4, -2)
        glVertex3f(w / 2+1.0, 0.4, -2)
        glVertex3f(w / 2-1.0, 0.4, l)
        glVertex3f(w / 2+1.0, 0.4, l)
        glEnd()   
        shaders.setVar("offset",(-3.5,w/2))
        shaders.setVar("time",shaders.time()+0.5)
        glBegin(GL_TRIANGLE_STRIP)
        glVertex3f(-w / 2+1.0, 0.4, -2)
        glVertex3f(-w / 2-1.0, 0.4, -2)
        glVertex3f(-w / 2+1.0, 0.4, l)
        glVertex3f(-w / 2-1.0, 0.4, l)
        glEnd()  
        shaders.disable()

  def drawBPM(self, visibility, song, pos):
    if not song:
      return
    if not song.readyToGo:
      return


    v            = visibility
    w            = self.boardWidth

    track = song.track[self.player]

    glEnable(GL_TEXTURE_2D)

    for time, event in track.getEvents(pos - self.currentPeriod * 2, pos + self.currentPeriod * self.beatsPerBoard):
      if not isinstance(event, Bars):
        continue   

      glPushMatrix()

      z  = ((time - pos) / self.currentPeriod) / self.beatsPerUnit
      z2 = ((time + event.length - pos) / self.currentPeriod) / self.beatsPerUnit

      if z > self.boardLength:
        f = (self.boardLength - z) / (self.boardLength * .2)
      elif z < 0:
        f = min(1, max(0, 1 + z2))
      else:
        f = 1.0
        
      if event.barType == 0: #half-beat
        sw  = 0.1 #width
        self.bpm_halfbeat.texture.bind()
      elif event.barType == 1: #beat
        sw  = 0.1 #width
        self.bpm_beat.texture.bind()
      elif event.barType == 2: #measure
        sw  = 0.1 #width
        self.bpm_measure.texture.bind()

      bpm_vtx  = array([[-(w / 2), 0,  z + sw],
                         [-(w / 2), 0,  z - sw],
                         [(w / 2), 0,  z + sw],
                         [(w / 2), 0,  z - sw]], dtype=float32)

      bpm_tex  = array([[0.0, 1.0],
                         [0.0, 0.0],
                         [1.0, 1.0],
                         [1.0, 0.0]], dtype=float32)

      bpm_col  = array([[1, 1, 1, v],
                         [1, 1, 1, v],
                         [1, 1, 1, v],
                         [1, 1, 1, v]], dtype=float32)

      glEnableClientState(GL_VERTEX_ARRAY)
      glEnableClientState(GL_COLOR_ARRAY)
      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
      glVertexPointerf(bpm_vtx)
      glColorPointerf(bpm_col)
      glTexCoordPointerf(bpm_tex)
      glDrawArrays(GL_TRIANGLE_STRIP, 0, bpm_vtx.shape[0])
      glDisableClientState(GL_VERTEX_ARRAY)
      glDisableClientState(GL_COLOR_ARRAY)
      glDisableClientState(GL_TEXTURE_COORD_ARRAY);

      glPopMatrix()

    glDisable(GL_TEXTURE_2D)
    
  def render(self, visibility, song, pos):
    self.currentPeriod = self.instrument.neckSpeed
    
    if self.isFailing == True:
      if self.failcount <= 1 and self.failcount2 == False:
        self.failcount += .05
      elif self.failcount >= 1 and self.failcount2 == False:
        self.failcount = 1
        self.failcount2 = True
        
      if self.failcount >= 0 and self.failcount2 == True:
        self.failcount -= .05
      elif self.failcount <= 0 and self.failcount2 == True:
        self.failcount = 0
        self.failcount2 = False
    if self.isFailing == False and self.failcount > 0:
      self.failcount -= .05
      self.failcount2 = False
    if self.instrument.starPowerActive == True:
      if self.spcount < 1.2:
        self.spcount += .05
        self.spcount2 = 1
      elif self.spcount >=1.2:
        self.spcount = 1.2
        self.spcount2 = 0
    else:
      if self.spcount > 0:
        self.spcount -= .05
        self.spcount2 = 2
      elif self.spcount <=0:
        self.spcount = 0
        self.spcount2 = 0
    
    if self.scoreMultiplier > 4 and self.bgcount < 1:
      self.bgcount += .1
      if self.bgcount > 1:
        self.bgcount = 1
    if self.scoreMultiplier < 4 and self.bgcount > 0:
      self.bgcount -= .1
      if self.bgcount < 0:
        self.bgcount = 0
    if not (self.instrument.coOpFailed and not self.instrument.coOpRestart):

      if self.ocount < 1:
        self.ocount += .1
      else:
        self.ocount = 1
      self.vis = visibility
      self.renderNeck(visibility, song, pos)
      self.renderIncomingNecks(visibility, song, pos) #MFH
      self.drawTrack(self.ocount, song, pos)
      self.drawBPM(visibility, song, pos)
      self.drawSideBars(visibility, song, pos)


    if self.theme == 2 and self.overdriveFlashCount < self.overdriveFlashCounts:
      self.overdriveFlashCount = self.overdriveFlashCount + 1
