Another python demo, (enter to toggle between editor and demos, T to switch between demos), added code to delete modules from python VM so they get reloaded properly on code changes.

This commit is contained in:
Bobby Lucero 2024-10-12 19:34:16 -04:00
parent 611b6def6a
commit 29e3ba208e
6 changed files with 175 additions and 1393 deletions

View File

@ -15,8 +15,8 @@ class Blobs(Scene):
def draw(self): def draw(self):
clear(0) clear(0)
for i in range(128): for i in range(width):
for j in range(128): for j in range(height):
c = cos(i / 10) + (sin(j / 10) + 2) c = cos(i / 10) + (sin(j / 10) + 2)
#c2 = cos(i / 5) + sin(j / 5) #c2 = cos(i / 5) + sin(j / 5)
pixel(i, j, 2 * c + self.t) pixel(i, j, 2 * c + self.t)

View File

@ -3,7 +3,7 @@ from particles import Particles
from triangles import Triangles from triangles import Triangles
from squares import Squares from squares import Squares
from blobs import Blobs from blobs import Blobs
from mechanical import Mechanical from threeD import ThreeD
# Palette class (inherits from scene) # Palette class (inherits from scene)
class Palette(Scene): class Palette(Scene):
@ -29,11 +29,9 @@ class RGBTest(Scene):
self.title = "RGB To Palette" self.title = "RGB To Palette"
scenes = [Particles(), Triangles(), Palette(), Squares(), Blobs()] scenes = [ ThreeD(), Particles(), Squares(), Triangles(), Palette(), Blobs()]
current_scene = 0 current_scene = 0
KEY_T = 84 KEY_T = 84
switch = False switch = False
@ -53,3 +51,6 @@ def update():
if(not scenes[current_scene].paused): if(not scenes[current_scene].paused):
scenes[current_scene].update() scenes[current_scene].update()
scenes[current_scene].draw() scenes[current_scene].draw()
text("T to change scene", 255, 1,31)

File diff suppressed because it is too large Load Diff

159
python/threeD.py Normal file
View File

@ -0,0 +1,159 @@
from scene import Scene
from triangles import draw_line
import math
# Palette class (inherits from scene)
class ThreeD(Scene):
def __init__(self):
super().__init__()
self.title = "Squares"
self.t = 0
self.x = 0.01
self.y = 0
self.z = 0
self.a = 10
self.b = 28
self.c = 8.0/3.0
self.scale = 5
self.focal_length = 800
self.screen_width = width * 4
self.screen_height = height * 4
self.lines = []
self.points = []
self.gradient = [4, 8, 6, 15, 18, 19, 26, 25, 24, 23, 16, 23, 22, 7, 5]
def update(self):
self.t += 0.00002
if(len(self.points) > 1200):
return
dx = (self.a * (self.y - self.x)) * self.t
dy = (self.x * (self.b - self.z) - self.y) * self.t
dz = (self.x * self.y - self.c * self.z) * self.t
self.x += dx
self.y += dy
self.z += dz
self.points.append((self.x, self.y, self.z))
def line3D(self, x1, y1, z1, x2, y2, z2, c):
self.lines.append(((x1, y1, z1), (x2, y2, z2), c))
def draw(self):
self.lines.clear()
clear(0)
for i in range(len(self.points)):
size = len(self.points)
if(i < size - 1):
x, y, z = self.points[i]
x2, y2, z2 = self.points[i + 1]
x *= self.scale
y *= self.scale
z *= self.scale
x2 *= self.scale
y2 *= self.scale
z2 *= self.scale
self.line3D(x, y, z, x2, y2, z2, self.gradient[int(i / 5) % len(self.gradient)])
self.render_scene(self.focal_length, self.screen_width, self.screen_height, 0, self.t*500, self.t * 200, 0, 0, 300)
def rotate_point(self, x, y, z, angle_x, angle_y, angle_z):
"""Rotates a point around the X, Y, and Z axes."""
# Rotation around the X axis
cos_x, sin_x = math.cos(angle_x), math.sin(angle_x)
y, z = y * cos_x - z * sin_x, y * sin_x + z * cos_x
# Rotation around the Y axis
cos_y, sin_y = math.cos(angle_y), math.sin(angle_y)
x, z = x * cos_y + z * sin_y, -x * sin_y + z * cos_y
# Rotation around the Z axis
cos_z, sin_z = math.cos(angle_z), math.sin(angle_z)
x, y = x * cos_z - y * sin_z, x * sin_z + y * cos_z
return x, y, z
def project_point(self, x, y, z, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z):
x, y, z = self.rotate_point(x, y, z, angle_x, angle_y, angle_z)
# Apply translation
x += translate_x
y += translate_y
z += translate_z
"""Projects a 3D point onto a 2D screen using perspective projection."""
if z == 0:
z = 0.001 # Avoid division by zero
# Perspective projection formula
screen_x = (x * focal_length) / z
screen_y = (y * focal_length) / z
# Translate to screen coordinates (centered)
screen_x += screen_width / 2
screen_y += screen_height / 2
return screen_x, screen_y
def z_sort_lines(self, lines):
"""Sorts lines based on their average Z values for depth ordering."""
return sorted(lines, key=lambda line: (line[0][2] + line[1][2]) / 2, reverse=True)
def draw_3d_line(self, x1, y1, z1, x2, y2, z2, focal_length, screen_width, screen_height, color, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z):
"""Draws a 3D line projected onto a 2D screen."""
# Project the endpoints
screen_x1, screen_y1 = self.project_point(x1, y1, z1, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z)
screen_x2, screen_y2 = self.project_point(x2, y2, z2, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z)
# Use the renderer to draw the line on the screen
draw_line(int(screen_x1) / 4, int(screen_y1) / 4, int(screen_x2) / 4, int(screen_y2) / 4, color)
def render_scene(self, focal_length, screen_width, screen_height, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z):
"""Renders the 3D lines in the scene with perspective projection and Z-sorting."""
# Sort the lines by Z value (depth)
sorted_lines = self.z_sort_lines(self.lines)
i = 0
# Draw each line
for line in sorted_lines:
(x1, y1, z1), (x2, y2, z2), c = line
self.draw_3d_line(x1, y1, z1, x2, y2, z2, focal_length, screen_width, screen_height, c, angle_x, angle_y, angle_z, translate_x, translate_y, translate_z)
i += 1
# Example usage
# renderer is an object that has a draw_line(x1, y1, x2, y2) function
liines = [
((-50, -50, -50), (50, -50, -50)),
((50, -50, -50), (50, 50, -50)),
((50, 50, -50), (-50, 50, -50)),
((-50, 50, -50), (-50, -50, -50)),
((-50, -50, 50), (50, -50, 50)),
((50, -50, 50), (50, 50, 50)),
((50, 50, 50), (-50, 50, 50)),
((-50, 50, 50), (-50, -50, 50)),
((-50, -50, -50), (-50, -50, 50)),
((50, -50, -50), (50, -50, 50)),
((50, 50, -50), (50, 50, 50)),
((-50, 50, -50), (-50, 50, 50)),
]
# Assuming you have a renderer object

View File

@ -14,7 +14,7 @@
EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphics(graphics){ EditorState::EditorState(pkpy::VM *vm, Graphics *graphics) : m_vm(vm), m_graphics(graphics){
m_pythonTokenizer = new PythonTokenizer(); m_pythonTokenizer = new PythonTokenizer();
std::string randomSource = Pycron::loadFileToString("../python/particles.py"); std::string randomSource = Pycron::loadFileToString("../python/threeD.py");
//randomSource = Pycron::loadFileToString("../src/States/Editor/EditorState.cpp"); //randomSource = Pycron::loadFileToString("../src/States/Editor/EditorState.cpp");
m_editorFrame = m_graphics->loadImage("../resources/EditorFrame.png"); m_editorFrame = m_graphics->loadImage("../resources/EditorFrame.png");

View File

@ -11,6 +11,7 @@
GameState::GameState(pkpy::VM* vm, Graphics* graphics) :m_vm(vm), m_graphics(graphics){ GameState::GameState(pkpy::VM* vm, Graphics* graphics) :m_vm(vm), m_graphics(graphics){
m_updateFunction = nullptr; m_updateFunction = nullptr;
m_previousError = ""; m_previousError = "";
} }
void GameState::Draw() { void GameState::Draw() {
@ -28,10 +29,15 @@ void GameState::Draw() {
void GameState::OnEnter() { void GameState::OnEnter() {
m_graphics->Clear(0); m_graphics->Clear(0);
PreProcessScripts(); PreProcessScripts();
} }
void GameState::OnExit() { void GameState::OnExit() {
for(const auto& pair : m_vm->_lazy_modules){
m_vm->_modules.del(pair.first);
}
m_vm->_lazy_modules.clear(); m_vm->_lazy_modules.clear();
m_updateFunction = m_vm->None; m_updateFunction = m_vm->None;
} }
@ -80,6 +86,8 @@ std::unordered_map<std::string, std::string> GameState::readPythonFiles(const st
} }
void GameState::loadPythonModules(std::unordered_map<std::string, std::string> &fileContents) { void GameState::loadPythonModules(std::unordered_map<std::string, std::string> &fileContents) {
m_vm->_lazy_modules.clear();
for(const auto& pair : fileContents){ for(const auto& pair : fileContents){
try{ try{
if(pair.first != MAIN_FILE){ if(pair.first != MAIN_FILE){