lingdev
↓ 0 downloadsLingDev: a Godot / Unity-style game editor written in Ling. 2-D and 3-D scenes, Flash-style timeline and cutscenes, HUDs over 3-D, Ling scripting, audio / music / MIDI, builds for Windows, Linux, macOS, web, Raspberry Pi and LingOS. Ships with Ling Agent (an N64-style spy FPS), Ling Breaker (a 3-D breakout) and Moko's Picture Book (a kawaii storybook platformer).
Keywords game-engine, editor, 3d, 2d, cutscene, timeline, ling, lingos, raspberry-pi
lingfu install lingdevCode / Files (136)
ling/rt/rt_sw3d.ling
# rt_sw3d.ling - a small software 3-D renderer over the 2-D pixel builtins (px_line / spans).
# It is what the editor viewport draws with on every runtime, and what LingOS builds (which have
# no native 3-D) render games with. Wireframe primitives, flat-lit solid faces sorted back to
# front, grid, axes, gizmos and labels, all projected through rt_cam.
# rotate a local point by Euler angles applied X -> Y -> Z (the renderer's shape convention)
fn r3_rot(x, y, z, rx, ry, rz) {
bind cx = cos(rx)
bind sx = sin(rx)
bind y1 = y * cx - z * sx
bind z1 = y * sx + z * cx
bind cy = cos(ry)
bind sy = sin(ry)
bind x2 = x * cy + z1 * sy
bind z2 = 0.0 - x * sy + z1 * cy
bind cz = cos(rz)
bind sz = sin(rz)
bind x3 = x2 * cz - y1 * sz
bind y3 = x2 * sz + y1 * cz
return [x3, y3, z2]
}
# local point (lx,ly,lz) of a node with centre c, half size s, rotation r -> world
fn r3_local(lx, ly, lz, cx, cy, cz, sx, sy, sz, rx, ry, rz) {
bind p = r3_rot(lx * sx, ly * sy, lz * sz, rx, ry, rz)
return [list_get(p, 0) + cx, list_get(p, 1) + cy, list_get(p, 2) + cz]
}
# ── lines ────────────────────────────────────────────────────────────────────
# a world-space segment, clipped against the near plane, drawn with alpha a
fn sw_line(x0, y0, z0, x1, y1, z1, c, a) {
bind p0 = cam_to_view(x0, y0, z0)
bind p1 = cam_to_view(x1, y1, z1)
bind near = 0.08 - st_get("cam_zd", 2.0)
bind az = list_get(p0, 2)
bind bz = list_get(p1, 2)
if az < near && bz < near { return 0.0 }
bind ax = list_get(p0, 0)
bind ay = list_get(p0, 1)
bind bx = list_get(p1, 0)
bind by = list_get(p1, 1)
if az < near {
bind t = (near - az) / (bz - az)
bind ax = ax + (bx - ax) * t
bind ay = ay + (by - ay) * t
bind az = near
}
if bz < near {
bind t = (near - bz) / (az - bz)
bind bx = bx + (ax - bx) * t
bind by = by + (ay - by) * t
bind bz = near
}
bind f = st_get("vp_f", 600.0)
bind cx = st_get("vp_cx", 400.0)
bind cy = st_get("vp_cy", 300.0)
bind zd = st_get("cam_zd", 2.0)
bind sx0 = cx + f * ax / (az + zd)
bind sy0 = cy + f * ay / (az + zd)
bind sx1 = cx + f * bx / (bz + zd)
bind sy1 = cy + f * by / (bz + zd)
# cull segments far outside the viewport
bind vx = st_get("vp_x", 0.0)
bind vy = st_get("vp_y", 0.0)
bind vw = st_get("vp_w", 800.0)
bind vh = st_get("vp_h", 600.0)
if (sx0 < vx - 2000.0 && sx1 < vx - 2000.0) || (sx0 > vx + vw + 2000.0 && sx1 > vx + vw + 2000.0) { return 0.0 }
if (sy0 < vy - 2000.0 && sy1 < vy - 2000.0) || (sy0 > vy + vh + 2000.0 && sy1 > vy + vh + 2000.0) { return 0.0 }
px_line(sx0, sy0, sx1, sy1, c, a)
return 0.0
}
fn sw_point(x, y, z, r, c) {
bind p = cam_project(x, y, z)
if !cam_visible(list_get(p, 2)) { return 0.0 }
px_disc(list_get(p, 0), list_get(p, 1), r, c)
return 0.0
}
fn sw_label(x, y, z, size, c, text) {
bind p = cam_project(x, y, z)
if !cam_visible(list_get(p, 2)) { return 0.0 }
g_text(list_get(p, 0) + 6.0, list_get(p, 1) - size * 0.5, size, c, text)
return 0.0
}
# ── wire primitives (centre, half size, rotation) ────────────────────────────
fn sw_box(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
bind p0 = r3_local(0.0 - 1.0, 0.0 - 1.0, 0.0 - 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p1 = r3_local(1.0, 0.0 - 1.0, 0.0 - 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p2 = r3_local(1.0, 1.0, 0.0 - 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p3 = r3_local(0.0 - 1.0, 1.0, 0.0 - 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p4 = r3_local(0.0 - 1.0, 0.0 - 1.0, 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p5 = r3_local(1.0, 0.0 - 1.0, 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p6 = r3_local(1.0, 1.0, 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p7 = r3_local(0.0 - 1.0, 1.0, 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
sw_seg(p0, p1, c, a) sw_seg(p1, p2, c, a) sw_seg(p2, p3, c, a) sw_seg(p3, p0, c, a)
sw_seg(p4, p5, c, a) sw_seg(p5, p6, c, a) sw_seg(p6, p7, c, a) sw_seg(p7, p4, c, a)
sw_seg(p0, p4, c, a) sw_seg(p1, p5, c, a) sw_seg(p2, p6, c, a) sw_seg(p3, p7, c, a)
}
fn sw_seg(p, q, c, a) {
sw_line(list_get(p, 0), list_get(p, 1), list_get(p, 2), list_get(q, 0), list_get(q, 1), list_get(q, 2), c, a)
}
# a ring in a local plane: axis 0 = around x, 1 = around y, 2 = around z; `off` = offset along the axis
fn sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, axis, off, rad, segs, c, a) {
bind i = 0.0
bind prev = []
bind first = []
while i <= segs {
bind t = i / segs * 6.2831853
bind u = cos(t) * rad
bind v = sin(t) * rad
bind p = []
if axis == 1.0 { bind p = r3_local(u, off, v, cx, cy, cz, sx, sy, sz, rx, ry, rz) }
else if axis == 0.0 { bind p = r3_local(off, u, v, cx, cy, cz, sx, sy, sz, rx, ry, rz) }
else { bind p = r3_local(u, v, off, cx, cy, cz, sx, sy, sz, rx, ry, rz) }
if i > 0.0 { sw_seg(prev, p, c, a) }
bind prev = p
bind i = i + 1.0
}
}
fn sw_sphere(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 0.0, 1.0, 24.0, c, a)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 0.0, 0.0, 1.0, 24.0, c, a)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 2.0, 0.0, 1.0, 24.0, c, a)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 0.0 - 0.7, 0.71, 16.0, c, a * 0.6)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 0.7, 0.71, 16.0, c, a * 0.6)
}
fn sw_cylinder(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 0.0 - 1.0, 1.0, 20.0, c, a)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 1.0, 1.0, 20.0, c, a)
bind k = 0.0
while k < 4.0 {
bind t = k / 4.0 * 6.2831853
sw_seg(r3_local(cos(t), 0.0 - 1.0, sin(t), cx, cy, cz, sx, sy, sz, rx, ry, rz), r3_local(cos(t), 1.0, sin(t), cx, cy, cz, sx, sy, sz, rx, ry, rz), c, a)
bind k = k + 1.0
}
}
fn sw_cone(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 1.0, 1.0, 20.0, c, a)
bind apex = r3_local(0.0, 0.0 - 1.0, 0.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind k = 0.0
while k < 4.0 {
bind t = k / 4.0 * 6.2831853
sw_seg(r3_local(cos(t), 1.0, sin(t), cx, cy, cz, sx, sy, sz, rx, ry, rz), apex, c, a)
bind k = k + 1.0
}
}
fn sw_capsule(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
sw_cylinder(cx, cy, cz, sx, sy * 0.5, sz, rx, ry, rz, c, a)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 2.0, 0.0, 1.0, 20.0, c, a * 0.7)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 0.0, 0.0, 1.0, 20.0, c, a * 0.7)
}
fn sw_torus(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 0.0, 1.0, 28.0, c, a)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 0.0, 0.3, 20.0, c, a)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 0.35, 0.65, 24.0, c, a * 0.6)
sw_ring(cx, cy, cz, sx, sy, sz, rx, ry, rz, 1.0, 0.0 - 0.35, 0.65, 24.0, c, a * 0.6)
}
fn sw_plane(cx, cy, cz, sx, sz, ry, c, a) {
bind p0 = r3_local(0.0 - 1.0, 0.0, 0.0 - 1.0, cx, cy, cz, sx, 1.0, sz, 0.0, ry, 0.0)
bind p1 = r3_local(1.0, 0.0, 0.0 - 1.0, cx, cy, cz, sx, 1.0, sz, 0.0, ry, 0.0)
bind p2 = r3_local(1.0, 0.0, 1.0, cx, cy, cz, sx, 1.0, sz, 0.0, ry, 0.0)
bind p3 = r3_local(0.0 - 1.0, 0.0, 1.0, cx, cy, cz, sx, 1.0, sz, 0.0, ry, 0.0)
sw_seg(p0, p1, c, a) sw_seg(p1, p2, c, a) sw_seg(p2, p3, c, a) sw_seg(p3, p0, c, a)
sw_seg(p0, p2, c, a * 0.35) sw_seg(p1, p3, c, a * 0.35)
}
# ── scene furniture ──────────────────────────────────────────────────────────
fn sw_grid(half, step, y, cmaj, cmin) {
bind k = 0.0 - half
while k <= half {
bind major = abs(k % (step * 5.0)) < 0.001
bind c = sel(major, cmaj, cmin)
bind a = sel(major, 0.9, 0.5)
if abs(k) < 0.001 { bind a = 0.0 }
sw_line(k, y, 0.0 - half, k, y, half, c, a)
sw_line(0.0 - half, y, k, half, y, k, c, a)
bind k = k + step
}
sw_line(0.0 - half, y, 0.0, half, y, 0.0, C_AXIS_X, 0.8)
sw_line(0.0, y, 0.0 - half, 0.0, y, half, C_AXIS_Z, 0.8)
}
fn sw_axes(x, y, z, ln) {
sw_line(x, y, z, x + ln, y, z, C_AXIS_X, 1.0)
sw_line(x, y, z, x, y - ln, z, C_AXIS_Y, 1.0)
sw_line(x, y, z, x, y, z + ln, C_AXIS_Z, 1.0)
}
# camera frustum gizmo
fn sw_camera_gizmo(cx, cy, cz, yaw, pitch, c, a) {
bind cp = cos(pitch)
bind sp = sin(pitch)
bind fx = sin(yaw) * cp
bind fy = 0.0 - sp
bind fz = cos(yaw) * cp
bind rx = cos(yaw)
bind rz = 0.0 - sin(yaw)
bind ux = 0.0 - sin(yaw) * sp
bind uy = 0.0 - cp
bind uz = 0.0 - cos(yaw) * sp
bind d = 1.6
bind hw = 0.9
bind hh = 0.55
bind ex = cx + fx * d
bind ey = cy + fy * d
bind ez = cz + fz * d
bind c0x = ex - rx * hw - ux * hh
bind c0y = ey - uy * hh
bind c0z = ez - rz * hw - uz * hh
bind c1x = ex + rx * hw - ux * hh
bind c1y = ey - uy * hh
bind c1z = ez + rz * hw - uz * hh
bind c2x = ex + rx * hw + ux * hh
bind c2y = ey + uy * hh
bind c2z = ez + rz * hw + uz * hh
bind c3x = ex - rx * hw + ux * hh
bind c3y = ey + uy * hh
bind c3z = ez - rz * hw + uz * hh
sw_line(cx, cy, cz, c0x, c0y, c0z, c, a)
sw_line(cx, cy, cz, c1x, c1y, c1z, c, a)
sw_line(cx, cy, cz, c2x, c2y, c2z, c, a)
sw_line(cx, cy, cz, c3x, c3y, c3z, c, a)
sw_line(c0x, c0y, c0z, c1x, c1y, c1z, c, a)
sw_line(c1x, c1y, c1z, c2x, c2y, c2z, c, a)
sw_line(c2x, c2y, c2z, c3x, c3y, c3z, c, a)
sw_line(c3x, c3y, c3z, c0x, c0y, c0z, c, a)
# "up" tab
sw_line(c2x, c2y, c2z, ex + ux * hh * 1.6, ey + uy * hh * 1.6, ez + uz * hh * 1.6, c, a)
sw_line(c3x, c3y, c3z, ex + ux * hh * 1.6, ey + uy * hh * 1.6, ez + uz * hh * 1.6, c, a)
sw_box(cx, cy, cz, 0.35, 0.25, 0.25, 0.0, yaw, 0.0, c, a)
}
fn sw_light_gizmo(cx, cy, cz, radius, c, a) {
sw_sphere(cx, cy, cz, 0.3, 0.3, 0.3, 0.0, 0.0, 0.0, c, a)
sw_ring(cx, cy, cz, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, radius, 32.0, c, a * 0.25)
bind k = 0.0
while k < 8.0 {
bind t = k / 8.0 * 6.2831853
sw_line(cx + cos(t) * 0.45, cy, cz + sin(t) * 0.45, cx + cos(t) * 0.8, cy, cz + sin(t) * 0.8, c, a)
bind k = k + 1.0
}
sw_line(cx, cy - 0.45, cz, cx, cy - 0.8, cz, c, a)
sw_line(cx, cy + 0.45, cz, cx, cy + 0.8, cz, c, a)
}
fn sw_spawn_gizmo(cx, cy, cz, yaw, c, a) {
sw_line(cx, cy, cz, cx, cy - 1.6, cz, c, a)
bind fx = sin(yaw)
bind fz = cos(yaw)
bind rx = cos(yaw)
bind rz = 0.0 - sin(yaw)
sw_line(cx, cy - 1.6, cz, cx + fx * 0.9, cy - 1.3, cz + fz * 0.9, c, a)
sw_line(cx + fx * 0.9, cy - 1.3, cz + fz * 0.9, cx, cy - 1.0, cz, c, a)
sw_ring(cx, cy, cz, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.5, 16.0, c, a)
sw_line(cx, cy, cz, cx + fx * 1.2, cy, cz + fz * 1.2, c, a)
sw_line(cx + fx * 1.2, cy, cz + fz * 1.2, cx + fx * 0.8 + rx * 0.25, cy, cz + fz * 0.8 + rz * 0.25, c, a)
sw_line(cx + fx * 1.2, cy, cz + fz * 1.2, cx + fx * 0.8 - rx * 0.25, cy, cz + fz * 0.8 - rz * 0.25, c, a)
}
fn sw_audio_gizmo(cx, cy, cz, radius, c, a) {
sw_box(cx, cy, cz, 0.25, 0.3, 0.2, 0.0, 0.0, 0.0, c, a)
sw_ring(cx, cy, cz, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.7, 16.0, c, a * 0.7)
sw_ring(cx, cy, cz, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, max(0.8, radius), 24.0, c, a * 0.3)
}
fn sw_actor_gizmo(cx, cy, cz, yaw, h, c, a) {
sw_capsule(cx, cy - h * 0.5, cz, h * 0.22, h * 0.5, h * 0.22, 0.0, yaw, 0.0, c, a)
bind fx = sin(yaw)
bind fz = cos(yaw)
sw_line(cx, cy - h * 0.5, cz, cx + fx * h * 0.5, cy - h * 0.5, cz + fz * h * 0.5, c, a)
}
# ── solid faces, sorted back to front ────────────────────────────────────────
# faces are buffered as records in the store then flushed once, farthest first
fn sw_solid_begin() {
st_lclear("sf_d")
st_lclear("sf_rec")
}
# a quad face in world space with a flat colour; lit by the direction light
fn sw_face(x0, y0, z0, x1, y1, z1, x2, y2, z2, x3, y3, z3, c, a) {
bind p0 = cam_project(x0, y0, z0)
bind p1 = cam_project(x1, y1, z1)
bind p2 = cam_project(x2, y2, z2)
bind p3 = cam_project(x3, y3, z3)
bind near = 0.08 - st_get("cam_zd", 2.0)
if list_get(p0, 2) < near || list_get(p1, 2) < near || list_get(p2, 2) < near || list_get(p3, 2) < near { return 0.0 }
# normal (for lighting + back-face dimming)
bind ux = x1 - x0
bind uy = y1 - y0
bind uz = z1 - z0
bind vx = x3 - x0
bind vy = y3 - y0
bind vz = z3 - z0
bind nx = uy * vz - uz * vy
bind ny = uz * vx - ux * vz
bind nz = ux * vy - uy * vx
bind nl = sqrt(nx * nx + ny * ny + nz * nz)
if nl < 0.000001 { return 0.0 }
bind nx = nx / nl
bind ny = ny / nl
bind nz = nz / nl
bind lx = 0.0 - 0.42
bind ly = 0.0 - 0.78
bind lz = 0.0 - 0.46
bind ndl = abs(nx * lx + ny * ly + nz * lz)
bind amb = sc_get("amb", 0.25)
bind k = amb + (1.0 - amb) * ndl
bind col = c_rgb(c_r(c) * k, c_g(c) * k, c_b(c) * k)
bind d = (list_get(p0, 2) + list_get(p1, 2) + list_get(p2, 2) + list_get(p3, 2)) * 0.25
bind rec = num_str(list_get(p0, 0)) + "," + num_str(list_get(p0, 1)) + "," + num_str(list_get(p1, 0)) + "," + num_str(list_get(p1, 1)) + "," + num_str(list_get(p2, 0)) + "," + num_str(list_get(p2, 1)) + "," + num_str(list_get(p3, 0)) + "," + num_str(list_get(p3, 1)) + "," + num_str(col) + "," + num_str(a)
# keep the list sorted by depth (farthest first) as we insert
bind n = st_llen("sf_d")
bind pos = n
while pos > 0.0 && st_lget("sf_d", pos - 1.0) < d { bind pos = pos - 1.0 }
sl_insert("sf_d", pos, d)
sl_insert("sf_rec", pos, rec)
return 0.0
}
fn sw_solid_flush() {
bind n = st_llen("sf_rec")
bind i = 0.0
while i < n {
bind f = nums_parse(st_lget("sf_rec", i))
bind c = list_get(f, 8)
bind a = list_get(f, 9)
g_tri_a(list_get(f, 0), list_get(f, 1), list_get(f, 2), list_get(f, 3), list_get(f, 4), list_get(f, 5), c, a)
g_tri_a(list_get(f, 0), list_get(f, 1), list_get(f, 4), list_get(f, 5), list_get(f, 6), list_get(f, 7), c, a)
bind i = i + 1.0
}
st_lclear("sf_d")
st_lclear("sf_rec")
}
# the six faces of a box
fn sw_box_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
bind p0 = r3_local(0.0 - 1.0, 0.0 - 1.0, 0.0 - 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p1 = r3_local(1.0, 0.0 - 1.0, 0.0 - 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p2 = r3_local(1.0, 1.0, 0.0 - 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p3 = r3_local(0.0 - 1.0, 1.0, 0.0 - 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p4 = r3_local(0.0 - 1.0, 0.0 - 1.0, 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p5 = r3_local(1.0, 0.0 - 1.0, 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p6 = r3_local(1.0, 1.0, 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p7 = r3_local(0.0 - 1.0, 1.0, 1.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
sw_quad(p0, p1, p2, p3, c, a)
sw_quad(p5, p4, p7, p6, c, a)
sw_quad(p4, p0, p3, p7, c, a)
sw_quad(p1, p5, p6, p2, c, a)
sw_quad(p4, p5, p1, p0, c, a)
sw_quad(p3, p2, p6, p7, c, a)
}
fn sw_quad(p, q, r, s, c, a) {
sw_face(list_get(p, 0), list_get(p, 1), list_get(p, 2), list_get(q, 0), list_get(q, 1), list_get(q, 2), list_get(r, 0), list_get(r, 1), list_get(r, 2), list_get(s, 0), list_get(s, 1), list_get(s, 2), c, a)
}
fn sw_plane_solid(cx, cy, cz, sx, sz, ry, c, a) {
bind p0 = r3_local(0.0 - 1.0, 0.0, 0.0 - 1.0, cx, cy, cz, sx, 1.0, sz, 0.0, ry, 0.0)
bind p1 = r3_local(1.0, 0.0, 0.0 - 1.0, cx, cy, cz, sx, 1.0, sz, 0.0, ry, 0.0)
bind p2 = r3_local(1.0, 0.0, 1.0, cx, cy, cz, sx, 1.0, sz, 0.0, ry, 0.0)
bind p3 = r3_local(0.0 - 1.0, 0.0, 1.0, cx, cy, cz, sx, 1.0, sz, 0.0, ry, 0.0)
sw_quad(p0, p1, p2, p3, c, a)
}
# lat/long sphere as quads (low segment count: it is a software renderer)
fn sw_sphere_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
bind rings = 6.0
bind segs = 10.0
bind i = 0.0
while i < rings {
bind t0 = i / rings * 3.14159265
bind t1 = (i + 1.0) / rings * 3.14159265
bind j = 0.0
while j < segs {
bind u0 = j / segs * 6.2831853
bind u1 = (j + 1.0) / segs * 6.2831853
bind p0 = r3_local(sin(t0) * cos(u0), 0.0 - cos(t0), sin(t0) * sin(u0), cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p1 = r3_local(sin(t0) * cos(u1), 0.0 - cos(t0), sin(t0) * sin(u1), cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p2 = r3_local(sin(t1) * cos(u1), 0.0 - cos(t1), sin(t1) * sin(u1), cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p3 = r3_local(sin(t1) * cos(u0), 0.0 - cos(t1), sin(t1) * sin(u0), cx, cy, cz, sx, sy, sz, rx, ry, rz)
sw_quad(p0, p1, p2, p3, c, a)
bind j = j + 1.0
}
bind i = i + 1.0
}
}
fn sw_cylinder_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
bind segs = 12.0
bind j = 0.0
while j < segs {
bind u0 = j / segs * 6.2831853
bind u1 = (j + 1.0) / segs * 6.2831853
bind p0 = r3_local(cos(u0), 0.0 - 1.0, sin(u0), cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p1 = r3_local(cos(u1), 0.0 - 1.0, sin(u1), cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p2 = r3_local(cos(u1), 1.0, sin(u1), cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p3 = r3_local(cos(u0), 1.0, sin(u0), cx, cy, cz, sx, sy, sz, rx, ry, rz)
sw_quad(p0, p1, p2, p3, c, a)
bind top = r3_local(0.0, 0.0 - 1.0, 0.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind bot = r3_local(0.0, 1.0, 0.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
sw_quad(top, p1, p0, top, c, a)
sw_quad(bot, p3, p2, bot, c, a)
bind j = j + 1.0
}
}
fn sw_cone_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) {
bind segs = 12.0
bind apex = r3_local(0.0, 0.0 - 1.0, 0.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind bot = r3_local(0.0, 1.0, 0.0, cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind j = 0.0
while j < segs {
bind u0 = j / segs * 6.2831853
bind u1 = (j + 1.0) / segs * 6.2831853
bind p0 = r3_local(cos(u0), 1.0, sin(u0), cx, cy, cz, sx, sy, sz, rx, ry, rz)
bind p1 = r3_local(cos(u1), 1.0, sin(u1), cx, cy, cz, sx, sy, sz, rx, ry, rz)
sw_quad(apex, p1, p0, apex, c, a)
sw_quad(bot, p0, p1, bot, c, a)
bind j = j + 1.0
}
}
# wire or solid primitive by kind
fn sw_shape(kind, cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a, solid) {
if solid {
if kind == "box" || kind == "trigger" { sw_box_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "sphere" || kind == "capsule" || kind == "torus" { sw_sphere_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "cylinder" { sw_cylinder_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "cone" { sw_cone_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "plane" { sw_plane_solid(cx, cy, cz, sx, sz, ry, c, a) }
else { sw_box_solid(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
return 0.0
}
if kind == "box" || kind == "trigger" { sw_box(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "sphere" { sw_sphere(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "cylinder" { sw_cylinder(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "cone" { sw_cone(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "capsule" { sw_capsule(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "torus" { sw_torus(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
else if kind == "plane" { sw_plane(cx, cy, cz, sx, sz, ry, c, a) }
else { sw_box(cx, cy, cz, sx, sy, sz, rx, ry, rz, c, a) }
return 0.0
}