Last active
February 5, 2024 16:57
-
-
Save treytomes/3f15d6e93b2448d05a1c1e5fc0125225 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Metaballs / Marching Squares Demo | |
// https://jamie-wong.com/2014/08/19/metaballs-and-marching-squares/ | |
// https://jurasic.dev/marching_squares/ | |
import "tc" | |
GRID_RESOLUTION = 24 | |
PRINT_SAMPLES = false | |
SHOW_GRID = false | |
DRAW_CIRCLES = true | |
FILL_RECTS = false | |
SHOW_CORNERS = false | |
NUM_BLOBS = 10 | |
MIN_RADIUS = 40 | |
MAX_RADIUS = 80 | |
INTERPOLATED = true | |
Blob = {} | |
Blob.init = function(x, y, r) | |
self.x = x | |
self.y = y | |
self.radius = r | |
self.color = color.red | |
self.penSize = 1 | |
self.vx = (rnd * 3 - 2) * rnd * 8 + 8 | |
self.vy = (rnd * 3 - 2) * rnd * 8 + 8 | |
return self | |
end function | |
Blob.make = function(x, y, r) | |
return (new Blob).init(x, y, r) | |
end function | |
Blob.draw = function(dt) | |
self.x += self.vx * dt | |
self.y += self.vy * dt | |
if self.left < 0 or self.right >= gfx.width then self.vx = -self.vx | |
if self.bottom < 0 or self.top >= gfx.height then self.vy = -self.vy | |
if DRAW_CIRCLES then gfx.drawEllipse self.left, self.bottom, self.width, self.height, self.color, self.penSize | |
end function | |
Blob.left = function | |
return self.x - self.radius | |
end function | |
Blob.right = function | |
return self.left + self.width | |
end function | |
Blob.top = function | |
return self.bottom + self.height | |
end function | |
Blob.bottom = function | |
return self.y - self.radius | |
end function | |
Blob.width = function | |
return self.radius * 2 | |
end function | |
Blob.height = function | |
return self.radius * 2 | |
end function | |
Blob.makeRandom = function | |
r = floor(rnd * (MAX_RADIUS - MIN_RADIUS) + MIN_RADIUS) | |
x = floor(rnd * (gfx.width - r * 2) + r) | |
y = floor(rnd * (gfx.height - r * 2) + r) | |
return Blob.make(x, y, r) | |
end function | |
resetSamples = function | |
globals.samples = [] | |
for y in range(floor(gfx.height / GRID_RESOLUTION)) | |
row = [] | |
for x in range(floor(gfx.width / GRID_RESOLUTION)) | |
row.push null | |
end for | |
samples.push row | |
end for | |
end function | |
calculateSample = function(sx, sy) | |
if samples[sy][sx] != null then return samples[sy][sx] | |
x = sx * GRID_RESOLUTION | |
y = sy * GRID_RESOLUTION | |
sample = 0 | |
for b in blobs | |
sample += b.radius^2 / ((x - b.x)^2 + (y - b.y)^2) | |
end for | |
samples[sy][sx] = sample | |
return sample | |
end function | |
line = function(from, to) | |
gfx.line from[0], from[1], to[0], to[1], color.green, 3 | |
end function | |
lerp = function(x, x0, x1, y0 = 0, y1 = 1) | |
if x0 == x1 then return null | |
return y0 + ((y1 - y0) * (x - x0)) / (x1 - x0) | |
end function | |
blobs = [] | |
for n in range(NUM_BLOBS) | |
blobs.push Blob.makeRandom | |
end for | |
lastFrameTime = 0 | |
while true | |
deltaTime = time - lastFrameTime | |
lastFrameTime = time | |
resetSamples | |
flc | |
// Draw the grid. | |
if SHOW_GRID then | |
for x in range(0, gfx.width, GRID_RESOLUTION) | |
gfx.line x, 0, x, gfx.height, color.gray, 1 | |
end for | |
for y in range(0, gfx.height, GRID_RESOLUTION) | |
gfx.line 0, y, gfx.width, y, color.gray, 1 | |
end for | |
end if | |
// Render the line cases. | |
c = color.green | |
for sy in range(samples.len - 2) | |
for sx in range(samples[sy].len - 2) | |
if PRINT_SAMPLES then | |
x = sx * GRID_RESOLUTION | |
y = sy * GRID_RESOLUTION | |
sample = calculateSample(x, y) | |
sample = floor(sample * 100) / 100 | |
gfx.print sample, x - 16, y - 16, color.silver, "small" | |
end if | |
if INTERPOLATED then | |
bl = calculateSample(sx, sy) | |
br = calculateSample(sx + 1, sy) | |
tl = calculateSample(sx, sy + 1) | |
tr = calculateSample(sx + 1, sy + 1) | |
a = [ | |
sx * GRID_RESOLUTION + GRID_RESOLUTION * lerp(1, tl, tr), | |
sy * GRID_RESOLUTION + GRID_RESOLUTION, | |
] | |
b = [ | |
sx * GRID_RESOLUTION + GRID_RESOLUTION, | |
sy * GRID_RESOLUTION + GRID_RESOLUTION * lerp(1, br, tr), | |
] | |
c = [ | |
sx * GRID_RESOLUTION + GRID_RESOLUTION * lerp(1, bl, br), | |
sy * GRID_RESOLUTION, | |
] | |
d = [ | |
sx * GRID_RESOLUTION, | |
sy * GRID_RESOLUTION + GRID_RESOLUTION * lerp(1, bl, tl), | |
] | |
else | |
a = [ | |
sx * GRID_RESOLUTION + GRID_RESOLUTION / 2, | |
sy * GRID_RESOLUTION + GRID_RESOLUTION, | |
] | |
b = [ | |
sx * GRID_RESOLUTION + GRID_RESOLUTION, | |
sy * GRID_RESOLUTION + GRID_RESOLUTION / 2, | |
] | |
c = [ | |
sx * GRID_RESOLUTION + GRID_RESOLUTION / 2, | |
sy * GRID_RESOLUTION, | |
] | |
d = [ | |
sx * GRID_RESOLUTION, | |
sy * GRID_RESOLUTION + GRID_RESOLUTION / 2, | |
] | |
end if | |
bl = bl >= 1 | |
br = br >= 1 | |
tl = tl >= 1 | |
tr = tr >= 1 | |
case = bl + br * 2 + tr * 4 + tl * 8 | |
if case == 0 or case == 15 then | |
continue | |
else if case == 1 or case == 14 then | |
line d, c | |
else if case == 2 or case == 13 then | |
line b, c | |
else if case == 3 or case == 12 then | |
line d, b | |
else if case == 4 or case == 11 then | |
line a, b | |
else if case == 5 then | |
line d, a | |
line c, b | |
else if case == 6 or case == 9 then | |
line c, a | |
else if case == 7 or case == 8 then | |
line d, a | |
else if case == 10 then | |
line a, b | |
line c, d | |
end if | |
end for | |
end for | |
// Render the blobs. | |
for b in blobs | |
b.draw deltaTime | |
end for | |
end while |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment