Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save DenisBelmondo/d210926df4ee7e4bb39f9936e73f49a4 to your computer and use it in GitHub Desktop.
Save DenisBelmondo/d210926df4ee7e4bb39f9936e73f49a4 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import ctypes
import threading
import time
import tkinter as tk
def _main() -> None:
done = False
h = b'P6 320 240 255 '
hlen = len(h)
blen = hlen + 320 * 240 * 3
b1 = ctypes.create_string_buffer(blen)
b2 = ctypes.create_string_buffer(blen)
b1[0:hlen] = h
b2[0:hlen] = h
root = tk.Tk()
def on_delete_window() -> None:
nonlocal done
root.destroy()
done = True
root.protocol('WM_DELETE_WINDOW', on_delete_window)
photo = tk.PhotoImage(data=b1.raw)
label = tk.Label(root, image=photo)
def render_loop() -> None:
b = b1
worldMap = (
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 3, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 2, 0, 0, 0, 0, 0, 0, 0, 1,
1, 2, 0, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 3, 0, 0, 0, 0, 0, 0, 0, 1,
1, 3, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
)
worldMapWidth = 10
posX = 5
posY = 5
dirX = -1
dirY = 0
planeX = 0
planeY = 0.66
newTime = 0
oldTime = time.time()
while not done:
x = 0
while x < 320:
cameraX = 2 * x / 320 - 1
rayDirX = dirX + planeX * cameraX
rayDirY = dirY + planeY * cameraX
mapX = int(posX)
mapY = int(posY)
sideDistX = 0
sideDistY = 0
deltaDistX = abs(rayDirX and (1 / rayDirX) or 1e30)
deltaDistY = abs(rayDirY and (1 / rayDirY) or 1e30)
perpWallDist = 0
stepX = 0
stepY = 0
hit = 0
side = 0
if rayDirX < 0:
stepX = -1
sideDistX = (posX - mapX) * deltaDistX
else:
stepX = 1
sideDistX = (mapX + 1 - posX) * deltaDistX
if rayDirY < 0:
stepY = -1
sideDistY = (posY - mapY) * deltaDistY
else:
stepY = 1
sideDistY = (mapY + 1 - posY) * deltaDistY
while hit == 0:
if sideDistX < sideDistY:
sideDistX += deltaDistX
mapX += stepX
side = 0
else:
sideDistY += deltaDistY
mapY += stepY
side = 1
if worldMap[mapY * worldMapWidth + mapX != 0]:
hit = worldMap[mapY * worldMapWidth + mapX]
if side == 0:
perpWallDist = sideDistX - deltaDistX
else:
perpWallDist = sideDistY - deltaDistY
lineHeight = int(perpWallDist and (240 / perpWallDist) or 0)
drawStart = -lineHeight // 2 + 240 // 2
if drawStart < 0:
drawStart = 0
drawEnd = lineHeight // 2 + 240 // 2
if drawEnd >= 240:
drawEnd = 240 - 1
#
# draw vertical line
#
y = 0
while y < 240:
# this could probably be made to be more efficient
cr = 0
cg = 0
cb = 0
if y >= drawStart and y <= drawEnd:
if hit == 1:
cr = 255
elif hit == 2:
cg = 255
elif hit == 3:
cb = 255
if side == 1:
cr //= 2
cg //= 2
cb //= 2
b[hlen+(y*320+x)*3] = cr
b[hlen+(y*320+x)*3+1] = cg
b[hlen+(y*320+x)*3+2] = cb
y += 1
x += 1
newTime = time.time()
frameTime = newTime - oldTime
oldTime = newTime
posY -= frameTime / 2
# this does essentially <widget>.configure(data=<bytes>) but
# without unnecessary overhead
photo.tk.call((photo.name, 'config', '-data', b.raw))
if b == b1:
b = b2
else:
b = b1
label.pack()
root.geometry('320x240')
t = threading.Thread(target=render_loop, daemon=True)
t.start()
root.mainloop()
if __name__ == '__main__':
_main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment