From b487f62ba7cd7dbbcadb2b5704ec1c99f6578390 Mon Sep 17 00:00:00 2001 From: Tim Keller Date: Tue, 6 May 2025 21:17:38 -0500 Subject: initial commit --- .gitignore | 2 ++ pix.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ transition.py | 67 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 .gitignore create mode 100644 pix.py create mode 100644 transition.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf1238c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +*.jpg diff --git a/pix.py b/pix.py new file mode 100644 index 0000000..988f83d --- /dev/null +++ b/pix.py @@ -0,0 +1,89 @@ +import sys +from OpenGL.GL import * +from OpenGL.GLUT import * +from OpenGL.GLU import * +from PIL import Image +from time import time + +from transition import Transition + +display_time = 2.0 +transition_duration = 0.5 + +# Load image as a texture using PIL +def load_texture(image_path): + img = Image.open(image_path) + img = img.convert("RGBA") # Ensure the image is in RGBA mode (4 channels: R, G, B, A) + img_data = img.tobytes("raw", "RGBA", 0, -1) # Convert image data to bytes + + texture_id = glGenTextures(1) + glBindTexture(GL_TEXTURE_2D, texture_id) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width, img.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + return texture_id + +# Main display function +transition = Transition() +def display(): + global start_time, image_time, last_time, alpha, texture_id1, texture_id2 + + current_time = time() + alive_time = current_time - start_time + delta_time = current_time - last_time + last_time = current_time + image_time += delta_time + + if (image_time < display_time): + return + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glLoadIdentity() + + # Get window size + window_width, window_height = glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT) + + # DRAW + transition_time = image_time - display_time + complete = transition.draw(texture_id1, texture_id2, window_width, window_height, delta_time, transition_time, transition_duration) + + glClearColor(0.0, 0.0, 0.0, 1.0) # Set the background color to black + + glutSwapBuffers() + + if (complete): + image_time = 0 + texture_id1, texture_id2 = texture_id2, texture_id1 + +# Initialization and main loop +def main(): + global texture_id1, texture_id2, alpha, last_time, start_time, image_time + + # Initialize the window + glutInit(sys.argv) + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB) + glutCreateWindow("Image Viewer with Fade Transition") + glEnable(GL_TEXTURE_2D) + + # Load two images for transition + texture_id1 = load_texture("image1.jpg") + texture_id2 = load_texture("image2.jpg") + + alpha = 0.0 # Start with fully transparent + image_time = 0 + start_time = time() + last_time = time() + + # Set up the OpenGL viewport and projection + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(-1, 1, -1, 1, -1, 1) + glMatrixMode(GL_MODELVIEW) + + glutDisplayFunc(display) + glutIdleFunc(display) + glutMainLoop() + +if __name__ == "__main__": + main() + diff --git a/transition.py b/transition.py new file mode 100644 index 0000000..cf2acb4 --- /dev/null +++ b/transition.py @@ -0,0 +1,67 @@ +from OpenGL.GL import * +from OpenGL.GLUT import * +from OpenGL.GLU import * + +class Transition: + def draw(self, texture_prev, texture_next, window_width, window_height, delta_time, transition_time, transition_duration): + # Update alpha value for fade effect + alpha = transition_time / transition_duration + if alpha > 1.0: + alpha = 1.0 + + # Draw the first image + self._draw_image(texture_prev, 3840, 2160, window_width, window_height, 1 - alpha) # TODO instead of decreasing alpha, draw transparent letterboxes + # Draw the second image (with transparency) + self._draw_image(texture_next, 3840, 2160, window_width, window_height, alpha) + + return alpha >= 1.0 # Complete + + + + # Draw the image with blending enabled (to allow fade effect) + def _draw_image(self, texture_id, img_width, img_height, window_width, window_height, alpha): + if (not alpha): return + + glEnable(GL_BLEND) + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + glBindTexture(GL_TEXTURE_2D, texture_id) + glColor4f(1.0, 1.0, 1.0, alpha) # Set alpha to control transparency + + # Calculate aspect ratio + img_aspect = img_width / float(img_height) + win_aspect = window_width / float(window_height) + + scaled_width = window_width + scaled_height = window_height + + # Scale the image to fit inside the window while maintaining aspect ratio + if img_aspect > win_aspect: + # Image is wider than window, letterbox vertically + scaled_height = window_width / img_aspect + else: + # Image is taller than window, letterbox horizontally + scaled_width = window_height * img_aspect + + # Position the image so it is centered + offset_x = (window_width - scaled_width) / 2 + offset_y = (window_height - scaled_height) / 2 + + # Normalize coordinates to range from -1 to 1 + x1 = (offset_x / window_width ) * 2 - 1 + y1 = (offset_y / window_height) * 2 - 1 + x2 = ((offset_x + scaled_width ) / window_width ) * 2 - 1 + y2 = ((offset_y + scaled_height) / window_height) * 2 - 1 + + # Draw the image in the center with scaling + glBegin(GL_QUADS) + glTexCoord2f(0, 0) + glVertex2f(x1, y1) + glTexCoord2f(1, 0) + glVertex2f(x2, y1) + glTexCoord2f(1, 1) + glVertex2f(x2, y2) + glTexCoord2f(0, 1) + glVertex2f(x1, y2) + glEnd() + + glDisable(GL_BLEND) -- cgit v1.2.3