gaming-pads/triangulation-earclipping.py

173 lines
4.7 KiB
Python

import pyray as RL
from pyray import (
ffi,
Rectangle as Rect,
Vector2 as Vec2,
Vector3 as Vec3,
Camera3D,
BoundingBox,
Mesh,
Model
)
import math
import pdb
import random
from typing import Optional, Tuple, List
from dataclasses import dataclass, field
def dump(struct):
s = f"{RL.ffi.typeof(struct)}: (".replace('<ctype ', '').replace('>', '')
for field in dir(struct):
data = struct.__getattribute__(field)
if str(data).startswith("<cdata"):
data = dump(data)
s += f"{field}:{data} "
s += ")"
return s
screen_width = 1024
screen_height = 768
grid_slices = 100
grid_spacing = 0.2
vertex_radius = 0.12
@dataclass
class World:
cam: Camera3D
floor_bb: BoundingBox
rotate_cam: bool = True
draw_wireframe: bool = RL.ffi.new('bool *', False)
frame_count: int = 0
vertices: List[Vec3] = field(default_factory=list)
dragging_vert: Vec3 = None
convex_hull_points: List[Vec3] = field(default_factory=list)
mesh: Mesh = None
model: Model = None
def get_convex_hull(vertices: List[Vec3]):
convex_hull_points = []
pending = sorted(vertices, key=lambda v: v.x)
convex_hull_points.append(pending[0])
idx = 0
while True:
v1 = convex_hull_points[-1]
left_most = pending[(idx + 1) % len(pending)]
idx += 1
if v1 == left_most:
continue
for v2 in pending:
x1 = v1.x - left_most.x
x2 = v1.x - v2.x
y1 = v1.z - left_most.z
y2 = v1.z - v2.z
sign = y2*x1 - y1*x2
if v1 == v2:
continue
if sign > 0:
left_most = v2
if left_most == convex_hull_points[0]:
break
convex_hull_points.append(left_most)
return convex_hull_points
def init() -> World:
cam = Camera3D(Vec3(0, 10, 10), Vec3(0, 0, 0), Vec3(0, 1, 0), 45, RL.CAMERA_PERSPECTIVE)
half_grid = grid_slices * grid_spacing * 0.5
floor_bb = BoundingBox(Vec3(-half_grid, -0.01, -half_grid), Vec3(half_grid, 0.01, half_grid))
w = World(cam, floor_bb)
num_starting_verts = 10
radius = 4
w.vertices = [
Vec3(math.cos(math.pi * 2 / num_starting_verts * i) * radius,
0,
math.sin(math.pi * 2 / num_starting_verts * i) * radius)
for i in range(num_starting_verts)
]
vs = get_convex_hull(w.vertices)
def get_points(v: Vec3):
return v.x, v.y, v.z
vertices = ffi.new("float[]", len(vs) * 3 * 3)
# for i,v in enumerate([0,0,0 1,0,2, 2,0,0, 1,0,2, 3,0,2, 2,0,0]):
for i,v in enumerate(vs):
if i < 2:
continue
for j,vv in enumerate([*get_points(vs[0]), *get_points(vs[i - 1]), *get_points(vs[i])]):
vertices[(i-2)*9+j] = vv
texcoords = ffi.new("float[]", 0)
# for i,c in enumerate([0, 0, 0.5, 1, 1, 0]):
# texcoords[i] = c
normals = ffi.new("float[]", 0)
# for i,c in enumerate([0, 1, 0, 0, 1, 0, 0, 1, 0]):
# normals[i] = c
texcoords2 = ffi.new("float[]", 0)
# for i in range(6):
# texcoords[i] = 0
# mesh = Mesh(6, 2, vertices, texcoords, texcoords2, normals)
mesh = Mesh(len(vs) * 3, len(vs), vertices, texcoords, texcoords2, normals)
RL.upload_mesh(mesh, False)
w.mesh = mesh
w.model = RL.load_model_from_mesh(mesh)
return w
def player_input(w: World):
if RL.is_key_pressed(RL.KEY_SPACE):
w.rotate_cam = not w.rotate_cam
if RL.is_key_pressed(RL.KEY_W):
w.draw_wireframe[0] = not w.draw_wireframe[0]
def update(w: World):
pass
# mesh = Mesh(
# vertexCount = len(w.vertices),
# triangleCount = len(w.vertices) - 2,
# vertices = w.vertices
# )
# new_mesh = RL.gen_
def draw_3d(w: World):
RL.draw_grid(grid_slices, grid_spacing)
RL.draw_bounding_box(w.floor_bb, RL.GREEN)
for vert in w.vertices:
RL.draw_sphere(vert, vertex_radius, RL.GREEN)
if w.draw_wireframe[0]:
RL.rl_enable_wire_mode()
else:
RL.rl_disable_wire_mode()
RL.draw_model(w.model, RL.vector3_zero(), 1, RL.GREEN)
def draw_2d(w: World):
val = RL.gui_check_box(Rect(10, 30, 25, 25), "Draw Wireframe", w.draw_wireframe)
if val != 0:
print(val)
if val:
print('hello')
w.draw_wireframe = True
RL.init_window(screen_width, screen_height, "Starter");
RL.set_target_fps(60)
w = init()
while not RL.window_should_close():
player_input(w)
update(w)
# Drawing
if w.rotate_cam:
RL.update_camera(w.cam, RL.CameraMode.CAMERA_ORBITAL)
RL.begin_drawing()
RL.clear_background(RL.WHITE)
RL.begin_mode_3d(w.cam)
draw_3d(w)
RL.end_mode_3d()
draw_2d(w)
RL.end_drawing()
w.frame_count += 1