lingmodeler
↓ 0 downloadsLingModeler: box modeling with quads and tris, rigging + weight painting, 2D vector illustration and animation, procedural textures and game assets; .lmesh / .ling native formats, OBJ, glTF and SVG import / export
Keywords 3d, modeling, vector, svg, gltf, obj, rigging, animation, textures, ling
lingfu install lingmodelerCode / Files (67)
ling/prims.ling
# ━━━ prims.ling — parametric primitives (quads where possible) ━━━
# every pr_* builder returns [vx, vy, vz, fi, fs, fc]; pr_add puts one in the scene at the 3D cursor
fn pr_add(kind, p) {
bind g = pr_build(kind, p)
if len(g) < 6.0 { return 0.0 - 1.0 }
bind names = ["Plane", "Cube", "Circle", "Sphere", "Icosphere", "Cylinder", "Cone", "Torus", "Grid", "Capsule"]
bind nm = "Object"
bind kinds = ["plane", "cube", "circle", "sphere", "ico", "cylinder", "cone", "torus", "grid", "capsule"]
bind i = 0.0
while i < len(kinds) { if list_get(kinds, i) == kind { bind nm = list_get(names, i) } bind i = i + 1.0 }
bind o = me_add_object(nm, list_get(g, 0), list_get(g, 1), list_get(g, 2), list_get(g, 3), list_get(g, 4), list_get(g, 5))
st_set(mk(o, "px"), st_get("cursor_x", 0.0))
st_set(mk(o, "py"), st_get("cursor_y", 0.0))
st_set(mk(o, "pz"), st_get("cursor_z", 0.0))
uv_box(o)
return o
}
# default parameter sets for the Add dialog: [names, values, mins, maxs, decimals]
fn pr_params(kind) {
if kind == "plane" { return [["Size", "Subdivisions"], [2.0, 1.0], [0.1, 1.0], [20.0, 32.0], [2.0, 0.0]] }
if kind == "cube" { return [["Size", "Subdivisions"], [2.0, 1.0], [0.1, 1.0], [20.0, 8.0], [2.0, 0.0]] }
if kind == "circle" { return [["Vertices", "Radius", "Fill (0 none, 1 ngon, 2 fan)"], [16.0, 1.0, 1.0], [3.0, 0.1, 0.0], [128.0, 20.0, 2.0], [0.0, 2.0, 0.0]] }
if kind == "sphere" { return [["Segments", "Rings", "Radius"], [16.0, 8.0, 1.0], [3.0, 2.0, 0.1], [64.0, 32.0, 20.0], [0.0, 0.0, 2.0]] }
if kind == "ico" { return [["Subdivisions", "Radius"], [1.0, 1.0], [0.0, 0.1], [4.0, 20.0], [0.0, 2.0]] }
if kind == "cylinder" { return [["Vertices", "Radius", "Depth", "Caps (0/1)"], [16.0, 1.0, 2.0, 1.0], [3.0, 0.05, 0.05, 0.0], [128.0, 20.0, 40.0, 1.0], [0.0, 2.0, 2.0, 0.0]] }
if kind == "cone" { return [["Vertices", "Base radius", "Top radius", "Depth"], [16.0, 1.0, 0.0, 2.0], [3.0, 0.0, 0.0, 0.05], [128.0, 20.0, 20.0, 40.0], [0.0, 2.0, 2.0, 2.0]] }
if kind == "torus" { return [["Major segments", "Minor segments", "Major radius", "Minor radius"], [24.0, 12.0, 1.0, 0.3], [3.0, 3.0, 0.1, 0.01], [128.0, 64.0, 20.0, 10.0], [0.0, 0.0, 2.0, 2.0]] }
if kind == "grid" { return [["X subdivisions", "Y subdivisions", "Size"], [8.0, 8.0, 4.0], [1.0, 1.0, 0.1], [64.0, 64.0, 100.0], [0.0, 0.0, 2.0]] }
if kind == "capsule" { return [["Segments", "Rings", "Radius", "Length"], [12.0, 4.0, 0.5, 1.0], [3.0, 1.0, 0.05, 0.0], [64.0, 16.0, 20.0, 40.0], [0.0, 0.0, 2.0, 2.0]] }
return [[], [], [], [], []]
}
fn pr_build(kind, p) {
if kind == "plane" { return pr_grid(list_get(p, 1), list_get(p, 1), list_get(p, 0)) }
if kind == "cube" { return pr_cube(list_get(p, 0), list_get(p, 1)) }
if kind == "circle" { return pr_circle(list_get(p, 0), list_get(p, 1), list_get(p, 2)) }
if kind == "sphere" { return pr_sphere(list_get(p, 0), list_get(p, 1), list_get(p, 2)) }
if kind == "ico" { return pr_icosphere(list_get(p, 0), list_get(p, 1)) }
if kind == "cylinder" { return pr_cone(list_get(p, 0), list_get(p, 1), list_get(p, 1), list_get(p, 2), list_get(p, 3)) }
if kind == "cone" { return pr_cone(list_get(p, 0), list_get(p, 1), list_get(p, 2), list_get(p, 3), 1.0) }
if kind == "torus" { return pr_torus(list_get(p, 0), list_get(p, 1), list_get(p, 2), list_get(p, 3)) }
if kind == "grid" { return pr_grid(list_get(p, 0), list_get(p, 1), list_get(p, 2)) }
if kind == "capsule" { return pr_capsule(list_get(p, 0), list_get(p, 1), list_get(p, 2), list_get(p, 3)) }
return []
}
# helpers to build face lists
fn pr_quad(fi, fs, fc, a, b, c, d) {
bind fs2 = list_push(fs, len(fi))
bind fc2 = list_push(fc, 4.0)
bind fi2 = list_push(fi, a)
bind fi2 = list_push(fi2, b)
bind fi2 = list_push(fi2, c)
bind fi2 = list_push(fi2, d)
return [fi2, fs2, fc2]
}
fn pr_tri(fi, fs, fc, a, b, c) {
bind fs2 = list_push(fs, len(fi))
bind fc2 = list_push(fc, 3.0)
bind fi2 = list_push(fi, a)
bind fi2 = list_push(fi2, b)
bind fi2 = list_push(fi2, c)
return [fi2, fs2, fc2]
}
# grid in the XZ plane, facing +Y
fn pr_grid(nx, nz, size) {
bind nx = max(1.0, floor(nx)) bind nz = max(1.0, floor(nz))
bind vx = list_new() bind vy = list_new() bind vz = list_new()
bind j = 0.0
while j <= nz {
bind i = 0.0
while i <= nx {
bind vx = list_push(vx, (i / nx - 0.5) * size)
bind vy = list_push(vy, 0.0)
bind vz = list_push(vz, (j / nz - 0.5) * size)
bind i = i + 1.0
}
bind j = j + 1.0
}
bind fi = list_new() bind fs = list_new() bind fc = list_new()
bind j = 0.0
while j < nz {
bind i = 0.0
while i < nx {
bind a = j * (nx + 1.0) + i
bind r = pr_quad(fi, fs, fc, a, a + nx + 1.0, a + nx + 2.0, a + 1.0)
bind fi = list_get(r, 0) bind fs = list_get(r, 1) bind fc = list_get(r, 2)
bind i = i + 1.0
}
bind j = j + 1.0
}
return [vx, vy, vz, fi, fs, fc]
}
fn pr_cube(size, sub) {
bind h = size * 0.5
bind n = max(1.0, floor(sub))
if n == 1.0 {
bind vx = [0.0 - h, h, h, 0.0 - h, 0.0 - h, h, h, 0.0 - h]
bind vy = [0.0 - h, 0.0 - h, h, h, 0.0 - h, 0.0 - h, h, h]
bind vz = [h, h, h, h, 0.0 - h, 0.0 - h, 0.0 - h, 0.0 - h]
bind fi = [0.0, 1.0, 2.0, 3.0, 5.0, 4.0, 7.0, 6.0, 4.0, 0.0, 3.0, 7.0, 1.0, 5.0, 6.0, 2.0, 3.0, 2.0, 6.0, 7.0, 4.0, 5.0, 1.0, 0.0]
bind fs = [0.0, 4.0, 8.0, 12.0, 16.0, 20.0]
bind fc = [4.0, 4.0, 4.0, 4.0, 4.0, 4.0]
return [vx, vy, vz, fi, fs, fc]
}
# subdivided: six grids, merged by distance
bind vx = list_new() bind vy = list_new() bind vz = list_new()
bind fi = list_new() bind fs = list_new() bind fc = list_new()
bind face = 0.0
while face < 6.0 {
bind base = len(vx)
bind j = 0.0
while j <= n {
bind i = 0.0
while i <= n {
bind u = (i / n - 0.5) * size
bind v = (j / n - 0.5) * size
bind p = [0.0, 0.0, 0.0]
if face == 0.0 { bind p = [u, v, h] }
if face == 1.0 { bind p = [0.0 - u, v, 0.0 - h] }
if face == 2.0 { bind p = [0.0 - h, v, u] }
if face == 3.0 { bind p = [h, v, 0.0 - u] }
if face == 4.0 { bind p = [u, h, 0.0 - v] }
if face == 5.0 { bind p = [u, 0.0 - h, v] }
bind vx = list_push(vx, list_get(p, 0)) bind vy = list_push(vy, list_get(p, 1)) bind vz = list_push(vz, list_get(p, 2))
bind i = i + 1.0
}
bind j = j + 1.0
}
bind j = 0.0
while j < n {
bind i = 0.0
while i < n {
bind a = base + j * (n + 1.0) + i
bind r = pr_quad(fi, fs, fc, a, a + 1.0, a + n + 2.0, a + n + 1.0)
bind fi = list_get(r, 0) bind fs = list_get(r, 1) bind fc = list_get(r, 2)
bind i = i + 1.0
}
bind j = j + 1.0
}
bind face = face + 1.0
}
return pr_weld([vx, vy, vz, fi, fs, fc], 0.00001)
}
fn pr_circle(n, r, fillmode) {
bind n = max(3.0, floor(n))
bind vx = list_new() bind vy = list_new() bind vz = list_new()
bind i = 0.0
while i < n {
bind a = i / n * 6.28318530718
bind vx = list_push(vx, cos(a) * r) bind vy = list_push(vy, 0.0) bind vz = list_push(vz, sin(a) * r)
bind i = i + 1.0
}
bind fi = list_new() bind fs = list_new() bind fc = list_new()
if fillmode == 1.0 {
bind fs = [0.0] bind fc = [n]
bind i = n - 1.0
while i >= 0.0 { bind fi = list_push(fi, i) bind i = i - 1.0 }
} else if fillmode == 2.0 {
bind vx = list_push(vx, 0.0) bind vy = list_push(vy, 0.0) bind vz = list_push(vz, 0.0)
bind i = 0.0
while i < n {
bind r2 = pr_tri(fi, fs, fc, n, (i + 1.0) % n, i)
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind i = i + 1.0
}
} else {
# edge ring only: zero-area faces are not allowed, so keep it as a polygon with no faces: we add a
# single n-gon anyway (a wire circle is an n-gon the user can delete faces of)
bind fs = [0.0] bind fc = [n]
bind i = n - 1.0
while i >= 0.0 { bind fi = list_push(fi, i) bind i = i - 1.0 }
}
return [vx, vy, vz, fi, fs, fc]
}
fn pr_sphere(segs, rings, r) {
bind segs = max(3.0, floor(segs)) bind rings = max(2.0, floor(rings))
bind vx = list_new() bind vy = list_new() bind vz = list_new()
# top pole, rings, bottom pole
bind vx = list_push(vx, 0.0) bind vy = list_push(vy, r) bind vz = list_push(vz, 0.0)
bind j = 1.0
while j < rings {
bind phi = j / rings * 3.14159265359
bind i = 0.0
while i < segs {
bind th = i / segs * 6.28318530718
bind vx = list_push(vx, sin(phi) * cos(th) * r)
bind vy = list_push(vy, cos(phi) * r)
bind vz = list_push(vz, sin(phi) * sin(th) * r)
bind i = i + 1.0
}
bind j = j + 1.0
}
bind vx = list_push(vx, 0.0) bind vy = list_push(vy, 0.0 - r) bind vz = list_push(vz, 0.0)
bind bottom = len(vx) - 1.0
bind fi = list_new() bind fs = list_new() bind fc = list_new()
bind i = 0.0
while i < segs {
bind r2 = pr_tri(fi, fs, fc, 0.0, 1.0 + (i + 1.0) % segs, 1.0 + i)
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind i = i + 1.0
}
bind j = 0.0
while j < rings - 2.0 {
bind i = 0.0
while i < segs {
bind a = 1.0 + j * segs + i
bind b = 1.0 + j * segs + (i + 1.0) % segs
bind c = b + segs
bind d = a + segs
bind r2 = pr_quad(fi, fs, fc, a, b, c, d)
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind i = i + 1.0
}
bind j = j + 1.0
}
bind base = 1.0 + (rings - 2.0) * segs
bind i = 0.0
while i < segs {
bind r2 = pr_tri(fi, fs, fc, bottom, base + i, base + (i + 1.0) % segs)
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind i = i + 1.0
}
return [vx, vy, vz, fi, fs, fc]
}
fn pr_icosphere(sub, r) {
bind t = (1.0 + sqrt(5.0)) * 0.5
bind vx = [0.0 - 1.0, 1.0, 0.0 - 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, t, t, 0.0 - t, 0.0 - t]
bind vy = [t, t, 0.0 - t, 0.0 - t, 0.0 - 1.0, 1.0, 0.0 - 1.0, 1.0, 0.0, 0.0, 0.0, 0.0]
bind vz = [0.0, 0.0, 0.0, 0.0, t, t, 0.0 - t, 0.0 - t, 0.0 - 1.0, 1.0, 0.0 - 1.0, 1.0]
bind tris = [0.0, 11.0, 5.0, 0.0, 5.0, 1.0, 0.0, 1.0, 7.0, 0.0, 7.0, 10.0, 0.0, 10.0, 11.0, 1.0, 5.0, 9.0, 5.0, 11.0, 4.0, 11.0, 10.0, 2.0, 10.0, 7.0, 6.0, 7.0, 1.0, 8.0, 3.0, 9.0, 4.0, 3.0, 4.0, 2.0, 3.0, 2.0, 6.0, 3.0, 6.0, 8.0, 3.0, 8.0, 9.0, 4.0, 9.0, 5.0, 2.0, 4.0, 11.0, 6.0, 2.0, 10.0, 8.0, 6.0, 7.0, 9.0, 8.0, 1.0]
bind s = 0.0
while s < sub {
bind ntris = list_new()
bind i = 0.0
while i + 2.0 < len(tris) {
bind a = list_get(tris, i) bind b = list_get(tris, i + 1.0) bind c = list_get(tris, i + 2.0)
bind ab = len(vx)
bind vx = list_push(vx, (list_get(vx, a) + list_get(vx, b)) * 0.5) bind vy = list_push(vy, (list_get(vy, a) + list_get(vy, b)) * 0.5) bind vz = list_push(vz, (list_get(vz, a) + list_get(vz, b)) * 0.5)
bind bc = len(vx)
bind vx = list_push(vx, (list_get(vx, b) + list_get(vx, c)) * 0.5) bind vy = list_push(vy, (list_get(vy, b) + list_get(vy, c)) * 0.5) bind vz = list_push(vz, (list_get(vz, b) + list_get(vz, c)) * 0.5)
bind ca = len(vx)
bind vx = list_push(vx, (list_get(vx, c) + list_get(vx, a)) * 0.5) bind vy = list_push(vy, (list_get(vy, c) + list_get(vy, a)) * 0.5) bind vz = list_push(vz, (list_get(vz, c) + list_get(vz, a)) * 0.5)
bind ntris = list_push(ntris, a) bind ntris = list_push(ntris, ab) bind ntris = list_push(ntris, ca)
bind ntris = list_push(ntris, b) bind ntris = list_push(ntris, bc) bind ntris = list_push(ntris, ab)
bind ntris = list_push(ntris, c) bind ntris = list_push(ntris, ca) bind ntris = list_push(ntris, bc)
bind ntris = list_push(ntris, ab) bind ntris = list_push(ntris, bc) bind ntris = list_push(ntris, ca)
bind i = i + 3.0
}
bind tris = ntris
bind s = s + 1.0
}
# project to the sphere
bind i = 0.0
while i < len(vx) {
bind l = sqrt(list_get(vx, i) * list_get(vx, i) + list_get(vy, i) * list_get(vy, i) + list_get(vz, i) * list_get(vz, i))
bind vx = list_set(vx, i, list_get(vx, i) / l * r) bind vy = list_set(vy, i, list_get(vy, i) / l * r) bind vz = list_set(vz, i, list_get(vz, i) / l * r)
bind i = i + 1.0
}
bind fi = list_new() bind fs = list_new() bind fc = list_new()
bind i = 0.0
while i + 2.0 < len(tris) {
bind r2 = pr_tri(fi, fs, fc, list_get(tris, i), list_get(tris, i + 1.0), list_get(tris, i + 2.0))
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind i = i + 3.0
}
return pr_weld([vx, vy, vz, fi, fs, fc], 0.000001)
}
# cylinder / cone / frustum along Y. caps: n-gon caps when 1
fn pr_cone(n, r0, r1, depth, caps) {
bind n = max(3.0, floor(n))
bind h = depth * 0.5
bind vx = list_new() bind vy = list_new() bind vz = list_new()
bind i = 0.0
while i < n {
bind a = i / n * 6.28318530718
bind vx = list_push(vx, cos(a) * r0) bind vy = list_push(vy, 0.0 - h) bind vz = list_push(vz, sin(a) * r0)
bind i = i + 1.0
}
bind apex = r1 < 0.0001
if apex {
bind vx = list_push(vx, 0.0) bind vy = list_push(vy, h) bind vz = list_push(vz, 0.0)
} else {
bind i = 0.0
while i < n {
bind a = i / n * 6.28318530718
bind vx = list_push(vx, cos(a) * r1) bind vy = list_push(vy, h) bind vz = list_push(vz, sin(a) * r1)
bind i = i + 1.0
}
}
bind fi = list_new() bind fs = list_new() bind fc = list_new()
bind i = 0.0
while i < n {
bind j = (i + 1.0) % n
if apex {
bind r2 = pr_tri(fi, fs, fc, i, n, j)
} else {
bind r2 = pr_quad(fi, fs, fc, i, n + i, n + j, j)
}
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind i = i + 1.0
}
if caps > 0.5 {
# bottom cap (facing -Y): reverse order
bind fs = list_push(fs, len(fi)) bind fc = list_push(fc, n)
bind i = 0.0
while i < n { bind fi = list_push(fi, i) bind i = i + 1.0 }
if !apex {
bind fs = list_push(fs, len(fi)) bind fc = list_push(fc, n)
bind i = n - 1.0
while i >= 0.0 { bind fi = list_push(fi, n + i) bind i = i - 1.0 }
}
}
return [vx, vy, vz, fi, fs, fc]
}
fn pr_torus(nmaj, nmin, R, r) {
bind nmaj = max(3.0, floor(nmaj)) bind nmin = max(3.0, floor(nmin))
bind vx = list_new() bind vy = list_new() bind vz = list_new()
bind i = 0.0
while i < nmaj {
bind a = i / nmaj * 6.28318530718
bind j = 0.0
while j < nmin {
bind b = j / nmin * 6.28318530718
bind d = R + cos(b) * r
bind vx = list_push(vx, cos(a) * d) bind vy = list_push(vy, sin(b) * r) bind vz = list_push(vz, sin(a) * d)
bind j = j + 1.0
}
bind i = i + 1.0
}
bind fi = list_new() bind fs = list_new() bind fc = list_new()
bind i = 0.0
while i < nmaj {
bind i2 = (i + 1.0) % nmaj
bind j = 0.0
while j < nmin {
bind j2 = (j + 1.0) % nmin
bind r2 = pr_quad(fi, fs, fc, i * nmin + j, i * nmin + j2, i2 * nmin + j2, i2 * nmin + j)
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind j = j + 1.0
}
bind i = i + 1.0
}
return [vx, vy, vz, fi, fs, fc]
}
fn pr_capsule(segs, rings, r, length) {
bind segs = max(3.0, floor(segs)) bind rings = max(1.0, floor(rings))
bind h = length * 0.5
bind vx = list_new() bind vy = list_new() bind vz = list_new()
bind vx = list_push(vx, 0.0) bind vy = list_push(vy, h + r) bind vz = list_push(vz, 0.0)
# upper hemisphere rings (excluding pole), equator ring, lower rings
bind rows = list_new()
bind j = 1.0
while j <= rings {
bind phi = j / rings * 1.5707963268
bind rr = sin(phi) * r
bind yy = h + cos(phi) * r
bind i = 0.0
while i < segs {
bind th = i / segs * 6.28318530718
bind vx = list_push(vx, cos(th) * rr) bind vy = list_push(vy, yy) bind vz = list_push(vz, sin(th) * rr)
bind i = i + 1.0
}
bind j = j + 1.0
}
bind j = 1.0
while j <= rings {
bind phi = 1.5707963268 + j / rings * 1.5707963268
bind rr = sin(phi) * r
bind yy = 0.0 - h + cos(phi) * r
if j == rings { bind rr = 0.0 }
bind i = 0.0
while i < segs {
bind th = i / segs * 6.28318530718
bind vx = list_push(vx, cos(th) * rr) bind vy = list_push(vy, yy) bind vz = list_push(vz, sin(th) * rr)
bind i = i + 1.0
}
bind j = j + 1.0
}
bind nrows = rings * 2.0
bind fi = list_new() bind fs = list_new() bind fc = list_new()
bind i = 0.0
while i < segs {
bind r2 = pr_tri(fi, fs, fc, 0.0, 1.0 + (i + 1.0) % segs, 1.0 + i)
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind i = i + 1.0
}
bind j = 0.0
while j < nrows - 1.0 {
bind i = 0.0
while i < segs {
bind a = 1.0 + j * segs + i
bind b = 1.0 + j * segs + (i + 1.0) % segs
bind r2 = pr_quad(fi, fs, fc, a, b, b + segs, a + segs)
bind fi = list_get(r2, 0) bind fs = list_get(r2, 1) bind fc = list_get(r2, 2)
bind i = i + 1.0
}
bind j = j + 1.0
}
return pr_weld([vx, vy, vz, fi, fs, fc], 0.000001)
}
# weld coincident vertices (within d) and drop degenerate faces. g = [vx,vy,vz,fi,fs,fc]
fn pr_weld(g, d) {
bind vx = list_get(g, 0) bind vy = list_get(g, 1) bind vz = list_get(g, 2)
bind fi = list_get(g, 3) bind fs = list_get(g, 4) bind fc = list_get(g, 5)
bind n = len(vx)
# sort by x then scan neighbours
bind order = mx_argsort(vx)
bind remap = me_fill(n, 0.0 - 1.0)
bind nvx = list_new() bind nvy = list_new() bind nvz = list_new()
bind i = 0.0
while i < n {
bind vi = list_get(order, i)
if list_get(remap, vi) < 0.0 {
bind id = len(nvx)
bind nvx = list_push(nvx, list_get(vx, vi)) bind nvy = list_push(nvy, list_get(vy, vi)) bind nvz = list_push(nvz, list_get(vz, vi))
bind remap = list_set(remap, vi, id)
bind j = i + 1.0
bind go = true
while go {
if j >= n { bind go = false }
else {
bind vj = list_get(order, j)
if list_get(vx, vj) - list_get(vx, vi) > d { bind go = false }
else {
if list_get(remap, vj) < 0.0 && abs(list_get(vy, vj) - list_get(vy, vi)) <= d && abs(list_get(vz, vj) - list_get(vz, vi)) <= d { bind remap = list_set(remap, vj, id) }
bind j = j + 1.0
}
}
}
}
bind i = i + 1.0
}
bind nfi = list_new() bind nfs = list_new() bind nfc = list_new()
bind f = 0.0
while f < len(fc) {
bind s = list_get(fs, f) bind c = list_get(fc, f)
bind corners = list_new()
bind k = 0.0
while k < c {
bind v = list_get(remap, list_get(fi, s + k))
bind addc = true
if len(corners) > 0.5 { if list_get(corners, len(corners) - 1.0) == v { bind addc = false } }
if addc { bind corners = list_push(corners, v) }
bind k = k + 1.0
}
if len(corners) > 1.5 && list_get(corners, 0) == list_get(corners, len(corners) - 1.0) {
bind tmp = list_new()
bind k = 0.0
while k < len(corners) - 1.0 { bind tmp = list_push(tmp, list_get(corners, k)) bind k = k + 1.0 }
bind corners = tmp
}
if len(corners) >= 3.0 {
bind nfs = list_push(nfs, len(nfi)) bind nfc = list_push(nfc, len(corners))
bind k = 0.0
while k < len(corners) { bind nfi = list_push(nfi, list_get(corners, k)) bind k = k + 1.0 }
}
bind f = f + 1.0
}
return [nvx, nvy, nvz, nfi, nfs, nfc]
}