示例#1
0
文件: Stage.py 项目: maggotgdv/fofix
    def loadVideo(self, libraryName, songName):
        vidSource = None

        if self.songStage == 1:
            songBackgroundVideoPath = os.path.join(libraryName, songName,
                                                   "background.ogv")
            if os.path.isfile(songBackgroundVideoPath):
                vidSource = songBackgroundVideoPath
                loop = False
            else:
                Log.warn("Video not found: %s" % songBackgroundVideoPath)

        if vidSource is None:
            vidSource = os.path.join(self.pathfull, "default.ogv")
            loop = True

        if not os.path.isfile(vidSource):
            Log.warn("Video not found: %s" % vidSource)
            Log.warn("Falling back to default stage mode.")
            self.mode = 1  # Fallback
            return

        try:  # Catches invalid video files or unsupported formats
            Log.debug("Attempting to load video: %s" % vidSource)
            self.vidPlayer = VideoLayer(self.engine,
                                        vidSource,
                                        mute=True,
                                        loop=loop)
            self.engine.view.pushLayer(self.vidPlayer)
        except (IOError, VideoPlayerError):
            self.mode = 1
            Log.error(
                "Failed to load song video (falling back to default stage mode):"
            )
示例#2
0
文件: Stage.py 项目: HugoLnx/fofix
  def loadVideo(self, libraryName, songName):
    vidSource = None

    if self.songStage == 1:
      songBackgroundVideoPath = os.path.join(libraryName, songName, "background.ogv")
      if os.path.isfile(songBackgroundVideoPath):
        vidSource = songBackgroundVideoPath
        loop = False
      else:
        Log.warn("Video not found: %s" % songBackgroundVideoPath)

    if vidSource is None:
      vidSource = os.path.join(self.pathfull, "default.ogv")
      loop = True

    if not os.path.isfile(vidSource):
      Log.warn("Video not found: %s" % vidSource)
      Log.warn("Falling back to default stage mode.")
      self.mode = 1 # Fallback
      return

    try: # Catches invalid video files or unsupported formats
      Log.debug("Attempting to load video: %s" % vidSource)
      self.vidPlayer = VideoLayer(self.engine, vidSource,
                                  mute = True, loop = loop)
      self.engine.view.pushLayer(self.vidPlayer)
    except (IOError, VideoPlayerError):
      self.mode = 1
      Log.error("Failed to load song video (falling back to default stage mode):")
示例#3
0
文件: Credits.py 项目: chk666/fofix
    def __init__(self, engine, songName = None):
        self.engine      = engine
        self.time        = 0.0
        self.offset      = 0.5 # akedrou - this seems to fix the delay issue, but I'm not sure why. Return here!
        self.speedDiv    = 20000.0
        self.speedDir    = 1.0
        self.doneList    = []
        self.themename = Config.get("coffee", "themename")

        nf = self.engine.data.font
        ns = 0.002
        bs = 0.001
        hs = 0.003
        c1 = (1, 1, .5, 1)
        c2 = (1, .75, 0, 1)
        self.text_size = nf.getLineSpacing(scale = hs)

        #akedrou - Translatable Strings:
        self.bank = {}
        self.bank['intro']      = [_("Frets on Fire X is a progression of MFH-mod,"),
                                   _("which was built on Alarian's mod,"),
                                   _("which was built on UltimateCoffee's Ultimate mod,"),
                                   _("which was built on RogueF's RF_mod 4.15,"),
                                   _("which was, of course, built on Frets on Fire 1.2.451,"),
                                   _("which was created by Unreal Voodoo")]
        self.bank['noOrder']    = [_("No particular order")]
        self.bank['accessOrder']= [_("In order of project commit access")]
        self.bank['coders']     = [_("Active Coders")]
        self.bank['otherCoding']= [_("Programming")]
        self.bank['graphics']   = [_("Graphic Design")]
        self.bank['3d']         = [_("3D Textures")]
        self.bank['logo']       = [_("FoFiX Logo Design")]
        self.bank['hollowmind'] = [_("Hollowmind Necks")]
        self.bank['themes']     = [_("Included Themes")]
        self.bank['shaders']    = [_("Shaders")]
        self.bank['sounds']     = [_("Sound Design")]
        self.bank['translators']= [_("Translators")]
        self.bank['honorary']   = [_("Honorary Credits")]
        self.bank['codeHonor']  = [_("Without whom this game would not exist")]
        self.bank['giveThanks'] = [_("Special Thanks to")]
        self.bank['community']  = [_("nwru and all of the community at fretsonfire.net")]
        self.bank['other']      = [_("Other Contributors:")]
        self.bank['tutorial']   = [_("Jurgen FoF tutorial inspired by adam02"),
                                   _("Drum test song tutorial by Heka"),
                                   _("Drum Rolls practice tutorial by venom426")]
        self.bank['disclaimer'] = [_("If you have contributed to this game and are not credited,"),
                                   _("please let us know what and when you contributed.")]
        self.bank['thanks']     = [_("Thank you for your contribution.")]
        self.bank['oversight']  = [_("Please keep in mind that it is not easy to trace down and"),
                                   _("credit every single person who contributed; if your name is"),
                                   _("not included, it was not meant to slight you."),
                                   _("It was an oversight.")]
        # evilynux - Theme strings
        self.bank['themeCreators'] = [_("%s theme credits:") % self.themename]
        self.bank['themeThanks']   = [_("%s theme specific thanks:") % self.themename]
        # Languages
        self.bank['french']        = [_("French")]
        self.bank['french90']      = [_("French (reform 1990)")]
        self.bank['german']        = [_("German")]
        self.bank['italian']       = [_("Italian")]
        self.bank['piglatin']      = [_("Pig Latin")]
        self.bank['portuguese-b']  = [_("Portuguese (Brazilian)")]
        self.bank['russian']       = [_("Russian")]
        self.bank['spanish']       = [_("Spanish")]
        self.bank['swedish']       = [_("Swedish")]

        self.videoLayer = False
        self.background = None

        vidSource = os.path.join(Version.dataPath(), 'themes', self.themename, \
                                 'menu', 'credits.ogv')
        if os.path.isfile(vidSource):
            try:
                self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = True)
            except (IOError, VideoPlayerError):
                Log.error('Error loading credits video:')
            else:
                self.vidPlayer.play()
                self.engine.view.pushLayer(self.vidPlayer)
                self.videoLayer = True

        if not self.videoLayer and \
           not self.engine.loadImgDrawing(self, 'background', os.path.join('themes', self.themename, 'menu', 'credits.png')):
            self.background = None

        if not self.engine.loadImgDrawing(self, 'topLayer', os.path.join('themes', self.themename, 'menu', 'creditstop.png')):
            self.topLayer = None

        space = Text(nf, hs, c1, "center", " ")
        self.credits = [
          Picture(self.engine, "fofix_logo.png", .10),
          Text(nf, ns, c1, "center", "%s" % Version.version()), space]

        # evilynux: Main FoFiX credits (taken from CREDITS).
        self.parseText("CREDITS")
        self.credits.extend([space, space, space])
        # evilynux: Theme credits (taken from data/themes/<theme name>/CREDITS).
        self.parseText(os.path.join('data', 'themes', self.themename, 'CREDITS'))

        self.credits.extend( [
          space, space,
          Text(nf, ns, c1, "left",   _("Made with:")),
          Text(nf, ns, c2, "right",  "Python " + sys.version.split(' ')[0]),  #stump: the version that's actually in use
          Text(nf, bs, c2, "right",  "http://www.python.org"),
          space,
          Text(nf, ns, c2, "right",  "PyGame " + pygame.version.ver.replace('release', '')),  #stump: the version that's actually in use
          Text(nf, bs, c2, "right",  "http://www.pygame.org"),
          space,
          Text(nf, ns, c2, "right",  "PyOpenGL " + OpenGL.__version__), #evilynux: the version that's actually in use
          Text(nf, bs, c2, "right",  "http://pyopengl.sourceforge.net"),
          space,
          Text(nf, ns, c2, "right",  "Illusoft Collada module 0.3.159"),
          Text(nf, bs, c2, "right",  "http://colladablender.illusoft.com"),
          space,
          Text(nf, ns, c2, "right",  "MXM Python Midi Package 0.1.4"),
          Text(nf, bs, c2, "right",  "http://www.mxm.dk/products/public/pythonmidi"),
          space,
          space,
          Text(nf, bs, c1, "center", _("Source Code available under the GNU General Public License")),
          Text(nf, bs, c2, "center", "http://code.google.com/p/fofix"),
          space,
          space,
          Text(nf, bs, c1, "center", _("Copyright 2006, 2007 by Unreal Voodoo")),
          Text(nf, bs, c1, "center", _("Copyright 2008-2011 by Team FoFiX")),
          space,
          space
        ])
示例#4
0
文件: Credits.py 项目: chk666/fofix
class Credits(Layer, KeyListener):
    """Credits scroller."""
    def __init__(self, engine, songName = None):
        self.engine      = engine
        self.time        = 0.0
        self.offset      = 0.5 # akedrou - this seems to fix the delay issue, but I'm not sure why. Return here!
        self.speedDiv    = 20000.0
        self.speedDir    = 1.0
        self.doneList    = []
        self.themename = Config.get("coffee", "themename")

        nf = self.engine.data.font
        ns = 0.002
        bs = 0.001
        hs = 0.003
        c1 = (1, 1, .5, 1)
        c2 = (1, .75, 0, 1)
        self.text_size = nf.getLineSpacing(scale = hs)

        #akedrou - Translatable Strings:
        self.bank = {}
        self.bank['intro']      = [_("Frets on Fire X is a progression of MFH-mod,"),
                                   _("which was built on Alarian's mod,"),
                                   _("which was built on UltimateCoffee's Ultimate mod,"),
                                   _("which was built on RogueF's RF_mod 4.15,"),
                                   _("which was, of course, built on Frets on Fire 1.2.451,"),
                                   _("which was created by Unreal Voodoo")]
        self.bank['noOrder']    = [_("No particular order")]
        self.bank['accessOrder']= [_("In order of project commit access")]
        self.bank['coders']     = [_("Active Coders")]
        self.bank['otherCoding']= [_("Programming")]
        self.bank['graphics']   = [_("Graphic Design")]
        self.bank['3d']         = [_("3D Textures")]
        self.bank['logo']       = [_("FoFiX Logo Design")]
        self.bank['hollowmind'] = [_("Hollowmind Necks")]
        self.bank['themes']     = [_("Included Themes")]
        self.bank['shaders']    = [_("Shaders")]
        self.bank['sounds']     = [_("Sound Design")]
        self.bank['translators']= [_("Translators")]
        self.bank['honorary']   = [_("Honorary Credits")]
        self.bank['codeHonor']  = [_("Without whom this game would not exist")]
        self.bank['giveThanks'] = [_("Special Thanks to")]
        self.bank['community']  = [_("nwru and all of the community at fretsonfire.net")]
        self.bank['other']      = [_("Other Contributors:")]
        self.bank['tutorial']   = [_("Jurgen FoF tutorial inspired by adam02"),
                                   _("Drum test song tutorial by Heka"),
                                   _("Drum Rolls practice tutorial by venom426")]
        self.bank['disclaimer'] = [_("If you have contributed to this game and are not credited,"),
                                   _("please let us know what and when you contributed.")]
        self.bank['thanks']     = [_("Thank you for your contribution.")]
        self.bank['oversight']  = [_("Please keep in mind that it is not easy to trace down and"),
                                   _("credit every single person who contributed; if your name is"),
                                   _("not included, it was not meant to slight you."),
                                   _("It was an oversight.")]
        # evilynux - Theme strings
        self.bank['themeCreators'] = [_("%s theme credits:") % self.themename]
        self.bank['themeThanks']   = [_("%s theme specific thanks:") % self.themename]
        # Languages
        self.bank['french']        = [_("French")]
        self.bank['french90']      = [_("French (reform 1990)")]
        self.bank['german']        = [_("German")]
        self.bank['italian']       = [_("Italian")]
        self.bank['piglatin']      = [_("Pig Latin")]
        self.bank['portuguese-b']  = [_("Portuguese (Brazilian)")]
        self.bank['russian']       = [_("Russian")]
        self.bank['spanish']       = [_("Spanish")]
        self.bank['swedish']       = [_("Swedish")]

        self.videoLayer = False
        self.background = None

        vidSource = os.path.join(Version.dataPath(), 'themes', self.themename, \
                                 'menu', 'credits.ogv')
        if os.path.isfile(vidSource):
            try:
                self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = True)
            except (IOError, VideoPlayerError):
                Log.error('Error loading credits video:')
            else:
                self.vidPlayer.play()
                self.engine.view.pushLayer(self.vidPlayer)
                self.videoLayer = True

        if not self.videoLayer and \
           not self.engine.loadImgDrawing(self, 'background', os.path.join('themes', self.themename, 'menu', 'credits.png')):
            self.background = None

        if not self.engine.loadImgDrawing(self, 'topLayer', os.path.join('themes', self.themename, 'menu', 'creditstop.png')):
            self.topLayer = None

        space = Text(nf, hs, c1, "center", " ")
        self.credits = [
          Picture(self.engine, "fofix_logo.png", .10),
          Text(nf, ns, c1, "center", "%s" % Version.version()), space]

        # evilynux: Main FoFiX credits (taken from CREDITS).
        self.parseText("CREDITS")
        self.credits.extend([space, space, space])
        # evilynux: Theme credits (taken from data/themes/<theme name>/CREDITS).
        self.parseText(os.path.join('data', 'themes', self.themename, 'CREDITS'))

        self.credits.extend( [
          space, space,
          Text(nf, ns, c1, "left",   _("Made with:")),
          Text(nf, ns, c2, "right",  "Python " + sys.version.split(' ')[0]),  #stump: the version that's actually in use
          Text(nf, bs, c2, "right",  "http://www.python.org"),
          space,
          Text(nf, ns, c2, "right",  "PyGame " + pygame.version.ver.replace('release', '')),  #stump: the version that's actually in use
          Text(nf, bs, c2, "right",  "http://www.pygame.org"),
          space,
          Text(nf, ns, c2, "right",  "PyOpenGL " + OpenGL.__version__), #evilynux: the version that's actually in use
          Text(nf, bs, c2, "right",  "http://pyopengl.sourceforge.net"),
          space,
          Text(nf, ns, c2, "right",  "Illusoft Collada module 0.3.159"),
          Text(nf, bs, c2, "right",  "http://colladablender.illusoft.com"),
          space,
          Text(nf, ns, c2, "right",  "MXM Python Midi Package 0.1.4"),
          Text(nf, bs, c2, "right",  "http://www.mxm.dk/products/public/pythonmidi"),
          space,
          space,
          Text(nf, bs, c1, "center", _("Source Code available under the GNU General Public License")),
          Text(nf, bs, c2, "center", "http://code.google.com/p/fofix"),
          space,
          space,
          Text(nf, bs, c1, "center", _("Copyright 2006, 2007 by Unreal Voodoo")),
          Text(nf, bs, c1, "center", _("Copyright 2008-2011 by Team FoFiX")),
          space,
          space
        ])

    # evilynux - Text parsing method. Provides some style functionalities.
    def parseText(self, filename):
        nf = self.engine.data.font
        ns = 0.002
        bs = 0.001
        hs = 0.003
        c1 = (1, 1, .5, 1)
        c2 = (1, .75, 0, 1)
        space = Text(nf, hs, c1, "center", " ")
        scale = 1

        path = filename
        if not hasattr(sys,"frozen"): #MFH - add ".." to path only if running from sources - not if running from EXE
            path = os.path.join("..", path)
        if not os.path.exists(path):
            return

        file = open(path)
        for line in file:
            line = line.strip("\n")
            if line.startswith("=====") or line.startswith("-----"):
                continue
            try:
                if line.startswith("!") and line.endswith("!"):
                    scale = float(line.strip("!"))
                    continue
            except ValueError:
                Log.warn("CREDITS file does not parse properly")
            if line == "":
                self.credits.append(space)
            elif line.startswith("`") and line.endswith("`"):
                line = line.strip("`")
                if line.startswith("%") and line.endswith("%"):
                    line = line.strip("%")
                    try:
                        for text in self.bank[line]:
                            self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % text) )
                    except KeyError:
                        self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % line) )
                else:
                    self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % line) )
            elif line.startswith("_") and line.endswith("_"):
                line = line.strip("_")
                if line.startswith("%") and line.endswith("%"):
                    line = line.strip("%")
                    try:
                        for text in self.bank[line]:
                            self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % text) )
                    except KeyError:
                        self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % line) )
                else:
                    self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % line) )
            elif line.startswith("=") and line.endswith("="):
                line = line.strip("=")
                if line.startswith("%") and line.endswith("%"):
                    line = line.strip("%")
                    try:
                        for text in self.bank[line]:
                            self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % text) )
                    except KeyError:
                        self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % line) )
                else:
                    self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % line) )
            else:
                if line.startswith("%") and line.endswith("%"):
                    line = line.strip("%")
                    try:
                        for text in self.bank[line]:
                            self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % text) )
                    except KeyError:
                        self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % line) )
                else:
                    self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % line) )

    def shown(self):
        self.engine.input.addKeyListener(self)

    def hidden(self):
        self.engine.input.removeKeyListener(self)
        self.engine.view.pushLayer(self.engine.mainMenu)    #rchiav: use already-existing MainMenu instance

    def quit(self):
        if self.videoLayer:
            self.engine.view.popLayer(self.vidPlayer)
        self.engine.view.popLayer(self)

    def keyPressed(self, key, unicode):
        if self.engine.input.controls.getMapping(key) in (Player.menuYes + Player.menuNo) or key == pygame.K_RETURN or key == pygame.K_ESCAPE:
            self.quit()
        elif self.engine.input.controls.getMapping(key) in (Player.menuDown) or key == pygame.K_DOWN: #akedrou: so I was bored.
            if self.speedDiv > 1000.0:
                self.speedDiv -= 1000.0
                if self.speedDiv < 1000.0:
                    self.speedDiv = 1000.0
        elif self.engine.input.controls.getMapping(key) in (Player.menuUp) or key == pygame.K_UP:
            if self.speedDiv < 30000.0:
                self.speedDiv += 1000.0
                if self.speedDiv > 30000.0:
                    self.speedDiv = 30000.0
        elif self.engine.input.controls.getMapping(key) in (Player.key3s):
            self.speedDir *= -1
        elif self.engine.input.controls.getMapping(key) in (Player.key4s):
            if self.speedDir != 0:
                self.speedDir = 0
            else:
                self.speedDir = 1.0
        return True

    def run(self, ticks):
        self.time   += ticks / 50.0
        #self.offset -= ticks / 7500.0 # evilynux - corresponds to scroll speed
        #self.offset -= ticks / 15000.0 #MFH - slowin it down - # evilynux - corresponds to scroll speed
        self.offset -= (ticks / self.speedDiv) * self.speedDir #akedrou - some credits fun.

        # evilynux - approximating the end of the list from the (mostly used font size * lines)
        if self.offset < -( self.text_size * len(self.credits) ) or self.offset > 1.5:    #(MFH - adding 5% to estimated font height) undone: using larger scale for estimation.
            self.quit()
        if len(self.credits) == len(self.doneList): #akedrou - goofy workaround for string size glitch.
            self.quit()

    def render(self, visibility, topMost):
        v = 1.0 - ((1 - visibility) ** 2)

        # render the background
        w, h = self.engine.view.geometry[2:4]

        with self.engine.view.orthogonalProjection(normalize = True):
            if self.background:
                self.engine.drawImage(self.background, scale = (1.0,-1.0), coord = (w/2,h/2), stretched = 3)
            else:
                Dialogs.fadeScreen(.4)
            self.doneList = []

            # render the scroller elements
            y = self.offset
            glTranslatef(-(1 - v), 0, 0)
            for element in self.credits:
                hE = element.getHeight()
                if y + hE > 0.0 and y < 1.0:
                    element.render(y)
                if y + hE < 0.0:
                    self.doneList.append(element)
                y += hE
                if y > 1.0:
                    break
            if self.topLayer:
                wFactor = 640.000/self.topLayer.width1()
                hPos = h - ((self.topLayer.height1() * wFactor)*.75)
                if hPos < h * .6:
                    hPos = h * .6
                self.engine.drawImage(self.topLayer, scale = (wFactor,-wFactor), coord = (w/2,hPos))
示例#5
0
文件: FoFiX.py 项目: davwong/fofix
  if encoding is not None:
    #stump: XXX: Everything I have seen indicates that this is a
    # horrible, horrible hack.  Is there another way?  Do we even need this?
    reload(sys)
    sys.setdefaultencoding(encoding)

  # Play the intro video if it is present, we have the capability, and
  # we are not in one-shot mode.
  videoLayer = False
  if not engine.cmdPlay:
    themename = Config.get("coffee", "themename")
    vidSource = os.path.join(Version.dataPath(), 'themes', themename, \
                             'menu', 'intro.ogv')
    if os.path.isfile(vidSource):
      try:
        vidPlayer = VideoLayer(engine, vidSource, cancellable=True)
      except (IOError, VideoPlayerError):
        Log.error("Error loading intro video:")
      else:
        vidPlayer.play()
        engine.view.pushLayer(vidPlayer)
        videoLayer = True
        engine.ticksAtStart = pygame.time.get_ticks()
        while not vidPlayer.finished:
          engine.run()
        engine.view.popLayer(vidPlayer)
        engine.view.pushLayer(MainMenu(engine))
  if not videoLayer:
    engine.setStartupLayer(MainMenu(engine))

  #stump: make psyco optional
示例#6
0
文件: Stage.py 项目: HugoLnx/fofix
class Stage(object):
  def __init__(self, guitarScene, configFileName):
    self.scene            = guitarScene
    self.engine           = guitarScene.engine
    self.config           = LinedConfigParser()
    self.backgroundLayers = []
    self.foregroundLayers = []
    self.textures         = {}
    self.reset()
    

    self.wFull = None   #MFH - needed for new stage background handling
    self.hFull = None
    
    # evilynux - imported myfingershurt stuff from GuitarScene
    self.mode = self.engine.config.get("game", "stage_mode")
    self.songStage = self.engine.config.get("game", "song_stage")
    self.animatedFolder = self.engine.config.get("game", "animated_stage_folder")

    # evilynux - imported myfingershurt stuff from GuitarScene w/ minor modifs
    #MFH TODO - alter logic to accommodate separated animation and slideshow
    #           settings based on selected animated stage folder
    animationMode = self.engine.config.get("game", "stage_animate")
    slideShowMode = self.engine.config.get("game", "rotate_stages")

    if self.animatedFolder == _("None"):
      self.rotationMode = 0   #MFH: if no animated stage folders are available, disable rotation.
    elif self.animatedFolder == "Normal":
      self.rotationMode = slideShowMode
    else:
      self.rotationMode = animationMode
    
    self.imgArr = [] #QQstarS:random
    self.imgArrScaleFactors = []  #MFH - for precalculated scale factors
    self.rotateDelay = self.engine.config.get("game",  "stage_rotate_delay") #myfingershurt - user defined stage rotate delay
    self.animateDelay = self.engine.config.get("game",  "stage_animate_delay") #myfingershurt - user defined stage rotate delay
    self.animation = False

    self.indexCount = 0 #QQstarS:random time counter
    self.arrNum = 0 #QQstarS:random the array num
    self.arrDir = 1 #forwards

    self.config.read(configFileName)

    # evilynux - Improved stage error handling
    self.themename = self.engine.data.themeLabel
    self.path = os.path.join("themes",self.themename,"backgrounds")
    self.pathfull = self.engine.getPath(self.path)
    if not os.path.exists(self.pathfull): # evilynux
      Log.warn("Stage folder does not exist: %s" % self.pathfull)
      self.mode = 1 # Fallback to song-specific stage

    self.loadLayers(configFileName)
    
  def loadLayers(self, configFileName):
    self.config.read(configFileName)
    path = os.path.join("themes", self.themename, "stage")
    
    # Build the layers
    for i in range(32):
      section = "layer%d" % i
      if self.config.has_section(section):
        def get(value, type = str, default = None):
          if self.config.has_option(section, value):
            return type(self.config.get(section, value))
          return default
        
        xres    = get("xres", int, 256)
        yres    = get("yres", int, 256)
        texture = get("texture")

        try:
          drawing = self.textures[texture]
        except KeyError:
          drawing = self.engine.loadImgDrawing(self, None, os.path.join(path, texture), textureSize = (xres, yres))
          self.textures[texture] = drawing
          
        layer = Layer(self, drawing)

        layer.position    = (get("xpos",   float, 0.0), get("ypos",   float, 0.0))
        layer.scale       = (get("xscale", float, 1.0), get("yscale", float, 1.0))
        layer.angle       = math.pi * get("angle", float, 0.0) / 180.0
        layer.srcBlending = globals()["GL_%s" % get("src_blending", str, "src_alpha").upper()]
        layer.dstBlending = globals()["GL_%s" % get("dst_blending", str, "one_minus_src_alpha").upper()]
        layer.color       = (get("color_r", float, 1.0), get("color_g", float, 1.0), get("color_b", float, 1.0), get("color_a", float, 1.0))

        # Load any effects
        fxClasses = {
          "light":          LightEffect,
          "rotate":         RotateEffect,
          "wiggle":         WiggleEffect,
          "scale":          ScaleEffect,
        }
        
        for j in range(32):
          fxSection = "layer%d:fx%d" % (i, j)
          if self.config.has_section(fxSection):
            type = self.config.get(fxSection, "type")

            if not type in fxClasses:
              continue

            options = self.config.options(fxSection)
            options = dict([(opt, self.config.get(fxSection, opt)) for opt in options])

            fx = fxClasses[type](layer, options)
            layer.effects.append(fx)

        if get("foreground", int):
          self.foregroundLayers.append(layer)
        else:
          self.backgroundLayers.append(layer)

  def loadVideo(self, libraryName, songName):
    vidSource = None

    if self.songStage == 1:
      songBackgroundVideoPath = os.path.join(libraryName, songName, "background.ogv")
      if os.path.isfile(songBackgroundVideoPath):
        vidSource = songBackgroundVideoPath
        loop = False
      else:
        Log.warn("Video not found: %s" % songBackgroundVideoPath)

    if vidSource is None:
      vidSource = os.path.join(self.pathfull, "default.ogv")
      loop = True

    if not os.path.isfile(vidSource):
      Log.warn("Video not found: %s" % vidSource)
      Log.warn("Falling back to default stage mode.")
      self.mode = 1 # Fallback
      return

    try: # Catches invalid video files or unsupported formats
      Log.debug("Attempting to load video: %s" % vidSource)
      self.vidPlayer = VideoLayer(self.engine, vidSource,
                                  mute = True, loop = loop)
      self.engine.view.pushLayer(self.vidPlayer)
    except (IOError, VideoPlayerError):
      self.mode = 1
      Log.error("Failed to load song video (falling back to default stage mode):")

  def restartVideo(self):
    if not self.mode == 3:
      return
    self.vidPlayer.restart()
    
  def load(self, libraryName, songName, practiceMode = False):
    if self.scene.coOpType:
      rm = os.path.join("themes", self.themename, "rockmeter_coop.ini")
    elif self.scene.battle or self.scene.battleGH:
      rm = os.path.join("themes", self.themename, "rockmeter_profaceoff.ini")
    elif self.scene.gamePlayers > 1:
      rm = os.path.join("themes", self.themename, "rockmeter_faceoff.ini")
    else:
      rm = os.path.join("themes", self.themename, "rockmeter.ini")
    
    if os.path.exists(os.path.join("..", "data", rm)):
        rockmeter = self.engine.resource.fileName(rm)
    else:
        rockmeter = self.engine.resource.fileName(os.path.join("themes", self.themename, "rockmeter.ini"))
        
    self.rockmeter = Rockmeter.Rockmeter(self.scene, rockmeter, self.scene.coOpType)

    # evilynux - Fixes a self.background not defined crash
    self.background = None
    #MFH - new background stage logic:
    if self.mode == 2:   #blank / no stage
      self.songStage = 0
      self.rotationMode = 0
    elif practiceMode:   #check for existing practice stage; always disable stage rotation here
      self.songStage = 0
      self.rotationMode = 0
      self.mode = 1
      #separated practice stages for the instruments by k.i.d
      if self.scene.guitars[0].isDrum:
        background = "practicedrum"
      elif self.scene.guitars[0].isBassGuitar:
        background = "practicebass"
      else:
        background = "practice"
      if not self.engine.loadImgDrawing(self, "background", os.path.join("themes",self.themename,"backgrounds",background)):
        #MFH - must first fall back on the old practice.png before forcing blank stage mode!
        if not self.engine.loadImgDrawing(self, "background", os.path.join("themes",self.themename,"backgrounds","practice")):
          Log.warn("No practice stage, falling back on a forced Blank stage mode") # evilynux
          self.mode = 2    #if no practice stage, just fall back on a forced Blank stage mode
            
    elif self.songStage == 1:    #check for song-specific background
      test = True
      if not self.engine.loadImgDrawing(self, "background", os.path.join(libraryName, songName, "background")):
        Log.notice("No song-specific stage found") # evilynux
        test = False
      if test:  #does a song-specific background exist?
        self.rotationMode = 0
        self.mode = 1
      else:
        self.songStage = 0

    #MFH - now, after the above logic, we can run the normal stage mode logic
    #      only worrying about checking for Blank, song-specific and
    #      practice stage modes
    if self.mode != 2 and self.mode != 3 and self.songStage == 0 and not practiceMode: #still need to load stage(s)
      #myfingershurt: assign this first
      if self.mode == 1:   #just use Default.png
        if not self.engine.loadImgDrawing(self, "background", os.path.join(self.path, "default")):
          Log.warn("No default stage; falling back on a forced Blank stage mode") # evilynux
          self.mode = 2    #if no practice stage, just fall back on a forced Blank stage mode

      ##This checks how many Stage-background we have to select from
      if self.mode == 0 and self.rotationMode == 0:  #MFH: just display a random stage
        files = []
        fileIndex = 0
        allfiles = os.listdir(self.pathfull)
        for name in allfiles:
          if os.path.splitext(name)[0].lower() != "practice" and os.path.splitext(name)[0].lower() != "practicedrum" and os.path.splitext(name)[0].lower() != "practicebass" and name != ".svn":
            Log.debug("Valid background found, index (" + str(fileIndex) + "): " + name)
            files.append(name)
            fileIndex += 1
          else:
            Log.debug("Practice background filtered: " + name)
  
        # evilynux - improved error handling, fallback to blank background if no background are found
        if fileIndex == 0:
          Log.warn("No valid stage found!")
          self.mode = 2;
        else:
          i = random.randint(0,len(files)-1)
          filename = files[i]
      ##End check number of Stage-backgrounds
          if not self.engine.loadImgDrawing(self, "background", os.path.join(self.path, filename)):
            self.mode = 2;

      elif self.rotationMode > 0 and self.mode != 2:
        files = []
        fileIndex = 0
        
        if self.animatedFolder == "Random": #Select one of the subfolders under stages\ to animate randomly
          numAniStageFolders = len(self.engine.stageFolders)
          if numAniStageFolders > 0:
            self.animatedFolder = random.choice(self.engine.stageFolders)
          else:
            self.animatedFolder = "Normal"
          
        elif self.animatedFolder == "None":
          self.mode = 2
        
        if self.animatedFolder != "Normal" and self.mode != 2: #just use the base Stages folder for rotation
          self.path = os.path.join("themes",self.themename,"backgrounds",self.animatedFolder)
          self.pathfull = self.engine.getPath(self.path)
          self.animation = True

        allfiles = os.listdir(self.pathfull)
        for name in allfiles:

          if os.path.splitext(name)[1].lower() == ".png" or os.path.splitext(name)[1].lower() == ".jpg" or os.path.splitext(name)[1].lower() == ".jpeg":
            if os.path.splitext(name)[0].lower() != "practice" and os.path.splitext(name)[0].lower() != "practicedrum" and os.path.splitext(name)[0].lower() != "practicebass":
              Log.debug("Valid background found, index (" + str(fileIndex) + "): " + name)
              files.append(name)
              fileIndex += 1
            else:
              Log.debug("Practice background filtered: " + name)
          files.sort()

      if self.rotationMode > 0 and self.mode != 2:   #alarian: blank stage option is not selected
      #myfingershurt: just populate the image array in order, they are pulled in whatever order requested:
        for j in range(len(files)):
          self.engine.loadImgDrawing(self, "backgroundA", os.path.join(self.path, files[j]))
          self.imgArr.append(getattr(self, "backgroundA", os.path.join(self.path, files[j])))
    
    if self.rotationMode > 0 and len(self.imgArr) == 0:
      self.rotationMode = 0

  #stage rotation
  def rotate(self):
    if self.animation:
      whichDelay = self.animateDelay
    else:
      whichDelay = self.rotateDelay
    self.indexCount = self.indexCount + 1
    if self.indexCount > whichDelay:   #myfingershurt - adding user setting for stage rotate delay
      self.indexCount = 0
      if self.rotationMode == 1: #QQstarS:random
        self.arrNum = random.randint(0,len(self.imgArr)-1)
      elif self.rotationMode == 2: #myfingershurt: in order display mode
        self.arrNum += 1
        if self.arrNum > (len(self.imgArr)-1):
          self.arrNum = 0
      elif self.rotationMode == 3: #myfingershurt: in order, back and forth display mode
        if self.arrDir == 1:  #forwards
          self.arrNum += 1
          if self.arrNum > (len(self.imgArr)-1):
            self.arrNum -= 2
            self.arrDir = 0
        else:
          self.arrNum -= 1
          if self.arrNum < 0:
            self.arrNum += 2
            self.arrDir = 1

  def renderBackground(self):
    #myfingershurt: multiple rotation modes
    if self.mode != 2:
      if self.rotationMode == 0:
        self.engine.drawImage(self.background, scale = (1.0,-1.0),
                              coord = (self.wFull/2,self.hFull/2), stretched = 3)

      #myfingershurt:
      else:
        #MFH - use precalculated scale factors instead
        self.engine.drawImage(self.imgArr[self.arrNum], scale = (1.0,-1.0),
                              coord = (self.wFull/2,self.hFull/2), stretched = 3)

  def updateDelays(self):
    self.rotateDelay = self.engine.config.get("game",  "stage_rotate_delay") #myfingershurt - user defined stage rotate delay
    self.animateDelay = self.engine.config.get("game",  "stage_animate_delay") #myfingershurt - user defined stage rotate delay

  def reset(self):
    self.lastBeatPos        = None
    self.lastQuarterBeatPos = None
    self.lastMissPos        = None
    self.lastPickPos        = None
    self.beat               = 0
    self.quarterBeat        = 0
    self.pos                = 0.0
    self.playedNotes        = []
    self.averageNotes       = [0.0]
    self.beatPeriod         = 0.0

  def triggerPick(self, pos, notes):
    if notes:
      self.lastPickPos      = pos
      self.playedNotes      = self.playedNotes[-3:] + [sum(notes) / float(len(notes))]
      self.averageNotes[-1] = sum(self.playedNotes) / float(len(self.playedNotes))
      self.rockmeter.triggerPick(pos, notes)
      
  def triggerMiss(self, pos):
    self.lastMissPos = pos
    self.rockmeter.triggerMiss(pos)
    
  def triggerQuarterBeat(self, pos, quarterBeat):
    self.lastQuarterBeatPos = pos
    self.quarterBeat        = quarterBeat

  def triggerBeat(self, pos, beat):
    self.lastBeatPos  = pos
    self.beat         = beat
    self.averageNotes = self.averageNotes[-4:] + self.averageNotes[-1:]

  def run(self, pos, period):
    self.pos        = pos
    self.beatPeriod = period
    quarterBeat = int(4 * pos / period)

    if quarterBeat > self.quarterBeat:
      self.triggerQuarterBeat(pos, quarterBeat)

    beat = quarterBeat / 4

    if beat > self.beat:
      self.triggerBeat(pos, beat)

  def renderLayers(self, layers, visibility):
    if self.mode != 3:
      with self.engine.view.orthogonalProjection(normalize = True):
        for layer in layers:
          layer.render(visibility)
    
  def render(self, visibility):
    if self.mode != 3:
      self.renderBackground()
    self.renderLayers(self.backgroundLayers, visibility)
    if shaders.enable("stage"):
      height = 0.0
      for i in shaders.var["color"].keys():
        shaders.modVar("color",shaders.var["color"][i],0.05,10.0)
        height += shaders.var["color"][i][3]/3.0
      height=height**2
      shaders.setVar("height",2*height)
      shaders.setVar("ambientGlow",height/1.5)

      shaders.setVar("glowStrength",60+height*80.0)
      glBegin(GL_TRIANGLE_STRIP)
      glVertex3f(-8.0, 1.0,7.0)
      glVertex3f(8.0, 1.0,7.0)
      glVertex3f(-8.0, 4.0,7.0)
      glVertex3f(8.0, 4.0,7.0)
      glEnd()    
      shaders.disable()
      
    self.scene.renderGuitar()
    self.renderLayers(self.foregroundLayers, visibility)
    self.rockmeter.render(visibility)
示例#7
0
        #evilynux - Multiplayer and mode selection support
        if nbrplayers == 1:
            engine.cmdMode = nbrplayers, mode, 0
        else:
            engine.cmdMode = nbrplayers, 0, mode

    # Play the intro video if it is present, we have the capability, and
    # we are not in one-shot mode.
    videoLayer = False
    if not engine.cmdPlay:
        themename = Config.get("coffee", "themename")
        vidSource = os.path.join(Version.dataPath(), 'themes', themename, \
                                 'menu', 'intro.ogv')
        if os.path.isfile(vidSource):
            try:
                vidPlayer = VideoLayer(engine, vidSource, cancellable=True)
            except (IOError, VideoPlayerError):
                Log.error("Error loading intro video:")
            else:
                vidPlayer.play()
                engine.view.pushLayer(vidPlayer)
                videoLayer = True
                engine.ticksAtStart = pygame.time.get_ticks()
                while not vidPlayer.finished:
                    engine.run()
                engine.view.popLayer(vidPlayer)
                engine.view.pushLayer(MainMenu(engine))
    if not videoLayer:
        engine.setStartupLayer(MainMenu(engine))

    # Run the main game loop.
示例#8
0
文件: Stage.py 项目: maggotgdv/fofix
class Stage(object):
    def __init__(self, guitarScene, configFileName):
        self.scene = guitarScene
        self.engine = guitarScene.engine
        self.config = LinedConfigParser()
        self.backgroundLayers = []
        self.foregroundLayers = []
        self.textures = {}
        self.reset()

        self.wFull = None  #MFH - needed for new stage background handling
        self.hFull = None

        # evilynux - imported myfingershurt stuff from GuitarScene
        self.mode = self.engine.config.get("game", "stage_mode")
        self.songStage = self.engine.config.get("game", "song_stage")
        self.animatedFolder = self.engine.config.get("game",
                                                     "animated_stage_folder")

        # evilynux - imported myfingershurt stuff from GuitarScene w/ minor modifs
        #MFH TODO - alter logic to accommodate separated animation and slideshow
        #           settings based on selected animated stage folder
        animationMode = self.engine.config.get("game", "stage_animate")
        slideShowMode = self.engine.config.get("game", "rotate_stages")

        if self.animatedFolder == _("None"):
            self.rotationMode = 0  #MFH: if no animated stage folders are available, disable rotation.
        elif self.animatedFolder == "Normal":
            self.rotationMode = slideShowMode
        else:
            self.rotationMode = animationMode

        self.imgArr = []  #QQstarS:random
        self.imgArrScaleFactors = []  #MFH - for precalculated scale factors
        self.rotateDelay = self.engine.config.get(
            "game", "stage_rotate_delay"
        )  #myfingershurt - user defined stage rotate delay
        self.animateDelay = self.engine.config.get(
            "game", "stage_animate_delay"
        )  #myfingershurt - user defined stage rotate delay
        self.animation = False

        self.indexCount = 0  #QQstarS:random time counter
        self.arrNum = 0  #QQstarS:random the array num
        self.arrDir = 1  #forwards

        self.config.read(configFileName)

        # evilynux - Improved stage error handling
        self.themename = self.engine.data.themeLabel
        self.path = os.path.join("themes", self.themename, "backgrounds")
        self.pathfull = self.engine.getPath(self.path)
        if not os.path.exists(self.pathfull):  # evilynux
            Log.warn("Stage folder does not exist: %s" % self.pathfull)
            self.mode = 1  # Fallback to song-specific stage

        self.loadLayers(configFileName)

    def loadLayers(self, configFileName):
        self.config.read(configFileName)
        path = os.path.join("themes", self.themename, "stage")

        # Build the layers
        for i in range(32):
            section = "layer%d" % i
            if self.config.has_section(section):

                def get(value, type=str, default=None):
                    if self.config.has_option(section, value):
                        return type(self.config.get(section, value))
                    return default

                xres = get("xres", int, 256)
                yres = get("yres", int, 256)
                texture = get("texture")

                try:
                    drawing = self.textures[texture]
                except KeyError:
                    drawing = self.engine.loadImgDrawing(
                        self,
                        None,
                        os.path.join(path, texture),
                        textureSize=(xres, yres))
                    self.textures[texture] = drawing

                layer = Layer(self, drawing)

                layer.position = (get("xpos", float,
                                      0.0), get("ypos", float, 0.0))
                layer.scale = (get("xscale", float,
                                   1.0), get("yscale", float, 1.0))
                layer.angle = math.pi * get("angle", float, 0.0) / 180.0
                layer.srcBlending = globals()["GL_%s" % get(
                    "src_blending", str, "src_alpha").upper()]
                layer.dstBlending = globals()["GL_%s" % get(
                    "dst_blending", str, "one_minus_src_alpha").upper()]
                layer.color = (get("color_r", float,
                                   1.0), get("color_g", float,
                                             1.0), get("color_b", float, 1.0),
                               get("color_a", float, 1.0))

                # Load any effects
                fxClasses = {
                    "light": LightEffect,
                    "rotate": RotateEffect,
                    "wiggle": WiggleEffect,
                    "scale": ScaleEffect,
                }

                for j in range(32):
                    fxSection = "layer%d:fx%d" % (i, j)
                    if self.config.has_section(fxSection):
                        type = self.config.get(fxSection, "type")

                        if not type in fxClasses:
                            continue

                        options = self.config.options(fxSection)
                        options = dict([(opt, self.config.get(fxSection, opt))
                                        for opt in options])

                        fx = fxClasses[type](layer, options)
                        layer.effects.append(fx)

                if get("foreground", int):
                    self.foregroundLayers.append(layer)
                else:
                    self.backgroundLayers.append(layer)

    def loadVideo(self, libraryName, songName):
        vidSource = None

        if self.songStage == 1:
            songBackgroundVideoPath = os.path.join(libraryName, songName,
                                                   "background.ogv")
            if os.path.isfile(songBackgroundVideoPath):
                vidSource = songBackgroundVideoPath
                loop = False
            else:
                Log.warn("Video not found: %s" % songBackgroundVideoPath)

        if vidSource is None:
            vidSource = os.path.join(self.pathfull, "default.ogv")
            loop = True

        if not os.path.isfile(vidSource):
            Log.warn("Video not found: %s" % vidSource)
            Log.warn("Falling back to default stage mode.")
            self.mode = 1  # Fallback
            return

        try:  # Catches invalid video files or unsupported formats
            Log.debug("Attempting to load video: %s" % vidSource)
            self.vidPlayer = VideoLayer(self.engine,
                                        vidSource,
                                        mute=True,
                                        loop=loop)
            self.engine.view.pushLayer(self.vidPlayer)
        except (IOError, VideoPlayerError):
            self.mode = 1
            Log.error(
                "Failed to load song video (falling back to default stage mode):"
            )

    def restartVideo(self):
        if not self.mode == 3:
            return
        self.vidPlayer.restart()

    def load(self, libraryName, songName, practiceMode=False):
        if self.scene.coOpType:
            rm = os.path.join("themes", self.themename, "rockmeter_coop.ini")
        elif self.scene.battle or self.scene.battleGH:
            rm = os.path.join("themes", self.themename,
                              "rockmeter_profaceoff.ini")
        elif self.scene.gamePlayers > 1:
            rm = os.path.join("themes", self.themename,
                              "rockmeter_faceoff.ini")
        else:
            rm = os.path.join("themes", self.themename, "rockmeter.ini")

        if os.path.exists(os.path.join("..", "data", rm)):
            rockmeter = self.engine.resource.fileName(rm)
        else:
            rockmeter = self.engine.resource.fileName(
                os.path.join("themes", self.themename, "rockmeter.ini"))

        self.rockmeter = Rockmeter.Rockmeter(self.scene, rockmeter,
                                             self.scene.coOpType)

        # evilynux - Fixes a self.background not defined crash
        self.background = None
        #MFH - new background stage logic:
        if self.mode == 2:  #blank / no stage
            self.songStage = 0
            self.rotationMode = 0
        elif practiceMode:  #check for existing practice stage; always disable stage rotation here
            self.songStage = 0
            self.rotationMode = 0
            self.mode = 1
            #separated practice stages for the instruments by k.i.d
            if self.scene.instruments[0].isDrum:
                background = "practicedrum"
            elif self.scene.instruments[0].isBassGuitar:
                background = "practicebass"
            else:
                background = "practice"
            if not self.engine.loadImgDrawing(
                    self, "background",
                    os.path.join("themes", self.themename, "backgrounds",
                                 background)):
                #MFH - must first fall back on the old practice.png before forcing blank stage mode!
                if not self.engine.loadImgDrawing(
                        self, "background",
                        os.path.join("themes", self.themename, "backgrounds",
                                     "practice")):
                    Log.warn(
                        "No practice stage, falling back on a forced Blank stage mode"
                    )  # evilynux
                    self.mode = 2  #if no practice stage, just fall back on a forced Blank stage mode

        elif self.songStage == 1:  #check for song-specific background
            test = True
            if not self.engine.loadImgDrawing(
                    self, "background",
                    os.path.join(libraryName, songName, "background")):
                Log.notice("No song-specific stage found")  # evilynux
                test = False
            if test:  #does a song-specific background exist?
                self.rotationMode = 0
                self.mode = 1
            else:
                self.songStage = 0

        #MFH - now, after the above logic, we can run the normal stage mode logic
        #      only worrying about checking for Blank, song-specific and
        #      practice stage modes
        if self.mode != 2 and self.mode != 3 and self.songStage == 0 and not practiceMode:  #still need to load stage(s)
            #myfingershurt: assign this first
            if self.mode == 1:  #just use Default.png
                if not self.engine.loadImgDrawing(
                        self, "background", os.path.join(self.path,
                                                         "default")):
                    Log.warn(
                        "No default stage; falling back on a forced Blank stage mode"
                    )  # evilynux
                    self.mode = 2  #if no practice stage, just fall back on a forced Blank stage mode

            ##This checks how many Stage-background we have to select from
            if self.mode == 0 and self.rotationMode == 0:  #MFH: just display a random stage
                files = []
                fileIndex = 0
                allfiles = os.listdir(self.pathfull)
                for name in allfiles:
                    if os.path.splitext(name)[0].lower(
                    ) != "practice" and os.path.splitext(name)[0].lower(
                    ) != "practicedrum" and os.path.splitext(name)[0].lower(
                    ) != "practicebass" and name != ".svn":
                        Log.debug("Valid background found, index (" +
                                  str(fileIndex) + "): " + name)
                        files.append(name)
                        fileIndex += 1
                    else:
                        Log.debug("Practice background filtered: " + name)

                # evilynux - improved error handling, fallback to blank background if no background are found
                if fileIndex == 0:
                    Log.warn("No valid stage found!")
                    self.mode = 2
                else:
                    i = random.randint(0, len(files) - 1)
                    filename = files[i]
                    ##End check number of Stage-backgrounds
                    if not self.engine.loadImgDrawing(
                            self, "background",
                            os.path.join(self.path, filename)):
                        self.mode = 2

            elif self.rotationMode > 0 and self.mode != 2:
                files = []
                fileIndex = 0

                if self.animatedFolder == "Random":  #Select one of the subfolders under stages\ to animate randomly
                    numAniStageFolders = len(self.engine.stageFolders)
                    if numAniStageFolders > 0:
                        self.animatedFolder = random.choice(
                            self.engine.stageFolders)
                    else:
                        self.animatedFolder = "Normal"

                elif self.animatedFolder == "None":
                    self.mode = 2

                if self.animatedFolder != "Normal" and self.mode != 2:  #just use the base Stages folder for rotation
                    self.path = os.path.join("themes", self.themename,
                                             "backgrounds",
                                             self.animatedFolder)
                    self.pathfull = self.engine.getPath(self.path)
                    self.animation = True

                allfiles = os.listdir(self.pathfull)
                for name in allfiles:

                    if os.path.splitext(
                            name)[1].lower() == ".png" or os.path.splitext(
                                name)[1].lower() == ".jpg" or os.path.splitext(
                                    name)[1].lower() == ".jpeg":
                        if os.path.splitext(name)[0].lower(
                        ) != "practice" and os.path.splitext(name)[0].lower(
                        ) != "practicedrum" and os.path.splitext(
                                name)[0].lower() != "practicebass":
                            Log.debug("Valid background found, index (" +
                                      str(fileIndex) + "): " + name)
                            files.append(name)
                            fileIndex += 1
                        else:
                            Log.debug("Practice background filtered: " + name)
                    files.sort()

            if self.rotationMode > 0 and self.mode != 2:  #alarian: blank stage option is not selected
                #myfingershurt: just populate the image array in order, they are pulled in whatever order requested:
                for j in range(len(files)):
                    self.engine.loadImgDrawing(
                        self, "backgroundA", os.path.join(self.path, files[j]))
                    self.imgArr.append(
                        getattr(self, "backgroundA",
                                os.path.join(self.path, files[j])))

        if self.rotationMode > 0 and len(self.imgArr) == 0:
            self.rotationMode = 0

    #stage rotation
    def rotate(self):
        if self.animation:
            whichDelay = self.animateDelay
        else:
            whichDelay = self.rotateDelay
        self.indexCount = self.indexCount + 1
        if self.indexCount > whichDelay:  #myfingershurt - adding user setting for stage rotate delay
            self.indexCount = 0
            if self.rotationMode == 1:  #QQstarS:random
                self.arrNum = random.randint(0, len(self.imgArr) - 1)
            elif self.rotationMode == 2:  #myfingershurt: in order display mode
                self.arrNum += 1
                if self.arrNum > (len(self.imgArr) - 1):
                    self.arrNum = 0
            elif self.rotationMode == 3:  #myfingershurt: in order, back and forth display mode
                if self.arrDir == 1:  #forwards
                    self.arrNum += 1
                    if self.arrNum > (len(self.imgArr) - 1):
                        self.arrNum -= 2
                        self.arrDir = 0
                else:
                    self.arrNum -= 1
                    if self.arrNum < 0:
                        self.arrNum += 2
                        self.arrDir = 1

    def renderBackground(self):
        #myfingershurt: multiple rotation modes
        if self.mode != 2:
            if self.rotationMode == 0:
                self.engine.drawImage(self.background,
                                      scale=(1.0, -1.0),
                                      coord=(self.wFull / 2, self.hFull / 2),
                                      stretched=FULL_SCREEN)

            #myfingershurt:
            else:
                #MFH - use precalculated scale factors instead
                self.engine.drawImage(self.imgArr[self.arrNum],
                                      scale=(1.0, -1.0),
                                      coord=(self.wFull / 2, self.hFull / 2),
                                      stretched=FULL_SCREEN)

    def updateDelays(self):
        self.rotateDelay = self.engine.config.get(
            "game", "stage_rotate_delay"
        )  #myfingershurt - user defined stage rotate delay
        self.animateDelay = self.engine.config.get(
            "game", "stage_animate_delay"
        )  #myfingershurt - user defined stage rotate delay

    def reset(self):
        self.lastBeatPos = None
        self.lastQuarterBeatPos = None
        self.lastMissPos = None
        self.lastPickPos = None
        self.beat = 0
        self.quarterBeat = 0
        self.pos = 0.0
        self.playedNotes = []
        self.averageNotes = [0.0]
        self.beatPeriod = 0.0

    def triggerPick(self, pos, notes):
        if notes:
            self.lastPickPos = pos
            self.playedNotes = self.playedNotes[-3:] + [
                sum(notes) / float(len(notes))
            ]
            self.averageNotes[-1] = sum(self.playedNotes) / float(
                len(self.playedNotes))
            self.rockmeter.triggerPick(pos, notes)

    def triggerMiss(self, pos):
        self.lastMissPos = pos
        self.rockmeter.triggerMiss(pos)

    def triggerQuarterBeat(self, pos, quarterBeat):
        self.lastQuarterBeatPos = pos
        self.quarterBeat = quarterBeat

    def triggerBeat(self, pos, beat):
        self.lastBeatPos = pos
        self.beat = beat
        self.averageNotes = self.averageNotes[-4:] + self.averageNotes[-1:]

    def run(self, pos, period):
        self.pos = pos
        self.beatPeriod = period
        quarterBeat = int(4 * pos / period)

        if quarterBeat > self.quarterBeat:
            self.triggerQuarterBeat(pos, quarterBeat)

        beat = quarterBeat / 4

        if beat > self.beat:
            self.triggerBeat(pos, beat)

    def renderLayers(self, layers, visibility):
        if self.mode != 3:
            with self.engine.view.orthogonalProjection(normalize=True):
                for layer in layers:
                    layer.render(visibility)

    def render(self, visibility):
        if self.mode != 3:
            self.renderBackground()
        self.renderLayers(self.backgroundLayers, visibility)
        if shaders.enable("stage"):
            height = 0.0
            for i in shaders.var["color"].keys():
                shaders.modVar("color", shaders.var["color"][i], 0.05, 10.0)
                height += shaders.var["color"][i][3] / 3.0
            height = height**2
            shaders.setVar("height", 2 * height)
            shaders.setVar("ambientGlow", height / 1.5)

            shaders.setVar("glowStrength", 60 + height * 80.0)
            glBegin(GL_TRIANGLE_STRIP)
            glVertex3f(-8.0, 1.0, 7.0)
            glVertex3f(8.0, 1.0, 7.0)
            glVertex3f(-8.0, 4.0, 7.0)
            glVertex3f(8.0, 4.0, 7.0)
            glEnd()
            shaders.disable()

        self.scene.renderGuitar()
        self.renderLayers(self.foregroundLayers, visibility)
        self.rockmeter.render(visibility)
示例#9
0
    def __init__(self, engine, songName=None):
        self.engine = engine
        self.time = 0.0
        self.offset = 0.5  # akedrou - this seems to fix the delay issue, but I'm not sure why. Return here!
        self.speedDiv = 20000.0
        self.speedDir = 1.0
        self.doneList = []
        self.themename = Config.get("coffee", "themename")

        nf = self.engine.data.font
        ns = 0.002
        bs = 0.001
        hs = 0.003
        c1 = (1, 1, .5, 1)
        c2 = (1, .75, 0, 1)
        self.text_size = nf.getLineSpacing(scale=hs)

        #akedrou - Translatable Strings:
        self.bank = {}
        self.bank['intro'] = [
            _("Frets on Fire X is a progression of MFH-mod,"),
            _("which was built on Alarian's mod,"),
            _("which was built on UltimateCoffee's Ultimate mod,"),
            _("which was built on RogueF's RF_mod 4.15,"),
            _("which was, of course, built on Frets on Fire 1.2.451,"),
            _("which was created by Unreal Voodoo")
        ]
        self.bank['noOrder'] = [_("No particular order")]
        self.bank['accessOrder'] = [_("In order of project commit access")]
        self.bank['coders'] = [_("Active Coders")]
        self.bank['otherCoding'] = [_("Programming")]
        self.bank['graphics'] = [_("Graphic Design")]
        self.bank['3d'] = [_("3D Textures")]
        self.bank['logo'] = [_("FoFiX Logo Design")]
        self.bank['hollowmind'] = [_("Hollowmind Necks")]
        self.bank['themes'] = [_("Included Themes")]
        self.bank['shaders'] = [_("Shaders")]
        self.bank['sounds'] = [_("Sound Design")]
        self.bank['translators'] = [_("Translators")]
        self.bank['honorary'] = [_("Honorary Credits")]
        self.bank['codeHonor'] = [_("Without whom this game would not exist")]
        self.bank['giveThanks'] = [_("Special Thanks to")]
        self.bank['community'] = [
            _("nwru and all of the community at fretsonfire.net")
        ]
        self.bank['other'] = [_("Other Contributors:")]
        self.bank['tutorial'] = [
            _("Jurgen FoF tutorial inspired by adam02"),
            _("Drum test song tutorial by Heka"),
            _("Drum Rolls practice tutorial by venom426")
        ]
        self.bank['disclaimer'] = [
            _("If you have contributed to this game and are not credited,"),
            _("please let us know what and when you contributed.")
        ]
        self.bank['thanks'] = [_("Thank you for your contribution.")]
        self.bank['oversight'] = [
            _("Please keep in mind that it is not easy to trace down and"),
            _("credit every single person who contributed; if your name is"),
            _("not included, it was not meant to slight you."),
            _("It was an oversight.")
        ]
        # evilynux - Theme strings
        self.bank['themeCreators'] = [_("%s theme credits:") % self.themename]
        self.bank['themeThanks'] = [
            _("%s theme specific thanks:") % self.themename
        ]
        # Languages
        self.bank['french'] = [_("French")]
        self.bank['french90'] = [_("French (reform 1990)")]
        self.bank['german'] = [_("German")]
        self.bank['italian'] = [_("Italian")]
        self.bank['piglatin'] = [_("Pig Latin")]
        self.bank['portuguese-b'] = [_("Portuguese (Brazilian)")]
        self.bank['russian'] = [_("Russian")]
        self.bank['spanish'] = [_("Spanish")]
        self.bank['swedish'] = [_("Swedish")]

        self.videoLayer = False
        self.background = None

        vidSource = os.path.join(Version.dataPath(), 'themes', self.themename, \
                                 'menu', 'credits.ogv')
        if os.path.isfile(vidSource):
            try:
                self.vidPlayer = VideoLayer(self.engine,
                                            vidSource,
                                            mute=True,
                                            loop=True)
            except (IOError, VideoPlayerError):
                Log.error('Error loading credits video:')
            else:
                self.vidPlayer.play()
                self.engine.view.pushLayer(self.vidPlayer)
                self.videoLayer = True

        if not self.videoLayer and \
           not self.engine.loadImgDrawing(self, 'background', os.path.join('themes', self.themename, 'menu', 'credits.png')):
            self.background = None

        if not self.engine.loadImgDrawing(
                self, 'topLayer',
                os.path.join('themes', self.themename, 'menu',
                             'creditstop.png')):
            self.topLayer = None

        space = Text(nf, hs, c1, "center", " ")
        self.credits = [
            Picture(self.engine, "fofix_logo.png", .10),
            Text(nf, ns, c1, "center", "%s" % Version.version()), space
        ]

        # evilynux: Main FoFiX credits (taken from CREDITS).
        self.parseText("CREDITS")
        self.credits.extend([space, space, space])
        # evilynux: Theme credits (taken from data/themes/<theme name>/CREDITS).
        self.parseText(
            os.path.join('data', 'themes', self.themename, 'CREDITS'))

        self.credits.extend([
            space,
            space,
            Text(nf, ns, c1, "left", _("Made with:")),
            Text(nf, ns, c2, "right", "Python " + sys.version.split(' ')[0]
                 ),  #stump: the version that's actually in use
            Text(nf, bs, c2, "right", "http://www.python.org"),
            space,
            Text(nf, ns, c2, "right", "PyGame " + pygame.version.ver.replace(
                'release', '')),  #stump: the version that's actually in use
            Text(nf, bs, c2, "right", "http://www.pygame.org"),
            space,
            Text(nf, ns, c2, "right", "PyOpenGL " + OpenGL.__version__
                 ),  #evilynux: the version that's actually in use
            Text(nf, bs, c2, "right", "http://pyopengl.sourceforge.net"),
            space,
            Text(nf, ns, c2, "right", "Illusoft Collada module 0.3.159"),
            Text(nf, bs, c2, "right", "http://colladablender.illusoft.com"),
            space,
            Text(nf, ns, c2, "right", "MXM Python Midi Package 0.1.4"),
            Text(nf, bs, c2, "right",
                 "http://www.mxm.dk/products/public/pythonmidi"),
            space,
            space,
            Text(
                nf, bs, c1, "center",
                _("Source Code available under the GNU General Public License")
            ),
            Text(nf, bs, c2, "center", "http://code.google.com/p/fofix"),
            space,
            space,
            Text(nf, bs, c1, "center",
                 _("Copyright 2006, 2007 by Unreal Voodoo")),
            Text(nf, bs, c1, "center", _("Copyright 2008-2013 by Team FoFiX")),
            space,
            space
        ])
示例#10
0
class Credits(Layer, KeyListener):
    """Credits scroller."""
    def __init__(self, engine, songName=None):
        self.engine = engine
        self.time = 0.0
        self.offset = 0.5  # akedrou - this seems to fix the delay issue, but I'm not sure why. Return here!
        self.speedDiv = 20000.0
        self.speedDir = 1.0
        self.doneList = []
        self.themename = Config.get("coffee", "themename")

        nf = self.engine.data.font
        ns = 0.002
        bs = 0.001
        hs = 0.003
        c1 = (1, 1, .5, 1)
        c2 = (1, .75, 0, 1)
        self.text_size = nf.getLineSpacing(scale=hs)

        #akedrou - Translatable Strings:
        self.bank = {}
        self.bank['intro'] = [
            _("Frets on Fire X is a progression of MFH-mod,"),
            _("which was built on Alarian's mod,"),
            _("which was built on UltimateCoffee's Ultimate mod,"),
            _("which was built on RogueF's RF_mod 4.15,"),
            _("which was, of course, built on Frets on Fire 1.2.451,"),
            _("which was created by Unreal Voodoo")
        ]
        self.bank['noOrder'] = [_("No particular order")]
        self.bank['accessOrder'] = [_("In order of project commit access")]
        self.bank['coders'] = [_("Active Coders")]
        self.bank['otherCoding'] = [_("Programming")]
        self.bank['graphics'] = [_("Graphic Design")]
        self.bank['3d'] = [_("3D Textures")]
        self.bank['logo'] = [_("FoFiX Logo Design")]
        self.bank['hollowmind'] = [_("Hollowmind Necks")]
        self.bank['themes'] = [_("Included Themes")]
        self.bank['shaders'] = [_("Shaders")]
        self.bank['sounds'] = [_("Sound Design")]
        self.bank['translators'] = [_("Translators")]
        self.bank['honorary'] = [_("Honorary Credits")]
        self.bank['codeHonor'] = [_("Without whom this game would not exist")]
        self.bank['giveThanks'] = [_("Special Thanks to")]
        self.bank['community'] = [
            _("nwru and all of the community at fretsonfire.net")
        ]
        self.bank['other'] = [_("Other Contributors:")]
        self.bank['tutorial'] = [
            _("Jurgen FoF tutorial inspired by adam02"),
            _("Drum test song tutorial by Heka"),
            _("Drum Rolls practice tutorial by venom426")
        ]
        self.bank['disclaimer'] = [
            _("If you have contributed to this game and are not credited,"),
            _("please let us know what and when you contributed.")
        ]
        self.bank['thanks'] = [_("Thank you for your contribution.")]
        self.bank['oversight'] = [
            _("Please keep in mind that it is not easy to trace down and"),
            _("credit every single person who contributed; if your name is"),
            _("not included, it was not meant to slight you."),
            _("It was an oversight.")
        ]
        # evilynux - Theme strings
        self.bank['themeCreators'] = [_("%s theme credits:") % self.themename]
        self.bank['themeThanks'] = [
            _("%s theme specific thanks:") % self.themename
        ]
        # Languages
        self.bank['french'] = [_("French")]
        self.bank['french90'] = [_("French (reform 1990)")]
        self.bank['german'] = [_("German")]
        self.bank['italian'] = [_("Italian")]
        self.bank['piglatin'] = [_("Pig Latin")]
        self.bank['portuguese-b'] = [_("Portuguese (Brazilian)")]
        self.bank['russian'] = [_("Russian")]
        self.bank['spanish'] = [_("Spanish")]
        self.bank['swedish'] = [_("Swedish")]

        self.videoLayer = False
        self.background = None

        vidSource = os.path.join(Version.dataPath(), 'themes', self.themename, \
                                 'menu', 'credits.ogv')
        if os.path.isfile(vidSource):
            try:
                self.vidPlayer = VideoLayer(self.engine,
                                            vidSource,
                                            mute=True,
                                            loop=True)
            except (IOError, VideoPlayerError):
                Log.error('Error loading credits video:')
            else:
                self.vidPlayer.play()
                self.engine.view.pushLayer(self.vidPlayer)
                self.videoLayer = True

        if not self.videoLayer and \
           not self.engine.loadImgDrawing(self, 'background', os.path.join('themes', self.themename, 'menu', 'credits.png')):
            self.background = None

        if not self.engine.loadImgDrawing(
                self, 'topLayer',
                os.path.join('themes', self.themename, 'menu',
                             'creditstop.png')):
            self.topLayer = None

        space = Text(nf, hs, c1, "center", " ")
        self.credits = [
            Picture(self.engine, "fofix_logo.png", .10),
            Text(nf, ns, c1, "center", "%s" % Version.version()), space
        ]

        # evilynux: Main FoFiX credits (taken from CREDITS).
        self.parseText("CREDITS")
        self.credits.extend([space, space, space])
        # evilynux: Theme credits (taken from data/themes/<theme name>/CREDITS).
        self.parseText(
            os.path.join('data', 'themes', self.themename, 'CREDITS'))

        self.credits.extend([
            space,
            space,
            Text(nf, ns, c1, "left", _("Made with:")),
            Text(nf, ns, c2, "right", "Python " + sys.version.split(' ')[0]
                 ),  #stump: the version that's actually in use
            Text(nf, bs, c2, "right", "http://www.python.org"),
            space,
            Text(nf, ns, c2, "right", "PyGame " + pygame.version.ver.replace(
                'release', '')),  #stump: the version that's actually in use
            Text(nf, bs, c2, "right", "http://www.pygame.org"),
            space,
            Text(nf, ns, c2, "right", "PyOpenGL " + OpenGL.__version__
                 ),  #evilynux: the version that's actually in use
            Text(nf, bs, c2, "right", "http://pyopengl.sourceforge.net"),
            space,
            Text(nf, ns, c2, "right", "Illusoft Collada module 0.3.159"),
            Text(nf, bs, c2, "right", "http://colladablender.illusoft.com"),
            space,
            Text(nf, ns, c2, "right", "MXM Python Midi Package 0.1.4"),
            Text(nf, bs, c2, "right",
                 "http://www.mxm.dk/products/public/pythonmidi"),
            space,
            space,
            Text(
                nf, bs, c1, "center",
                _("Source Code available under the GNU General Public License")
            ),
            Text(nf, bs, c2, "center", "http://code.google.com/p/fofix"),
            space,
            space,
            Text(nf, bs, c1, "center",
                 _("Copyright 2006, 2007 by Unreal Voodoo")),
            Text(nf, bs, c1, "center", _("Copyright 2008-2013 by Team FoFiX")),
            space,
            space
        ])

    # evilynux - Text parsing method. Provides some style functionalities.
    def parseText(self, filename):
        nf = self.engine.data.font
        ns = 0.002
        bs = 0.001
        hs = 0.003
        c1 = (1, 1, .5, 1)
        c2 = (1, .75, 0, 1)
        space = Text(nf, hs, c1, "center", " ")
        scale = 1

        path = filename
        if not hasattr(
                sys, "frozen"
        ):  #MFH - add ".." to path only if running from sources - not if running from EXE
            path = os.path.join("..", path)
        if not os.path.exists(path):
            return

        file = open(path)
        for line in file:
            line = line.strip("\n")
            if line.startswith("=====") or line.startswith("-----"):
                continue
            try:
                if line.startswith("!") and line.endswith("!"):
                    scale = float(line.strip("!"))
                    continue
            except ValueError:
                Log.warn("CREDITS file does not parse properly")
            if line == "":
                self.credits.append(space)
            elif line.startswith("`") and line.endswith("`"):
                line = line.strip("`")
                if line.startswith("%") and line.endswith("%"):
                    line = line.strip("%")
                    try:
                        for text in self.bank[line]:
                            self.credits.append(
                                Text(nf, bs * scale, c1, "left", "%s" % text))
                    except KeyError:
                        self.credits.append(
                            Text(nf, bs * scale, c1, "left", "%s" % line))
                else:
                    self.credits.append(
                        Text(nf, bs * scale, c1, "left", "%s" % line))
            elif line.startswith("_") and line.endswith("_"):
                line = line.strip("_")
                if line.startswith("%") and line.endswith("%"):
                    line = line.strip("%")
                    try:
                        for text in self.bank[line]:
                            self.credits.append(
                                Text(nf, ns * scale, c2, "center",
                                     "%s" % text))
                    except KeyError:
                        self.credits.append(
                            Text(nf, ns * scale, c2, "center", "%s" % line))
                else:
                    self.credits.append(
                        Text(nf, ns * scale, c2, "center", "%s" % line))
            elif line.startswith("=") and line.endswith("="):
                line = line.strip("=")
                if line.startswith("%") and line.endswith("%"):
                    line = line.strip("%")
                    try:
                        for text in self.bank[line]:
                            self.credits.append(
                                Text(nf, ns * scale, c1, "left", "%s" % text))
                    except KeyError:
                        self.credits.append(
                            Text(nf, ns * scale, c1, "left", "%s" % line))
                else:
                    self.credits.append(
                        Text(nf, ns * scale, c1, "left", "%s" % line))
            else:
                if line.startswith("%") and line.endswith("%"):
                    line = line.strip("%")
                    try:
                        for text in self.bank[line]:
                            self.credits.append(
                                Text(nf, ns * scale, c2, "right", "%s" % text))
                    except KeyError:
                        self.credits.append(
                            Text(nf, ns * scale, c2, "right", "%s" % line))
                else:
                    self.credits.append(
                        Text(nf, ns * scale, c2, "right", "%s" % line))

    def shown(self):
        self.engine.input.addKeyListener(self)

    def hidden(self):
        self.engine.input.removeKeyListener(self)
        self.engine.view.pushLayer(
            self.engine.mainMenu
        )  #rchiav: use already-existing MainMenu instance

    def quit(self):
        if self.videoLayer:
            self.engine.view.popLayer(self.vidPlayer)
        self.engine.view.popLayer(self)

    def keyPressed(self, key, unicode):
        if self.engine.input.controls.getMapping(key) in (
                Player.menuYes + Player.menuNo
        ) or key == pygame.K_RETURN or key == pygame.K_ESCAPE:
            self.quit()
        elif self.engine.input.controls.getMapping(key) in (
                Player.menuDown
        ) or key == pygame.K_DOWN:  #akedrou: so I was bored.
            if self.speedDiv > 1000.0:
                self.speedDiv -= 1000.0
                if self.speedDiv < 1000.0:
                    self.speedDiv = 1000.0
        elif self.engine.input.controls.getMapping(key) in (
                Player.menuUp) or key == pygame.K_UP:
            if self.speedDiv < 30000.0:
                self.speedDiv += 1000.0
                if self.speedDiv > 30000.0:
                    self.speedDiv = 30000.0
        elif self.engine.input.controls.getMapping(key) in (Player.key3s):
            self.speedDir *= -1
        elif self.engine.input.controls.getMapping(key) in (Player.key4s):
            if self.speedDir != 0:
                self.speedDir = 0
            else:
                self.speedDir = 1.0
        return True

    def run(self, ticks):
        self.time += ticks / 50.0
        #self.offset -= ticks / 7500.0 # evilynux - corresponds to scroll speed
        #self.offset -= ticks / 15000.0 #MFH - slowin it down - # evilynux - corresponds to scroll speed
        self.offset -= (ticks / self.speedDiv
                        ) * self.speedDir  #akedrou - some credits fun.

        # evilynux - approximating the end of the list from the (mostly used font size * lines)
        if self.offset < -(
                self.text_size * len(self.credits)
        ) or self.offset > 1.5:  #(MFH - adding 5% to estimated font height) undone: using larger scale for estimation.
            self.quit()
        if len(self.credits) == len(
                self.doneList
        ):  #akedrou - goofy workaround for string size glitch.
            self.quit()

    def render(self, visibility, topMost):
        v = 1.0 - ((1 - visibility)**2)

        # render the background
        w, h = self.engine.view.geometry[2:4]

        with self.engine.view.orthogonalProjection(normalize=True):
            if self.background:
                self.engine.drawImage(self.background,
                                      scale=(1.0, -1.0),
                                      coord=(w / 2, h / 2),
                                      stretched=FULL_SCREEN)
            else:
                self.engine.fadeScreen(.4)
            self.doneList = []

            # render the scroller elements
            y = self.offset
            glTranslatef(-(1 - v), 0, 0)
            for element in self.credits:
                hE = element.getHeight()
                if y + hE > 0.0 and y < 1.0:
                    element.render(y)
                if y + hE < 0.0:
                    self.doneList.append(element)
                y += hE
                if y > 1.0:
                    break
            if self.topLayer:
                wFactor = 640.000 / self.topLayer.width1()
                hPos = h - ((self.topLayer.height1() * wFactor) * .75)
                if hPos < h * .6:
                    hPos = h * .6
                self.engine.drawImage(self.topLayer,
                                      scale=(wFactor, -wFactor),
                                      coord=(w / 2, hPos))