commit 2c643765d01791827865e6ea4932da8a96a8d7e5 Author: That_One_Nerd Date: Fri Sep 30 20:45:29 2022 -0400 Add files via upload diff --git a/main.py b/main.py new file mode 100644 index 0000000..ad2f1eb --- /dev/null +++ b/main.py @@ -0,0 +1,110 @@ +from objects import * +from useful import * + +from threading import Thread +import pygame + +def main(): + try: + print("Initializing...") + data.multithreading = settings.useMultithreading + data.running = True + pygame.init() + pygame.display.set_mode(settings.resolution) + data.display = pygame.display.get_surface() + data.pixelScale = int(pow(2, settings.maxPixelScale - 1)) + + if settings.useMultithreading: beginMultithreading() + + print("Ready") + + minPixelScale = int(pow(2, settings.minPixelScale - 1)) + while data.running and data.pixelScale >= minPixelScale: + render() + if not data.multithreading: pygame.display.update() + getInputs() + data.pixelScale /= 2 + + data.multithreading = False + pygame.display.update() + while data.running: + getInputs() + finally: + print("Closing...") + if settings.useMultithreading: endMultithreading() + pygame.quit() + +# begins any threads required for multithreading +def beginMultithreading(): + print("Beginning multithreading") + data.monitor = Thread(target=m_Monitor) + data.monitor.start() + +# kills all threads other than the main thread +def endMultithreading(): + print("Ending multithreading") + data.multithreading = False + data.monitor.join() + +# a monitor to constantly update the screen. +# only used in multithreading. +def m_Monitor(): + while data.multithreading: + pygame.display.update() + +# gets pygame inputs +def getInputs(): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + data.running = False + return + +# renders a screen of fractal +def render(): + for y in range(int(settings.resolution[1] / data.pixelScale)): + if data.multithreading: + pygame.draw.rect(data.display, (0, 0, 0), (0, y * data.pixelScale, settings.resolution[0], data.pixelScale)) + pygame.draw.rect(data.display, (255, 255, 255), (0, (y + 1) * data.pixelScale, settings.resolution[0], data.pixelScale)) + for x in range(int(settings.resolution[0] / data.pixelScale)): + unit = pixelsToUnits(x * data.pixelScale, y * data.pixelScale) + pygame.draw.rect(data.display, getColor(unit[0], unit[1]), (x * data.pixelScale, y * data.pixelScale, data.pixelScale, data.pixelScale)) + getInputs() + +# converts a given display pixel into the proper world coordinates. +# this is where the zoom and offset are factored in. +def pixelsToUnits(x, y): + fX = x / settings.resolution[0] + fY = y / settings.resolution[1] + fX = fX * 2 - 1 + fY = fY * 2 - 1 + fX *= settings.scale + fY *= settings.scale + fX += settings.offset[0] + fY += settings.offset[1] + return (fX, fY) + +# gets a color for a given coordinate. +# this function is just a handler for fractalContains() +def getColor(x, y): + insideColor = (0, 0, 0) + outsideColor = (0, 0, 255) + + val = fractalContains(x, y) + if val == -1: return insideColor + + percent = val / settings.fractalIterations + percent = sqrt(percent).real + return(outsideColor[0] * percent, outsideColor[1] * percent, outsideColor[2] * percent) + +# returns -1 if the point x + yi is contained in the fractal, otherwise +# it returns how many iterations it took to be determined outside. +# this is also where you can modify the recursive function +def fractalContains(x, y): + c = complex(x, y) + x = c + for i in range(settings.fractalIterations): + x = x * x + c + if x.__abs__() >= 2: return i + return -1 + +if __name__ == "__main__": main() diff --git a/objects.py b/objects.py new file mode 100644 index 0000000..f14d18a --- /dev/null +++ b/objects.py @@ -0,0 +1,27 @@ +from threading import Thread +import pygame + +# this is data for the program, and shouldn't be manually modified +class data: + display = pygame.Surface + monitor = Thread + multithreading = bool + running = bool + pixelScale = int + +# these are user settings. can be set to whatever +class settings: + # amount of iterations needed for the fractal + fractalIterations = 256 + # beginning upscale level + maxPixelScale = 8 + # ending upscale level + minPixelScale = 1 + # offset in world coordinates + offset = (-0.5, 0) + # the resolution will work best when set to a power of 2 + resolution = (512, 512) + # zoom level + scale = 2 + # enable/disable multithreading + useMultithreading = True diff --git a/useful.py b/useful.py new file mode 100644 index 0000000..375e16f --- /dev/null +++ b/useful.py @@ -0,0 +1,22 @@ +from cmath import sqrt +from random import random + +def magXY(x1, y1, x2, y2): + diffX = x2 - x1 + diffY = y2 - y1 + return sqrt(diffX * diffX + diffY * diffY).real +def magXYZ(x1, y1, z1, x2, y2, z2): + diffX = x2 - x1 + diffY = y2 - y1 + diffZ = z2 - z1 + return sqrt(diffX * diffX + diffY * diffY + diffZ * diffZ).real + +def normalizeColor(color): + mag = magXYZ(0, 0, 0, color[0], color[1], color[2]) / 255 + return (color[0] / mag, color[1] / mag, color[2] / mag) + +def randomColor(): + return (randomInt(255), randomInt(255), randomInt(255)) + +def randomInt(max): + return int(random() * max)