plot_sdl.c 92.6 KB
Newer Older
1
2
3
4
5
6
7
8
/*
 * SDL functions (plot curves and handles keyboard, joystick... inputs) functions
 *
 * author: Nicolas Van der Noot
 */

#ifdef SDL

9
#include "useful_functions.h"
10
#include "plot_sdl.h"
Timothee Habra's avatar
Timothee Habra committed
11
#include "cmake_sdl_config.h"
12
13
14
15
#include "time_functions.h"
#include "events_sdl.h"
#include "set_plot.h"
#include "realtime_functions.h"
16
#include "mbs_message.h"
17
#include "mbs_errors_names.h"
18

Nicolas Van der Noot's avatar
Nicolas Van der Noot committed
19
20
21
22
#ifdef JAVA
#include "java_functions.h"
#endif

Nicolas Van der Noot's avatar
Nicolas Van der Noot committed
23
24
25
26
#ifdef OPEN_GL
#include "open_gl_c_int.h"
#endif

27
28
#define TIME_NO_INTERACTION_BREAK 3e6 //!< time eith no interaction to go on break mode [us]
#define TIME_SDL_DELAY 25             //!< time delay for SDL
29

30
 //#define SDL_FILES_PATH ROBOTRAN_SOURCE_DIR"/mbs_common/mbs_realtime/sdl/SDL_files"
31

32
33
34
 /*! \brief initialize the Screen_sdl structure
  *
  * \param[in] options real-time options
35
  * \param[in,out] err <0 if error occurs
36
37
  * \return the initialized SDL main data structure
  */
38
Screen_sdl* init_screen_sdl(Realtime_option *options, int *err, AutoPlot *auto_plot)
39
40
41
42
43
44
{
    // -- Variables declaration -- //

    int i, j;
    int screen_width, screen_height;
    int max_nb_curves, buffer_size;
45
46
    
    *err = 0;
47

48
#ifdef UNIX
49
50
    int x_SDL_position;
    int min_x_SDL_position;
51
#endif
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

    double t0;

    // genral structure
    Screen_sdl *screen_sdl;

    // SDL window
    SDL_Window *win;

    // SDL Renderer
    SDL_Renderer *ren;

    // SDL colors
    SDL_Color text_color;

67
#ifdef UNIX
68
    // display information
69
    SDL_DisplayMode current;
70
#endif
71
72
73

    // -- Structure initialization -- //

74
    screen_sdl = (Screen_sdl*)malloc(sizeof(Screen_sdl));
75

76
    screen_width = options->screen_width;
77
78
    screen_height = options->screen_height;

Nicolas Van der Noot's avatar
Nicolas Van der Noot committed
79
    max_nb_curves = options->max_nb_curves;
80
    buffer_size = options->buffer_size;
81
82

    // initialize SDL
83
84
    SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) != 0)
85
    {
86
87
88
        *err = log_SDL_error("SDL_Init"); 
        free(screen_sdl);
        return NULL;
89
90
91
92
93
94
    }

    screen_sdl->nb_joysticks = SDL_NumJoysticks();

    if (screen_sdl->nb_joysticks >= 1)
    {
95
#ifdef PRINT_REPORT
96
        mbs_msg("Number of joysticks detected: %d\n\n", screen_sdl->nb_joysticks);
97
#endif
98

99
        screen_sdl->joysticks = (SDL_Joystick**)malloc(screen_sdl->nb_joysticks * sizeof(SDL_Joystick*));
100

101
        for (i = 0; i < screen_sdl->nb_joysticks; i++)
102
103
104
        {
            screen_sdl->joysticks[i] = SDL_JoystickOpen(i);

105
            if (screen_sdl->joysticks[i] == NULL)
106
            {
107
108
109
110
111
                mbs_msg("\t >> SDL>> Error to open the joystick !\n");
                *err = _MBS_ERR_MOD_SPEC_13;
                free(screen_sdl->joysticks);
                free(screen_sdl);
                return NULL;
112
113
114
115
116
117
            }
        }

        SDL_JoystickEventState(SDL_ENABLE);
    }

118
#ifdef UNIX
119
120

    // display information
121
    if (SDL_GetCurrentDisplayMode(0, &current))
122
    {
123
124
125
126
        *err = log_SDL_error("SDL_GetCurrentDisplayMode");
        free(screen_sdl->joysticks);
        free(screen_sdl);
        return NULL;
127
128
129
    }

    // SDL window X position
130
    x_SDL_position = (int)(0.75 * current.w - screen_width / 2.0);
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
    min_x_SDL_position = current.w / 2;

    if (x_SDL_position < min_x_SDL_position)
    {
        x_SDL_position = min_x_SDL_position;
    }

    // window
    win = SDL_CreateWindow(
        "Real-time graph",                   // window title
        x_SDL_position,                      // initial x position
        SDL_WINDOWPOS_CENTERED,              // initial y position
        screen_width,                        // width, in pixels
        screen_height,                       // height, in pixels
        SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL // flags
    );

148
#else
149
150
151
152
153
154
155
156
157
158
159

    // window
    win = SDL_CreateWindow(
        "Real-time graph",                   // window title
        SDL_WINDOWPOS_CENTERED,              // initial x position
        SDL_WINDOWPOS_CENTERED,              // initial y position
        screen_width,                        // width, in pixels
        screen_height,                       // height, in pixels
        SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL // flags
    );

160
#endif
161
162

    // pixel size related
163
164
    screen_sdl->curve_width = options->curve_width;
    screen_sdl->screen_width = options->screen_width;
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
    screen_sdl->screen_height = options->screen_height;

    // screen width related
    screen_sdl->plot_x_end = (screen_width - SCREEN_WIDTH_LOSS);
    screen_sdl->screen_plot_width = (screen_sdl->plot_x_end - PLOT_X_START);
    screen_sdl->x_label_width = (screen_sdl->screen_plot_width / X_LABEL_NB);

    // screen height related
    screen_sdl->plot_y_end = (screen_height - SCREEN_BOTTOM_HEIGHT_LOSS);
    screen_sdl->plot_y_mid = ((PLOT_Y_START + screen_sdl->plot_y_end) / 2);
    screen_sdl->screen_plot_height = (screen_sdl->plot_y_end - PLOT_Y_START);
    screen_sdl->y_label_height = (screen_sdl->screen_plot_height / Y_LABEL_NB);

    // bottom indications: y axis
    screen_sdl->bottom_mid_y_indications = (screen_height - (SCREEN_BOTTOM_HEIGHT_LOSS / 2));
    screen_sdl->scaling_indications = (screen_sdl->bottom_mid_y_indications + 3);
    screen_sdl->x_axis_indication = (screen_sdl->bottom_mid_y_indications - 8);
    screen_sdl->y_axis_indication = (screen_sdl->bottom_mid_y_indications + 10);
    screen_sdl->speed_indication_1 = (screen_sdl->bottom_mid_y_indications - 4);
    screen_sdl->speed_indication_2 = (screen_sdl->bottom_mid_y_indications + 14);
    screen_sdl->legend_speed_indication_1 = (screen_sdl->speed_indication_1 - 5);
    screen_sdl->legend_speed_indication_2 = (screen_sdl->speed_indication_2 - 5);
187
    screen_sdl->scaling_bottom_indications = (screen_height - (SCREEN_BOTTOM_HEIGHT_LOSS / 3) + 2);
188
189
190
    screen_sdl->scaling_bottom_arrow_indications_1 = (screen_sdl->scaling_bottom_indications + 2);
    screen_sdl->scaling_bottom_arrow_indications_2 = (screen_sdl->scaling_bottom_indications);
    screen_sdl->scaling_bottom_arrow_indications_3 = (screen_sdl->scaling_bottom_indications + 5);
191
    screen_sdl->scaling_up_indications = (screen_height - ((2 * SCREEN_BOTTOM_HEIGHT_LOSS) / 3));
192
193
    screen_sdl->scaling_up_indications_2 = (screen_sdl->scaling_up_indications + 2);

194
    if (win == NULL)
195
    {
196
197
198
199
        *err = log_SDL_error("SDL_CreateWindow");
        free(screen_sdl->joysticks);
        free(screen_sdl);
        return NULL;
200
201
202
203
204
205
206
    }
    screen_sdl->win = win;

    // renderer
    ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE);

    // the next line is faster, but it causes problems on some computers
207
    //ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
208
209
    if (ren == NULL)
    {
210
211
212
213
        *err = log_SDL_error("SDL_CreateRenderer");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
214
215
216
217
218
219
220
    }
    SDL_RenderClear(ren);
    screen_sdl->ren = ren;

    // TTF (SDL text)
    if (TTF_Init() != 0)
    {
221
222
223
224
        *err = log_SDL_error("TTF_Init");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
225
226
227
    }

    // font for thes axes
228
229
230
231
232
233
234
235
    screen_sdl->font_axis = init_font(SDL_FILES_PATH"/HunDIN1451.ttf", FONT_AXIS_SIZE, err);
    if (*err < 0) 
    { 
        *err = log_SDL_error("Font axis HunDIN1451"); 
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
236
237

    // font for the labels
238
239
240
241
242
243
244
245
    screen_sdl->font_label = init_font(SDL_FILES_PATH"/MonospaceTypewriter.ttf", FONT_LABEL_SIZE, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis MonospaceTypewriter");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
246
247

    // font for the small labels
248
249
250
251
252
253
254
255
    screen_sdl->font_small_label = init_font(SDL_FILES_PATH"/MonospaceTypewriter.ttf", FONT_SMALL_LABEL_SIZE, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis MonospaceTypewriter");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
256
257

    // font for the scaling
258
259
260
261
262
263
264
265
    screen_sdl->font_scaling = init_font(SDL_FILES_PATH"/arrow_7.ttf", FONT_SCALING, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis arrow_7");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
266
267

    // font for the arrows
268
269
270
271
272
273
274
275
    screen_sdl->font_arrows = init_font(SDL_FILES_PATH"/Arrows.ttf", FONT_ARROWS, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis Arrows");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
276
277

    // font for the play icon
278
279
280
281
282
283
284
285
    screen_sdl->font_play = init_font(SDL_FILES_PATH"/Arrows_tbf.ttf", FONT_PLAY_BREAK, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis Arrows_tbf");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
286
287

    // font for the horizontal mouse
288
289
290
291
292
293
294
295
    screen_sdl->font_hor_mouse = init_font(SDL_FILES_PATH"/Arrows_tbf.ttf", FONT_HOR_MOUSE, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis Arrows_tbf");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
296
297

    // font for the mouse (horizontal and vertical)
298
299
300
301
302
303
304
305
    screen_sdl->font_mouse = init_font(SDL_FILES_PATH"/arrow_7.ttf", FONT_MOUSE, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis arrow_7");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
306
307

    // font for the break icon
308
309
310
311
312
313
314
315
    screen_sdl->font_break = init_font(SDL_FILES_PATH"/PIZZADUDEBULLETS.ttf", FONT_PLAY_BREAK, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis PIZZADUDEBULLETS");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
316
317

    // font for the speed of the simulation
318
319
320
321
322
323
324
325
    screen_sdl->font_speed = init_font(SDL_FILES_PATH"/Arrows.ttf", FONT_SPEED, err);
    if (*err < 0)
    {
        *err = log_SDL_error("Font axis Arrows");
        if (screen_sdl->nb_joysticks >= 1) { free(screen_sdl->joysticks); }
        free(screen_sdl);
        return NULL;
    }
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365


    // text color: black
    text_color.r = 0;
    text_color.g = 0;
    text_color.b = 0;
    text_color.a = 0;
    screen_sdl->text_color = text_color;

    // index of the sdl window and vectors
    screen_sdl->index_vec = 0;
    screen_sdl->index_sdl = 0;

    // time for a pixel
    screen_sdl->tsim_pixel = 1.0 / options->fqc_screen;

    // x axis bounds
    screen_sdl->x_min = 0.0;
    screen_sdl->x_max = 0.0;

    // y axis bounds
    screen_sdl->y_min = options->y_min_init;
    screen_sdl->y_max = options->y_max_init;

    screen_sdl->last_y_min = screen_sdl->y_min;
    screen_sdl->last_y_max = screen_sdl->y_max;

    screen_sdl->last_legend_x_min = screen_sdl->x_min;
    screen_sdl->last_legend_x_max = screen_sdl->x_max;

    screen_sdl->last_legend_y_min = screen_sdl->y_min;
    screen_sdl->last_legend_y_max = screen_sdl->y_max;

    // time limits
    t0 = options->t0;

    screen_sdl->min_tsim = t0;
    screen_sdl->max_tsim = t0 + SAFETY_TIME;

    screen_sdl->min_tsim_index = 0;
366
367
    screen_sdl->max_tsim_index = buffer_size - 1;

368
369
370
371
372
    screen_sdl->flag_started = 0;
    screen_sdl->flag_buffer_round = 0;

    // x label
    screen_sdl->x_label_print_count = 0;
373
    screen_sdl->last_x_label_flag = 0;
374
375

    // scaling
376
    screen_sdl->scaling_flag = 0;
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
    screen_sdl->last_scaling_flag = 0;

    // break
    screen_sdl->break_plot_flag = 0;

    // string exponents
    screen_sdl->expo_y = 0;
    screen_sdl->expo_x = 0;

    // flag: horizontal plot
    screen_sdl->hor_plot_scaling = 0;

    // flag: bottom indications
    screen_sdl->bottom_flag = 1;

    // flags: modify y axis
    screen_sdl->increase_plot_y_diff_flag = 0;
    screen_sdl->decrease_plot_y_diff_flag = 0;
    screen_sdl->up_plot_y_flag = 0;
    screen_sdl->bottom_plot_y_flag = 0;

    // flags: modify x axis
    screen_sdl->increase_plot_x_diff_flag = 0;
    screen_sdl->decrease_plot_x_diff_flag = 0;
401
    screen_sdl->left_plot_y_flag = 0;
402
403
404
405
    screen_sdl->right_plot_y_flag = 0;

    screen_sdl->cur_nb_curves = 0;

406
    // full vectors save
407
    screen_sdl->y_save = (double**)malloc(max_nb_curves * sizeof(double*));
408

409
    screen_sdl->previous_y_vec = (double*)malloc(max_nb_curves * sizeof(double));
410

411
    for (i = 0; i < max_nb_curves; i++)
412
413
414
415
416
    {
        screen_sdl->previous_y_vec[i] = 0.0;
    }

    // y values tab for SDL
417
418
    screen_sdl->y_tab = (double**)malloc(max_nb_curves * sizeof(double*));
    for (i = 0; i < max_nb_curves; i++)
419
    {
420
        screen_sdl->y_tab[i] = (double*)malloc(screen_sdl->screen_plot_width * sizeof(double));
421

422
        for (j = 0; j < screen_sdl->screen_plot_width; j++)
423
424
425
426
427
428
        {
            screen_sdl->y_tab[i][j] = 0.0;
        }
    }

    // minimal and maximal values (for auto-scaling)
429
430
    screen_sdl->y_tab_min = (double*)malloc(max_nb_curves * sizeof(double));
    screen_sdl->y_tab_max = (double*)malloc(max_nb_curves * sizeof(double));
431

432
433
    screen_sdl->scaling_expo_mult = (int*)malloc(max_nb_curves * sizeof(int));
    screen_sdl->last_scaling_expo_mult = (int*)malloc(max_nb_curves * sizeof(int));
434

435
436
437
438
    screen_sdl->scaling_offset = (double*)malloc(max_nb_curves * sizeof(double));
    screen_sdl->last_scaling_offset = (double*)malloc(max_nb_curves * sizeof(double));

    for (i = 0; i < max_nb_curves; i++)
439
440
441
442
    {
        screen_sdl->y_tab_min[i] = START_VECTOR;
        screen_sdl->y_tab_max[i] = START_VECTOR;

443
        screen_sdl->scaling_expo_mult[i] = 0;
444
445
        screen_sdl->last_scaling_expo_mult[i] = 0;

446
        screen_sdl->scaling_offset[i] = 0.0;
447
448
449
450
        screen_sdl->last_scaling_offset[i] = 0.0;
    }

    // full time save
451
    screen_sdl->tsim_save = (double*)malloc(buffer_size * sizeof(double));
452

453
    for (i = 0; i < buffer_size; i++)
454
455
456
457
458
459
460
461
    {
        screen_sdl->tsim_save[i] = t0;
    }

    // buffer size
    screen_sdl->buffer_size = buffer_size;

    // time vector for SDL
462
463
    screen_sdl->t_vec = (double*)malloc(screen_sdl->screen_plot_width * sizeof(double));
    for (i = 0; i < screen_sdl->screen_plot_width; i++)
464
465
466
467
468
    {
        screen_sdl->t_vec[i] = t0;
    }

    // colors
469
    for (i = 0; i < NB_COLORS_SDL; i++)
470
471
    {
        screen_sdl->color_tab[i] = options->color_tab[i];
472
    }
473
474
475
476

    screen_sdl->last_color = -1;

    // auto-scaling
477
478
479
    screen_sdl->plot_auto_scaling = 0;
    screen_sdl->signal_auto_scaling = 0;
    screen_sdl->last_plot_auto_scaling = 0;
480
    screen_sdl->last_signal_auto_scaling = 0;
481
    screen_sdl->change_mouse_wheel_flag = 0;
482
483
484
485
486
487

    screen_sdl->nb_legends = 0;
    screen_sdl->max_nb_legends = options->max_nb_legends;

    screen_sdl->max_nb_curves = max_nb_curves;

488
489

    screen_sdl->auto_plot = auto_plot;
490
491
492
493
494
495
496
497
498

    // clean the screen for the first time
    refresh_screen(screen_sdl);

    // return structure
    return screen_sdl;
}

/*! \brief update for new user curves
499
 *
500
501
 * \param[in,out] screen_sdl SDL main data structure
 * \param[in] nb_new_curves number of new curves
502
 * \param[in] y_curves current y values
503
 */
504
void new_curves_save(Screen_sdl *screen_sdl, int nb_new_curves, double *y_curves)
505
506
507
508
{
    int i, j;
    int cur_nb_curves, buffer_size;

509
    cur_nb_curves = screen_sdl->cur_nb_curves;
510
511
    buffer_size = screen_sdl->buffer_size;

512
    for (i = cur_nb_curves; i < cur_nb_curves + nb_new_curves; i++)
513
    {
514
        screen_sdl->y_save[i] = (double*)malloc(buffer_size * sizeof(double));
515

516
        for (j = 0; j <= screen_sdl->min_tsim_index; j++)
517
        {
518
519
520
            screen_sdl->y_save[i][j] = y_curves[i];
        }

521
        for (j = screen_sdl->min_tsim_index + 1; j < buffer_size; j++)
522
523
        {
            screen_sdl->y_save[i][j] = 0.0;
524
525
        }
    }
526

527
528
529
530
    screen_sdl->cur_nb_curves += nb_new_curves;
}

/*! \brief initialize a new Font variable (pointer)
531
 *
532
533
 * \param[in] folder folder with Fonts
 * \param[in] font_size font size
534
535
 * \param[in,out] err <0 if error occurs
 *
536
537
 * \return requested Font variable (pointer)
 */
538
TTF_Font* init_font(char *folder, int font_size, int *err)
539
540
541
{
    TTF_Font* font;

542
543
    *err = 0;

544
545
546
547
    font = TTF_OpenFont(folder, font_size);

    if (font == NULL)
    {
548
        *err = log_SDL_error("TTF_OpenFont");
549
550
551
552
553
554
    }

    return font;
}

/*! \brief free the main SDL structure
555
 *
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
 * \param[out] screen_sdl SDL main data structure
 */
void free_screen_sdl(Screen_sdl *screen_sdl)
{
    // variable declaration
    int i;

    // fonts
    TTF_CloseFont(screen_sdl->font_label);
    TTF_CloseFont(screen_sdl->font_small_label);
    TTF_CloseFont(screen_sdl->font_axis);
    TTF_CloseFont(screen_sdl->font_scaling);
    TTF_CloseFont(screen_sdl->font_arrows);
    TTF_CloseFont(screen_sdl->font_play);
    TTF_CloseFont(screen_sdl->font_hor_mouse);
    TTF_CloseFont(screen_sdl->font_mouse);
    TTF_CloseFont(screen_sdl->font_break);
    TTF_CloseFont(screen_sdl->font_speed);

    // joystick
    if (screen_sdl->nb_joysticks >= 1)
    {
578
        for (i = 0; i < screen_sdl->nb_joysticks; i++)
579
580
581
582
583
584
585
586
587
588
589
        {
            SDL_JoystickClose(screen_sdl->joysticks[i]);
        }
        free(screen_sdl->joysticks);
    }

    // SDL main variables
    SDL_DestroyRenderer(screen_sdl->ren);
    SDL_DestroyWindow(screen_sdl->win);
    SDL_Quit();

590
    free(screen_sdl->tsim_save);
591
592
593

    free(screen_sdl->t_vec);

594
595

    for (i = 0; i < screen_sdl->max_nb_curves; i++)
596
597
598
599
    {
        free(screen_sdl->y_tab[i]);
    }

600
    for (i = 0; i < screen_sdl->cur_nb_curves; i++)
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
    {
        free(screen_sdl->y_save[i]);
    }

    free(screen_sdl->y_tab);
    free(screen_sdl->y_save);
    free(screen_sdl->previous_y_vec);
    free(screen_sdl->y_tab_min);
    free(screen_sdl->y_tab_max);
    free(screen_sdl->scaling_expo_mult);
    free(screen_sdl->last_scaling_expo_mult);
    free(screen_sdl->scaling_offset);
    free(screen_sdl->last_scaling_offset);

    free_set_plot();

    if (screen_sdl->nb_legends)
    {
        free(screen_sdl->pixel_pos_label);
    }

    free(screen_sdl);
}

/*! \brief show an error message and exit the simulation
626
 *
627
 * \param[in] SDL_function SDL function name
628
 * \return Error status, <0 in case of failure.
629
 */
630
int log_SDL_error(char *SDL_function)
631
{
632
    mbs_msg("\t >SDL> %s error: %s\n", SDL_function, SDL_GetError());
633
634
    mbs_msg("[%d] in log_SDL_error !! \n", _MBS_ERR_MOD_SPEC_13);
    return _MBS_ERR_MOD_SPEC_13;
635
636
637
}

/*! \brief change the color in SDL
638
 *
639
640
641
642
643
644
645
646
647
 * \param[in,out] screen_sdl SDL main data structure
 * \param[in] color_num color number
 */
void SDL_set_color(Screen_sdl *screen_sdl, int color_num)
{
    // variable decalration
    SDL_Renderer *ren;

    // safety
648
    while (color_num >= NB_COLORS_TOT_SDL)
649
    {
650
        color_num -= NB_COLORS_TOT_SDL;
651
    }
652
    while (color_num < 0)
653
    {
654
        color_num += NB_COLORS_TOT_SDL;
655
    }
656

657
658
659
660
661
662
663
664
665
666
667
668
669
    // no change in the color since previous time
    if (screen_sdl->last_color == color_num)
    {
        return;
    }

    screen_sdl->last_color = color_num;

    ren = screen_sdl->ren;

    // select the good color
    switch (color_num)
    {
670
671
672
    case WHITE_SDL:
        SDL_SetRenderDrawColor(ren, 255, 255, 255, 0);
        break;
673

674
675
676
    case BLACK_SDL:
        SDL_SetRenderDrawColor(ren, 0, 0, 0, 1);
        break;
677

678
679
680
    case LIGHT_GRAY_SDL:
        SDL_SetRenderDrawColor(ren, 220, 212, 212, 0);
        break;
681

682
683
684
    case BLUE_SDL:
        SDL_SetRenderDrawColor(ren, 0, 0, 255, 0);
        break;
685

686
687
688
    case RED_SDL:
        SDL_SetRenderDrawColor(ren, 255, 0, 0, 0);
        break;
689

690
691
692
    case DARK_GREEN_SDL:
        SDL_SetRenderDrawColor(ren, 33, 75, 31, 0);
        break;
693

694
695
696
    case PURPLE_SDL:
        SDL_SetRenderDrawColor(ren, 131, 15, 246, 0);
        break;
697

698
699
700
    case TURQUOISE_SDL:
        SDL_SetRenderDrawColor(ren, 15, 246, 238, 0);
        break;
701

702
703
704
    case ORANGE_SDL:
        SDL_SetRenderDrawColor(ren, 243, 134, 26, 0);
        break;
705

706
707
708
    case LIGHT_BLUE_SDL:
        SDL_SetRenderDrawColor(ren, 15, 146, 246, 0);
        break;
709

710
711
712
    case PINK_SDL:
        SDL_SetRenderDrawColor(ren, 246, 15, 215, 0);
        break;
713

714
715
716
    case LIGHT_GREEN_SDL:
        SDL_SetRenderDrawColor(ren, 23, 246, 15, 0);
        break;
717

718
719
720
    case DARK_YELLOW_SDL:
        SDL_SetRenderDrawColor(ren, 175, 165, 27, 0);
        break;
721

722
723
724
    case YELLOW_SDL:
        SDL_SetRenderDrawColor(ren, 239, 225, 36, 0);
        break;
725

726
727
728
729
730
731
    case GREEN_SDL:
        SDL_SetRenderDrawColor(ren, 0, 255, 0, 0);
        break;

    default:
        break;
732
733
734
735
    }
}

/*! \brief refresh the screen with the white color
736
 *
737
738
 * \param[in,out] screen_sdl SDL main data structure
 */
739
int refresh_screen(Screen_sdl *screen_sdl)
740
{
741
    int err = 0;
742
    SDL_set_color(screen_sdl, WHITE_SDL);
743
744
    err = SDL_RenderClear(screen_sdl->ren);
    return err;
745
746
747
}

/*! \brief draw a pixel, coordinates: i, j
748
 *
749
750
751
752
 * \param[in] ren SDL renderer
 * \param[in] i x coordinate
 * \param[in] j y coordinate
 *
753
754
 * For some mysterious reasons, using the 'SDL_RenderFillRect'
 * function with 1x1 rectangles is 2 times faster than using
755
756
757
758
759
 * the 'SDL_RenderDrawPoint' function
 */
void draw_pixel(SDL_Renderer *ren, int i, int j)
{
    SDL_Rect rectangle;
760

761
762
763
764
765
766
767
768
    rectangle.x = i;
    rectangle.y = j;
    rectangle.w = 1;
    rectangle.h = 1;
    SDL_RenderFillRect(ren, &rectangle);
}

/*! \brief draw a rectangle (x axis: [x1 ; x2] , y axis: [y1 ; y2])
769
 *
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
 * \pre x1 <= x2
 * \pre y1 <= y2
 * \param[in] ren SDL renderer
 * \param[in] x1 min x coordinate
 * \param[in] x2 max x coordinate
 * \param[in] y1 min y coordinate
 * \param[in] y2 max y coordinate
 */
void draw_rectangle(SDL_Renderer *ren, int x1, int x2, int y1, int y2)
{
    SDL_Rect rect;

    rect.x = x1;
    rect.y = y1;
    rect.w = x2 - x1 + 1;
    rect.h = y2 - y1 + 1;
    SDL_RenderFillRect(ren, &rect);
}

/*! \brief draw a horizontal line (x axis: [x1 ; x2] , y axis: y)
790
 *
791
792
793
794
795
796
797
798
799
800
801
802
 * \pre x1 <= x2
 * \param[in] ren SDL renderer
 * \param[in] x1 min x coordinate
 * \param[in] x2 max x coordinate
 * \param[in] y y coordinate
 */
void draw_horizontal_line(SDL_Renderer *ren, int x1, int x2, int y)
{
    SDL_RenderDrawLine(ren, x1, y, x2, y);
}

/*! \brief draw a vertical line (x axis: x , y axis: [y1 ; y2])
803
 *
804
805
806
807
808
809
810
811
812
813
814
815
 * \pre y1 <= y2
 * \param[in] ren SDL renderer
 * \param[in] x x coordinate
 * \param[in] y1 min y coordinate
 * \param[in] y2 max y coordinate
 */
void draw_vertical_line(SDL_Renderer *ren, int x, int y1, int y2)
{
    SDL_RenderDrawLine(ren, x, y1, x, y2);
}

/*! \brief print a text
816
 *
817
818
819
 * \param[in] str string to print
 * \param[in] font Font to use
 * \param[in] txt_col text color
820
 * \param[in] ren SDL renderer
821
822
823
824
825
826
827
 * \param[in] x x position
 * \param[in] y y position
 * \param[in] pos_flag position flag
 */
void print_text_sdl(char *str, TTF_Font *font, SDL_Color txt_col, SDL_Renderer *ren, int x, int y, int pos_flag)
{
    SDL_Texture *text_texture;
828

829
830
831
832
833
834
    text_texture = renderText(font, str, txt_col, ren);
    renderTexture(text_texture, ren, x, y, pos_flag);
    SDL_DestroyTexture(text_texture);
}

/*! \brief apply a texture at a given corrdinate point
835
 *
836
 * \param[in] tex SDL texture
837
 * \param[in] ren SDL renderer
838
839
840
841
842
843
844
845
846
847
848
 * \param[in] x x position
 * \param[in] y y position
 * \param[in] pos_flag position flag
 */
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y, int pos_flag)
{
    //Setup the destination rectangle to be at the position we want
    SDL_Rect dst;
    SDL_Rect clip;

    //Query the texture to get its width and height to use
849
    SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
850
851
852
853
854
855
856
857
858

    clip.x = 0;
    clip.y = 0;

    clip.w = dst.w;
    clip.h = dst.h;

    switch (pos_flag)
    {
859
860
861
862
    case 1: // position: right-bottom corner
        dst.x = x - dst.w;
        dst.y = y - dst.h;
        break;
863

864
865
866
867
868
869
870
871
872
    case 2: // position: left-mid height
        dst.x = x;
        dst.y = y - (dst.h / 2);
        break;

    default:
        dst.x = x;
        dst.y = y;
        break;
873
874
    }

875
    SDL_RenderCopy(ren, tex, &clip, &dst);
876
877
878
}

/*! \brief create a texture for a message
879
 *
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
 * \param[in] font requested Font
 * \param[in] message requested message
 * \param[in] text_color text color
 * \param[in] ren SDL renderer
 * \return requested message texture
 */
SDL_Texture* renderText(TTF_Font *font, char *message, SDL_Color text_color, SDL_Renderer *ren)
{
    SDL_Surface *text_surf;
    SDL_Texture *text_texture;

    text_surf = TTF_RenderText_Solid(font, message, text_color);
    if (text_surf == NULL)
    {
        log_SDL_error("TTF_RenderText_Solid");
    }

    text_texture = SDL_CreateTextureFromSurface(ren, text_surf);

    if (text_texture == NULL)
    {
        log_SDL_error("SDL_CreateTextureFromSurface");
    }

    SDL_FreeSurface(text_surf);

    return text_texture;
}

/*! \brief update the vectors and tabs used for the plots
910
 *
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
 * \param[in,out] realtime real-time structure
 * \param[in] t curent simulation time [s]
 *
 * the min-max vectors used for the auto-scaling are also updated
 */
void update_plot_vectors(Simu_realtime *realtime, double t)
{
    Screen_sdl *screen_sdl;

    screen_sdl = realtime->ext->sdl->screen_sdl;

    screen_sdl->index_vec++;

    if (screen_sdl->index_vec >= screen_sdl->screen_plot_width)
    {
        screen_sdl->index_vec -= screen_sdl->screen_plot_width;
    }

    screen_sdl->t_vec[screen_sdl->index_vec] = t;
930

931
932
933
    update_scale_signals(screen_sdl, realtime, 0);
}

934
/*! \brief update 'y_tab' and 't_vec' for plot data during the breaks
935
 *
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
 * \param[in,out] screen_sdl SDL main data structure
 */
void update_y_tab(Screen_sdl *screen_sdl)
{
    // -- Variables declaration -- //

    int i, j;
    int nb_curves;
    int prev_index, next_index;
    int buffer_size;
    int min_tsim_index, max_tsim_index;
    int flag_buffer_round;

    double weight_prev;
    double x_min, x_max, diff_x, step_x;
    double request_tsim;
    double tsim_prev, tsim_next;
    double min_tsim, max_tsim;
Nicolas Van der Noot's avatar
Nicolas Van der Noot committed
954
    double delta_tsim;
955
956
957
958
959
960
961
962
963
964
965
966

    double *tsim_save;
    double **y_save;
    double **y_tab;
    double *t_vec;

    AutoPlot *auto_plot;

    // -- Variables initialization -- //

    auto_plot = screen_sdl->auto_plot;

967
    nb_curves = auto_plot->nb;
968

Nicolas Van der Noot's avatar
Nicolas Van der Noot committed
969
970
971
972
973
974
    min_tsim = screen_sdl->min_tsim;
    max_tsim = screen_sdl->max_tsim;

    t_vec = screen_sdl->t_vec;

    // no curves: just fill t_vec with time from origin
975
976
    if (!nb_curves)
    {
Nicolas Van der Noot's avatar
Nicolas Van der Noot committed
977
978
979
980
981
        delta_tsim = (max_tsim - min_tsim) / (screen_sdl->screen_plot_width - 1);

        // safety
        if (delta_tsim <= 0.0) { return; }

982
        for (i = 0; i < screen_sdl->screen_plot_width; i++)
Nicolas Van der Noot's avatar
Nicolas Van der Noot committed
983
984
985
986
        {
            t_vec[i] = min_tsim + i * delta_tsim;
        }

987
        screen_sdl->index_vec = screen_sdl->screen_plot_width - 1;
988
989
990
        return;
    }

991
    tsim_save = screen_sdl->tsim_save;
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
    y_save = screen_sdl->y_save;

    min_tsim_index = screen_sdl->min_tsim_index;
    max_tsim_index = screen_sdl->max_tsim_index;

    buffer_size = screen_sdl->buffer_size;

    x_min = screen_sdl->x_min;
    x_max = screen_sdl->x_max;

    y_tab = screen_sdl->y_tab;

    flag_buffer_round = screen_sdl->flag_buffer_round;

    if (!max_tsim)
    {
        return;
    }

    // safety if not yet updated
    if (!screen_sdl->flag_started)
    {
1014
        for (i = 0; i < screen_sdl->screen_plot_width; i++)
1015
1016
1017
        {
            t_vec[i] = 0.0;

1018
            for (j = 0; j < nb_curves; j++)
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
            {
                y_tab[j][i] = 0.0;
            }
        }

        // update the index for SDL
        screen_sdl->index_vec = screen_sdl->screen_plot_width - 1;

        return;
    }

    // step in the x axis for each pixel
    diff_x = x_max - x_min;
    step_x = diff_x / screen_sdl->screen_plot_width;

    // tsim value expected
    request_tsim = x_min + (step_x / 2.0);

    // loop on all the pixels
1038
    for (i = 0; i < screen_sdl->screen_plot_width; i++)
1039
1040
1041
1042
1043
1044
    {
        guess_tsim_index(request_tsim, tsim_save, min_tsim_index, max_tsim_index, min_tsim, max_tsim, buffer_size, flag_buffer_round, &prev_index, &next_index);

        if (prev_index == next_index)
        {
            // loop on all the curves
1045
            for (j = 0; j < nb_curves; j++)
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
            {
                y_tab[j][i] = y_save[j][prev_index];
            }

            // time vector
            t_vec[i] = tsim_save[prev_index];
        }
        else
        {
            // time
            tsim_prev = tsim_save[prev_index];
            tsim_next = tsim_save[next_index];

            // weight for the linear interpolation
            if (tsim_next > tsim_prev)
            {
                weight_prev = (tsim_next - request_tsim) / (tsim_next - tsim_prev);
            }
            else
            {
                weight_prev = 0.0;
            }

            // loop on all the curves
1070
            for (j = 0; j < nb_curves; j++)
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
            {
                y_tab[j][i] = weight_prev * y_save[j][prev_index] + (1 - weight_prev) * y_save[j][next_index];
            }

            // time vector
            t_vec[i] = weight_prev * tsim_prev + (1 - weight_prev) * tsim_next;
        }

        // new time value
        request_tsim += step_x;
    }

    // update the index for SDL
    screen_sdl->index_vec = screen_sdl->screen_plot_width - 1;
}

/*! \brief update legends for new number of curves
1088
 *
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
 * \param[in,out] realtime real-time structure
 * \param[in] new_nb_legends new number of curves
 */
void update_sdl_legend(Simu_realtime *realtime, int new_nb_legends)
{
    int i;
    int nb_legends;
    int space_up_label;

    Screen_sdl *screen_sdl;

    screen_sdl = realtime->ext->sdl->screen_sdl;

    // safety
    if (new_nb_legends > screen_sdl->max_nb_legends)
    {
        new_nb_legends = screen_sdl->max_nb_legends;
    }
    else if (new_nb_legends < 0)
    {
        new_nb_legends = 0;
    }

    nb_legends = screen_sdl->nb_legends;

    // no update needed
    if (new_nb_legends == nb_legends)
    {
        return;
    }

    if (nb_legends)
    {
        free(screen_sdl->pixel_pos_label);
    }

    // position of the labels
    if (new_nb_legends)
    {
1128
        screen_sdl->pixel_pos_label = (int*)malloc(new_nb_legends * sizeof(int));
1129
1130
1131

        space_up_label = (screen_sdl->screen_width - UP_COLOR_WIDTH_LOSS_BEGIN - UP_COLOR_WIDTH_LOSS_END) / new_nb_legends;

1132
        for (i = 0; i < new_nb_legends; i++)
1133
        {
1134
            screen_sdl->pixel_pos_label[i] = UP_COLOR_WIDTH_LOSS_BEGIN + i * space_up_label;
1135
1136
1137
1138
        }
    }

    screen_sdl->nb_legends = new_nb_legends;
1139

1140
1141
1142
1143
    plot_screen_sdl(realtime, realtime->tsim, 3);
}

/*! \brief bound the screen motion to stay in the x bounds
1144
 *
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
 * \param[in] min_thres minimal threshold
 * \param[in] max_thres maximal threshold
 * \param[in] cur_min current minimum
 * \param[in] cur_max current maximum
 * \param[in] cur_move current move
 * \param[in] sign_flag flag for sign
 * \return move bounded
 */
double bound_diff_min_max(double min_thres, double max_thres, double cur_min, double cur_max, double cur_move, int sign_flag)
{
    // variables declaration

    double new_min, new_max;

1159
    // bound: minimal
1160
1161
1162
1163
1164

    if (sign_flag <= 0)
    {
        new_min = cur_min - cur_move;
    }
1165
    else
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
    {
        new_min = cur_min + cur_move;
    }

    if (new_min <= min_thres)
    {
        if (sign_flag <= 0)
        {
            cur_move = cur_min - min_thres;
        }
1176
        else
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
        {
            cur_move = min_thres - cur_min;
        }
    }

    // bound: maximal

    if (sign_flag >= 0)
    {
        new_max = cur_max + cur_move;
    }
1188
    else
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
    {
        new_max = cur_max - cur_move;
    }

    if (new_max >= max_thres)
    {
        if (sign_flag >= 0)
        {
            cur_move = max_thres - cur_max;
        }
        else
        {
            cur_move = cur_max - max_thres;
        }
    }

    return cur_move;
}

/*! \brief update the plot ranges according to the mouse inputs
1209
 *
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
 * \param[in,out] screen_sdl SDL main data structure
 * \param[in,out] realtime real-time structure
 * \param[in] tsim current simulation time [s]
 * \param[in] mouse_flag flag for the mouse
 */
void mouse_sdl(Screen_sdl *screen_sdl, Simu_realtime *realtime, double tsim, int mouse_flag)
{
    // variables declaration

    double x_min_plot, x_max_plot, y_min_plot, y_max_plot;
    double diff_x_plot, diff_y_plot;
    double new_diff_x_plot, new_diff_y_plot;
    double move_x_min_max, move_y_min_max;
    double ratio_min_x, ratio_min_y;
    double x_star, y_star;

    Realtime_sdl *realtime_sdl;

    realtime_sdl = realtime->ext->sdl;

    // y axis

1232
    if ((!realtime_sdl->mouse_wheel_flag) || (realtime_sdl->mouse_wheel_flag == 1))
1233
    {
1234
1235
        y_min_plot = screen_sdl->y_min;
        y_max_plot = screen_sdl->y_max;
1236
1237
1238
1239
1240
1241
1242
1243
        diff_y_plot = y_max_plot - y_min_plot;

        if (!mouse_flag)
        {
            move_y_min_max = (realtime_sdl->mouse_delta_y * diff_y_plot) / screen_sdl->screen_plot_height;
        }
        else
        {
1244
1245
            ratio_min_y = 1.0 - (((double)realtime_sdl->mouse_cur_y - PLOT_Y_START) / screen_sdl->screen_plot_height);
            y_star = y_min_plot + ratio_min_y * diff_y_plot;
1246
1247
1248
1249
1250
1251
1252
        }

        if (!mouse_flag)
        {
            screen_sdl->y_min = y_min_plot + move_y_min_max;
            screen_sdl->y_max = y_max_plot + move_y_min_max;
        }
1253
        else
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
        {
            if (mouse_flag < 0)
            {
                new_diff_y_plot = diff_y_plot / WHEEL_MOUSE_FACTOR;
            }
            else
            {
                new_diff_y_plot = diff_y_plot * WHEEL_MOUSE_FACTOR;
            }

            screen_sdl->y_min = y_star - ratio_min_y * new_diff_y_plot;
            screen_sdl->y_max = screen_sdl->y_min + new_diff_y_plot;
        }
    }


    // x axis

    if (realtime->simu_break)
    {
1274
        if ((!realtime_sdl->mouse_wheel_flag) || (realtime_sdl->mouse_wheel_flag == 2))
1275
        {
1276
1277
            x_min_plot = screen_sdl->x_min;
            x_max_plot = screen_sdl->x_max;
1278
1279
1280
1281
1282
1283
1284
1285
            diff_x_plot = x_max_plot - x_min_plot;

            if (!mouse_flag)
            {
                move_x_min_max = (realtime_sdl->mouse_delta_x * diff_x_plot) / screen_sdl->screen_plot_width;
            }
            else
            {
1286
1287
                ratio_min_x = ((double)realtime_sdl->mouse_cur_x) / screen_sdl->screen_plot_width;
                x_star = x_min_plot + ratio_min_x * diff_x_plot;
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
            }

            if (!mouse_flag)
            {
                // safety for the bounds
                move_x_min_max = bound_diff_min_max(screen_sdl->min_tsim, screen_sdl->max_tsim, x_min_plot, x_max_plot, move_x_min_max, -1);

                screen_sdl->x_min = x_min_plot - move_x_min_max;
                screen_sdl->x_max = x_max_plot - move_x_min_max;
            }
            else
            {
                if (mouse_flag < 0)
                {
                    new_diff_x_plot = diff_x_plot / WHEEL_MOUSE_FACTOR;
                }
                else
                {
                    new_diff_x_plot = diff_x_plot * WHEEL_MOUSE_FACTOR;
                }

                screen_sdl->x_min = x_star - ratio_min_x * new_diff_x_plot;
                screen_sdl->x_max = screen_sdl->x_min + new_diff_x_plot;

                if (screen_sdl->x_min <= realtime->t0)
                {
                    screen_sdl->x_min = realtime->t0;
                }

                if (screen_sdl->x_max >= tsim)
                {
                    screen_sdl->x_max = tsim;
                }
            }
1322
        }
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
    }
    else
    {
        screen_sdl->scaling_flag = 1;
    }

    limit_x_limits(screen_sdl);

    // update the plots
    plot_screen_sdl(realtime, tsim, realtime->simu_break);
}

/*! \brief set 'bottom_flag' to 1
1336
 *
1337
1338
1339
1340
1341
1342
 * \param[in,out] realtime real-time structure
 */
void set_bottom_flag(Simu_realtime *realtime)
{
    Screen_sdl *screen_sdl;

1343
    screen_sdl = (Screen_sdl*)realtime->ext->sdl->screen_sdl;
1344
1345
1346
1347
1348

    screen_sdl->bottom_flag = 1;
}

/*! \brief compute the minimal and maximal times at the beginning and at the end of a break
1349
 *
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
 * \param[in,out] screen_sdl SDL main data structure
 * \param[in,out] realtime real-time structure
 */
void update_x_min_max(Screen_sdl *screen_sdl, Simu_realtime *realtime)
{
    double cur_tsim;

    cur_tsim = screen_sdl->tsim_save[screen_sdl->max_tsim_index];

    screen_sdl->x_max = cur_tsim;
1360
    screen_sdl->x_min = cur_tsim - (screen_sdl->tsim_pixel * screen_sdl->screen_plot_width * get_simu_speed_factor(realtime->simu_speed_flag));
1361
1362
1363
1364
1365

    limit_x_limits(screen_sdl);
}

/*! \brief update the minimal and maximal value of each signal
1366
 *
1367
1368
1369
1370
1371
1372
1373
1374
1375