init
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
libs/
|
||||
.build/
|
||||
@@ -0,0 +1,26 @@
|
||||
#run {
|
||||
w := compiler_create_workspace();
|
||||
bo := get_build_options(w);
|
||||
|
||||
bo.output_executable_name = "metaballs";
|
||||
args := bo.compile_time_command_line;
|
||||
for arg : args {
|
||||
if arg == "-release" {
|
||||
set_optimization(*bo, .OPTIMIZED);
|
||||
bo.stack_trace = false;
|
||||
}
|
||||
}
|
||||
|
||||
import_paths: [..]string;
|
||||
for bo.import_path array_add(*import_paths, it);
|
||||
array_add(*import_paths, "libs");
|
||||
bo.import_path = import_paths;
|
||||
|
||||
set_build_options(bo, w);
|
||||
add_build_file("main.jai", w);
|
||||
|
||||
set_build_options_dc(.{do_output=false});
|
||||
}
|
||||
|
||||
#import "Basic";
|
||||
#import "Compiler";
|
||||
@@ -0,0 +1,205 @@
|
||||
circle :: struct {
|
||||
pos: Vector2;
|
||||
vel: Vector2;
|
||||
radius: float;
|
||||
r2: float;
|
||||
}
|
||||
|
||||
corner :: struct {
|
||||
pos: Vector2;
|
||||
height: float;
|
||||
}
|
||||
|
||||
resolution : s32 = 8;
|
||||
min_res :: 1;
|
||||
max_res :: 128;
|
||||
num_circles :: 10;
|
||||
show_raw_metaballs := false;
|
||||
show_circles := false;
|
||||
show_grid := false;
|
||||
show_fps := false;
|
||||
do_lerp := true;
|
||||
fps_high := true;
|
||||
|
||||
BACKGROUND_COL :Color: .{0x11, 0x11, 0x11, 0x11};
|
||||
GRID_COL :Color: .{0x33, 0x33, 0x33, 0x88};
|
||||
CIRCLE_COL :Color: .{0xaa, 0xaa, 0xaa, 0xaa};
|
||||
METABALL_COL :Color: SKYBLUE;
|
||||
|
||||
main :: () {
|
||||
InitWindow(800, 600, "Metaballs");
|
||||
defer CloseWindow();
|
||||
SetTargetFPS(240);
|
||||
width := GetScreenWidth();
|
||||
height := GetScreenHeight();
|
||||
|
||||
circles : [..]circle;
|
||||
|
||||
for 0..num_circles {
|
||||
r := cast(float) GetRandomValue(10, 75);
|
||||
x := cast(float) GetRandomValue(xx (0 + r), xx (width - r));
|
||||
y := cast(float) GetRandomValue(xx (0 + r), xx (height - r));
|
||||
vx := GetRandomValue(0, 2000) / 10.0;
|
||||
vy := GetRandomValue(0, 2000) / 10.0;
|
||||
|
||||
h := GetRandomValue(5, height / 2);
|
||||
w := GetRandomValue(5, height / 2);
|
||||
r2 := r * r;
|
||||
c := circle.{.{x, y}, .{vx, vy}, r, r2};
|
||||
array_add(*circles, c);
|
||||
}
|
||||
|
||||
while !WindowShouldClose() {
|
||||
if IsMouseButtonPressed(.MOUSE_BUTTON_MIDDLE) {
|
||||
if fps_high SetTargetFPS(30); else SetTargetFPS(240);
|
||||
fps_high = !fps_high;
|
||||
}
|
||||
|
||||
if IsKeyPressed(.KEY_R) show_raw_metaballs = !show_raw_metaballs;
|
||||
if IsKeyPressed(.KEY_C) show_circles = !show_circles;
|
||||
if IsKeyPressed(.KEY_G) show_grid = !show_grid;
|
||||
if IsKeyPressed(.KEY_L) do_lerp = !do_lerp;
|
||||
if IsKeyPressed(.KEY_F) show_fps = !show_fps;
|
||||
if IsKeyPressed(.KEY_LEFT) && resolution != min_res resolution >>= 1;
|
||||
if IsKeyPressed(.KEY_RIGHT) && resolution != max_res resolution <<= 1;
|
||||
|
||||
cols := width / resolution + 1;
|
||||
rows := height / resolution + 1;
|
||||
corner_count := cols * rows;
|
||||
corners := NewArray(corner_count, float);
|
||||
defer array_free(corners);
|
||||
|
||||
dt := GetFrameTime();
|
||||
if show_fps DrawFPS(10, 10);
|
||||
for *c : circles {
|
||||
using c;
|
||||
if pos.x + radius > xx width || pos.x - radius < 0
|
||||
vel.x = -vel.x;
|
||||
if pos.y + radius > xx height || pos.y - radius < 0
|
||||
vel.y = -vel.y;
|
||||
|
||||
pos += vel * dt;
|
||||
}
|
||||
|
||||
for x : 0..cols - 1 {
|
||||
for y : 0..rows - 1 {
|
||||
corners[x + (y * cols)] = field(.{xx (x * resolution), xx (y * resolution)}, circles);
|
||||
}
|
||||
}
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(BACKGROUND_COL);
|
||||
|
||||
if show_grid {
|
||||
for col : 0..cols - 1 {
|
||||
y := col * resolution;
|
||||
DrawLine(y, 0, y, height, GRID_COL);
|
||||
}
|
||||
for row : 0..rows - 1 {
|
||||
x := row * resolution;
|
||||
DrawLine(0, x, width, x, GRID_COL);
|
||||
}
|
||||
}
|
||||
|
||||
for col : 0..cols - 2 {
|
||||
x := col * resolution;
|
||||
for row : 0..rows - 2 {
|
||||
y := row * resolution;
|
||||
if show_raw_metaballs && point_in_circles_sum(.{xx x, xx y}, circles) DrawRectangle(x, y, resolution, resolution, WHITE);
|
||||
if show_raw_metaballs && point_in_circles_max(.{xx x, xx y}, circles) DrawRectangle(x, y, resolution, resolution, GRAY);
|
||||
fx0 := corners[col + ((row ) * cols)];
|
||||
fx1 := corners[col + ((row + 1) * cols)];
|
||||
fy0 := corners[col + 1 + ((row ) * cols)];
|
||||
fy1 := corners[col + 1 + ((row + 1) * cols)];
|
||||
draw_corner_line(.{xx x, xx y}, fx0, fx1, fy0, fy1);
|
||||
}
|
||||
}
|
||||
|
||||
if show_circles draw_circles(circles);
|
||||
|
||||
EndDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
draw_circles :: (circles: []circle) {
|
||||
for c : circles {
|
||||
using c;
|
||||
DrawCircleLinesV(pos, radius, CIRCLE_COL);
|
||||
}
|
||||
}
|
||||
|
||||
draw_corner_line :: (pos: Vector2, fx0: float, fx1: float, fy0: float, fy1: float){
|
||||
corners: s64;
|
||||
corners |= ifx fx0 >= 1 then 0x1;
|
||||
corners |= ifx fx1 >= 1 then 0x2;
|
||||
corners |= ifx fy0 >= 1 then 0x4;
|
||||
corners |= ifx fy1 >= 1 then 0x8;
|
||||
|
||||
if corners == 0 || corners == 15 return;
|
||||
|
||||
using pos;
|
||||
x0 := Vector2.{x, y};
|
||||
x1 := Vector2.{x, y + resolution};
|
||||
y0 := Vector2.{x + resolution, y};
|
||||
y1 := Vector2.{x + resolution, y + resolution};
|
||||
|
||||
calc_intersect :: (a: Vector2, fa: float, b: Vector2, fb: float) -> Vector2 #expand {
|
||||
t := ifx do_lerp then (1 - fa) / (fb - fa) else 0.5;
|
||||
return lerp(a, b, t);
|
||||
}
|
||||
|
||||
left :: () -> Vector2 #expand { return calc_intersect(`x0, `fx0, `x1, `fx1); }
|
||||
right :: () -> Vector2 #expand { return calc_intersect(`y0, `fy0, `y1, `fy1); }
|
||||
up :: () -> Vector2 #expand { return calc_intersect(`x0, `fx0, `y0, `fy0); }
|
||||
down :: () -> Vector2 #expand { return calc_intersect(`x1, `fx1, `y1, `fy1); }
|
||||
|
||||
if corners == {
|
||||
case 1; DrawLineV(up(), left(), METABALL_COL);
|
||||
case 2; DrawLineV(left(), down(), METABALL_COL);
|
||||
case 3; DrawLineV(up(), down(), METABALL_COL);
|
||||
case 4; DrawLineV(up(), right(), METABALL_COL);
|
||||
case 5; DrawLineV(left(), right(), METABALL_COL);
|
||||
case 6; DrawLineV(up(), right(), METABALL_COL); DrawLineV(left(), down(), METABALL_COL);
|
||||
case 7; DrawLineV(right(), down(), METABALL_COL);
|
||||
case 8; DrawLineV(right(), down(), METABALL_COL);
|
||||
case 9; DrawLineV(up(), left(), METABALL_COL); DrawLineV(right(), down(), METABALL_COL);
|
||||
case 10; DrawLineV(left(), right(), METABALL_COL);
|
||||
case 11; DrawLineV(up(), right(), METABALL_COL);
|
||||
case 12; DrawLineV(up(), down(), METABALL_COL);
|
||||
case 13; DrawLineV(left(), down(), METABALL_COL);
|
||||
case 14; DrawLineV(up(), left(), METABALL_COL);
|
||||
}
|
||||
}
|
||||
|
||||
// heightmap at given point based on circle proximity
|
||||
field :: (point: Vector2, circles: []circle) -> float {
|
||||
sum := 0.0;
|
||||
for c : circles {
|
||||
using c;
|
||||
v := r2 / (((point.x - pos.x) * (point.x - pos.x)) + ((point.y - pos.y) * (point.y - pos.y)));
|
||||
sum += v;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
// used to draw metaballs at given resolution using field calculation
|
||||
point_in_circles_sum :: (point: Vector2, circles: []circle) -> bool {
|
||||
f := field(point, circles);
|
||||
//return f <= 1.05 && f >= 0.95; // Nicer edges!
|
||||
return f >= 1;
|
||||
}
|
||||
|
||||
// used to draw circles at given resolution
|
||||
point_in_circles_max :: (point: Vector2, circles: []circle) -> bool {
|
||||
for c : circles {
|
||||
using c;
|
||||
v := r2 / (((point.x - pos.x) * (point.x - pos.x)) + ((point.y - pos.y) * (point.y - pos.y)));
|
||||
if v >= 1 return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#import "raylib";
|
||||
|
||||
#import "Basic";
|
||||
#import "Math";
|
||||
Reference in New Issue
Block a user