Added triangle demo scene, triangle algo needs work, probably needs to be rewritten

This commit is contained in:
Bobby Lucero 2024-04-27 23:14:48 -04:00
parent 9e48025846
commit c93eab9963
7 changed files with 434 additions and 154 deletions

View File

@ -1,30 +1,6 @@
from scene import Scene from scene import Scene
from particles import Particles
white = 63 from triangles import Triangles
fire1 = 6
fire2 = 5
fire3 = 4
fire4 = 3
fire5 = 2
fire6 = 56
water1 = 31
water2 = 30
water3 = 29
water4 = 28
fireGradient = [white, white, fire1, fire1, fire2, fire3, fire4, fire3, fire4, fire5, fire6, fire6, fire6]
waterGradient = [white, white, water1, water2, water3, water4, water4]
class Particle:
def __init__(self, x, y, velX, velY):
self.x = x
self.y = y
self.velX = velX
self.velY = velY
self.c = fireGradient[0]
self.size = 5
class Palette(Scene): class Palette(Scene):
@ -43,102 +19,10 @@ class Palette(Scene):
text(str(j * 8 + i), 11 + (i * 20), 10 + (j * 20), 63) text(str(j * 8 + i), 11 + (i * 20), 10 + (j * 20), 63)
class Main(Scene): scenes = [Particles(), Triangles(), Palette()]
current_scene = 0
def __init__(self):
super().__init__()
self.fireParts = []
self.waterParts = []
for i in range(10):
self.fireParts.append(Particle(width/2, height/2, rnd(-1, 1), rnd(-1, 1)))
self.waterParts.append(Particle(width/2, height/2, rnd(-1, 1), rnd(-1, 1)))
self.counter = 0
def update(self):
global mouseVelX
global mouseVelY
self.counter += 1
for p in self.fireParts[:]:
p.x += p.velX
p.y += p.velY
p.velX += rnd(-0.3,0.3)
p.velY += rnd(-0.3,0.3)
idx = int(p.size / 5.0 * len(fireGradient) - 1)
p.c = fireGradient[(len(fireGradient) - 1) - idx]
if(p.size < 1):
p.size -= 0.01
else:
p.size -= 0.05
if(p.size < 0):
self.fireParts.remove(p)
for p in self.waterParts[:]:
p.x += p.velX
p.y += p.velY
p.velX += rnd(-0.3,0.3)
p.velY += rnd(-0.3,0.3)
idx = int(p.size / 5.0 * len(waterGradient) - 1)
p.c = waterGradient[(len(waterGradient) - 1) - idx]
if(p.size < 1):
p.size -= 0.01
else:
p.size -= 0.05
if(p.size < 0):
self.waterParts.remove(p)
if(mouse(0)):
rad = sin(self.counter * 0.01) * 50
x1 = mouseX + (sin(self.counter * 0.1) * rad)
y1 = mouseY + (cos(self.counter * 0.1) * rad)
x2 = mouseX + (sin(self.counter * 0.1 + (3.141592653)) * rad)
y2 = mouseY + (cos(self.counter * 0.1 + (3.141592653)) * rad)
for i in range(10):
self.fireParts.append(Particle(x1, y1, rnd(-1,1) + mouseVelX * 0.25, rnd(-1,1) + mouseVelY * 0.25))
self.waterParts.append(Particle(x2, y2, rnd(-1,1) + mouseVelX * 0.25, rnd(-1,1) + mouseVelY * 0.25))
def draw(self):
clear(0)
for p in self.fireParts:
if(p.size <= 1):
pixel(p.x, p.y, p.c)
else:
circle(p.x, p.y, int(p.size), p.c)
for p in self.waterParts:
if(p.size <= 1):
pixel(p.x, p.y, p.c)
else:
circle(p.x, p.y, int(p.size), p.c)
text("C to add particles, T to toggle palette", 3, 3, 59)
text("C to add particles, T to toggle palette", 2, 2, 31)
text("Num Particles: " + str(len(self.fireParts) + len(self.waterParts)), 3, 16, 59)
text("Num Particles: " + str(len(self.fireParts) + len(self.waterParts)), 2, 15, 30)
text("FPS: " + str(fps()), 3, 29, 59)
text("FPS: " + str(fps()), 2, 28, 29)
paletteScene = Palette()
mainScene = Main()
current_scene = mainScene
oldMouseX = 0
oldMouseY = 0
mouseVelX = 0
mouseVelY = 0
KEY_T = 84 KEY_T = 84
@ -147,30 +31,21 @@ switch = False
def update(): def update():
global switch global switch
global current_scene global current_scene
global mouseVelX
global mouseVelY
global oldMouseX
global oldMouseY
mouseVelX = (mouseX - oldMouseX)
mouseVelY = (mouseY - oldMouseY)
oldMouseX = mouseX
oldMouseY = mouseY
if(keyp(KEY_T)): if(keyp(KEY_T)):
switch = not switch current_scene += 1
if(switch): if(current_scene >= len(scenes)):
current_scene = paletteScene current_scene = 0
else:
current_scene = mainScene
if(mousep(1)): if(mousep(1)):
current_scene.paused = not current_scene.paused scenes[current_scene].paused = not scenes[current_scene].paused
if(not scenes[current_scene].paused):
scenes[current_scene].update()
scenes[current_scene].draw()
text(scenes[current_scene].title, 2, 15, 63)
if(not current_scene.paused):
current_scene.update()
current_scene.draw()
circle(mouseX, mouseY, 3, 30)

136
python/particles.py Normal file
View File

@ -0,0 +1,136 @@
from scene import Scene
from triangles import draw_line
white = 63
fire1 = 6
fire2 = 5
fire3 = 4
fire4 = 3
fire5 = 2
fire6 = 56
water1 = 31
water2 = 30
water3 = 29
water4 = 28
fireGradient = [white, white, fire1, fire1, fire2, fire3, fire4, fire3, fire4, fire5, fire6, fire6, fire6]
waterGradient = [white, white, water1, water2, water3, water4, water4]
oldMouseX = 0
oldMouseY = 0
mouseVelX = 0
mouseVelY = 0
def tri(x1,y1,x2,y2,x3,y3,c):
draw_line(x1,y1,x2,y2,c)
draw_line(x2,y2,x3,y3,c)
draw_line(x1,y1,x3,y3,c)
class Particle:
def __init__(self, x, y, velX, velY):
self.x = x
self.y = y
self.velX = velX
self.velY = velY
self.c = fireGradient[0]
self.size = 5
class Particles(Scene):
def __init__(self):
super().__init__()
self.fireParts = []
self.waterParts = []
for i in range(10):
self.fireParts.append(Particle(width/2, height/2, rnd(-1, 1), rnd(-1, 1)))
self.waterParts.append(Particle(width/2, height/2, rnd(-1, 1), rnd(-1, 1)))
self.counter = 0
def update(self):
global mouseVelX
global mouseVelY
global oldMouseX
global oldMouseY
mouseVelX = (mouseX - oldMouseX)
mouseVelY = (mouseY - oldMouseY)
oldMouseX = mouseX
oldMouseY = mouseY
self.counter += 1
for p in self.fireParts[:]:
p.x += p.velX
p.y += p.velY
p.velX += rnd(-0.3,0.3)
p.velY += rnd(-0.3,0.3)
idx = int(p.size / 5.0 * len(fireGradient) - 1)
p.c = fireGradient[(len(fireGradient) - 1) - idx]
if(p.size < 1):
p.size -= 0.01
else:
p.size -= 0.05
if(p.size < 0):
self.fireParts.remove(p)
for p in self.waterParts[:]:
p.x += p.velX
p.y += p.velY
p.velX += rnd(-0.3,0.3)
p.velY += rnd(-0.3,0.3)
idx = int(p.size / 5.0 * len(waterGradient) - 1)
p.c = waterGradient[(len(waterGradient) - 1) - idx]
if(p.size < 1):
p.size -= 0.01
else:
p.size -= 0.05
if(p.size < 0):
self.waterParts.remove(p)
if(mouse(0)):
rad = sin(self.counter * 0.01) * 50
x1 = mouseX + (sin(self.counter * 0.1) * rad)
y1 = mouseY + (cos(self.counter * 0.1) * rad)
x2 = mouseX + (sin(self.counter * 0.1 + (3.141592653)) * rad)
y2 = mouseY + (cos(self.counter * 0.1 + (3.141592653)) * rad)
for i in range(10):
self.fireParts.append(Particle(x1, y1, rnd(-1,1) + mouseVelX * 0.25, rnd(-1,1) + mouseVelY * 0.25))
self.waterParts.append(Particle(x2, y2, rnd(-1,1) + mouseVelX * 0.25, rnd(-1,1) + mouseVelY * 0.25))
def draw(self):
clear(0)
for p in self.fireParts:
if(p.size <= 1):
pixel(p.x, p.y, p.c)
else:
circle(p.x, p.y, int(p.size), p.c)
for p in self.waterParts:
if(p.size <= 1):
pixel(p.x, p.y, p.c)
else:
circle(p.x, p.y, int(p.size), p.c)
text("C to add particles, T to toggle palette", 3, 3, 59)
text("C to add particles, T to toggle palette", 2, 2, 31)
text("Num Particles: " + str(len(self.fireParts) + len(self.waterParts)), 3, 16, 59)
text("Num Particles: " + str(len(self.fireParts) + len(self.waterParts)), 2, 15, 30)
text("FPS: " + str(fps()), 3, 29, 59)
text("FPS: " + str(fps()), 2, 28, 29)

View File

@ -2,6 +2,7 @@ class Scene:
def __init__(self): def __init__(self):
self.paused = False self.paused = False
self.title = ""
def update(self): def update(self):
pass pass

117
python/triangles.py Normal file
View File

@ -0,0 +1,117 @@
from scene import Scene
cols = [(6,8),(16,17),(31,30),(5,4),(41,40),(51,50)]
def draw_line(x0, y0, x1, y1, c):
x0 = int(x0)
y0 = int(y0)
x1 = int(x1)
y1 = int(y1)
"Bresenham's line algorithm"
dx = abs(x1 - x0)
dy = abs(y1 - y0)
x, y = x0, y0
sx = -1 if x0 > x1 else 1
sy = -1 if y0 > y1 else 1
if dx > dy:
err = dx / 2.0
while x != x1:
pixel(x, y, c)
err -= dy
if err < 0:
y += sy
err += dx
x += sx
else:
err = dy / 2.0
while y != y1:
pixel(x, y, c)
err -= dx
if err < 0:
x += sx
err += dy
y += sy
pixel(x, y, c)
def lineTri(x1,y1,x2,y2,x3,y3,c):
draw_line(x1,y1,x2,y2,c)
draw_line(x2,y2,x3,y3,c)
draw_line(x1,y1,x3,y3,c)
class spinTri():
def __init__(self):
self.x = rnd(0,width)
self.y = 240
self.r = 4 + rnd(0, 4)
self.t = rnd(0, 1)
self.a = rnd(0, 1)
self.vy = -0.5-rnd(0,1)
self.c = int(rnd(0, len(cols)))
self.colidx = 0
self.count = rnd(0,50)
class Triangles(Scene):
def __init__(self):
super().__init__()
self.p = []
self.t = 0.0
self.count = 0
self.tpo3 = (2 * 3.141592654)/3
self.skip = False
def draw(self):
self.skip = not self.skip
if(self.skip):
return
self.t += 0.01
self.count += 1
for i in range(999):
x = rnd(0, width)
y = rnd(0, height)
c = 0
if(rnd(0,9) < 5):
c = get_pixel(x,y-3)
else:
c = 0
circle(x, y, 1, c)
for pt in self.p[:]:
pt.y += pt.vy
pt.t += 0.05
pt.a += 0.1
pt.count += 1
r = (0.8 + 0.2 * cos(pt.t * 8)) * pt.r
x1 = pt.x + r * cos(pt.a)
y1 = pt.y + r * sin(pt.a)
x2 = pt.x + r * cos(pt.a + self.tpo3)
y2 = pt.y + r * sin(pt.a + self.tpo3)
x3 = pt.x + r * cos(pt.a + self.tpo3 * 2)
y3 = pt.y + r * sin(pt.a + self.tpo3 * 2)
if(int(pt.count) % 5 == 0):
pt.colidx += 1
if(pt.colidx >= len(cols)):
pt.colidx = 0
light, dark = cols[pt.colidx]
triangle(x1, y1, x2, y2, x3, y3, light)
lineTri(x1, y1, x2, y2, x3, y3, dark)
if(pt.y < - 40):
self.p.remove(pt)
#if(self.count % 3 == 0):
#for i in range(1):
self.p.append(spinTri())
# if(mousep(0)):
# self.p.append(spinTri())

View File

@ -131,34 +131,37 @@ void Graphics::toggleFullScreen() {
} }
void Graphics::bindMethods(pkpy::VM *vm) { void Graphics::bindMethods(pkpy::VM *vm) {
// vm->bind(vm->builtins, "clear(color: int)", reinterpret_cast<pkpy::NativeFuncC>(Clear)); vm->bind(vm->builtins, "clear(color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
// vm->bind(vm->builtins, "pixel(x: int, y: int, color: int)", reinterpret_cast<pkpy::NativeFuncC>(Pixel));
// vm->bind(vm->builtins, "circle(x: int, y: int, radius: float, color: int)", reinterpret_cast<pkpy::NativeFuncC>(Circle));
vm->bind(vm->builtins, "clear(color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){{
int index = pkpy::py_cast<int>(vm, args[0]); int index = pkpy::py_cast<int>(vm, args[0]);
Clear(index); Clear(index);
return vm->None; return vm->None;
}}); });
vm->bind(vm->builtins, "pixel(x: int, y: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){{ vm->bind(vm->builtins, "pixel(x: int, y: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
float x = pkpy::py_cast<float>(vm, args[0]); float x = pkpy::py_cast<float>(vm, args[0]);
float y = pkpy::py_cast<float>(vm, args[1]); float y = pkpy::py_cast<float>(vm, args[1]);
float paletteIndex = pkpy::py_cast<float>(vm, args[2]); float paletteIndex = pkpy::py_cast<float>(vm, args[2]);
this->Pixel(x, y, paletteIndex); this->Pixel(x, y, paletteIndex);
return vm->None; return vm->None;
}}); });
vm->bind(vm->builtins, "circle(x: int, y: int, radius: float, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){{ vm->bind(vm->builtins, "get_pixel(x: int, y: int) -> int", [this](pkpy::VM* vm, pkpy::ArgsView args){
float x = pkpy::py_cast<float>(vm, args[0]);
float y = pkpy::py_cast<float>(vm, args[1]);
return pkpy::py_var(vm, this->GetPixel(x, y));
});
vm->bind(vm->builtins, "circle(x: int, y: int, radius: float, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
float x = pkpy::py_cast<float>(vm, args[0]); float x = pkpy::py_cast<float>(vm, args[0]);
float y = pkpy::py_cast<float>(vm, args[1]); float y = pkpy::py_cast<float>(vm, args[1]);
float radius = pkpy::py_cast<float>(vm, args[2]); float radius = pkpy::py_cast<float>(vm, args[2]);
float paletteIndex = pkpy::py_cast<float>(vm, args[3]); float paletteIndex = pkpy::py_cast<float>(vm, args[3]);
this->Circle(x, y, radius, paletteIndex); this->Circle(x, y, radius, paletteIndex);
return vm->None; return vm->None;
}}); });
vm->bind(vm->builtins, "rectangle(x: int, y: int, width: int, height: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){{ vm->bind(vm->builtins, "rectangle(x: int, y: int, width: int, height: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
float x = pkpy::py_cast<float>(vm, args[0]); float x = pkpy::py_cast<float>(vm, args[0]);
float y = pkpy::py_cast<float>(vm, args[1]); float y = pkpy::py_cast<float>(vm, args[1]);
float width = pkpy::py_cast<float>(vm, args[2]); float width = pkpy::py_cast<float>(vm, args[2]);
@ -166,7 +169,19 @@ void Graphics::bindMethods(pkpy::VM *vm) {
float paletteIndex = pkpy::py_cast<float>(vm, args[4]); float paletteIndex = pkpy::py_cast<float>(vm, args[4]);
this->Rect(x, y, width, height, paletteIndex); this->Rect(x, y, width, height, paletteIndex);
return vm->None; return vm->None;
}}); });
vm->bind(vm->builtins, "triangle(x1: int, y1: int, x2: int, y2: int, x3: int, y3: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
float x1 = pkpy::py_cast<float>(vm, args[0]);
float y1 = pkpy::py_cast<float>(vm, args[1]);
float x2 = pkpy::py_cast<float>(vm, args[2]);
float y2 = pkpy::py_cast<float>(vm, args[3]);
float x3 = pkpy::py_cast<float>(vm, args[4]);
float y3 = pkpy::py_cast<float>(vm, args[5]);
float paletteIndex = pkpy::py_cast<float>(vm, args[6]);
this->Triangle(x1, y1, x2, y2, x3, y3, paletteIndex);
return vm->None;
});
vm->bind(vm->builtins, "text(t: string, x: int, y: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){ vm->bind(vm->builtins, "text(t: string, x: int, y: int, color: int)", [this](pkpy::VM* vm, pkpy::ArgsView args){
pkpy::PyObject* func_str = vm->builtins->attr("str"); pkpy::PyObject* func_str = vm->builtins->attr("str");
@ -342,6 +357,104 @@ void Graphics::v_line(int x, int y1, int y2, int paletteIndex) {
} }
} }
int Graphics::GetPixel(int x, int y) {
if(x < 0 || y < 0 || x >= m_screenWidth || y >= m_screenHeight) return 0;
return m_virtualScreenColorBuffer[y * m_screenWidth + x];
}
void Graphics::fillBottomFlatTriangle(float x1, float y1, float x2, float y2, float x3, float y3, int paletteIndex)
{
float invslope1 = (x2 - x1) / (y2 - y1);
float invslope2 = (x3 - x1) / (y3 - y1);
float curx1 = x1;
float curx2 = x1;
for (int scanlineY = y1; scanlineY <= y2; scanlineY++)
{
h_line((int)curx1, scanlineY, (int)curx2, paletteIndex);
curx1 += invslope1;
curx2 += invslope2;
}
}
void Graphics::fillTopFlatTriangle(float x1, float y1, float x2, float y2, float x3, float y3, int paletteIndex)
{
float invslope1 = (x3 - x1) / (y3 - y1);
float invslope2 = (x3 - x2) / (y3 - y2);
float curx1 = x3;
float curx2 = x3;
for (int scanlineY = y3; scanlineY > y1; scanlineY--)
{
h_line((int)curx1, scanlineY, (int)curx2, paletteIndex);
curx1 -= invslope1;
curx2 -= invslope2;
}
}
void Graphics::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, int paletteIndex)
{
int aX = x1;
int aY = y1;
int bX = x2;
int bY = y2;
int cX = x3;
int cY = y3;
if(bY < aY){
int t = bY;
bY = aY;
aY = t;
t = bX;
bX = aX;
aX = t;
}
if(cY < aY){
int t = cY;
cY = aY;
aY = t;
t = cX;
cX = aX;
aX = t;
}
if(cY < bY){
int t = cY;
cY = bY;
bY = t;
t = cX;
cX = bX;
bX = t;
}
//std::cout << aX << " " << aY << " " << bX << " " << bY << " " << cX << " " << cY << "\n";
/* here we know that v1.y <= v2.y <= v3.y */
/* check for trivial case of bottom-flat triangle */
if (bY == cY)
{
fillBottomFlatTriangle(aX, aY, bX, bY, cX, cY, paletteIndex);
}
/* check for trivial case of top-flat triangle */
else if (aY == bY)
{
fillTopFlatTriangle(aX, aY, bX, bY, cX, cY, paletteIndex);
}
else
{
/* general case - split the triangle in a topflat and bottom-flat one */
int dX = aX + ((float)(bY - aY) / (float)(cY - aY)) * (cX - aX);
int dY = bY;
fillBottomFlatTriangle(aX, aY, bX, bY, dX, dY, paletteIndex);
fillTopFlatTriangle(bX, bY, dX, dY, cX, cY, paletteIndex);
}
}

View File

@ -33,7 +33,8 @@ private:
void h_line(int x1, int y, int x2, int paletteIndex); void h_line(int x1, int y, int x2, int paletteIndex);
void v_line(int x, int y1, int y2, int paletteIndex); void v_line(int x, int y1, int y2, int paletteIndex);
void fillBottomFlatTriangle(float x1, float y1, float x2, float y2, float x3, float y3, int paletteIndex);
void fillTopFlatTriangle(float x1, float y1, float x2, float y2, float x3, float y3, int paletteIndex);
public: public:
// virtual screen // virtual screen
int m_screenWidth = 0; int m_screenWidth = 0;
@ -71,6 +72,9 @@ public:
void Rect(int x, int y, int width, int height, int paletteIndex); void Rect(int x, int y, int width, int height, int paletteIndex);
void RectBorder(int x, int y, int width, int height, int paletteIndex); void RectBorder(int x, int y, int width, int height, int paletteIndex);
void Text(std::string s, int x, int y, int paletteIndex); void Text(std::string s, int x, int y, int paletteIndex);
void Triangle(int x1, int y1, int x2, int y2, int x3, int y3, int paletteIndex);
int GetPixel(int x, int y);
}; };

View File

@ -68,6 +68,40 @@ void Pycron::bindMethods() {
m_vm->bind(m_vm->builtins, "key(keycode: int) -> bool", getKeyDown); m_vm->bind(m_vm->builtins, "key(keycode: int) -> bool", getKeyDown);
m_vm->bind(m_vm->builtins, "mousep(button: int) -> bool", getMousePressed); m_vm->bind(m_vm->builtins, "mousep(button: int) -> bool", getMousePressed);
m_vm->bind(m_vm->builtins, "mouse(button: int) -> bool", getMouseDown); m_vm->bind(m_vm->builtins, "mouse(button: int) -> bool", getMouseDown);
m_vm->bind(m_vm->builtins, "debug(msg: any) -> None", [](pkpy::VM* vm, pkpy::ArgsView args){
pkpy::PyObject* func_str = vm->builtins->attr("str");
pkpy::PyObject* result = vm->call(func_str, args[0]);
std::string s = pkpy::py_cast<pkpy::Str&>(vm, result).str();
std::cout << s.c_str() << "\n";
return vm->None;
});
m_vm->bind(m_vm->builtins, "fmod(a: float, b: float) -> float", [](pkpy::VM* vm, pkpy::ArgsView args){
float a = pkpy::py_cast<float>(vm, args[0]);
float b = pkpy::py_cast<float>(vm, args[1]);
float mod;
// Handling negative values
if (a < 0)
mod = -a;
else
mod = a;
if (b < 0)
b = -b;
// Finding mod by repeated subtraction
while (mod >= b)
mod = mod - b;
// Sign of result typically depends
// on sign of a.
if (a < 0)
return pkpy::py_var(vm, -mod);
return pkpy::py_var(vm, mod);
});
} }