mirror of
https://github.com/raylib-zig/raylib-zig.git
synced 2025-12-06 06:13:08 +00:00
example: add splines_drawing
This commit is contained in:
parent
346e87c8aa
commit
813f0323af
@ -264,6 +264,11 @@ pub fn build(b: *std.Build) !void {
|
||||
.path = "examples/shapes/rectangle_scaling.zig",
|
||||
.desc = "Renders a resizable rectangle",
|
||||
},
|
||||
.{
|
||||
.name = "splines_drawing",
|
||||
.path = "examples/shapes/splines_drawing.zig",
|
||||
.desc = "Renders a spline",
|
||||
},
|
||||
.{
|
||||
.name = "sprite_anim",
|
||||
.path = "examples/textures/sprite_anim.zig",
|
||||
|
||||
226
examples/shapes/splines_drawing.zig
Normal file
226
examples/shapes/splines_drawing.zig
Normal file
@ -0,0 +1,226 @@
|
||||
const rl = @import("raylib");
|
||||
const rgui = @import("raygui");
|
||||
|
||||
const MAX_SPLINE_POINTS = 32;
|
||||
const screenWidth = 800;
|
||||
const screenHeight = 450;
|
||||
|
||||
// Cubic Bezier spline control points
|
||||
// NOTE: Every segment has two control points
|
||||
const ControlPoint = struct {
|
||||
start: rl.Vector2,
|
||||
end: rl.Vector2,
|
||||
};
|
||||
|
||||
// Spline types
|
||||
const SplineType = enum(i32) {
|
||||
linear = 0, // Linear
|
||||
basis = 1, // B-Spline
|
||||
catmullrom = 2, // Catmull-Rom
|
||||
bezier = 3, // Cubic Bezier
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Program main entry point
|
||||
//------------------------------------------------------------------------------------
|
||||
pub fn main() anyerror!void {
|
||||
// Initialization
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
rl.setConfigFlags(.{ .msaa_4x_hint = true });
|
||||
rl.initWindow(screenWidth, screenHeight, "raylib [shapes] example - splines drawing");
|
||||
defer rl.closeWindow(); // Close window and OpenGL context
|
||||
|
||||
var points: [MAX_SPLINE_POINTS]rl.Vector2 = undefined;
|
||||
points[0] = rl.Vector2{ .x = 50.0, .y = 400.0 };
|
||||
points[1] = rl.Vector2{ .x = 160.0, .y = 220.0 };
|
||||
points[2] = rl.Vector2{ .x = 340.0, .y = 380.0 };
|
||||
points[3] = rl.Vector2{ .x = 520.0, .y = 60.0 };
|
||||
points[4] = rl.Vector2{ .x = 710.0, .y = 260.0 };
|
||||
for (5..MAX_SPLINE_POINTS) |i| {
|
||||
points[i] = rl.Vector2{ .x = 0, .y = 0 };
|
||||
}
|
||||
|
||||
// Array required for spline bezier-cubic,
|
||||
// including control points interleaved with start-end segment points
|
||||
var pointsInterleaved: [3 * (MAX_SPLINE_POINTS - 1) + 1]rl.Vector2 = undefined;
|
||||
for (&pointsInterleaved) |*point| {
|
||||
point.* = rl.Vector2{ .x = 0, .y = 0 };
|
||||
}
|
||||
|
||||
var pointCount: usize = 5;
|
||||
var selectedPoint: ?*rl.Vector2 = null;
|
||||
var focusedPoint: ?*rl.Vector2 = null;
|
||||
var selectedControlPoint: ?*rl.Vector2 = null;
|
||||
var focusedControlPoint: ?*rl.Vector2 = null;
|
||||
|
||||
// Cubic Bezier control points initialization
|
||||
var control: [MAX_SPLINE_POINTS - 1]ControlPoint = undefined;
|
||||
for (&control) |*cp| {
|
||||
cp.* = .{ .end = .{ .x = 0, .y = 0 }, .start = .{ .x = 0, .y = 0 } };
|
||||
}
|
||||
for (0..pointCount) |i| {
|
||||
control[i].start = .{ .x = points[i].x + 50, .y = points[i].y };
|
||||
control[i].end = .{ .x = points[i + 1].x - 50, .y = points[i + 1].y };
|
||||
}
|
||||
|
||||
// Spline config variables
|
||||
var splineThickness: f32 = 8.0;
|
||||
var splineTypeActive = SplineType.linear;
|
||||
var splineTypeEditMode = false;
|
||||
var splineHelpersActive = true;
|
||||
|
||||
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Main game loop
|
||||
while (!rl.windowShouldClose()) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
//----------------------------------------------------------------------------------
|
||||
// Spline points creation logic (at the end of spline)
|
||||
if (rl.isMouseButtonPressed(.right) and (pointCount < MAX_SPLINE_POINTS)) {
|
||||
points[pointCount] = rl.getMousePosition();
|
||||
const i = pointCount - 1;
|
||||
control[i].start = rl.Vector2{ .x = points[i].x + 50, .y = points[i].y };
|
||||
control[i].end = rl.Vector2{ .x = points[i + 1].x - 50, .y = points[i + 1].y };
|
||||
pointCount += 1;
|
||||
}
|
||||
|
||||
// Spline point focus and selection logic
|
||||
if (selectedPoint == null and ((splineTypeActive != SplineType.bezier) or selectedControlPoint == null)) {
|
||||
focusedPoint = null;
|
||||
for (0..pointCount) |i| {
|
||||
if (rl.checkCollisionPointCircle(rl.getMousePosition(), points[i], 8.0)) {
|
||||
focusedPoint = &points[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rl.isMouseButtonPressed(.left)) selectedPoint = focusedPoint;
|
||||
}
|
||||
|
||||
// Spline point movement logic
|
||||
if (selectedPoint) |point| {
|
||||
point.* = rl.getMousePosition();
|
||||
if (rl.isMouseButtonReleased(.left)) selectedPoint = null;
|
||||
}
|
||||
|
||||
// Cubic Bezier spline control points logic
|
||||
if ((splineTypeActive == SplineType.bezier) and focusedPoint == null) {
|
||||
// Spline control point focus and selection logic
|
||||
if (selectedControlPoint == null) {
|
||||
focusedControlPoint = null;
|
||||
for (0..pointCount) |i| {
|
||||
if (rl.checkCollisionPointCircle(rl.getMousePosition(), control[i].start, 6.0)) {
|
||||
focusedControlPoint = &control[i].start;
|
||||
break;
|
||||
} else if (rl.checkCollisionPointCircle(rl.getMousePosition(), control[i].end, 6.0)) {
|
||||
focusedControlPoint = &control[i].end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rl.isMouseButtonPressed(.left)) selectedControlPoint = focusedControlPoint;
|
||||
}
|
||||
|
||||
// Spline control point movement logic
|
||||
if (selectedControlPoint) |cp| {
|
||||
cp.* = rl.getMousePosition();
|
||||
if (rl.isMouseButtonReleased(.left)) selectedControlPoint = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Spline selection logic
|
||||
splineTypeActive = switch (rl.getKeyPressed()) {
|
||||
.one => SplineType.linear,
|
||||
.two => SplineType.basis,
|
||||
.three => SplineType.catmullrom,
|
||||
.four => SplineType.basis,
|
||||
else => splineTypeActive,
|
||||
};
|
||||
|
||||
// Clear selection when changing to a spline without control points
|
||||
if (rl.isKeyPressed(.one) or rl.isKeyPressed(.two) or rl.isKeyPressed(.three)) selectedControlPoint = null;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
rl.beginDrawing();
|
||||
defer rl.endDrawing();
|
||||
|
||||
rl.clearBackground(.ray_white);
|
||||
|
||||
switch (splineTypeActive) {
|
||||
SplineType.linear => rl.drawSplineLinear(points[0..pointCount], splineThickness, .red),
|
||||
SplineType.basis => rl.drawSplineBasis(points[0..pointCount], splineThickness, .red),
|
||||
SplineType.catmullrom => rl.drawSplineCatmullRom(points[0..pointCount], splineThickness, .red),
|
||||
SplineType.bezier => {
|
||||
// NOTE: Cubic-bezier spline requires the 2 control points of each segnment to be
|
||||
// provided interleaved with the start and end point of every segment
|
||||
for (0..pointCount - 1) |i| {
|
||||
pointsInterleaved[3 * i] = points[i];
|
||||
pointsInterleaved[3 * i + 1] = control[i].start;
|
||||
pointsInterleaved[3 * i + 2] = control[i].end;
|
||||
}
|
||||
|
||||
pointsInterleaved[3 * (pointCount - 1)] = points[pointCount - 1];
|
||||
|
||||
// Draw spline: cubic-bezier (with control points)
|
||||
rl.drawSplineBezierCubic(pointsInterleaved[0 .. 3 * pointCount], splineThickness, .red);
|
||||
|
||||
// Draw spline control points
|
||||
for (0..pointCount - 1) |i| {
|
||||
// Every cubic bezier point have two control points
|
||||
rl.drawCircleV(control[i].start, 6, .gold);
|
||||
rl.drawCircleV(control[i].end, 6, .gold);
|
||||
|
||||
if (focusedControlPoint == &control[i].start) rl.drawCircleV(control[i].start, 8, .green) else if (focusedControlPoint == &control[i].end) rl.drawCircleV(control[i].end, 8, .green);
|
||||
rl.drawLineEx(points[i], control[i].start, 1.0, .light_gray);
|
||||
rl.drawLineEx(points[i + 1], control[i].end, 1.0, .light_gray);
|
||||
|
||||
// Draw spline control lines
|
||||
rl.drawLineV(points[i], control[i].start, .gray);
|
||||
rl.drawLineV(control[i].end, points[i + 1], .gray);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
if (splineHelpersActive) {
|
||||
// Draw spline point helpers
|
||||
for (0..pointCount) |i| {
|
||||
const radius: f32 = if (focusedPoint == &points[i]) 12 else 8;
|
||||
const color: rl.Color = if (focusedPoint == &points[i]) .blue else .dark_blue;
|
||||
rl.drawCircleLinesV(points[i], radius, color);
|
||||
if ((splineTypeActive != SplineType.linear) and
|
||||
(splineTypeActive != SplineType.bezier) and
|
||||
(i < pointCount - 1)) rl.drawLineV(points[i], points[i + 1], .gray);
|
||||
|
||||
rl.drawText(rl.textFormat("[%.0f, %.0f]", .{ points[i].x, points[i].y }), @intFromFloat(points[i].x), @intFromFloat(points[i].y + 10), 10, .black);
|
||||
}
|
||||
}
|
||||
|
||||
// Check all possible UI states that require controls lock
|
||||
if (splineTypeEditMode or selectedPoint != null or selectedControlPoint != null) rgui.lock();
|
||||
|
||||
// Draw spline config
|
||||
_ = rgui.label(.{ .x = 12, .y = 62, .width = 140, .height = 24 }, rl.textFormat("Spline thickness: %i", .{@as(i64, @intFromFloat(splineThickness))}));
|
||||
|
||||
_ = rgui.sliderBar(.{ .x = 12, .y = 60 + 24, .width = 140, .height = 16 }, "", "", &splineThickness, 1.0, 40.0);
|
||||
|
||||
_ = rgui.checkBox(.{ .x = 12, .y = 110, .width = 20, .height = 20 }, "Show point helpers", &splineHelpersActive);
|
||||
|
||||
if (splineTypeEditMode) rgui.unlock();
|
||||
|
||||
_ = rgui.label(.{ .x = 12, .y = 10, .width = 140, .height = 24 }, "Spline type:");
|
||||
var active: i32 = @intFromEnum(splineTypeActive);
|
||||
if (rgui.dropdownBox(.{
|
||||
.x = 12,
|
||||
.y = 8 + 24,
|
||||
.width = 140,
|
||||
.height = 28,
|
||||
}, "LINEAR;BSPLINE;CATMULLROM;BEZIER", &active, splineTypeEditMode) > 0) splineTypeEditMode = !splineTypeEditMode;
|
||||
splineTypeActive = @enumFromInt(active);
|
||||
|
||||
rgui.unlock();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user