# Copyright 2004-2019 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# This contains code to choose between OpenGL and Software rendering, when
# a system supports both.

init -1500:

    python hide:
        import os
        store.__dxwebsetup = os.path.join(config.renpy_base, "lib", "windows-i686", "dxwebsetup.exe")

    python:
        class _SetRenderer(Action):
            """
            Sets the preferred renderer to one of "auto", "angle", "gl", or
            "sw".
            """

            def __init__(self, renderer):
                self.renderer = renderer

            def __call__(self):
                _preferences.renderer = self.renderer
                renpy.restart_interaction()

            def get_selected(self):
                return _preferences.renderer == self.renderer

    # This is displayed to ask the user to choose the renderer he or she
    # wants to use. It takes no parameters, doesn't return anything, and
    # is expected to call _SetRenderer actions and quit when done.
    #
    # This screen can be customized by the creator, provided the actions
    # remain available.
    screen _choose_renderer:

        frame:
            style_group ""

            has side "c b":
                spacing gui._scale(10)
                xfill True
                yfill True

            fixed:

                vbox:

                    xmaximum 0.48

                    label _("Renderer")

                    null height 10

                    textbutton _("Automatically Choose"):
                        action _SetRenderer("auto")
                        style_suffix "radio_button"

                    if renpy.renpy.windows:
                        textbutton _("Force Angle/DirectX Renderer"):
                            action _SetRenderer("angle")
                            style_suffix "radio_button"

                    textbutton _("Force OpenGL Renderer"):
                        action _SetRenderer("gl")
                        style_suffix "radio_button"

                    textbutton _("Force Software Renderer"):
                        action _SetRenderer("sw")
                        style_suffix "radio_button"

                    null height 10

                    label _("NPOT")

                    null height 10

                    textbutton _("Enable"):
                        action SetField(_preferences, "gl_npot", True)
                        style_suffix "radio_button"

                    textbutton _("Disable"):
                        action SetField(_preferences, "gl_npot", False)
                        style_suffix "radio_button"


                    null height 10

                    label _("Gamepad")

                    null height 10

                    textbutton _("Enable"):
                        action SetField(_preferences, "pad_enabled", True)
                        style_suffix "radio_button"

                    textbutton _("Disable"):
                        action SetField(_preferences, "pad_enabled", False)
                        style_suffix "radio_button"

                    null height 10

                    textbutton _("Calibrate"):
                        action ui.invokesinnewcontext(_gamepad.calibrate)
                        xfill True

                vbox:

                    xmaximum 0.48
                    xpos 0.5

                    label _("Powersave")

                    null height 10

                    textbutton _("Enable"):
                        action Preference("gl powersave", True)
                        style_suffix "radio_button"

                    textbutton _("Disable"):
                        action Preference("gl powersave", False)
                        style_suffix "radio_button"

                    null height 10

                    label _("Framerate")

                    null height 10

                    textbutton _("Screen"):
                        action Preference("gl framerate", None)
                        style_suffix "radio_button"

                    textbutton _("60"):
                        action Preference("gl framerate", 60)
                        style_suffix "radio_button"

                    textbutton _("30"):
                        action Preference("gl framerate", 30)
                        style_suffix "radio_button"

                    null height 10

                    label _("Tearing")

                    null height 10

                    textbutton _("Enable"):
                        action Preference("gl tearing", True)
                        style_suffix "radio_button"

                    textbutton _("Disable"):
                        action Preference("gl tearing", False)
                        style_suffix "radio_button"

                    null height 10

            vbox:

                text _("Changes will take effect the next time this program is run.") substitute True

                null height 10

                hbox:
                    spacing gui._scale(25)

                    textbutton _(u"Quit"):
                        action Quit(confirm=False)
                        yalign 1.0

                    if not renpy.display.interface.safe_mode:
                        textbutton _("Return"):
                            action Return(0)
                            yalign 1.0


    # This is displayed when a display performance problem occurs.
    #
    # `problem` is the kind of problem that is occuring. It can be:
    # - "sw" if the software renderer was selected.
    # - "slow" if the performance test failed.
    # - "fixed" if we're operating w/o shaders.
    # - other things, added in the future.
    #
    # `url` is the url of a web page on renpy.org that will include
    # info on troubleshooting display problems.
    screen _performance_warning:

        frame:
            style_group ""

            has vbox

            label _("Performance Warning")

            null height 10

            if problem == "sw":
                text _("This computer is using software rendering.")
            elif problem == "fixed":
                text _("This computer is not using shaders.")
            elif problem == "slow":
                text _("This computer is displaying graphics slowly.")
            else:
                text _("This computer has a problem displaying graphics: [problem].") substitute True

            null height 10

            if directx_update:
                text _("Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem.")
            else:
                text _("Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display.")

            if directx_update:
                null height 10

                textbutton _("Update DirectX"):
                    action directx_update
                    xfill True

            null height 10

            textbutton _("Continue, Show this warning again"):
                action Return(True)
                xfill True

            textbutton _("Continue, Don't show warning again"):
                action Return(False)
                xfill True

            null height 10

            textbutton _("Quit"):
                action Quit(confirm=False)
                xfill True

    # Used while a directx update is ongoing.
    screen _directx_update:

        frame:
            style_group ""

            has vbox

            label _("Updating DirectX.")

            null height 10

            text _("DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX.")

            null height 10

            text _("{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box.")

            null height 10

            text _("When setup finishes, please click below to restart this program.")

            textbutton _("Restart") action Return(True)



init -1500 python:
    # The image that we fill the screen with in GL-test mode.
    config.gl_test_image = "black"

    class __GLTest(renpy.Displayable):
        """
         This counts the number of times it's been rendered, and
         the number of seconds it's been displayed, and uses them
         to make the decisions as to if OpenGL is working or not.
         """

        def __init__(self, frames, fps, timeout):
            super(__GLTest, self).__init__()

            self.target = 1.0 * frames / fps
            self.frames = frames
            self.timeout = timeout

            self.times = [ ]
            self.success = False

            renpy.renpy.display.log.write("- Target is {0} frames in {1} seconds.".format(frames, self.target))

        def render(self, width, height, st, at):
            rv = renpy.Render(width, height)

            if self.success:
                return rv

            self.times.append(st)

            renpy.redraw(self, 0)

            renpy.renpy.display.log.write("- Frame drawn at %f seconds." % st)

            if len(self.times) >= self.frames:
                frames_timing = self.times[-1] - self.times[-self.frames]

                renpy.renpy.display.log.write("- %f seconds to render %d frames.", frames_timing, self.frames)

                if frames_timing <= self.target:
                    self.success = True
                    renpy.timeout(0)

            return rv

        def event(self, ev, x, y, st):

            if self.success:
                return True

            if st > self.timeout:
                return False

            renpy.timeout(self.timeout - st)

    config.performance_test = True

    def __gl_test():

        import os

        # If we've entered safe mode, display the renderer choice screen.
        # This screen will cause us to quit.

        if _restart:
            return

        if not config.gl_enable:
            return

        if renpy.display.interface.safe_mode:
            renpy.call_in_new_context("_choose_renderer")

        if not config.performance_test:
            return

        _gl_performance_test()

    def _gl_performance_test():

        import os

        performance_test = os.environ.get("RENPY_PERFORMANCE_TEST", None)

        if performance_test is not None:
            performance_test = int(performance_test)

        if performance_test == 0:
            return

        if not _preferences.performance_test and not performance_test:
            return

        # Don't bother on android or ios - there's nothing the user can do.
        if renpy.mobile:
            return

        renpy.renpy.display.log.write("Performance test:")

        # This will cause the screen to start displaying.
        ui.pausebehavior(0)
        ui.interact(suppress_underlay=True, suppress_overlay=True)

        # The problem we have.
        problem = None

        renderer_info = renpy.get_renderer_info()

        # Software renderer check.
        if config.renderer != "sw" and renderer_info["renderer"] == "sw":
            problem = "sw"

        # Speed check.
        if problem is None:

            # The parameters of the performance test. If we do not hit FPS fps
            # over FRAMES frames before DELAY seconds are up, we fail.
            FRAMES = 5
            FPS = 15
            DELAY = 1.5

            renpy.transition(Dissolve(DELAY), always=True, force=True)
            ui.add(__GLTest(FRAMES, FPS, DELAY))
            result = ui.interact(suppress_overlay=True, suppress_underlay=True)

            if not result:
                problem = "slow"

        # Lack of shaders check.
        if problem is None:
            if not "RENPY_GL_ENVIRON" in os.environ:
                if renderer_info["renderer"] == "gl" and renderer_info["environ"] == "fixed":
                    problem = "fixed"

        if problem is None:
            return

        if renpy.renpy.windows and os.path.exists(__dxwebsetup):
            directx_update = Jump("_directx_update")
        else:
            directx_update = None

        # Give the warning message to the user.
        renpy.show_screen("_performance_warning", problem=problem, directx_update=directx_update, _transient=True)
        result = ui.interact(suppress_overlay=True, suppress_underlay=True)


        # Store the user's choice, and continue.
        _preferences.performance_test = result
        return


label _gl_test:

    # Show the test image.
    scene black
    show expression config.gl_test_image
    with None

    $ __gl_test()

    # Hide the test image.
    scene black

    return

# We can assume we're on windows here. We're also always restart once we
# make it here.
label _directx_update:

    if renpy.has_label("directx_update"):
        jump expression "directx_update"

label _directx_update_main:

    python hide:

        # Start dxsetup. We have to go through startfile to ensure that UAC
        # doesn't cause problems.
        import os
        os.startfile(__dxwebsetup)

        renpy.show_screen("_directx_update")
        ui.interact(suppress_overlay=True, suppress_underlay=True)

        renpy.quit(relaunch=True)

label _choose_renderer:
    scene expression "#000"

    $ renpy.shown_window()
    $ renpy.show_screen("_choose_renderer",  _transient=True)
    $ ui.interact(suppress_overlay=True, suppress_underlay=True)
    return
