Subversion Repositories shark

Rev

Rev 1655 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1655 giacomo 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
11
 *   Luca Abeni          <luca@gandalf.sssup.it>
12
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
 
22
/**
23
 ------------
24
 CVS :        $Id: control.c,v 1.1.1.1 2004-05-24 18:03:39 giacomo Exp $
25
 
26
 File:        $File$
27
 Revision:    $Revision: 1.1.1.1 $
28
 Last update: $Date: 2004-05-24 18:03:39 $
29
 ------------
30
**/
31
 
32
/*
33
 * Copyright (C) 2000 Marco Dallera and Marco Fiocca
34
 *
35
 * This program is free software; you can redistribute it and/or modify
36
 * it under the terms of the GNU General Public License as published by
37
 * the Free Software Foundation; either version 2 of the License, or
38
 * (at your option) any later version.
39
 *
40
 * This program is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43
 * GNU General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU General Public License
46
 * along with this program; if not, write to the Free Software
47
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
48
 *
49
 */
50
 
51
/*
52
 *              AUTO
53
 *
54
 * Another Unuseful Track simulatOr
55
 *
56
 * Authors: Marco Dallera
57
 *          Marco Fiocca
58
 *
59
 */
60
 
61
/* ------------- */
62
/*  Car control  */
63
/* ------------- */
64
 
65
#include "include/auto.h"
66
#include "include/const.h"
67
#include "include/utils.h"
68
 
69
#define TURN_QUANTUM    2
70
#define KM     18.0             // pixel
71
#define HOUR 3600.0             // seconds
72
#define KPH  (KM/HOUR)          // 0.005 pixel/second
73
#define HIGHWAY_LIMIT  6
74
#define MAZE_LIMIT    45
75
#define CURVE_LIMIT     25      // il limite della curva per cui imposta la traiettoria
76
#define BORDER_LIMIT  ((1.0 / params.rage) * 2.0)
77
#define STEERING_LIMIT  3       // limite di sterzata
78
 
79
/* Road state */
80
#define HIGHWAY         1
81
#define MIXED           2
82
#define MAZE            3
83
#define CENTER     10
84
#define TOO_LEFT   11
85
#define TOO_RIGHT  12
86
 
87
/* Opponents relationship */
88
#define ATTACK                  20
89
#define DEFENSE                 21
90
#define SUPERATTACK             22
91
 
92
/* Car parameters */
93
#define MAX_SPEED       (300 * KPH)
94
#define MIN_SPEED       (10 * KPH)
95
#define MIN_ACC         (-0.1)
96
#define MAX_ACC      (0.02)
97
 
98
extern sem_t grx_mutex;
99
 
100
char track_img[TRACK_WIDTH*TRACK_HEIGHT];
101
char sprite[18][CAR_WIDTH*CAR_HEIGHT];
102
 
103
/* Display functions */
104
void put_transimage(int x1, int y1, int x2, int y2, BYTE *img,int car_color, int color);
105
void draw_car(point_f old_pos, car_status cs, int car_color, int fumo);
106
void put_trackbox(int x1, int y1, int x2, int y2);
107
void show_display(int, int, float, float, float, float);
108
void car_crash(PID sp, PID cp, point_f old_pos, int free);
109
 
110
/* ------------------------------------------------------------------ */
111
 
112
TASK control(int index) {
113
  int i = 0;                            // general purpose counter
114
  car_status old_car_status;            // the previous car state
115
  car_status actual_car_status;         // the actual car state
116
  road_info actual_road_info;           // the actual road informations
117
  int road_state;                       // the state of the road: HIGHWAY, MIXED; MAZE
118
  int car_align;                        // the car alignment with respect to road limits
119
  int opps_state;                       // the relationship with other cars
120
  float old_speed = 0;                  // the previous car speed value
121
  float actual_speed = 0;               // the actual car speed value
122
  float old_acc = 0;                    // the previous acceleration value
123
  float acc = 0;                        // the new acceleration
124
  point polepos;
125
 
126
  // Variabili che dipendono dal tipo di macchina
127
  float max_speed;                      // maximum car speed
128
  float min_acc;                        // minimum acceleration
129
  float max_acc;                        // maximum acceleration
130
 
131
  int killed = 0;                       // flag for killed cars
132
  int crashed = 0;                      // flag for crashed cars
133
 
134
  /* Timing variables */
135
  float t = 0;
136
  float dt = (float)CONTROL_PERIOD/100000.0;  // time quantum
137
  time ts = int2time(t);
138
  float crash_t = 0;
139
  time crash_ts = int2time(crash_t);
140
  float bestlap = 999999999.9;
141
  time bestlap_s = int2time(bestlap);
142
  int bestlap_done = 0;
143
  int laps = 0;
144
 
145
  /* Display vars */
146
  point spd_p, acc_p, time_p, drv_p;
147
  char *txt;
148
 
149
  /* Car data */
150
  car_params params;    // car data structure
151
 
152
  /* ----------------------------------------------------- */
153
 
154
  txt = (char *)malloc(15*sizeof(char));
155
 
156
  params = cars[index];
157
 
158
  max_speed = params.max_speed * MAX_SPEED;             // maximum car speed
159
  min_acc   = params.min_acc * MIN_ACC;                 // minimum acceleration
160
  max_acc   = params.max_acc * MAX_ACC;                 // maximum acceleration
161
 
162
  /* Get track data */
163
  while (track_list[i].selected == 0)
164
    i++;
165
 
166
  /* Same pole for all */
167
  polepos.x = track_list[i].pole_pos.x;
168
  polepos.y = track_list[i].pole_pos.y;
169
  actual_car_status.pos.x  = polepos.x;
170
  actual_car_status.pos.y  = polepos.y;
171
  actual_car_status.orient = track_list[i].pole_orient;
172
  set_car_status(actual_car_status, params.car_status_cab);
173
 
174
  /* Initialize old values */
175
  old_car_status = actual_car_status;
176
  old_acc = acc;
177
  old_speed = actual_speed;
178
 
179
  /* POWER IS NOTHING WITHOUT CONTROL */
180
  while(1) {
181
 
182
    if (crashed) {
183
      crash_t += dt;
184
      crash_ts = int2time(crash_t);
185
      if (crash_ts.sec > 2) {
186
        car_crash(params.sensor_pid,params.control_pid,
187
                  old_car_status.pos, 1);
188
        killed=1;
189
      }
190
    }
191
 
192
    else {
193
 
194
      /* Reads road informations */
195
      actual_road_info = get_road_info(params.road_status_cab);
196
 
197
      /* Defines the state of the road */
198
      if (fabs(actual_road_info.curve) < HIGHWAY_LIMIT  ||
199
          actual_road_info.distance > 0.9*TEL_HEIGHT) {
200
        road_state = HIGHWAY;
201
      } else if (fabs(actual_road_info.curve) > MAZE_LIMIT ||
202
                 actual_road_info.distance < 0.1*TEL_HEIGHT) {
203
        road_state = MAZE;
204
      } else {
205
        road_state = MIXED;
206
      }
207
 
208
      /* Defines the car position whitin road borders */
209
      if (actual_road_info.left_border < BORDER_LIMIT)
210
        car_align = TOO_LEFT;
211
      else if (actual_road_info.right_border < BORDER_LIMIT)
212
        car_align = TOO_RIGHT;
213
      else car_align = CENTER;
214
 
215
      /* Sets the power percentage */
216
      switch (road_state)
217
        {
218
        case HIGHWAY:
219
          acc = max_acc;                // tarella!!!!
220
          break;
221
        case MIXED:
222
          actual_speed = params.rage * (((float)actual_road_info.distance/(float)TEL_HEIGHT) /
223
                                        (fabs(actual_road_info.curve)/90.0)) * max_speed;
224
          acc = (actual_speed - old_speed) / dt;
225
          break;
226
        case MAZE:
227
          actual_speed = params.rage * (1.0 - (fabs(actual_road_info.curve)/90.0)) * max_speed;
228
          acc = (actual_speed - old_speed) / dt;
229
          break;
230
        default:
231
          acc = 0.0;
232
        }
233
 
234
      /* Can't go off road */
235
      /* When car is near a border, it steers to come in */
236
      switch (car_align)
237
        {
238
        case TOO_LEFT:
239
          actual_car_status.orient -= TURN_QUANTUM;
240
          break;
241
        case TOO_RIGHT:
242
          actual_car_status.orient += TURN_QUANTUM;
243
          break;
244
        }
245
 
246
      if (road_state != HIGHWAY) {
247
        // C'e' una curva vicina.
248
        // Se la curva e' a destra si tiene vicino al bordo di sinistra
249
        // per impostare la traiettoria migliore e viceversa
250
        if (actual_road_info.curve < 0 && actual_road_info.left_border > BORDER_LIMIT
251
            && fabs(actual_road_info.curve) > CURVE_LIMIT)
252
          actual_car_status.orient += TURN_QUANTUM;
253
        else if (actual_road_info.curve > 0 && actual_road_info.right_border > BORDER_LIMIT
254
                 && fabs(actual_road_info.curve) > CURVE_LIMIT)
255
          actual_car_status.orient -= TURN_QUANTUM;
256
 
257
        // Fa la curva dolcemente
258
        if (actual_road_info.distance < ((1.0/params.rage) * (TEL_HEIGHT * 0.25))) {
259
          actual_car_status.orient += actual_road_info.curve * (params.rage/8.0);
260
                                //actual_car_status.orient += actual_road_info.curve / 4.0;
261
        }
262
      }
263
 
264
      /* Defines the state of interactions with other cars */
265
      if (actual_road_info.opps_number > 0)
266
        {
267
          if (road_state == HIGHWAY && actual_road_info.opps_list[0].y > (TEL_HEIGHT/3.0))
268
            opps_state = ATTACK;
269
          else if (road_state == MAZE && actual_road_info.opps_list[0].y < (TEL_HEIGHT/3.0))
270
            opps_state = DEFENSE;
271
          else if (actual_road_info.opps_list[0].y < (TEL_HEIGHT/6.0) &&
272
                   actual_road_info.opps_list[0].x != 0 &&
273
                   (abs(actual_road_info.opps_list[0].x) < CAR_W/2)) {
274
            // Defends and steers to avoid opponents
275
            opps_state = DEFENSE;
276
            acc *= -((TEL_HEIGHT/6.0) / (actual_road_info.opps_list[0].y));
277
            actual_car_status.orient -= ((actual_road_info.opps_list[0].x) /
278
                                         abs(actual_road_info.opps_list[0].x)) * TURN_QUANTUM/2;
279
          }
280
          else if (actual_road_info.opps_list[0].y < (TEL_HEIGHT/3.0) &&
281
                   actual_road_info.opps_list[0].x != 0 &&
282
                   abs(actual_road_info.opps_list[0].x) < CAR_W/2) {
283
            // Attacks and steers to override the opponent
284
            opps_state = ATTACK;
285
            actual_car_status.orient -= ((actual_road_info.opps_list[0].x) /
286
                                         abs(actual_road_info.opps_list[0].x)) * TURN_QUANTUM;
287
          }
288
          else
289
            opps_state = DEFENSE;
290
 
291
          // Response to opponents positions
292
          if (opps_state == ATTACK)
293
            acc = max_acc;
294
          else if (opps_state == DEFENSE)
295
            acc *= 0.5;
296
        }
297
 
298
 
299
      /* Checking car position: road/offroad */
300
      if (actual_road_info.left_border * actual_road_info.right_border < 0)
301
        acc = 0.5 * min_acc;
302
 
303
      if (actual_road_info.flag != ROAD_OK) {
304
        switch (actual_road_info.flag) {
305
        case LEFT_ONLY:
306
          if (actual_road_info.left_border < 0)
307
            actual_car_status.orient -= TURN_QUANTUM;
308
          acc = 0.5 * max_acc;
309
          break;
310
        case RIGHT_ONLY:
311
          if (actual_road_info.right_border < 0)
312
            actual_car_status.orient += TURN_QUANTUM;
313
          acc = 0.5 * max_acc;
314
          break;
315
        case NO_ROAD:
316
          crashed = 1;
317
          car_crash(params.sensor_pid,params.control_pid,
318
                    old_car_status.pos, 0);
319
          break;
320
        }
321
      }
322
 
323
      /* Checking collisions... */
324
      if (actual_road_info.collision != NO_COLL) {
325
        switch(actual_road_info.collision) {
326
        case COLLISION_LEFT:
327
          actual_car_status.orient -= TURN_QUANTUM;
328
          acc *= (0.5 * params.rage);
329
          break;
330
        case COLLISION_RIGHT:
331
          actual_car_status.orient += TURN_QUANTUM;
332
          acc *= (0.5 * params.rage);
333
          break;
334
        }
335
      }
336
 
337
      /* Checking acceleration range... */
338
      acc = max(min(max_acc,acc),min_acc);
339
      actual_speed = old_speed + acc*dt;
340
 
341
      /* Checking speed range... */
342
      actual_speed = min(max(actual_speed,MIN_SPEED),max_speed);
343
 
344
      /* Checking steering angle ... */
345
      if (fabs(actual_car_status.orient - old_car_status.orient) >
346
          STEERING_LIMIT) {
347
        if ((actual_car_status.orient - old_car_status.orient) > 0)
348
          actual_car_status.orient = old_car_status.orient + STEERING_LIMIT;
349
        else
350
          actual_car_status.orient = old_car_status.orient - STEERING_LIMIT;
351
      }
352
 
353
      /* Setting new car position... */
354
      actual_car_status.pos.x += actual_speed * cos(degree_to_rad(actual_car_status.orient));
355
      actual_car_status.pos.y -= actual_speed * sin(degree_to_rad(actual_car_status.orient));
356
 
357
      /* Checking track limits... */
358
      if (actual_car_status.pos.x < MIN_CAR_X)
359
        actual_car_status.pos.x = MIN_CAR_X;
360
      if (actual_car_status.pos.x > MAX_CAR_X)
361
        actual_car_status.pos.x = MAX_CAR_X;
362
      if (actual_car_status.pos.y < MIN_CAR_Y)
363
        actual_car_status.pos.y = MIN_CAR_Y;
364
      if (actual_car_status.pos.y > MAX_CAR_Y)
365
        actual_car_status.pos.y = MAX_CAR_Y;
366
 
367
      /* Sends new status to car_status_cab */
368
      set_car_status(actual_car_status, params.car_status_cab);
369
 
370
      if (!crashed) {
371
        /* Updates car */
372
        if (acc == min_acc)
373
          draw_car(old_car_status.pos,actual_car_status, params.color, 1);
374
        else
375
          draw_car(old_car_status.pos,actual_car_status, params.color, 0);
376
      }
377
 
378
      /* Sets display points */
379
      spd_p.x = TRACK_X1 + TRACK_WIDTH + TEL_HEIGHT + TEL_WIDTH + 9;
380
      spd_p.y = TEL_HEIGHT*index + 1 + index + 1;
381
      bar_display(spd_p, 70, 4, GREEN, actual_speed, max_speed, LIGHTGRAY, "Spd");
382
 
383
      acc_p.x = spd_p.x;
384
      acc_p.y = spd_p.y + 24;
385
      bidir_bar_display(acc_p, 70, 4, GREEN, acc, max(fabs(min_acc), max_acc), LIGHTGRAY, "Acc");
386
 
387
      sem_wait(&grx_mutex);
388
 
389
      /* Displays driver's name */
390
      drv_p.x = spd_p.x + 80;
391
      drv_p.y = spd_p.y;
392
      grx_text(params.driver, drv_p.x, drv_p.y, params.color, BLACK);
393
 
394
      /* Displays timer */
395
      time_p.x = spd_p.x + 80;
396
      time_p.y = spd_p.y + 8;
397
      if( (!bestlap_done) || (bestlap_done && t > 50))
398
        {
399
          /* Mins */
400
          txt = itoa(ts.min, txt);
401
          grx_text(txt, time_p.x,     time_p.y, WHITE, BLACK);
402
          grx_text(":", time_p.x + 8, time_p.y, WHITE, BLACK);
403
          /* Secs */
404
          txt = itoa(ts.sec, txt);
405
          if (ts.sec < 10) {
406
            grx_text("0", time_p.x+16, time_p.y, WHITE, BLACK);
407
            grx_text(txt, time_p.x+24, time_p.y, WHITE, BLACK);
408
          }
409
          else
410
            grx_text(txt, time_p.x+16, time_p.y, WHITE, BLACK);
411
          /* Decs */
412
          grx_text(":", time_p.x+32, time_p.y, WHITE, BLACK);
413
          txt = itoa(ts.dec, txt);
414
          grx_text(txt, time_p.x+40, time_p.y, WHITE, BLACK);
415
        }
416
 
417
      /* Displays the best lap */
418
      if(bestlap_done == 1)
419
        {
420
          time_p.x = spd_p.x + 80;
421
          time_p.y = spd_p.y + 16;
422
          /* Mins */
423
          txt = itoa(bestlap_s.min, txt);
424
          grx_text(txt, time_p.x,     time_p.y, YELLOW, BLACK);
425
          grx_text(":", time_p.x + 8, time_p.y, YELLOW, BLACK);
426
          /* Secs */
427
          txt = itoa(bestlap_s.sec, txt);
428
          if (bestlap_s.sec < 10) {
429
            grx_text("0", time_p.x+16, time_p.y, YELLOW, BLACK);
430
            grx_text(txt, time_p.x+24, time_p.y, YELLOW, BLACK);
431
          }
432
          else
433
            grx_text(txt, time_p.x+16, time_p.y, YELLOW, BLACK);
434
          /* Decs */
435
          grx_text(":", time_p.x+32, time_p.y, YELLOW, BLACK);
436
          txt = itoa(bestlap_s.dec, txt);
437
          grx_text(txt, time_p.x+40, time_p.y, YELLOW, BLACK);
438
        }
439
 
440
      /* Displays lap number */
441
      time_p.x = spd_p.x + 80;
442
      time_p.y = spd_p.y + 24;
443
      grx_text("Lap ", time_p.x, time_p.y, LIGHTGRAY, BLACK);
444
      txt = itoa(laps, txt);
445
      grx_text(txt, time_p.x+32, time_p.y, LIGHTGRAY, BLACK);
446
 
447
      sem_post(&grx_mutex);
448
 
449
      /* Control the best lap */
450
      t += dt;
451
      ts = int2time(t);
452
 
453
      /* Finish line */
454
      if ((track_list[i].lap == CLOCK &&
455
           (actual_car_status.pos.x >= polepos.x) && (old_car_status.pos.x < polepos.x)
456
           && (actual_car_status.pos.y > polepos.y-20) && (actual_car_status.pos.y < polepos.y+20)) ||
457
          (track_list[i].lap == ANTICLOCK &&
458
           (actual_car_status.pos.x <= polepos.x) && (old_car_status.pos.x > polepos.x)
459
           && (actual_car_status.pos.y > polepos.y-20) && (actual_car_status.pos.y < polepos.y+20))) {
460
        laps++;         // increases lap number
461
 
462
        bestlap = min(bestlap,t);
463
        bestlap_s = int2time(bestlap);
464
        bestlap_done = 1;
465
        t = 0;
466
        ts = int2time(t);
467
      }
468
 
469
      /* Updates old values */
470
      old_car_status = actual_car_status;
471
      old_acc = acc;
472
      old_speed = actual_speed;
473
 
474
    }  // end crashed
475
 
476
    task_endcycle();
477
 
478
    // Esce se e' morto
479
    if (killed) return 0;
480
  }
481
}
482
 
483
/* ------------------------------------------------------------------ */
484
 
485
void car_crash(PID sp, PID cp, point_f old_pos, int free)
486
{
487
  point p1, p2;
488
  p1.x = round(old_pos.x) - CAR_WIDTH/2 - 1;
489
  p1.y = round(old_pos.y) - CAR_HEIGHT/2 - 1;
490
  p2.x = p1.x + CAR_WIDTH + 1;
491
  p2.y = p1.y + CAR_HEIGHT + 1;
492
 
493
  sem_wait(&grx_mutex);
494
  /* Find the track box to redraw */
495
  put_trackbox(p1.x,p1.y,p2.x,p2.y);
496
 
497
  if (free == 0) {
498
    // Draw the explosion
499
    put_transimage(p1.x+1,p1.y+1,p2.x-1,p2.y-1,&sprite[16][0],0,0);
500
  }
501
  else if (free == 1) {
502
    // Delete the explosion
503
    put_trackbox(p1.x,p1.y,p2.x,p2.y);
504
    task_kill(sp);
505
    task_kill(cp);
506
  }
507
  sem_post(&grx_mutex);
508
}
509
 
510
/* ------------------------------------------------------------------ */
511
 
512
void draw_car(point_f old_pos, car_status cs, int car_color, int fumo)
513
{
514
  int index;
515
  point p1, p2;
516
  p1.x = round(old_pos.x) - CAR_WIDTH/2 - 1;
517
  p1.y = round(old_pos.y) - CAR_HEIGHT/2 - 1;
518
  p2.x = p1.x + CAR_WIDTH + 1;
519
  p2.y = p1.y + CAR_HEIGHT + 1;
520
 
521
  sem_wait(&grx_mutex);
522
  /* Find the track box to redraw */
523
  put_trackbox(p1.x,p1.y,p2.x,p2.y);
524
 
525
 
526
  p1.x = round(cs.pos.x) + (CAR_WIDTH/2  * cos(degree_to_rad(cs.orient)));
527
  p1.y = round(cs.pos.y) - (CAR_HEIGHT/2 * sin(degree_to_rad(cs.orient)));
528
  p2.x = round(cs.pos.x) - (CAR_WIDTH/2  * cos(degree_to_rad(cs.orient)));
529
  p2.y = round(cs.pos.y) + (CAR_HEIGHT/2 * sin(degree_to_rad(cs.orient)));
530
 
531
  index = ((((int)cs.orient%360)+360)%360);
532
  index = (int)(index + 11.25)%360;
533
  index /= 22.5;
534
 
535
  put_transimage(round(cs.pos.x) - CAR_WIDTH/2 + 1,round(cs.pos.y) - CAR_HEIGHT/2 + 1,
536
                 round(cs.pos.x) + CAR_WIDTH/2 ,round(cs.pos.y) + CAR_HEIGHT/2,
537
                 &sprite[index][0], car_color, 0);
538
  if (fumo)
539
    put_transimage(round(cs.pos.x) - CAR_WIDTH/2 + 1,round(cs.pos.y) - CAR_HEIGHT/2 + 1,
540
                   round(cs.pos.x) + CAR_WIDTH/2 ,round(cs.pos.y) + CAR_HEIGHT/2,
541
                   &sprite[17][0], car_color, 0);
542
  sem_post(&grx_mutex);
543
}
544
 
545
/* ------------------------------------------------------------------ */
546
 
547
/* Copy a box of track_image to screen */
548
void put_trackbox(int x1, int y1, int x2, int y2)
549
{
550
  int y;
551
  int tx1,ty1,tx2,ty2;
552
  BYTE *addr;
553
 
554
  tx1 = x1-TRACK_X1+1;
555
  ty1 = y1-TRACK_Y1;
556
  tx2 = x2-TRACK_X1+1;
557
  ty2 = y2-TRACK_Y1;
558
 
559
  if (tx1 < 0)  tx1 = 0;
560
  if (ty1 < 0)  ty1 = 0;
561
  if (tx2 > TRACK_WIDTH-1)      tx2 = TRACK_WIDTH-1;
562
  if (ty2 > TRACK_HEIGHT-1)     ty2 = TRACK_HEIGHT-1;
563
 
564
  tx1 = max(tx1,0);
565
  ty1 = max(ty1,0);
566
  tx2 = min(tx2,TRACK_WIDTH-1);
567
  ty2 = min(ty2,TRACK_HEIGHT-1);
568
 
569
  addr = &track_img[0] + tx1 + TRACK_WIDTH * ty1;
570
 
571
  x1 = max(0,x1);
572
  y1 = max(0,y1);
573
 
574
  for (y = y1; y <= y2; y++) {
575
    grx_putimage(x1+1, y, x2, y, addr);
576
    addr += TRACK_WIDTH;
577
  }
578
}
579
 
580
/* ------------------------------------------------------------------ */
581
 
582
void put_transimage(int x1, int y1, int x2, int y2, BYTE *img, int car_color,
583
                    int color)
584
{
585
  int x,y;
586
  BYTE *addr;
587
  addr = img;
588
 
589
 
590
  for (y = y1; y < y2; y++) {
591
    for ( x = x1; x < x2; x++, addr++) {
592
      if (*addr != color) {
593
        if (*addr == 26)
594
          grx_plot(x,y,car_color);
595
        else
596
          grx_plot(x,y,*addr);
597
 
598
      }
599
    }
600
    addr++;
601
  }
602
}
603
 
604
/* ------------------------------------------------------------------ */
605
 
606
void show_display(int rs, int ca, float speed, float max_speed,
607
                  float acc, float max_acc)
608
{
609
  point hw, mx, mz;     // three road states
610
  point tl, ct, tr;     // three car alignments
611
  point sp1, sp2;               // speed display coordinates
612
  point ap1, ap2;               // acceleration display coordinates
613
  int s_amp = 0;
614
  int a_amp = 0;
615
 
616
  /* Leds coordinates */
617
  hw.x = 10;
618
  hw.y = SCREEN_HEIGHT-50;
619
  mx.x = 25;
620
  mx.y = SCREEN_HEIGHT-50;
621
  mz.x = 40;
622
  mz.y = SCREEN_HEIGHT-50;
623
  tl.x = 10;
624
  tl.y = SCREEN_HEIGHT-35;
625
  ct.x = 25;
626
  ct.y = SCREEN_HEIGHT-35;
627
  tr.x = 40;
628
  tr.y = SCREEN_HEIGHT-35;
629
  sp1.x = 10;
630
  sp1.y = SCREEN_HEIGHT-75;
631
  sp2.x = 110;
632
  sp2.y = SCREEN_HEIGHT-65;
633
  ap1.x = 10;
634
  ap1.y = SCREEN_HEIGHT-90;
635
  ap2.x = 110;
636
  ap2.y = SCREEN_HEIGHT-80;
637
 
638
  sem_wait(&grx_mutex);
639
 
640
  /* Writes out controller titles */
641
  grx_text("Road",  mz.x+15, mz.y, YELLOW, BLACK);
642
  grx_text("Curve", tr.x+15, tr.y, YELLOW, BLACK);
643
  switch (rs)
644
    {
645
    case HIGHWAY:
646
      grx_box(hw.x, hw.y, hw.x+10, hw.y+10, GREEN);
647
      grx_box(mx.x, mx.y, mx.x+10, mx.y+10, BLACK);
648
      grx_box(mz.x, mz.y, mz.x+10, mz.y+10, BLACK);
649
      break;
650
    case MIXED:
651
      grx_box(hw.x, hw.y, hw.x+10, hw.y+10, BLACK);
652
      grx_box(mx.x, mx.y, mx.x+10, mx.y+10, YELLOW);
653
      grx_box(mz.x, mz.y, mz.x+10, mz.y+10, BLACK);
654
      break;
655
    case MAZE:
656
      grx_box(hw.x, hw.y, hw.x+10, hw.y+10, BLACK);
657
      grx_box(mx.x, mx.y, mx.x+10, mx.y+10, BLACK);
658
      grx_box(mz.x, mz.y, mz.x+10, mz.y+10, RED);
659
      break;
660
    }
661
 
662
  switch (ca)
663
    {
664
    case TOO_LEFT:
665
      grx_box(tl.x, tl.y, tl.x+10, tl.y+10, RED);
666
      grx_box(ct.x, ct.y, ct.x+10, ct.y+10, BLACK);
667
      grx_box(tr.x, tr.y, tr.x+10, tr.y+10, BLACK);
668
      break;
669
    case TOO_RIGHT:
670
      grx_box(tl.x, tl.y, tl.x+10, tl.y+10, BLACK);
671
      grx_box(ct.x, ct.y, ct.x+10, ct.y+10, BLACK);
672
      grx_box(tr.x, tr.y, tr.x+10, tr.y+10, BLUE);
673
      break;
674
    default:
675
      grx_box(tl.x, tl.y, tl.x+10, tl.y+10, BLACK);
676
      grx_box(ct.x, ct.y, ct.x+10, ct.y+10, WHITE);
677
      grx_box(tr.x, tr.y, tr.x+10, tr.y+10, BLACK);
678
    }
679
 
680
  /* Draws speed display */
681
  grx_text("Speed", sp1.x+120, sp1.y, YELLOW, BLACK);
682
  grx_rect(sp1.x-1, sp1.y-1, sp2.x+1, sp2.y+1, GREEN);
683
  /* Updates speed display */
684
  grx_box(sp1.x, sp1.y, sp2.x, sp2.y, BLACK);
685
  s_amp = round( (speed * (float)(sp2.x-sp1.x)) / max_speed );
686
  grx_box(sp1.x, sp1.y, sp1.x+s_amp, sp2.y, LIGHTGRAY);
687
 
688
        /* Draws acceleration display */
689
  grx_text("Acceleration", ap1.x+120, ap1.y, YELLOW, BLACK);
690
  grx_rect(ap1.x-1, ap1.y-1, ap2.x+1, ap2.y+1, GREEN);
691
  /* Updates acceleration display */
692
  grx_box(ap1.x, ap1.y, ap2.x, ap2.y, BLACK);
693
  a_amp = round( (float)acc * (float)((ap2.x-ap1.x)/2) / (float)max_acc );
694
  if (a_amp >= 0)
695
    grx_box((ap1.x+ap2.x)/2, ap1.y, ((ap1.x+ap2.x)/2)+a_amp, ap2.y, LIGHTGRAY);
696
  else
697
    grx_box((ap1.x+ap2.x)/2+a_amp, ap1.y, ((ap1.x+ap2.x)/2), ap2.y, LIGHTGRAY);
698
  grx_line((ap1.x+ap2.x)/2, ap1.y-2, (ap1.x+ap2.x)/2, ap2.y+2, WHITE);
699
  sem_post(&grx_mutex);
700
}
701