summaryrefslogtreecommitdiff
path: root/window.py
blob: 8e04225a2c4c23d296eace142735a0ec216a5815 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from time import time

from renderer import ImageRenderer, TransitionMix
from texture import ImageTexture


class PixDisplay:
    def __init__(self):
        self.last_time = 0
        self.start_time = 0
        self.image_time = 0
        self.textures = []
        self.current_texture_index = 0
        self.renderer = None
        self.win_w = 0
        self.win_h = 0
        self.max_framerate = 30

        self.image_duration = 2.0
        self.transition_duration = 0.5
        self.auto_transition = True
        self.transition_reverse = False

        self.tex = None
        self.text_next = None

        self._force_redraw = False

    @property
    def max_framerate(self):
        return self._max_fps

    @max_framerate.setter
    def max_framerate(self, max_fps):
        self._max_fps = max_fps  # This is just for the getter since otherwise e.g. int(1000/int(1000/60)) would round to 62
        self.frame_time = int(1000 / 60)  # In ms

    def increment_texture_index(self, increment):
        if len(self.textures) < 2:
            return

        self.transition_reverse = increment < 0

        self.tex_prev = self.textures[self.current_texture_index]
        self.current_texture_index = (self.current_texture_index + increment) % len(self.textures)
        self.tex      = self.textures[self.current_texture_index]

        # Ensure textures are initialized
        self.tex_prev.gl_init()
        self.tex.gl_init()

    # Main display function
    def display(self):
        # Calculate timings
        current_time = time()
        alive_time = current_time - self.start_time
        delta_time = current_time - self.last_time
        self.last_time = current_time

        if not self.tex:
            self.increment_texture_index(0)
            # Draw black window if no textures are available
            if not self.tex:
                glClearColor(0.0, 0.0, 0.0, 1.0)
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
                glutSwapBuffers()
                return

        # Progress image time
        self.image_time += delta_time

        # Get window size
        old_win_w, old_win_h = self.win_w, self.win_h
        self.win_w, self.win_h = glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)

        # Draw static image except during a transition
        if self.image_time < self.image_duration:
            # Avoid unforced-redraw unless window size has changed
            if self._force_redraw or self.win_w != old_win_w or self.win_h != old_win_h:
                self.renderer.draw_static(self.tex, self.win_w, self.win_h, 1.0)
                self._force_redraw = False
            return

        # Start drawing transition once image_time >= image_duration
        if self.auto_transition:
            self.increment_texture_index(1)
            self.auto_transition = False

        transition_time = self.image_time - self.image_duration

        self.renderer.draw_transition(self.tex_prev, self.tex, self.win_w, self.win_h, delta_time, transition_time, self.transition_duration, self.transition_reverse)

        if transition_time >= self.transition_duration:
            self.image_time = 0
            self.auto_transition = True

    # Limit framerate
    def timer(self, value):
        glutPostRedisplay()
        glutTimerFunc(self.frame_time, self.timer, 0)  # Schedule next frame

    def skip(self, increment):
        self.auto_transition = False
        self.increment_texture_index(increment)
        self.image_time = self.image_duration

    def handle_special_key(self, key, x, y):
        if   key == GLUT_KEY_LEFT:
            self.skip(-1)
        elif key == GLUT_KEY_RIGHT:
            self.skip(1)

    def handle_visibility_change(self, state):
        if state == GLUT_VISIBLE:
            self._force_redraw = True
            glutPostRedisplay()

    # Initialization and main loop
    def main(self, glut_args):
        # Initialize the window
        glutInit(glut_args)
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
        glutCreateWindow("Image Viewer with Fade Transition")
        glEnable(GL_TEXTURE_2D)

        self.renderer = ImageRenderer()
        self.renderer.set_transition(TransitionMix)
        self.image_time = 0
        self.start_time = time()
        self.last_time  = time()

        # Set up the OpenGL viewport and projection
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glOrtho(-1, 1, -1, 1, -1, 1)
        glMatrixMode(GL_MODELVIEW)

        # Enable alpha blending
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        # Run display
        glutDisplayFunc(self.display)
        glutTimerFunc(self.frame_time, self.timer, 0)
        glutVisibilityFunc(self.handle_visibility_change)  # Redraw in case framebuffer gets destroyed when window is obscured
        glutSpecialFunc(self.handle_special_key)
        glutMainLoop()