ay OpenGL in python aint bad

This commit is contained in:
2024-06-20 19:50:25 +02:00
parent 7d5881081c
commit 1891d76591
9 changed files with 389 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.11" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+32
View File
@@ -0,0 +1,32 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="11">
<item index="0" class="java.lang.String" itemvalue="notebook_shim" />
<item index="1" class="java.lang.String" itemvalue="jupyter_server" />
<item index="2" class="java.lang.String" itemvalue="jupyterlab_widgets" />
<item index="3" class="java.lang.String" itemvalue="automium_web" />
<item index="4" class="java.lang.String" itemvalue="jupyterlab_pygments" />
<item index="5" class="java.lang.String" itemvalue="jupyter_client" />
<item index="6" class="java.lang.String" itemvalue="typing_extensions" />
<item index="7" class="java.lang.String" itemvalue="jupyter_server_terminals" />
<item index="8" class="java.lang.String" itemvalue="prometheus_client" />
<item index="9" class="java.lang.String" itemvalue="jupyter_core" />
<item index="10" class="java.lang.String" itemvalue="jupyterlab_server" />
</list>
</value>
</option>
</inspection_tool>
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="statsmodels.tsa.arima.model.*" />
</list>
</option>
</inspection_tool>
</profile>
</component>
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="C:\Users\0piet\miniconda3" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Mandelbrot.iml" filepath="$PROJECT_DIR$/.idea/Mandelbrot.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+199
View File
@@ -0,0 +1,199 @@
import os
import pygame
import numpy as np
import pyopencl as cl
import threading
from queue import Queue as ThreadQueue
os.environ['PYOPENCL_COMPILER_OUTPUT'] = '1'
os.environ['PYOPENCL_NO_CACHE'] = '1'
# Constants
WIDTH, HEIGHT = 800, 600
INITIAL_MAX_ITER = 256
ZOOM_FACTOR = 1.2
MIN_RENDER_WIDTH, MIN_RENDER_HEIGHT = 100, 75
MAX_RENDER_WIDTH, MAX_RENDER_HEIGHT = WIDTH, HEIGHT
# Initialize Pygame
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mandelbrot Set Zoom")
# OpenCL setup
platform = cl.get_platforms()[0]
device = platform.get_devices()[0]
context = cl.Context([device])
queue = cl.CommandQueue(context)
program_src = """
__kernel void mandelbrot(
const int width, const int height,
const float xmin, const float xmax,
const float ymin, const float ymax,
const int max_iter, __global int* output) {
int gid = get_global_id(0);
int x = gid % width;
int y = gid / width;
float real = xmin + (xmax - xmin) * x / (float) width;
float imag = ymin + (ymax - ymin) * y / (float) height;
float c_real = real;
float c_imag = imag;
int iter;
for (iter = 0; iter < max_iter; iter++) {
float real2 = real * real;
float imag2 = imag * imag;
if (real2 + imag2 > 4.0f) break;
imag = 2.0f * real * imag + c_imag;
real = real2 - imag2 + c_real;
}
output[gid] = iter;
}
"""
program = cl.Program(context, program_src).build()
# Functions to calculate Mandelbrot set using OpenCL
def mandelbrot_set(xmin, xmax, ymin, ymax, width, height, max_iter):
output = np.empty((height, width), dtype=np.int32)
output_buffer = cl.Buffer(context, cl.mem_flags.WRITE_ONLY, output.nbytes)
program.mandelbrot(queue, (width * height,), None,
np.int32(width), np.int32(height),
np.float32(xmin), np.float32(xmax),
np.float32(ymin), np.float32(ymax),
np.int32(max_iter), output_buffer)
cl.enqueue_copy(queue, output, output_buffer).wait()
return output
# Function to draw the Mandelbrot set with colors
def draw_mandelbrot(surface, mandelbrot_image, width, height, max_iter):
for x in range(width):
for y in range(height):
iter_count = mandelbrot_image[y, x]
if iter_count == max_iter:
color = (0, 0, 0)
else:
color = (iter_count % 256, (iter_count * 5) % 256, (iter_count * 13) % 256)
surface.set_at((x, y), color)
# Initial boundaries
xmin, xmax = -2.0, 1.0
ymin, ymax = -1.5, 1.5
# Initial resolution and iteration count
RENDER_WIDTH, RENDER_HEIGHT = 800, 600
MAX_ITER = INITIAL_MAX_ITER
# Create a surface for rendering
render_surface = pygame.Surface((RENDER_WIDTH, RENDER_HEIGHT))
# Variables for pre-rendering
next_mandelbrot_image = None
next_render_surface = None
needs_update = False
is_rendering = False
# Render queue setup
render_queue = ThreadQueue()
render_thread = None
def render_worker():
global next_mandelbrot_image, next_render_surface, is_rendering
while True:
task = render_queue.get()
if task is None:
break
print("Pre-rendering started")
is_rendering = True
next_mandelbrot_image = mandelbrot_set(xmin, xmax, ymin, ymax, RENDER_WIDTH, RENDER_HEIGHT, MAX_ITER)
next_render_surface = pygame.Surface((RENDER_WIDTH, RENDER_HEIGHT))
draw_mandelbrot(next_render_surface, next_mandelbrot_image, RENDER_WIDTH, RENDER_HEIGHT, MAX_ITER)
is_rendering = False
print("Pre-rendering finished")
render_queue.task_done()
def start_new_render():
global render_thread, needs_update
if render_thread is None or not render_thread.is_alive():
render_thread = threading.Thread(target=render_worker)
render_thread.start()
render_queue.put(True)
needs_update = True
def auto_zoom(zoom_factor, mouse_x, mouse_y):
global xmin, xmax, ymin, ymax, RENDER_WIDTH, RENDER_HEIGHT, MAX_ITER
# Convert screen coordinates to fractal coordinates
x_center = xmin + (xmax - xmin) * mouse_x / WIDTH
y_center = ymin + (ymax - ymin) * mouse_y / HEIGHT
width = (xmax - xmin) / zoom_factor
height = (ymax - ymin) / zoom_factor
xmin, xmax = x_center - width / 2, x_center + width / 2
ymin, ymax = y_center - height / 2, y_center + height / 2
RENDER_WIDTH = min(MAX_RENDER_WIDTH, int(RENDER_WIDTH * zoom_factor))
RENDER_HEIGHT = min(MAX_RENDER_HEIGHT, int(RENDER_HEIGHT * zoom_factor))
MAX_ITER = min(2048, int(MAX_ITER * zoom_factor))
return pygame.Surface((RENDER_WIDTH, RENDER_HEIGHT))
# Start pre-rendering the first frame
start_new_render()
# Main loop
running = True
auto_zooming = False
mouse_x, mouse_y = WIDTH // 2, HEIGHT // 2 # Default to center
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
auto_zooming = not auto_zooming
print("Auto-zooming:", "ON" if auto_zooming else "OFF")
elif event.type == pygame.MOUSEMOTION:
mouse_x, mouse_y = event.pos
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and not is_rendering: # Left mouse button for zoom in
render_surface = auto_zoom(ZOOM_FACTOR, *event.pos)
start_new_render()
print(f"Zoom in at {event.pos}: needs_update set to True")
elif event.button == 3 and not is_rendering: # Right mouse button for zoom out
render_surface = auto_zoom(1/ZOOM_FACTOR, *event.pos)
start_new_render()
print(f"Zoom out at {event.pos}: needs_update set to True")
elif event.type == pygame.MOUSEWHEEL and not is_rendering:
if event.y > 0: # Scroll up for zoom in
render_surface = auto_zoom(ZOOM_FACTOR, mouse_x, mouse_y)
start_new_render()
print(f"Scroll up zoom at ({mouse_x}, {mouse_y}): needs_update set to True")
elif event.y < 0: # Scroll down for zoom out
render_surface = auto_zoom(1/ZOOM_FACTOR, mouse_x, mouse_y)
start_new_render()
print(f"Scroll down zoom at ({mouse_x}, {mouse_y}): needs_update set to True")
if auto_zooming and not is_rendering:
render_surface = auto_zoom(ZOOM_FACTOR, mouse_x, mouse_y)
start_new_render()
print(f"Auto zoom at ({mouse_x}, {mouse_y}): needs_update set to True")
if next_render_surface is not None:
print("Updating render_surface with pre-rendered surface")
render_surface = next_render_surface
next_render_surface = None
next_mandelbrot_image = None
needs_update = False
if not is_rendering and not auto_zooming:
start_new_render()
# Scale the render surface to the screen size and blit it
scaled_surface = pygame.transform.scale(render_surface, (WIDTH, HEIGHT))
screen.blit(scaled_surface, (0, 0))
pygame.display.flip()
# Cleanup
render_queue.put(None)
if render_thread:
render_thread.join()
pygame.quit()
+115
View File
@@ -0,0 +1,115 @@
import pygame
import numpy as np
from concurrent.futures import ThreadPoolExecutor
# Constants
WIDTH, HEIGHT = 800, 600
MAX_ITER = 256
ZOOM_FACTOR = 1.2
RENDER_WIDTH, RENDER_HEIGHT = 400, 300 # Lower resolution for rendering
# Initialize Pygame
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mandelbrot Set Zoom")
# Functions to calculate Mandelbrot set
def mandelbrot(c, max_iter):
z = c
for n in range(max_iter):
if abs(z) > 2:
return n
z = z * z + c
return max_iter
def mandelbrot_row(xmin, xmax, ymin, ymax, width, height, max_iter, y):
r1 = np.linspace(xmin, xmax, width)
r2 = np.linspace(ymin, ymax, height)
row = np.empty(width, dtype=np.int32)
for i in range(width):
row[i] = mandelbrot(r1[i] + 1j * r2[y], max_iter)
return row
def mandelbrot_set(xmin, xmax, ymin, ymax, width, height, max_iter):
with ThreadPoolExecutor() as executor:
rows = list(executor.map(lambda y: mandelbrot_row(xmin, xmax, ymin, ymax, width, height, max_iter, y), range(height)))
return np.array(rows)
def draw_mandelbrot(surface, mandelbrot_image, width, height):
for x in range(width):
for y in range(height):
color_value = mandelbrot_image[y, x] / MAX_ITER * 255
color = (int(color_value), int(color_value), int(color_value))
surface.set_at((x, y), color)
# Initial boundaries
xmin, xmax = -2.0, 1.0
ymin, ymax = -1.5, 1.5
# Create a surface for rendering
render_surface = pygame.Surface((RENDER_WIDTH, RENDER_HEIGHT))
# Main loop
running = True
needs_update = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Left mouse button for zoom in
mouse_x, mouse_y = event.pos
mouse_x = mouse_x * RENDER_WIDTH // WIDTH
mouse_y = mouse_y * RENDER_HEIGHT // HEIGHT
r1 = np.linspace(xmin, xmax, RENDER_WIDTH)
r2 = np.linspace(ymin, ymax, RENDER_HEIGHT)
x_center = r1[mouse_x]
y_center = r2[mouse_y]
width = (xmax - xmin) / ZOOM_FACTOR
height = (ymax - ymin) / ZOOM_FACTOR
xmin, xmax = x_center - width / 2, x_center + width / 2
ymin, ymax = y_center - height / 2, y_center + height / 2
needs_update = True
elif event.button == 3: # Right mouse button for zoom out
mouse_x, mouse_y = event.pos
mouse_x = mouse_x * RENDER_WIDTH // WIDTH
mouse_y = mouse_y * RENDER_HEIGHT // HEIGHT
r1 = np.linspace(xmin, xmax, RENDER_WIDTH)
r2 = np.linspace(ymin, ymax, RENDER_HEIGHT)
x_center = r1[mouse_x]
y_center = r2[mouse_y]
width = (xmax - xmin) * ZOOM_FACTOR
height = (ymax - ymin) * ZOOM_FACTOR
xmin, xmax = x_center - width / 2, x_center + width / 2
ymin, ymax = y_center - height / 2, y_center + height / 2
needs_update = True
elif event.type == pygame.MOUSEWHEEL:
if event.y > 0: # Scroll up for zoom in
x_center = (xmin + xmax) / 2
y_center = (ymin + ymax) / 2
width = (xmax - xmin) / ZOOM_FACTOR
height = (ymax - ymin) / ZOOM_FACTOR
xmin, xmax = x_center - width / 2, x_center + width / 2
ymin, ymax = y_center - height / 2, y_center + height / 2
needs_update = True
elif event.y < 0: # Scroll down for zoom out
x_center = (xmin + xmax) / 2
y_center = (ymin + ymax) / 2
width = (xmax - xmin) * ZOOM_FACTOR
height = (ymax - ymin) * ZOOM_FACTOR
xmin, xmax = x_center - width / 2, x_center + width / 2
ymin, ymax = y_center - height / 2, y_center + height / 2
needs_update = True
if needs_update:
mandelbrot_image = mandelbrot_set(xmin, xmax, ymin, ymax, RENDER_WIDTH, RENDER_HEIGHT, MAX_ITER)
draw_mandelbrot(render_surface, mandelbrot_image, RENDER_WIDTH, RENDER_HEIGHT)
needs_update = False
# Scale the render surface to the screen size and blit it
scaled_surface = pygame.transform.scale(render_surface, (WIDTH, HEIGHT))
screen.blit(scaled_surface, (0, 0))
pygame.display.flip()
pygame.quit()