TORCS  1.3.10
The Open Racing Car Simulator
Loading...
Searching...
No Matches
trackselect.cpp
Go to the documentation of this file.
1/***************************************************************************
2 trackselect.cpp -- interactive track selection
3 -------------------
4 created : Mon Aug 16 21:43:00 CEST 1999
5 copyright : (C) 1999-2026 by Eric EspiƩ, Bernhard Wymann
6 email : berniw@bluewin.ch
7
8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
22
23
24#include <stdlib.h>
25#include <stdio.h>
26#ifdef WIN32
27#include <windows.h>
28#endif
29#include <tgfclient.h>
30#include <track.h>
31#include <osspec.h>
32#include <raceman.h>
33#include <racescreens.h>
34#include <portability.h>
35
36
37/* Tracks Categories */
39static void *scrHandle;
40static int TrackLabelId;
41static int CatLabelId;
42static int MapId;
43static int AuthorId;
44static int LengthId;
45static int WidthId;
46static int DescId;
47static int PitsId;
49
50
51static void rmtsActivate(void)
52{
53 /* call display function of graphic */
54 //gfuiReleaseImage(MapId);
55}
56
57
58static void rmtsFreeLists(void *vl)
59{
60 GfDirFreeList((tFList*)vl, NULL, true, true);
61}
62
63
64static int rmtsListLength(tFList *list)
65{
66 int length = 0;
67 tFList *cur;
68
69 if (!list) {
70 return 0;
71 }
72
73 cur = list;
74 do {
75 length++;
76 cur = cur->next;
77 } while (cur != list);
78
79 return length;
80}
81
82
83static tFList *rmtsRemoveListEntry(tFList *list, tFList *entry, tfDirfreeUserData freeUserData)
84{
85 tFList *nextEntry;
86 bool lastEntry;
87 bool headEntry;
88
89 if (!list || !entry) {
90 return list;
91 }
92
93 nextEntry = entry->next;
94 lastEntry = entry->next == entry;
95 headEntry = list == entry;
96
97 if (!lastEntry) {
98 entry->prev->next = entry->next;
99 entry->next->prev = entry->prev;
100 }
101 if (freeUserData && entry->userData) {
102 freeUserData(entry->userData);
103 }
104 if (entry->name) {
105 free(entry->name);
106 }
107 if (entry->dispName) {
108 free(entry->dispName);
109 }
110 free(entry);
111
112 if (lastEntry) {
113 return NULL;
114 }
115 if (headEntry) {
116 return nextEntry;
117 }
118 return list;
119}
120
121
122static char * rmGetMapName(char* buf, const int BUFSIZE)
123{
124 snprintf(buf, BUFSIZE, "tracks/%s/%s/%s.png", CategoryList->name,
125 ((tFList*)CategoryList->userData)->name, ((tFList*)CategoryList->userData)->name);
126 return buf;
127}
128
129
130static void rmtsDeactivate(void *screen)
131{
133
135 if (screen) {
136 GfuiScreenActivate(screen);
137 }
138}
139
140
141static void rmUpdateTrackInfo(void)
142{
143 void *trackHandle;
144 float tmp;
145 tTrack *trk;
146 const int BUFSIZE = 1024;
147 char buf[BUFSIZE];
148
149 snprintf(buf, BUFSIZE, "tracks/%s/%s/%s.%s", CategoryList->name, ((tFList*)CategoryList->userData)->name,
150 ((tFList*)CategoryList->userData)->name, TRKEXT);
151 trackHandle = GfParmReadFile(buf, GFPARM_RMODE_STD); /* COMMENT VALID? don't release, the name is used later */
152
153 if (!trackHandle) {
154 GfTrace("File %s has pb\n", buf);
155 return;
156 }
157 trk = ts->trackItf.trkBuild(buf);
158
161
162 tmp = GfParmGetNum(trackHandle, TRK_SECT_MAIN, TRK_ATT_WIDTH, NULL, 0);
163 snprintf(buf, BUFSIZE, "%.2f m", tmp);
165 tmp = trk->length;
166 snprintf(buf, BUFSIZE, "%.2f m", tmp);
168
169 if (trk->pits.nMaxPits != 0) {
170 snprintf(buf, BUFSIZE, "%d", trk->pits.nMaxPits);
172 } else {
174 }
175
176 ts->trackItf.trkShutdown();
177 GfParmReleaseHandle(trackHandle);
178}
179
180
181static void rmtsPrevNext(int delta)
182{
183 const int BUFSIZE = 1024;
184 char buf[BUFSIZE];
185
186 if (delta < 0) {
187 CategoryList->userData = (void*)(((tFList*)CategoryList->userData)->prev);
188 } else {
189 CategoryList->userData = (void*)(((tFList*)CategoryList->userData)->next);
190 }
191
192 GfuiLabelSetText(scrHandle, TrackLabelId, ((tFList*)CategoryList->userData)->dispName);
195}
196
197
198static void rmCatPrevNext(int delta)
199{
200 const int BUFSIZE = 1024;
201 char buf[BUFSIZE];
202
203 if (delta < 0) {
205 } else {
207 }
208
210 GfuiLabelSetText(scrHandle, TrackLabelId, ((tFList*)CategoryList->userData)->dispName);
213}
214
215
216void rmtsSelect(void)
217{
218 int curTrkIdx;
219 const int BUFSIZE = 1024;
220 char path[BUFSIZE];
221
222 curTrkIdx = (int)GfParmGetNum(ts->param, RM_SECT_TRACKS, RE_ATTR_CUR_TRACK, NULL, 1);
223 snprintf(path, BUFSIZE, "%s/%d", RM_SECT_TRACKS, curTrkIdx);
224 GfParmSetStr(ts->param, path, RM_ATTR_CATEGORY, CategoryList->name);
225 GfParmSetStr(ts->param, path, RM_ATTR_NAME, ((tFList*)CategoryList->userData)->name);
226
227 rmtsDeactivate(ts->nextScreen);
228}
229
230
231static void rmtsAddKeys(void)
232{
233 GfuiAddKeyAction(scrHandle, 13, "Select Track", rmtsSelect, tGfuiAction());
234 GfuiAddKeyAction(scrHandle, 27, "Cancel Selection", [] { rmtsDeactivate(ts->prevScreen); }, tGfuiAction());
235 GfuiAddSKeyAction(scrHandle, GLUT_KEY_LEFT, "Previous Track", [] { rmtsPrevNext(-1); }, tGfuiAction());
236 GfuiAddSKeyAction(scrHandle, GLUT_KEY_RIGHT, "Next Track", [] { rmtsPrevNext(1); }, tGfuiAction());
237 GfuiAddSKeyAction(scrHandle, GLUT_KEY_F12, "Screen-Shot", [] { GfuiScreenShot(NULL); }, tGfuiAction());
238 GfuiAddSKeyAction(scrHandle, GLUT_KEY_UP, "Previous Track Category", [] { rmCatPrevNext(-1); }, tGfuiAction());
239 GfuiAddSKeyAction(scrHandle, GLUT_KEY_DOWN, "Next Track Category", [] { rmCatPrevNext(1); }, tGfuiAction());
240}
241
242
251char* RmGetTrackName(char *category, char *trackName)
252{
253 void *trackHandle;
254 char *name;
255 const int BUFSIZE = 1024;
256 char buf[BUFSIZE];
257
258 snprintf(buf, BUFSIZE, "tracks/%s/%s/%s.%s", category, trackName, trackName, TRKEXT);
259 trackHandle = GfParmReadFile(buf, GFPARM_RMODE_STD); /* don't release, the name is used later */
260
261 if (trackHandle) {
262 name = strdup(GfParmGetStr(trackHandle, TRK_SECT_HDR, TRK_ATT_NAME, trackName));
263 } else {
264 GfTrace("File %s has pb\n", buf);
265 return strdup("");
266 }
267
268 GfParmReleaseHandle(trackHandle);
269 return name;
270}
271
272
280char* RmGetCategoryName(char *category)
281{
282 void *categoryHandle;
283 char *name;
284 const int BUFSIZE = 1024;
285 char buf[BUFSIZE];
286
287 snprintf(buf, BUFSIZE, "data/tracks/%s.%s", category, TRKEXT);
288 categoryHandle = GfParmReadFile(buf, GFPARM_RMODE_STD); /* don't release, the name is used later */
289
290 if (categoryHandle) {
291 name = strdup(GfParmGetStr(categoryHandle, TRK_SECT_HDR, TRK_ATT_NAME, category));
292 } else {
293 GfTrace("File %s has pb\n", buf);
294 return strdup("");
295 }
296
297 GfParmReleaseHandle(categoryHandle);
298 return name;
299}
300
301
302static tFList *rmtsFilterTracks(char *category, tFList *trackList)
303{
304 tFList *trackCur;
305 int nbTrack;
306 int i;
307
308 nbTrack = rmtsListLength(trackList);
309 trackCur = trackList;
310 for (i = 0; i < nbTrack && trackList; i++) {
311 tFList *nextTrack = trackCur->next;
312
313 trackCur->dispName = RmGetTrackName(category, trackCur->name);
314 if (strlen(trackCur->dispName) == 0) {
315 GfTrace("RmTrackSelect: Skipping track %s/%s without a readable definition\n", category, trackCur->name);
316 trackList = rmtsRemoveListEntry(trackList, trackCur, NULL);
317 }
318 trackCur = nextTrack;
319 }
320
321 return trackList ? trackList->next : NULL;
322}
323
324
332void RmTrackSelect(void *vs)
333{
334 const char *defaultTrack;
335 const char *defaultCategory;
336 tFList *CatCur;
337 tFList *TrList, *TrCur;
338 int Xpos, Ypos, DX, DY;
339 int curTrkIdx;
340 const int BUFSIZE = 1024;
341 char buf[BUFSIZE];
342 char path[BUFSIZE];
343 bool foundCategory = false;
344 bool foundTrack = false;
345
346 ts = (tRmTrackSelect*)vs;
347
348 /* Get the list of categories directories */
349 CategoryList = GfDirGetList("tracks");
350 if (CategoryList == NULL) {
351 GfTrace("RmTrackSelect: No track category available\n");
352 return;
353 }
354
355 const int nbCategory = rmtsListLength(CategoryList);
356 CatCur = CategoryList;
357 for (int i = 0; i < nbCategory && CategoryList; i++) {
358 tFList *nextCategory = CatCur->next;
359
360 CatCur->dispName = RmGetCategoryName(CatCur->name);
361 if (strlen(CatCur->dispName) == 0) {
362 GfTrace("RmTrackSelect: Skipping track category %s without a readable definition\n", CatCur->name);
364 CatCur = nextCategory;
365 continue;
366 }
367
368 /* get the tracks in the category directory */
369 snprintf(buf, BUFSIZE, "tracks/%s", CatCur->name);
370 TrList = GfDirGetList(buf);
371 if (TrList == NULL) {
372 GfTrace("RmTrackSelect: No track for category %s available\n", CatCur->name);
374 CatCur = nextCategory;
375 continue;
376 }
377 TrList = rmtsFilterTracks(CatCur->name, TrList);
378 if (TrList == NULL) {
379 GfTrace("RmTrackSelect: No valid track for category %s available\n", CatCur->name);
381 CatCur = nextCategory;
382 continue;
383 }
384 CatCur->userData = (void*)TrList;
385
386 CatCur = CatCur->next;
387 }
388 if (CategoryList == NULL) {
389 GfTrace("RmTrackSelect: No valid track category available\n");
390 return;
391 }
392
393 curTrkIdx = (int)GfParmGetNum(ts->param, RM_SECT_TRACKS, RE_ATTR_CUR_TRACK, NULL, 1);
394 snprintf(path, BUFSIZE, "%s/%d", RM_SECT_TRACKS, curTrkIdx);
395 defaultCategory = GfParmGetStr(ts->param, path, RM_ATTR_CATEGORY, CategoryList->name);
396 defaultTrack = GfParmGetStr(ts->param, path, RM_ATTR_NAME, ((tFList*)CategoryList->userData)->name);
397
398 tFList *categoryHead = CategoryList;
399 CatCur = categoryHead;
400 do {
401 if (strcmp(CatCur->name, defaultCategory) == 0) {
402 CategoryList = CatCur;
403 foundCategory = true;
404 tFList *trackHead = (tFList*)(CatCur->userData);
405 TrCur = trackHead;
406 do {
407 if (strcmp(TrCur->name, defaultTrack) == 0) {
408 CatCur->userData = (void*)TrCur;
409 foundTrack = true;
410 break;
411 }
412 TrCur = TrCur->next;
413 } while (TrCur != trackHead);
414 break;
415 }
416 CatCur = CatCur->next;
417 } while (CatCur != categoryHead);
418
419 if (!foundCategory || !foundTrack) {
420 GfTrace("RmTrackSelect: Selected track %s/%s is not available, falling back to %s/%s\n",
421 defaultCategory,
422 defaultTrack,
423 CategoryList->name,
424 ((tFList*)CategoryList->userData)->name);
425 GfParmSetStr(ts->param, path, RM_ATTR_CATEGORY, CategoryList->name);
426 GfParmSetStr(ts->param, path, RM_ATTR_NAME, ((tFList*)CategoryList->userData)->name);
427 }
428
430 GfuiScreenAddBgImg(scrHandle, "data/img/splash-qrtrk.png");
431
432 rmtsAddKeys();
433
434 GfuiTitleCreate(scrHandle, "Select Track", 0);
435
437 "data/img/arrow-left.png",
438 "data/img/arrow-left.png",
439 "data/img/arrow-left.png",
440 "data/img/arrow-left-pushed.png",
441 80, 400, GFUI_ALIGN_HC_VB, 0,
442 [] { rmCatPrevNext(-1); }, tGfuiAction(), tGfuiAction());
443
444
446 CategoryList->dispName,
448 320, 400, GFUI_ALIGN_HC_VB,
449 30);
450
452 "data/img/arrow-right.png",
453 "data/img/arrow-right.png",
454 "data/img/arrow-right.png",
455 "data/img/arrow-right-pushed.png",
456 540, 400, GFUI_ALIGN_HC_VB, 0,
457 [] { rmCatPrevNext(1); }, tGfuiAction(), tGfuiAction());
458
460 "data/img/arrow-left.png",
461 "data/img/arrow-left.png",
462 "data/img/arrow-left.png",
463 "data/img/arrow-left-pushed.png",
464 80, 370, GFUI_ALIGN_HC_VB, 0,
465 [] { rmtsPrevNext(-1); }, tGfuiAction(), tGfuiAction());
466
467
469 ((tFList*)CategoryList->userData)->dispName,
471 320, 370, GFUI_ALIGN_HC_VB,
472 30);
473
475 "data/img/arrow-right.png",
476 "data/img/arrow-right.png",
477 "data/img/arrow-right.png",
478 "data/img/arrow-right-pushed.png",
479 540, 370, GFUI_ALIGN_HC_VB, 0,
480 [] { rmtsPrevNext(1); }, tGfuiAction(), tGfuiAction());
481
482 int scrw, scrh, vw, vh;
483 GfScrGetSize(&scrw, &scrh, &vw, &vh);
485 320, 100, (int) (vh*260.0f/vw), 195,
486 rmGetMapName(buf, BUFSIZE));
487
490
492 [] { rmtsDeactivate(ts->prevScreen); }, tGfuiAction(), tGfuiAction());
493
494 Xpos = 20;
495 Ypos = 320;
496 DX = 110;
497 DY = 30;
498
500 "Description:",
502 Xpos, Ypos,
504
506 "",
508 Xpos + DX, Ypos,
509 GFUI_ALIGN_HL_VB, 50);
510
511 Ypos -= DY;
512
514 "Author:",
516 Xpos, Ypos,
518
520 "",
522 Xpos + DX, Ypos,
523 GFUI_ALIGN_HL_VB, 20);
524
525 Ypos -= DY;
526
528 "Length:",
530 Xpos, Ypos,
532
534 "",
536 Xpos + DX, Ypos,
537 GFUI_ALIGN_HL_VB, 20);
538
539 Ypos -= DY;
540
542 "Width:",
544 Xpos, Ypos,
546
548 "",
550 Xpos + DX, Ypos,
551 GFUI_ALIGN_HL_VB, 20);
552
553 Ypos -= DY;
554
556 "Pits:",
558 Xpos, Ypos,
560
562 "",
564 Xpos + DX, Ypos,
565 GFUI_ALIGN_HL_VB, 20);
566
568
570}
Scalar length(const Quaternion &q)
Definition Quaternion.h:193
static void * scrHandle
void GfDirFreeList(tFList *list, tfDirfreeUserData freeUserData, bool freename, bool freedispname)
Free a directory list.
Definition directory.cpp:75
tFList * GfDirGetList(const char *dir)
Get the list of files of a given directory.
Definition directory.cpp:43
void * GfuiScreenCreateExAction(float *bgColor, const tGfuiAction &onActivate, const tGfuiAction &onDeactivate, int mouseAllowed)
Create a screen.
Definition gui.cpp:619
void GfuiLabelSetText(void *scr, int id, const char *text)
Change the text of a label.
Definition guilabel.cpp:193
void GfuiScreenRelease(void *scr)
Release the given screen.
Definition gui.cpp:670
int GfuiTitleCreate(void *scr, const char *text, int maxlen)
Add a Title to the screen.
Definition guilabel.cpp:150
void GfuiStaticImageSet(void *scr, int id, char *name)
Replace an image by another one.
Definition guiimage.cpp:90
void GfuiAddKeyAction(void *scr, unsigned char key, const char *descr, const tGfuiAction &onKeyPressed, const tGfuiAction &onKeyReleased)
Add a Keyboard callback to a screen.
Definition gui.cpp:809
void GfuiScreenAddBgImg(void *scr, const char *filename)
Add an image background to a screen.
Definition gui.cpp:1058
void GfuiAddSKeyAction(void *scr, int key, const char *descr, const tGfuiAction &onKeyPressed, const tGfuiAction &onKeyReleased)
Add a Special Keyboard shortcut to the screen.
Definition gui.cpp:895
int GfuiLabelCreate(void *scr, const char *text, int font, int x, int y, int align, int maxlen)
Add a label to a screen.
Definition guilabel.cpp:121
int GfuiGrButtonCreateAction(void *scr, const char *disabled, const char *enabled, const char *focused, const char *pushed, int x, int y, int align, int mouse, const tGfuiAction &onPush, const tGfuiAction &onFocus, const tGfuiAction &onFocusLost)
Add a graphical button to a screen.
Definition guibutton.cpp:58
void GfuiScreenActivate(void *screen)
Activate a screen and make it current.
Definition gui.cpp:508
int GfuiButtonCreateAction(void *scr, const char *text, int font, int x, int y, int width, int align, int mouse, const tGfuiAction &onPush, const tGfuiAction &onFocus, const tGfuiAction &onFocusLost)
Add a button to a screen.
int GfuiStaticImageCreate(void *scr, int x, int y, int w, int h, char *name)
Create a new static image.
Definition guiimage.cpp:48
const char * GfParmGetStr(void *parmHandle, const char *path, const char *key, const char *deflt)
Get a string parameter from the parameter set handle.
Definition params.cpp:2453
int GfParmSetStr(void *handle, const char *path, const char *key, const char *val)
Set a string parameter in the parameter set handle.
Definition params.cpp:2623
tdble GfParmGetNum(void *handle, const char *path, const char *key, const char *unit, tdble deflt)
Get a numerical parameter from the parameter set handle.
Definition params.cpp:2534
void GfParmReleaseHandle(void *parmHandle)
Release given parameter set handle parmHandle.
Definition params.cpp:1963
void * GfParmReadFile(const char *file, int mode)
Read parameter set from file and return handle to parameter set.
Definition params.cpp:1173
char * RmGetCategoryName(char *category)
Get the track category name from the track category file.
char * RmGetTrackName(char *category, char *trackName)
Get the track name defined in the parameters.
void RmTrackSelect(void *vs)
Track selection, the race manager parameter set is handed over in vs, tRmTrackSelect....
void GfuiScreenShot(void *)
Save a screen shot in png format.
Definition gui.cpp:998
void GfScrGetSize(int *scrw, int *scrh, int *vieww, int *viewh)
Get the screen and viewport sizes.
Definition screen.cpp:529
static int scrh
static int scrw
#define RM_ATTR_NAME
Definition raceman.h:258
#define RE_ATTR_CUR_TRACK
Definition raceman.h:335
#define RM_SECT_TRACKS
Definition raceman.h:240
#define RM_ATTR_CATEGORY
Definition raceman.h:260
static tRmTrackSelect ts
struct FList * next
Next entry.
Definition tgf.h:230
struct FList * prev
Previous entry.
Definition tgf.h:231
char * name
File name.
Definition tgf.h:232
char * dispName
Name to display on screen.
Definition tgf.h:233
void * userData
User data.
Definition tgf.h:234
Structure for track selection.
Definition racescreens.h:32
Track structure.
Definition track.h:533
tdble length
main track length
Definition track.h:542
tTrackPitInfo pits
Pits information.
Definition track.h:544
int nMaxPits
number max of pits
Definition track.h:477
void(* tfDirfreeUserData)(void *)
Function to call for releasing the user data associated with file entry.
Definition tgf.h:239
#define GFPARM_RMODE_STD
Return a new handle sharing cached data for this filename, if available.
Definition tgf.h:264
#define GfTrace
Definition tgf.h:335
struct FList tFList
List of (DLL) files for a Directory.
#define GFUI_FONT_LARGE
Definition tgfclient.h:248
#define GFUI_FONT_MEDIUM
Definition tgfclient.h:249
#define GFUI_FONT_LARGE_C
Definition tgfclient.h:252
#define GFUI_FONT_MEDIUM_C
Definition tgfclient.h:253
#define GFUI_ALIGN_HL_VB
Definition tgfclient.h:71
#define GFUI_MOUSE_UP
Definition tgfclient.h:82
std::function< void()> tGfuiAction
Definition tgfclient.h:107
#define GFUI_ALIGN_HC_VB
Definition tgfclient.h:74
#define TRK_ATT_AUTHOR
Definition track.h:49
#define TRK_ATT_WIDTH
Definition track.h:45
#define TRK_ATT_DESCR
Definition track.h:50
#define TRK_SECT_MAIN
Definition track.h:150
#define TRK_ATT_NAME
Definition track.h:47
#define TRK_SECT_HDR
Definition track.h:43
static void rmtsDeactivate(void *screen)
static tFList * rmtsFilterTracks(char *category, tFList *trackList)
static char * rmGetMapName(char *buf, const int BUFSIZE)
static void rmtsFreeLists(void *vl)
static int rmtsListLength(tFList *list)
void rmtsSelect(void)
static int CatLabelId
static int AuthorId
static int WidthId
static tFList * CategoryList
static int DescId
static void rmtsAddKeys(void)
static int PitsId
static tFList * rmtsRemoveListEntry(tFList *list, tFList *entry, tfDirfreeUserData freeUserData)
static void rmtsPrevNext(int delta)
static void rmtsActivate(void)
static int TrackLabelId
static int LengthId
static void rmUpdateTrackInfo(void)
static int MapId
static void rmCatPrevNext(int delta)