Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_trajectory.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
41#define ALLEGRO_UNSTABLE 1
42
43#define WIDTH 800
44#define HEIGHT 600
45#define PANEL_W 400
46#define FPS 60.0
47#define DT (1.0 / FPS)
48#define MAX_TRAIL 300
49
50#include <stdio.h>
51#include <string.h>
52#include <math.h>
53
54#include "nilorea/n_common.h"
55#include "nilorea/n_log.h"
57
58#include <allegro5/allegro.h>
59#include <allegro5/allegro_primitives.h>
60#include <allegro5/allegro_font.h>
61
62#ifndef M_PI
63#define M_PI 3.14159265358979323846
64#endif
65
66/* 2D Demo State */
67static TRAJECTORY* traj_2d = NULL;
68static double time_2d = 0.0;
69static int running_2d = 0;
70
71/* raw waypoint storage for Catmull-Rom velocity computation */
72#define MAX_WP2D 50
74static int wp2d_count = 0;
75static const double WP2D_SPEED = 80.0; /* pixels/sec reference speed */
76
77static float trail_2d[MAX_TRAIL][2];
78static int trail_2d_count = 0;
79static int trail_2d_head = 0;
80
81/* 3D Demo State */
82static TRAJECTORY* traj_3d = NULL;
83static double time_3d = 0.0;
84static double time_3d_end = 0.0;
85
86static float trail_3d[MAX_TRAIL][2];
87static int trail_3d_count = 0;
88static int trail_3d_head = 0;
89
90/* 3D waypoints forming a closed loop (last = first for seamless looping) */
91typedef struct {
92 double x, y, z, vx, vy, vz;
94
95#define NUM_WP3D 7
97 {0.0, 0.0, 0.0, 2.0, 1.0, 0.5},
98 {3.0, 2.0, 1.0, 1.0, 1.5, -0.5},
99 {4.0, 4.0, -1.0, -1.0, 1.0, -1.0},
100 {1.0, 5.0, -2.0, -2.0, 0.0, 0.5},
101 {-2.0, 3.0, 0.0, -1.0, -1.5, 1.0},
102 {-1.0, 1.0, 1.5, 1.0, -1.0, 0.0},
103 {0.0, 0.0, 0.0, 2.0, 1.0, 0.5}, /* loop back to start */
104};
105static const double WP3D_DUR = 4.0; /* seconds per 3D segment */
106
107/* Helpers */
108
109static void init_physics_2d(PHYSICS* p, double px, double py, double vx, double vy) {
110 memset(p, 0, sizeof(PHYSICS));
111 VECTOR3D_SET(p->position, px, py, 0.0);
112 VECTOR3D_SET(p->speed, vx, vy, 0.0);
113}
114
115static void init_physics_3d(PHYSICS* p, double px, double py, double pz, double vx, double vy, double vz) {
116 memset(p, 0, sizeof(PHYSICS));
117 VECTOR3D_SET(p->position, px, py, pz);
118 VECTOR3D_SET(p->speed, vx, vy, vz);
119}
120
121static void trail_push_2d(float x, float y) {
122 trail_2d[trail_2d_head][0] = x;
123 trail_2d[trail_2d_head][1] = y;
126}
127
128static void trail_push_3d(float x, float y) {
129 trail_3d[trail_3d_head][0] = x;
130 trail_3d[trail_3d_head][1] = y;
133}
134
135/* 3D Projection (Cabinet) */
136
137static void project_3d(double x, double y, double z, float* sx, float* sy) {
138 double scale = 30.0;
139 double cx = (double)PANEL_W + (double)PANEL_W / 2.0;
140 double cy = (double)HEIGHT / 2.0;
141 double angle = M_PI / 4.0;
142 *sx = (float)(cx + x * scale + z * 0.5 * cos(angle) * scale);
143 *sy = (float)(cy - y * scale - z * 0.5 * sin(angle) * scale);
144}
145
146/* Drawing Utilities */
147
148static void draw_arrow(float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness) {
149 al_draw_line(x1, y1, x2, y2, color, thickness);
150 float dx = x2 - x1, dy = y2 - y1;
151 float len = sqrtf(dx * dx + dy * dy);
152 if (len < 2.0f) return;
153 float ux = dx / len, uy = dy / len;
154 float px = -uy * 4.0f, py = ux * 4.0f;
155 float bx = x2 - ux * 8.0f, by = y2 - uy * 8.0f;
156 al_draw_filled_triangle(x2, y2, bx + px, by + py,
157 bx - px, by - py, color);
158}
159
160static void draw_trail(float trail[][2], int count, int head, ALLEGRO_COLOR base_color) {
161 if (count < 2) return;
162 unsigned char r, g, b;
163 al_unmap_rgb(base_color, &r, &g, &b);
164 for (int i = 1; i < count; i++) {
165 int i0 = (head - count + i - 1 + MAX_TRAIL) % MAX_TRAIL;
166 int i1 = (head - count + i + MAX_TRAIL) % MAX_TRAIL;
167 float alpha = (float)i / (float)count;
168 ALLEGRO_COLOR c = al_map_rgba(
169 (unsigned char)(r * alpha),
170 (unsigned char)(g * alpha),
171 (unsigned char)(b * alpha),
172 (unsigned char)(alpha * 200));
173 al_draw_line(trail[i0][0], trail[i0][1],
174 trail[i1][0], trail[i1][1], c, 2);
175 }
176}
177
178/* 2D Demo: Init / Reset / Click / Rebuild / Draw */
179
180static void rebuild_2d_trajectory(void) {
182 if (wp2d_count < 2) return;
183
184 for (int i = 0; i < wp2d_count; i++) {
185 double vx, vy;
186
187 if (i == 0) {
188 /* forward difference */
189 double dt = wp2d_t[1] - wp2d_t[0];
190 vx = (wp2d_x[1] - wp2d_x[0]) / dt;
191 vy = (wp2d_y[1] - wp2d_y[0]) / dt;
192 } else if (i == wp2d_count - 1) {
193 /* backward difference */
194 double dt = wp2d_t[i] - wp2d_t[i - 1];
195 vx = (wp2d_x[i] - wp2d_x[i - 1]) / dt;
196 vy = (wp2d_y[i] - wp2d_y[i - 1]) / dt;
197 } else {
198 /* Catmull-Rom: central difference */
199 double dt = wp2d_t[i + 1] - wp2d_t[i - 1];
200 vx = (wp2d_x[i + 1] - wp2d_x[i - 1]) / dt;
201 vy = (wp2d_y[i + 1] - wp2d_y[i - 1]) / dt;
202 }
203
204 PHYSICS state;
205 init_physics_2d(&state, wp2d_x[i], wp2d_y[i], vx, vy);
207 }
208
209 running_2d = 1;
210}
211
212static void reset_2d(void) {
215 time_2d = 0.0;
216 running_2d = 0;
217 wp2d_count = 0;
218 trail_2d_count = 0;
219 trail_2d_head = 0;
220}
221
222static void handle_click_2d(float mx, float my) {
223 if (mx >= PANEL_W || wp2d_count >= MAX_WP2D) return;
224
225 if (wp2d_count == 0) {
226 wp2d_x[0] = (double)mx;
227 wp2d_y[0] = (double)my;
228 wp2d_t[0] = 0.0;
229 wp2d_count = 1;
230 return;
231 }
232
233 /* compute time for new waypoint based on distance */
234 double dx = (double)mx - wp2d_x[wp2d_count - 1];
235 double dy = (double)my - wp2d_y[wp2d_count - 1];
236 double dist = sqrt(dx * dx + dy * dy);
237 if (dist < 10.0) return;
238
239 double dur = dist / WP2D_SPEED;
240 if (dur < 0.3) dur = 0.3;
241
242 wp2d_x[wp2d_count] = (double)mx;
243 wp2d_y[wp2d_count] = (double)my;
244 wp2d_t[wp2d_count] = wp2d_t[wp2d_count - 1] + dur;
245 wp2d_count++;
246
248}
249
250static void draw_full_path_2d(void) {
251 if (!traj_2d || traj_2d->nb_points < 2) return;
252
253 double t0 = traj_2d->points[0].time_val;
254 double t1 = traj_2d->points[traj_2d->nb_points - 1].time_val;
255 int total_steps = (traj_2d->nb_points - 1) * 30;
256
257 VECTOR3D pos;
259 float px = (float)pos[0], py = (float)pos[1];
260
261 for (int i = 1; i <= total_steps; i++) {
262 double t = t0 + (t1 - t0) * (double)i / (double)total_steps;
264 float nx = (float)pos[0], ny = (float)pos[1];
265 al_draw_line(px, py, nx, ny,
266 al_map_rgba(0, 200, 255, 180), 2);
267 px = nx;
268 py = ny;
269 }
270
271 /* extrapolation tail: base length on last segment, not total path */
272 double last_seg_dur = traj_2d->points[traj_2d->nb_points - 1].time_val - traj_2d->points[traj_2d->nb_points - 2].time_val;
273 double ext = last_seg_dur * 0.5;
274 if (ext < 0.3) ext = 0.3;
275 for (int i = 1; i <= 20; i++) {
276 double t = t1 + ext * (double)i / 20.0;
278 float nx = (float)pos[0], ny = (float)pos[1];
279 if (i % 2 == 0)
280 al_draw_line(px, py, nx, ny,
281 al_map_rgba(255, 255, 0, 120), 1);
282 px = nx;
283 py = ny;
284 }
285}
286
287static void draw_2d_panel(ALLEGRO_FONT* font) {
288 al_draw_filled_rectangle(0, 0, PANEL_W, HEIGHT,
289 al_map_rgb(15, 15, 30));
290
291 ALLEGRO_COLOR grid = al_map_rgba(35, 35, 55, 255);
292 for (int x = 0; x < PANEL_W; x += 40)
293 al_draw_line((float)x, 0, (float)x, HEIGHT, grid, 1);
294 for (int y = 0; y < HEIGHT; y += 40)
295 al_draw_line(0, (float)y, PANEL_W, (float)y, grid, 1);
296
297 al_draw_text(font, al_map_rgb(220, 220, 220), 5, 5, 0,
298 "2D Multi-Waypoint Path");
299
300 /* draw full spline path */
302
303 /* draw all waypoint markers */
304 for (int i = 0; i < wp2d_count; i++) {
305 float wx = (float)wp2d_x[i], wy = (float)wp2d_y[i];
306 ALLEGRO_COLOR wc;
307 if (i == 0)
308 wc = al_map_rgb(0, 200, 0);
309 else if (i == wp2d_count - 1)
310 wc = al_map_rgb(200, 0, 0);
311 else
312 wc = al_map_rgb(100, 150, 255);
313 al_draw_filled_circle(wx, wy, 5, wc);
314 al_draw_circle(wx, wy, 5, al_map_rgb(255, 255, 255), 1);
315
316 char num[16];
317 snprintf(num, sizeof(num), "%d", i);
318 al_draw_text(font, al_map_rgb(200, 200, 200),
319 wx + 7, wy - 6, 0, num);
320 }
321
322 if (running_2d && traj_2d && traj_2d->nb_points >= 2) {
323 /* trail */
325 al_map_rgb(100, 180, 255));
326
327 /* current object */
329 float ox = (float)traj_2d->current.position[0];
330 float oy = (float)traj_2d->current.position[1];
331
332 al_draw_filled_circle(ox, oy, 8,
333 al_map_rgb(255, 180, 0));
334 al_draw_circle(ox, oy, 8,
335 al_map_rgb(255, 255, 255), 2);
336
337 /* velocity arrow */
338 float vs = 0.15f;
339 draw_arrow(ox, oy,
340 ox + (float)traj_2d->current.speed[0] * vs,
341 oy + (float)traj_2d->current.speed[1] * vs,
342 al_map_rgb(255, 255, 100), 1);
343
344 /* info text */
345 char buf[128];
346 const char* mode = "???";
348 mode = "INTERP";
349 else if (traj_2d->mode == TRAJECTORY_EXTRAP)
350 mode = "EXTRAP";
351 else if (traj_2d->mode == TRAJECTORY_BEFORE)
352 mode = "BEFORE";
353
354 snprintf(buf, sizeof(buf), "t=%.2f seg=%d/%d [%s]",
356 traj_2d->nb_points - 1, mode);
357 al_draw_text(font, al_map_rgb(200, 200, 200), 5, 18, 0, buf);
358 snprintf(buf, sizeof(buf), "pos=(%.0f,%.0f) vel=(%.0f,%.0f) wp=%d",
363 wp2d_count);
364 al_draw_text(font, al_map_rgb(200, 200, 200), 5, 34, 0, buf);
365 } else {
366 const char* msg = (wp2d_count == 0)
367 ? "Click to place waypoints"
368 : "Click to add more waypoints";
369 al_draw_text(font, al_map_rgb(150, 150, 150),
370 PANEL_W / 2, 18,
371 ALLEGRO_ALIGN_CENTER, msg);
372 }
373
374 /* legend */
375 al_draw_line(5, HEIGHT - 60, 25, HEIGHT - 60,
376 al_map_rgba(0, 200, 255, 180), 2);
377 al_draw_text(font, al_map_rgb(160, 160, 160),
378 30, HEIGHT - 66, 0, "Interpolation");
379 al_draw_line(5, HEIGHT - 46, 15, HEIGHT - 46,
380 al_map_rgba(255, 255, 0, 120), 1);
381 al_draw_line(18, HEIGHT - 46, 25, HEIGHT - 46,
382 al_map_rgba(255, 255, 0, 120), 1);
383 al_draw_text(font, al_map_rgb(160, 160, 160),
384 30, HEIGHT - 52, 0, "Extrapolation");
385
386 al_draw_text(font, al_map_rgb(90, 90, 90), 5, HEIGHT - 15, 0,
387 "[R] Reset [ESC] Quit");
388}
389
390/* 3D Demo: Init / Update / Draw */
391
392static void init_3d(void) {
394 time_3d = 0.0;
395 trail_3d_count = 0;
396 trail_3d_head = 0;
397
398 /* add all waypoints to the trajectory */
399 double t = 0.0;
400 for (int i = 0; i < NUM_WP3D; i++) {
401 const WAYPOINT3D* w = &waypoints_3d[i];
402 PHYSICS state;
403 init_physics_3d(&state, w->x, w->y, w->z,
404 w->vx, w->vy, w->vz);
405 trajectory_add_point(traj_3d, &state, t);
406 t += WP3D_DUR;
407 }
408 time_3d_end = t - WP3D_DUR; /* time of last waypoint */
409}
410
411static void update_3d_logic(void) {
412 if (!traj_3d || traj_3d->nb_points < 2) return;
413
414 time_3d += DT;
415
416 /* loop when past the last waypoint */
417 if (time_3d >= time_3d_end) {
419 trail_3d_count = 0;
420 trail_3d_head = 0;
421 }
422
424 float sx, sy;
427 traj_3d->current.position[2], &sx, &sy);
428 trail_push_3d(sx, sy);
429}
430
431static void draw_3d_axes(ALLEGRO_FONT* font) {
432 float ox, oy, ax, ay;
433 project_3d(0, 0, 0, &ox, &oy);
434
435 project_3d(2.5, 0, 0, &ax, &ay);
436 draw_arrow(ox, oy, ax, ay, al_map_rgb(200, 60, 60), 2);
437 al_draw_text(font, al_map_rgb(200, 60, 60),
438 ax + 4, ay - 6, 0, "X");
439
440 project_3d(0, 2.5, 0, &ax, &ay);
441 draw_arrow(ox, oy, ax, ay, al_map_rgb(60, 200, 60), 2);
442 al_draw_text(font, al_map_rgb(60, 200, 60),
443 ax + 4, ay - 6, 0, "Y");
444
445 project_3d(0, 0, 2.5, &ax, &ay);
446 draw_arrow(ox, oy, ax, ay, al_map_rgb(60, 60, 200), 2);
447 al_draw_text(font, al_map_rgb(60, 60, 200),
448 ax + 4, ay - 6, 0, "Z");
449}
450
451static void draw_ground_grid(void) {
452 ALLEGRO_COLOR gc = al_map_rgba(45, 45, 45, 128);
453 for (int i = -4; i <= 4; i++) {
454 float x1, y1, x2, y2;
455 project_3d((double)i, 0, -4, &x1, &y1);
456 project_3d((double)i, 0, 4, &x2, &y2);
457 al_draw_line(x1, y1, x2, y2, gc, 1);
458 project_3d(-4, 0, (double)i, &x1, &y1);
459 project_3d(4, 0, (double)i, &x2, &y2);
460 al_draw_line(x1, y1, x2, y2, gc, 1);
461 }
462}
463
464static void draw_full_path_3d(void) {
465 if (!traj_3d || traj_3d->nb_points < 2) return;
466
467 double t0 = traj_3d->points[0].time_val;
468 double t1 = traj_3d->points[traj_3d->nb_points - 1].time_val;
469 int total_steps = (traj_3d->nb_points - 1) * 30;
470
471 VECTOR3D pos;
473 float px, py;
474 project_3d(pos[0], pos[1], pos[2], &px, &py);
475
476 for (int i = 1; i <= total_steps; i++) {
477 double t = t0 + (t1 - t0) * (double)i / (double)total_steps;
479 float nx, ny;
480 project_3d(pos[0], pos[1], pos[2], &nx, &ny);
481 al_draw_line(px, py, nx, ny,
482 al_map_rgba(255, 100, 255, 140), 2);
483 px = nx;
484 py = ny;
485 }
486}
487
488static void draw_3d_panel(ALLEGRO_FONT* font) {
489 al_draw_filled_rectangle(PANEL_W, 0, WIDTH, HEIGHT,
490 al_map_rgb(18, 18, 22));
491
492 al_draw_text(font, al_map_rgb(220, 220, 220),
493 PANEL_W + 5, 5, 0, "3D Multi-Waypoint Loop");
494
496 draw_3d_axes(font);
497
498 if (!traj_3d || traj_3d->nb_points < 2) return;
499
500 /* draw full looping path */
502
503 /* draw waypoint markers */
504 for (int i = 0; i < NUM_WP3D; i++) {
505 float sx, sy;
507 waypoints_3d[i].z, &sx, &sy);
508 ALLEGRO_COLOR c = (i == traj_3d->current_segment ||
509 i == traj_3d->current_segment + 1)
510 ? al_map_rgb(255, 80, 80)
511 : al_map_rgb(100, 100, 200);
512 al_draw_filled_circle(sx, sy, 4, c);
513 al_draw_circle(sx, sy, 4, al_map_rgb(200, 200, 200), 1);
514
515 char num[16];
516 snprintf(num, sizeof(num), "%d", i);
517 al_draw_text(font, al_map_rgb(180, 180, 180),
518 sx + 6, sy - 6, 0, num);
519 }
520
521 /* trail */
523 al_map_rgb(200, 120, 255));
524
525 /* current object */
527 float obj_sx, obj_sy;
531 &obj_sx, &obj_sy);
532
533 /* vertical drop line (depth cue) */
534 float gnd_sx, gnd_sy;
537 &gnd_sx, &gnd_sy);
538 al_draw_line(gnd_sx, gnd_sy, obj_sx, obj_sy,
539 al_map_rgba(100, 100, 100, 80), 1);
540 al_draw_filled_circle(gnd_sx, gnd_sy, 2,
541 al_map_rgba(100, 100, 100, 60));
542
543 /* object */
544 al_draw_filled_circle(obj_sx, obj_sy, 7,
545 al_map_rgb(255, 200, 50));
546 al_draw_circle(obj_sx, obj_sy, 7,
547 al_map_rgb(255, 255, 255), 2);
548
549 /* velocity arrow */
550 double vs3 = 0.4;
551 float vel_sx, vel_sy;
553 traj_3d->current.speed[0] * vs3,
555 traj_3d->current.speed[1] * vs3,
557 traj_3d->current.speed[2] * vs3,
558 &vel_sx, &vel_sy);
559 draw_arrow(obj_sx, obj_sy, vel_sx, vel_sy,
560 al_map_rgb(255, 255, 100), 1);
561
562 /* info text */
563 char buf[128];
564 snprintf(buf, sizeof(buf), "t=%.2f seg=%d/%d wp=%d",
567 al_draw_text(font, al_map_rgb(200, 200, 200),
568 PANEL_W + 5, 18, 0, buf);
569 snprintf(buf, sizeof(buf), "pos=(%.1f, %.1f, %.1f)",
573 al_draw_text(font, al_map_rgb(200, 200, 200),
574 PANEL_W + 5, 34, 0, buf);
575 snprintf(buf, sizeof(buf), "vel=(%.1f, %.1f, %.1f)",
578 traj_3d->current.speed[2]);
579 al_draw_text(font, al_map_rgb(200, 200, 200),
580 PANEL_W + 5, 50, 0, buf);
581}
582
583/* Main */
584
585int main(int argc, char* argv[]) {
586 (void)argc;
588
589 n_log(LOG_NOTICE, "%s is starting ...", argv[0]);
590
591 if (!al_init()) {
592 n_abort("Could not init Allegro.\n");
593 }
594 if (!al_init_primitives_addon()) {
595 n_abort("Unable to initialize primitives addon\n");
596 }
597 if (!al_init_font_addon()) {
598 n_abort("Unable to initialize font addon\n");
599 }
600 if (!al_install_keyboard()) {
601 n_abort("Unable to initialize keyboard handler\n");
602 }
603 if (!al_install_mouse()) {
604 n_abort("Unable to initialize mouse handler\n");
605 }
606
607 al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED);
608 ALLEGRO_DISPLAY* display = al_create_display(WIDTH, HEIGHT);
609 if (!display) {
610 n_abort("Unable to create display\n");
611 }
612 al_set_window_title(display,
613 "Nilorea Trajectory API - Multi-Waypoint Demo");
614
615 ALLEGRO_FONT* font = al_create_builtin_font();
616 ALLEGRO_TIMER* timer = al_create_timer(1.0 / FPS);
617
618 ALLEGRO_EVENT_QUEUE* event_queue = al_create_event_queue();
619 al_register_event_source(event_queue,
620 al_get_display_event_source(display));
621 al_register_event_source(event_queue,
622 al_get_timer_event_source(timer));
623 al_register_event_source(event_queue,
624 al_get_keyboard_event_source());
625 al_register_event_source(event_queue,
626 al_get_mouse_event_source());
627
628 ALLEGRO_BITMAP* scrbuf = al_create_bitmap(WIDTH, HEIGHT);
629
630 reset_2d();
631 init_3d();
632
633 al_start_timer(timer);
634
635 int done = 0;
636 int do_draw = 0;
637
638 while (!done) {
639 ALLEGRO_EVENT ev;
640 al_wait_for_event(event_queue, &ev);
641
642 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
643 done = 1;
644 } else if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
645 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
646 done = 1;
647 } else if (ev.keyboard.keycode == ALLEGRO_KEY_R) {
648 reset_2d();
649 }
650 } else if (ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
651 if (ev.mouse.button == 1) {
652 handle_click_2d((float)ev.mouse.x,
653 (float)ev.mouse.y);
654 }
655 } else if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN ||
656 ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) {
657 al_clear_keyboard_state(display);
658 al_flush_event_queue(event_queue);
659 } else if (ev.type == ALLEGRO_EVENT_TIMER) {
660 /* 2D logic */
661 if (running_2d && traj_2d && traj_2d->nb_points >= 2) {
662 time_2d += DT;
665 (float)traj_2d->current.position[0],
666 (float)traj_2d->current.position[1]);
667 }
668
669 /* 3D logic */
671
672 do_draw = 1;
673 }
674
675 if (do_draw && al_is_event_queue_empty(event_queue)) {
676 al_set_target_bitmap(scrbuf);
677 al_clear_to_color(al_map_rgb(0, 0, 0));
678
679 draw_2d_panel(font);
680 draw_3d_panel(font);
681
682 al_draw_line(PANEL_W, 0, PANEL_W, HEIGHT,
683 al_map_rgb(80, 80, 80), 2);
684
685 al_set_target_bitmap(al_get_backbuffer(display));
686 al_draw_bitmap(scrbuf, 0, 0, 0);
687 al_flip_display();
688 do_draw = 0;
689 }
690 }
691
694 al_destroy_bitmap(scrbuf);
695 al_destroy_font(font);
696 al_destroy_timer(timer);
697 al_destroy_event_queue(event_queue);
698 al_destroy_display(display);
699
700 return 0;
701}
int main(void)
ALLEGRO_DISPLAY * display
Definition ex_fluid.c:54
#define WIDTH
Definition ex_gui.c:42
#define HEIGHT
Definition ex_gui.c:43
#define FPS
static int mode
#define M_PI
bool done
static void draw_3d_axes(ALLEGRO_FONT *font)
static int trail_2d_head
static TRAJECTORY * traj_3d
static void reset_2d(void)
static void rebuild_2d_trajectory(void)
static double wp2d_x[50]
#define NUM_WP3D
static void trail_push_2d(float x, float y)
static void trail_push_3d(float x, float y)
static int running_2d
#define MAX_WP2D
#define PANEL_W
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 double time_3d
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 double time_2d
#define DT
static double wp2d_t[50]
static void init_3d(void)
static const WAYPOINT3D waypoints_3d[7]
static int trail_3d_count
static int trail_2d_count
#define MAX_TRAIL
static double wp2d_y[50]
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 int trail_3d_head
static void draw_ground_grid(void)
static void draw_arrow(float x1, float y1, float x2, float y2, ALLEGRO_COLOR color, float thickness)
static int wp2d_count
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
Definition n_common.c:53
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:80
VECTOR3D speed
vx,vy,vz actual speed
Definition n_3d.h:76
VECTOR3D position
x,y,z actual position
Definition n_3d.h:74
#define VECTOR3D_SET(VECTOR, X, Y, Z)
helper to set a VECTOR3D position
Definition n_3d.h:62
double VECTOR3D[3]
struct of a point
Definition n_3d.h:59
structure of the physics of an object
Definition n_3d.h:70
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.
Generic log system.
Trajectory interpolation and dead reckoning for 2D/3D networked simulations.