Created
November 20, 2024 22:24
-
-
Save EncodeTheCode/de87a169861e42f70017910b8e03b745 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pygame | |
from pygame.locals import * | |
from OpenGL.GL import * | |
from OpenGL.GLU import * | |
from PIL import Image | |
import numpy as np | |
# Cube vertices and faces | |
vertices = [ | |
[1, 1, -1], | |
[1, -1, -1], | |
[-1, -1, -1], | |
[-1, 1, -1], | |
[1, 1, 1], | |
[1, -1, 1], | |
[-1, -1, 1], | |
[-1, 1, 1] | |
] | |
faces = [ | |
(0, 1, 2, 3), | |
(3, 2, 6, 7), | |
(7, 6, 5, 4), | |
(4, 5, 1, 0), | |
(0, 3, 7, 4), | |
(1, 5, 6, 2) | |
] | |
def load_texture(image_path): | |
try: | |
img = Image.open(image_path).transpose(Image.FLIP_TOP_BOTTOM) | |
img_data = np.array(img.convert("RGBA"), dtype=np.uint8) | |
texture_id = glGenTextures(1) | |
glBindTexture(GL_TEXTURE_2D, texture_id) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width, img.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img_data) | |
return texture_id | |
except Exception as e: | |
print(f"Failed to load texture: {e}") | |
return None | |
def draw_textured_cube(texture_id, opacity): | |
if texture_id is None: | |
print("No texture loaded!") | |
return | |
glBindTexture(GL_TEXTURE_2D, texture_id) | |
glColor4f(1.0, 1.0, 1.0, opacity) # Apply opacity | |
glBegin(GL_QUADS) | |
texture_coords = [ | |
(0, 0), (1, 0), (1, 1), (0, 1) | |
] | |
for face in faces: | |
for j, vertex in enumerate(face): | |
glTexCoord2f(*texture_coords[j]) | |
glVertex3fv(vertices[vertex]) | |
glEnd() | |
glColor4f(1.0, 1.0, 1.0, 1.0) # Reset opacity after drawing | |
def draw_text(position, text, color): | |
font = pygame.font.SysFont("Arial", 24) | |
text_surface = font.render(text, True, color) | |
text_data = pygame.image.tostring(text_surface, "RGBA", True) | |
glWindowPos2i(position[0], position[1]) | |
glDrawPixels(text_surface.get_width(), text_surface.get_height(), GL_RGBA, GL_UNSIGNED_BYTE, text_data) | |
class Camera: | |
def __init__(self, fov=45, view_distance=50): | |
self.position = np.array([0.0, 0.5, -3.0], dtype=float) | |
self.yaw = 0.0 | |
self.pitch = 0.0 | |
self.sensitivity = 0.1 # Mouse sensitivity for looking around | |
self.max_speed = 0.1 # Speed of movement | |
self.fov = fov | |
self.view_distance = view_distance | |
self.update_perspective() | |
pygame.mouse.set_visible(False) # Hide the mouse cursor | |
pygame.event.set_grab(True) # Capture the mouse within the window | |
def update_perspective(self): | |
glMatrixMode(GL_PROJECTION) | |
glLoadIdentity() | |
gluPerspective(self.fov, 800 / 600, 0.1, self.view_distance) | |
glMatrixMode(GL_MODELVIEW) | |
def update(self): | |
# Calculate the direction vector based on yaw and pitch | |
direction = np.array([ | |
np.cos(np.radians(self.yaw)) * np.cos(np.radians(self.pitch)), | |
np.sin(np.radians(self.pitch)), | |
np.sin(np.radians(self.yaw)) * np.cos(np.radians(self.pitch)) | |
]) | |
look_at = self.position + direction | |
glLoadIdentity() | |
gluLookAt(*self.position, *look_at, 0, 1, 0) # Camera looks forward at the calculated direction | |
def handle_mouse(self): | |
x, y = pygame.mouse.get_rel() # Get mouse movement | |
self.yaw += x * self.sensitivity | |
self.pitch -= y * self.sensitivity # Invert pitch for natural movement | |
# Normalize yaw to [0, 360) degrees | |
self.yaw = self.yaw % 360 | |
# Clamp pitch to avoid flipping | |
self.pitch = max(-90, min(90, self.pitch)) | |
def move(self, keys): | |
# Forward/backward and strafe directions | |
forward = np.array([ | |
np.cos(np.radians(self.yaw)), | |
0, # No vertical movement yet | |
np.sin(np.radians(self.yaw)) | |
]) | |
right = np.array([ | |
np.sin(np.radians(self.yaw)), | |
0, # No vertical movement yet | |
-np.cos(np.radians(self.yaw)) | |
]) | |
# Adjust vertical movement based on pitch | |
vertical_movement = np.sin(np.radians(self.pitch)) # Movement up/down based on pitch | |
if keys[pygame.K_w]: # Move forward | |
self.position += forward * self.max_speed | |
self.position[1] += vertical_movement * self.max_speed # Adjust Y position | |
if keys[pygame.K_s]: # Move backward | |
self.position -= forward * self.max_speed | |
self.position[1] -= vertical_movement * self.max_speed # Adjust Y position | |
if keys[pygame.K_a]: # Move left | |
self.position += right * self.max_speed # Strafe left | |
if keys[pygame.K_d]: # Move right | |
self.position -= right * self.max_speed # Strafe right | |
def calculate_opacity(camera, cube_position, fade_start=20.0, fade_end=5.0): | |
distance = np.linalg.norm(camera.position - cube_position) | |
if distance <= fade_end: | |
return 1.0 # Fully opaque when near | |
elif distance >= fade_start: | |
return 0.0 # Fully transparent when far | |
else: | |
return (fade_start - distance) / (fade_start - fade_end) | |
def draw_pitch_yaw_roll(camera): | |
pitch_yaw_roll_text = f"Pitch: {camera.pitch:.2f}°, Yaw: {camera.yaw:.2f}°" | |
draw_text((10, 40), pitch_yaw_roll_text, (255, 255, 0)) # Yellow color | |
def draw_camera_position(position): | |
camera_position_text = f"X: {position[0]:.2f}, Y: {position[1]:.2f}, Z: {position[2]:.2f}" | |
draw_text((10, 10), camera_position_text, (255, 255, 0)) # Yellow color | |
# Initialize PyGame and OpenGL | |
pygame.init() | |
display = (800, 600) | |
pygame.display.set_mode(display, DOUBLEBUF | OPENGL) | |
glEnable(GL_TEXTURE_2D) | |
glEnable(GL_DEPTH_TEST) | |
glEnable(GL_BLEND) | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) | |
# Load texture for the cube | |
texture_id = load_texture("texture.png") | |
# Position the mouse cursor at the center of the screen. | |
def center_mouse(): | |
width, height = pygame.display.get_window_size() | |
pygame.mouse.set_pos(width // 2, height // 2) | |
# Set up camera and cube position | |
camera = Camera(fov=45, view_distance=50) | |
cube_position = np.array([0.0, 0.0, 0.0]) # Correct initialization of cube position | |
camera_control_enabled = False # Initialize the camera control flag | |
c_key_pressed = False # Track if the 'C' key was just pressed | |
# Main loop | |
clock = pygame.time.Clock() | |
while True: | |
for event in pygame.event.get(): | |
if event.type == pygame.QUIT: | |
pygame.quit() | |
quit() | |
keys = pygame.key.get_pressed() # Get the currently pressed keys | |
# Detect if 'C' key is pressed and toggle camera control only on key press | |
if keys[pygame.K_c]: | |
if not c_key_pressed: # Only toggle if 'C' was not previously pressed | |
camera_control_enabled = not camera_control_enabled # Toggle camera control | |
c_key_pressed = True # Set the flag to indicate the key was pressed | |
else: | |
c_key_pressed = False # Reset the flag when 'C' is not pressed | |
# ESC key to disengage camera control and release the mouse | |
if keys[pygame.K_ESCAPE]: | |
pygame.mouse.set_visible(True) # Show the mouse cursor | |
pygame.event.set_grab(False) # Release the mouse from the window | |
elif camera_control_enabled: # Only apply the following logic if camera control is enabled | |
center_mouse() | |
pygame.mouse.set_visible(False) # Hide the mouse cursor | |
pygame.event.set_grab(True) # Capture the mouse within the window | |
# Handle the camera movements (handle_mouse and move should be your camera functions) | |
camera.handle_mouse() # Handle mouse movement | |
camera.move(keys) # Move the camera | |
elif camera_control_enabled == False: | |
pygame.mouse.set_visible(True) # Show the mouse cursor | |
else: | |
pygame.mouse.set_visible(True) # Show the mouse cursor | |
pygame.event.set_grab(False) # Release the mouse from the window | |
camera.update() # Update the camera view | |
# Calculate opacity based on distance to the cube | |
opacity = calculate_opacity(camera, cube_position) | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) | |
draw_textured_cube(texture_id, opacity) | |
draw_camera_position(camera.position) | |
draw_pitch_yaw_roll(camera) | |
pygame.display.flip() | |
clock.tick(60) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment