40#define ALLEGRO_UNSTABLE 1
57#include <allegro5/allegro.h>
58#include <allegro5/allegro_primitives.h>
59#include <allegro5/allegro_font.h>
62#define M_PI 3.14159265358979323846
91 double x, y, z,
vx, vy, vz;
96 {0.0, 0.0, 0.0, 2.0, 1.0, 0.5},
97 {3.0, 2.0, 1.0, 1.0, 1.5, -0.5},
98 {4.0, 4.0, -1.0, -1.0, 1.0, -1.0},
99 {1.0, 5.0, -2.0, -2.0, 0.0, 0.5},
100 {-2.0, 3.0, 0.0, -1.0, -1.5, 1.0},
101 {-1.0, 1.0, 1.5, 1.0, -1.0, 0.0},
102 {0.0, 0.0, 0.0, 2.0, 1.0, 0.5},
136static void project_3d(
double x,
double y,
double z,
float* sx,
float* sy) {
139 double cy = (double)
HEIGHT / 2.0;
140 double angle =
M_PI / 4.0;
141 *sx = (float)(cx + x * scale + z * 0.5 * cos(angle) * scale);
142 *sy = (float)(cy - y * scale - z * 0.5 * sin(angle) * scale);
147static void draw_arrow(
float x1,
float y1,
float x2,
float y2, ALLEGRO_COLOR color,
float thickness) {
148 al_draw_line(x1, y1, x2, y2, color, thickness);
149 float dx = x2 - x1, dy = y2 - y1;
150 float len = sqrtf(dx * dx + dy * dy);
151 if (len < 2.0f)
return;
152 float ux = dx / len, uy = dy / len;
153 float px = -uy * 4.0f, py = ux * 4.0f;
154 float bx = x2 - ux * 8.0f, by = y2 - uy * 8.0f;
155 al_draw_filled_triangle(x2, y2, bx + px, by + py,
156 bx - px, by - py, color);
159static void draw_trail(
float trail[][2],
int count,
int head, ALLEGRO_COLOR base_color) {
160 if (count < 2)
return;
161 unsigned char r, g, b;
162 al_unmap_rgb(base_color, &r, &g, &b);
163 for (
int i = 1; i < count; i++) {
166 float alpha = (float)i / (
float)count;
167 ALLEGRO_COLOR c = al_map_rgba(
168 (
unsigned char)(r * alpha),
169 (
unsigned char)(g * alpha),
170 (
unsigned char)(b * alpha),
171 (
unsigned char)(alpha * 200));
172 al_draw_line(trail[i0][0], trail[i0][1],
173 trail[i1][0], trail[i1][1], c, 2);
235 double dist = sqrt(dx * dx + dy * dy);
236 if (dist < 10.0)
return;
239 if (dur < 0.3) dur = 0.3;
258 float px = (float)pos[0], py = (
float)pos[1];
260 for (
int i = 1; i <= total_steps; i++) {
261 double t = t0 + (t1 - t0) * (
double)i / (double)total_steps;
263 float nx = (float)pos[0], ny = (
float)pos[1];
264 al_draw_line(px, py, nx, ny,
265 al_map_rgba(0, 200, 255, 180), 2);
272 double ext = last_seg_dur * 0.5;
273 if (ext < 0.3) ext = 0.3;
274 for (
int i = 1; i <= 20; i++) {
275 double t = t1 + ext * (double)i / 20.0;
277 float nx = (float)pos[0], ny = (
float)pos[1];
279 al_draw_line(px, py, nx, ny,
280 al_map_rgba(255, 255, 0, 120), 1);
288 al_map_rgb(15, 15, 30));
290 ALLEGRO_COLOR grid = al_map_rgba(35, 35, 55, 255);
291 for (
int x = 0; x <
PANEL_W; x += 40)
292 al_draw_line((
float)x, 0, (
float)x,
HEIGHT, grid, 1);
293 for (
int y = 0; y <
HEIGHT; y += 40)
294 al_draw_line(0, (
float)y,
PANEL_W, (
float)y, grid, 1);
296 al_draw_text(font, al_map_rgb(220, 220, 220), 5, 5, 0,
297 "2D Multi-Waypoint Path");
307 wc = al_map_rgb(0, 200, 0);
309 wc = al_map_rgb(200, 0, 0);
311 wc = al_map_rgb(100, 150, 255);
312 al_draw_filled_circle(wx, wy, 5, wc);
313 al_draw_circle(wx, wy, 5, al_map_rgb(255, 255, 255), 1);
316 snprintf(num,
sizeof(num),
"%d", i);
317 al_draw_text(font, al_map_rgb(200, 200, 200),
318 wx + 7, wy - 6, 0, num);
324 al_map_rgb(100, 180, 255));
331 al_draw_filled_circle(ox, oy, 8,
332 al_map_rgb(255, 180, 0));
333 al_draw_circle(ox, oy, 8,
334 al_map_rgb(255, 255, 255), 2);
341 al_map_rgb(255, 255, 100), 1);
345 const char*
mode =
"???";
353 snprintf(buf,
sizeof(buf),
"t=%.2f seg=%d/%d [%s]",
356 al_draw_text(font, al_map_rgb(200, 200, 200), 5, 18, 0, buf);
357 snprintf(buf,
sizeof(buf),
"pos=(%.0f,%.0f) vel=(%.0f,%.0f) wp=%d",
363 al_draw_text(font, al_map_rgb(200, 200, 200), 5, 34, 0, buf);
366 ?
"Click to place waypoints"
367 :
"Click to add more waypoints";
368 al_draw_text(font, al_map_rgb(150, 150, 150),
370 ALLEGRO_ALIGN_CENTER, msg);
375 al_map_rgba(0, 200, 255, 180), 2);
376 al_draw_text(font, al_map_rgb(160, 160, 160),
377 30,
HEIGHT - 66, 0,
"Interpolation");
379 al_map_rgba(255, 255, 0, 120), 1);
381 al_map_rgba(255, 255, 0, 120), 1);
382 al_draw_text(font, al_map_rgb(160, 160, 160),
383 30,
HEIGHT - 52, 0,
"Extrapolation");
385 al_draw_text(font, al_map_rgb(90, 90, 90), 5,
HEIGHT - 15, 0,
386 "[R] Reset [ESC] Quit");
399 for (
int i = 0; i <
NUM_WP3D; i++) {
431 float ox, oy, ax, ay;
435 draw_arrow(ox, oy, ax, ay, al_map_rgb(200, 60, 60), 2);
436 al_draw_text(font, al_map_rgb(200, 60, 60),
437 ax + 4, ay - 6, 0,
"X");
440 draw_arrow(ox, oy, ax, ay, al_map_rgb(60, 200, 60), 2);
441 al_draw_text(font, al_map_rgb(60, 200, 60),
442 ax + 4, ay - 6, 0,
"Y");
445 draw_arrow(ox, oy, ax, ay, al_map_rgb(60, 60, 200), 2);
446 al_draw_text(font, al_map_rgb(60, 60, 200),
447 ax + 4, ay - 6, 0,
"Z");
451 ALLEGRO_COLOR gc = al_map_rgba(45, 45, 45, 128);
452 for (
int i = -4; i <= 4; i++) {
453 float x1, y1, x2, y2;
456 al_draw_line(x1, y1, x2, y2, gc, 1);
459 al_draw_line(x1, y1, x2, y2, gc, 1);
475 for (
int i = 1; i <= total_steps; i++) {
476 double t = t0 + (t1 - t0) * (
double)i / (double)total_steps;
480 al_draw_line(px, py, nx, ny,
481 al_map_rgba(255, 100, 255, 140), 2);
489 al_map_rgb(18, 18, 22));
491 al_draw_text(font, al_map_rgb(220, 220, 220),
492 PANEL_W + 5, 5, 0,
"3D Multi-Waypoint Loop");
503 for (
int i = 0; i <
NUM_WP3D; i++) {
509 ? al_map_rgb(255, 80, 80)
510 : al_map_rgb(100, 100, 200);
511 al_draw_filled_circle(sx, sy, 4, c);
512 al_draw_circle(sx, sy, 4, al_map_rgb(200, 200, 200), 1);
515 snprintf(num,
sizeof(num),
"%d", i);
516 al_draw_text(font, al_map_rgb(180, 180, 180),
517 sx + 6, sy - 6, 0, num);
522 al_map_rgb(200, 120, 255));
526 float obj_sx, obj_sy;
533 float gnd_sx, gnd_sy;
537 al_draw_line(gnd_sx, gnd_sy, obj_sx, obj_sy,
538 al_map_rgba(100, 100, 100, 80), 1);
539 al_draw_filled_circle(gnd_sx, gnd_sy, 2,
540 al_map_rgba(100, 100, 100, 60));
543 al_draw_filled_circle(obj_sx, obj_sy, 7,
544 al_map_rgb(255, 200, 50));
545 al_draw_circle(obj_sx, obj_sy, 7,
546 al_map_rgb(255, 255, 255), 2);
550 float vel_sx, vel_sy;
559 al_map_rgb(255, 255, 100), 1);
563 snprintf(buf,
sizeof(buf),
"t=%.2f seg=%d/%d wp=%d",
566 al_draw_text(font, al_map_rgb(200, 200, 200),
568 snprintf(buf,
sizeof(buf),
"pos=(%.1f, %.1f, %.1f)",
572 al_draw_text(font, al_map_rgb(200, 200, 200),
574 snprintf(buf,
sizeof(buf),
"vel=(%.1f, %.1f, %.1f)",
578 al_draw_text(font, al_map_rgb(200, 200, 200),
584int main(
int argc,
char* argv[]) {
591 n_abort(
"Could not init Allegro.\n");
593 if (!al_init_primitives_addon()) {
594 n_abort(
"Unable to initialize primitives addon\n");
596 if (!al_init_font_addon()) {
597 n_abort(
"Unable to initialize font addon\n");
599 if (!al_install_keyboard()) {
600 n_abort(
"Unable to initialize keyboard handler\n");
602 if (!al_install_mouse()) {
603 n_abort(
"Unable to initialize mouse handler\n");
606 al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED);
609 n_abort(
"Unable to create display\n");
612 "Nilorea Trajectory API - Multi-Waypoint Demo");
614 ALLEGRO_FONT* font = al_create_builtin_font();
615 ALLEGRO_TIMER* timer = al_create_timer(1.0 /
FPS);
617 ALLEGRO_EVENT_QUEUE* event_queue = al_create_event_queue();
618 al_register_event_source(event_queue,
619 al_get_display_event_source(
display));
620 al_register_event_source(event_queue,
621 al_get_timer_event_source(timer));
622 al_register_event_source(event_queue,
623 al_get_keyboard_event_source());
624 al_register_event_source(event_queue,
625 al_get_mouse_event_source());
627 ALLEGRO_BITMAP* scrbuf = al_create_bitmap(
WIDTH,
HEIGHT);
632 al_start_timer(timer);
639 al_wait_for_event(event_queue, &ev);
641 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
643 }
else if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
644 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
646 }
else if (ev.keyboard.keycode == ALLEGRO_KEY_R) {
649 }
else if (ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
650 if (ev.mouse.button == 1) {
654 }
else if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN ||
655 ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) {
656 al_clear_keyboard_state(
display);
657 al_flush_event_queue(event_queue);
658 }
else if (ev.type == ALLEGRO_EVENT_TIMER) {
674 if (do_draw && al_is_event_queue_empty(event_queue)) {
675 al_set_target_bitmap(scrbuf);
676 al_clear_to_color(al_map_rgb(0, 0, 0));
682 al_map_rgb(80, 80, 80), 2);
684 al_set_target_bitmap(al_get_backbuffer(
display));
685 al_draw_bitmap(scrbuf, 0, 0, 0);
693 al_destroy_bitmap(scrbuf);
694 al_destroy_font(font);
695 al_destroy_timer(timer);
696 al_destroy_event_queue(event_queue);
ALLEGRO_DISPLAY * display
static void draw_3d_axes(ALLEGRO_FONT *font)
static TRAJECTORY * traj_3d
static void reset_2d(void)
static void rebuild_2d_trajectory(void)
static void trail_push_2d(float x, float y)
static void trail_push_3d(float x, float y)
static double time_3d_end
static void draw_full_path_3d(void)
static void init_physics_3d(PHYSICS *p, double px, double py, double pz, double vx, double vy, double vz)
static void draw_3d_panel(ALLEGRO_FONT *font)
static void draw_full_path_2d(void)
static void handle_click_2d(float mx, float my)
static void init_physics_2d(PHYSICS *p, double px, double py, double vx, double vy)
static void project_3d(double x, double y, double z, float *sx, float *sy)
static void init_3d(void)
static const WAYPOINT3D waypoints_3d[7]
static int trail_3d_count
static int trail_2d_count
static void draw_2d_panel(ALLEGRO_FONT *font)
static const double WP3D_DUR
static float trail_2d[300][2]
static void update_3d_logic(void)
static void draw_ground_grid(void)
static void draw_arrow(float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness)
static float trail_3d[300][2]
static void draw_trail(float trail[][2], int count, int head, ALLEGRO_COLOR base_color)
static TRAJECTORY * traj_2d
static const double WP2D_SPEED
void n_abort(char const *format,...)
abort program with a text
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_ERR
error conditions
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
#define LOG_NOTICE
normal but significant condition
VECTOR3D speed
vx,vy,vz actual speed
VECTOR3D position
x,y,z actual position
#define VECTOR3D_SET(VECTOR, X, Y, Z)
helper to set a VECTOR3D position
double VECTOR3D[3]
struct of a point
structure of the physics of an object
PHYSICS current
current computed state at current_time
int nb_points
number of waypoints in the points array
double time_val
timestamp of this waypoint
TRAJECTORY_POINT * points
array of waypoints for multi-point paths (NULL if single segment)
int current_segment
index of the currently loaded segment (points[i] -> points[i+1]), -1 if none
int mode
current computation mode: TRAJECTORY_INTERP, TRAJECTORY_EXTRAP, or TRAJECTORY_BEFORE
int trajectory_get_position(TRAJECTORY *traj, double time_val, VECTOR3D out)
Compute position at a given time.
TRAJECTORY * trajectory_new(int nb_components)
Allocate and initialize a new TRAJECTORY.
int trajectory_add_point(TRAJECTORY *traj, const PHYSICS *state, double time_val)
Add a waypoint to the multi-point trajectory path.
#define TRAJECTORY_EXTRAP
trajectory is extrapolating beyond the end state using quadratic motion
void trajectory_delete(TRAJECTORY **traj)
Free a TRAJECTORY and set the pointer to NULL.
#define TRAJECTORY_3D
use 3 components (x,y,z) for trajectory computation
#define TRAJECTORY_BEFORE
trajectory is extrapolating before the start state using quadratic motion
#define TRAJECTORY_2D
use 2 components (x,y) for trajectory computation
#define TRAJECTORY_INTERP
trajectory is interpolating along the cubic Hermite spline between start and end
int trajectory_compute(TRAJECTORY *traj, double time_val)
Compute the full state (position, speed, acceleration, orientation, angular_speed) at a given time us...
int trajectory_clear_points(TRAJECTORY *traj)
Clear all waypoints from the multi-point path.
structure holding all data for trajectory interpolation / extrapolation
Common headers and low-level functions & define.
Trajectory interpolation and dead reckoning for 2D/3D networked simulations.