<reponame>DrummerSly/3D-ASCII-Spinning-Donut<gh_stars>0
import os
import pygame
import configparser
import tkinter
from math import cos, sin
from pygame import *

def IntCon(header, option):
    return int(con[header][option])

con = configparser.ConfigParser()
con.read('settings.ini')

vRed, vGrn, vBlu = con['Video']['Color'].split(',')
vBackgrd = (int(vRed), int(vGrn), int(vBlu))

fRed, fGrn, fBlu = con['Font']['Color'].split(',')
fCol = (int(fRed), int(fGrn), int(fBlu))

os.environ['SDL_VIDEO_CENTERED'] = '1'

pixWidth = IntCon('Donut', 'UCharacters')
pixHeight = IntCon('Donut', 'UCharacters')

xPix = 0
yPix = 0

scrWidth = tkinter.Tk().winfo_screenwidth() // pixWidth
scrHeight = tkinter.Tk().winfo_screenheight() // pixHeight

A, B = 0, 0

chars = con['Font']['Characters']

R1 = IntCon('Donut', 'Thickness')
K1 = scrHeight * 100 * 3 / (8 * (R1 + 20))

init()
scr = display.set_mode((0, 0), FULLSCREEN, vsync = IntCon('Video', 'VSync'))
clock = time.Clock()
font = font.SysFont(con['Font']['Font'], IntCon('Font', 'Size'), bold = IntCon('Font', 'Bold'), italic = IntCon('Font', 'Italic'))

def TxtDisplay(char, x, y):
    txt = font.render(char, True, fCol)
    scr.blit(txt, txt.get_rect(center = (x, y)))

k = 0

paused = False
running = True

while running:
    clock.tick(IntCon('Video', 'FPS'))
    display.set_caption("Spinning Donut")
    scr.fill(vBackgrd)

    out = [' '] * (scrWidth * scrHeight)
    zBuf = [0] * (scrWidth * scrHeight)

    for theta in range(0, 628, IntCon('Donut', 'TSpacing')):
            for phi in range(0, 628, IntCon('Donut', 'PSpacing')):
               cosA = cos(A)
               cosB = cos(B)
               sinA = sin(A)
               sinB = sin(B)

               costheta = cos(theta)
               sintheta = sin(theta)
               cosphi = cos(phi)
               sinphi = sin(phi)

               cirX = 20 + R1 * costheta
               cirY = R1 * sintheta

               ooz = 1 / (100 + cosA * cirX * sinphi + cirY * sinA)

               pos = int(scrWidth / 2 + K1 * ooz * (cirX * (cosB * cosphi + sinA * sinB * sinphi) - cirY * cosA * sinB)) + scrWidth * int(scrHeight / 2 - K1 * ooz * (cirX * (sinB * cosphi - sinA * cosB * sinphi) + cirY * cosA * cosB))

               if ooz > zBuf[pos]:
                   zBuf[pos] = ooz 
                   lumIndex = int((cosphi * costheta * sinB - cosA * costheta * sinphi - sinA * sintheta + cosB * (cosA * sintheta - costheta * sinA * sinphi)) * 8) 
                   out[pos] = chars[lumIndex if lumIndex > 0 else 0]

    for i in range(scrHeight):
        yPix += pixHeight
        for j in range(scrWidth):
            xPix += pixWidth
            TxtDisplay(out[k], xPix, yPix)
            k += 1
        xPix = 0
    yPix = 0
    k = 0

    if not paused:
        display.update()
        A += float(con['Donut']['SpeedX'])
        B += float(con['Donut']['SpeedY'])

    for event in pygame.event.get():
        if event.type == QUIT:
            running = False
        if event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                running = False 
            if event.key == K_SPACE:
                paused = not paused
