1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <time.h>
5 #include <math.h>
6 #include <sys/types.h>
7
8 #ifdef __MSW__
9 # include <windows.h>
10 #else
11 # include <sys/time.h>
12 # include <unistd.h>
13 #endif
14 #include <GL/gl.h>
15
16 #include "../include/strexp.h"
17 #include "../include/string.h"
18
19 #include "menu.h"
20 #include "obj.h"
21 #include "sar.h"
22 #include "sardraw.h"
23 #include "config.h"
24
25
26 #ifdef __MSW__
27 static double rint(double x);
28 #endif /* __MSW__ */
29
30 Boolean SARGetGLVersion(int *major, int *minor, int *release);
31 char *SARGetGLVendorName(void);
32 char *SARGetGLRendererName(void);
33 char **SARGelGLExtensionNames(int *strc);
34
35 int SARIsMenuAllocated(sar_core_struct *core_ptr, int n);
36 int SARMatchMenuByName(
37 sar_core_struct *core_ptr, const char *name
38 );
39 sar_menu_struct *SARMatchMenuByNamePtr(
40 sar_core_struct *core_ptr, const char *name
41 );
42 sar_menu_struct *SARGetCurrentMenuPtr(sar_core_struct *core_ptr);
43
44 sar_player_stat_struct *SARGetPlayerStatPtr(
45 sar_core_struct *core_ptr, int i
46 );
47 sar_player_stat_struct *SARPlayerStatNew(
48 const char *name,
49 int score
50 );
51 void SARPlayerStatDelete(sar_player_stat_struct *pstat);
52 void SARPlayerStatResort(sar_player_stat_struct **list, int total);
53 sar_player_stat_struct *SARPlayerStatCurrent(
54 sar_core_struct *core_ptr, int *n
55 );
56
57 void SARDeleteListItemData(sar_menu_list_item_struct *item_ptr);
58
59 char *SARTimeOfDayString(sar_core_struct *core_ptr, float t);
60 char *SARDeltaTimeString(sar_core_struct *core_ptr, time_t t);
61
62 void SARSetGlobalTextColorBrightness(
63 sar_core_struct *core_ptr, float g
64 );
65
66 void SARReportGLError(
67 sar_core_struct *core_ptr, GLenum error_code
68 );
69
70
71 #define ATOI(s) (((s) != NULL) ? atoi(s) : 0)
72 #define ATOL(s) (((s) != NULL) ? atol(s) : 0)
73 #define ATOF(s) (((s) != NULL) ? atof(s) : 0.0f)
74 #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL)
75
76 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
77 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
78 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
79 #define IS_STRING_EMPTY(s) (((s) != NULL) ? (*(s) == '\0') : TRUE)
80
81 #define RADTODEG(r) ((r) * 180 / PI)
82 #define DEGTORAD(d) ((d) * PI / 180)
83
84
85 #ifdef __MSW__
rint(double x)86 static double rint(double x)
87 {
88 if((double)((double)x - (int)x) > (double)0.5)
89 return((double)((int)x + (int)1));
90 else
91 return((double)((int)x));
92 }
93 #endif /* __MSW__ */
94
95
96 /*
97 * Returns the version numbers for the GL version, returns
98 * GL_TRUE on success or GL_FALSE on failure.
99 *
100 * If any of the inputs are NULL, then that respective input will
101 * not be set.
102 */
SARGetGLVersion(int * major,int * minor,int * release)103 Boolean SARGetGLVersion(int *major, int *minor, int *release)
104 {
105 const GLubyte *strptr;
106 char **strv;
107 int strc;
108
109
110 /* Reset inputs. */
111 if(major != NULL)
112 *major = 0;
113 if(minor != NULL)
114 *minor = 0;
115 if(release != NULL)
116 *release = 0;
117
118 /* Get statically allocated '.' character separated string
119 * containing the version numbers. Format can be either
120 * "major.minor" or "major.minor.release".
121 */
122 strptr = glGetString(GL_VERSION);
123 if(strptr == NULL)
124 return(GL_FALSE);
125
126 /* Explode version string at the '.' characters. */
127 strv = strchrexp((const char *)strptr, '.', &strc);
128 if(strv == NULL)
129 return(GL_FALSE);
130
131 if((strc > 0) && (major != NULL))
132 *major = atoi(strv[0]);
133
134 if((strc > 1) && (minor != NULL))
135 *minor = atoi(strv[1]);
136
137 if((strc > 2) && (release != NULL))
138 *release = atoi(strv[2]);
139
140 strlistfree(strv, strc);
141
142 return(GL_TRUE);
143 }
144
145 /*
146 * Returns a dynamically allocated string containing the GL
147 * vendor name. The returned string must be free()'ed by the
148 * calling function.
149 *
150 * Can return NULL on error.
151 */
SARGetGLVendorName(void)152 char *SARGetGLVendorName(void)
153 {
154 /* Return copy of string describing the GL vendor name. */
155 return(STRDUP((const char *)glGetString(GL_VENDOR)));
156 }
157
158 /*
159 * Returns a dynamically allocated string containing the GL
160 * renderer name. The returned string must be free()'ed by the
161 * calling function.
162 *
163 * Can return NULL on error.
164 */
SARGetGLRendererName(void)165 char *SARGetGLRendererName(void)
166 {
167 /* Return copy of string describing the GL renderer name. */
168 return(STRDUP((const char *)glGetString(GL_RENDERER)));
169 }
170
171
172 /*
173 * Returns a dynamically allocated array of strings containing
174 * the list of GL extension names available.
175 *
176 * If strc is not NULL then it will be set to the number of
177 * strings returned.
178 *
179 * Can return NULL on error.
180 */
SARGelGLExtensionNames(int * strc)181 char **SARGelGLExtensionNames(int *strc)
182 {
183 const GLubyte *strptr;
184 char **strv;
185 int lstrc;
186
187
188 /* Reset inputs. */
189 if(strc != NULL)
190 *strc = 0;
191
192 /* Get statically allocated space separated string containing
193 * the GL extensions list.
194 */
195 strptr = glGetString(GL_EXTENSIONS);
196 if(strptr == NULL)
197 return(NULL);
198
199 /* Explode space separated string. */
200 strv = strexp((char *)strptr, &lstrc);
201 if(strv == NULL)
202 return(NULL);
203
204 /* Update number of strings reciefved (hence number of
205 * extensions).
206 */
207 if(strc != NULL)
208 *strc = lstrc;
209
210 return(strv);
211 }
212
213
214 /*
215 * Is menu allocated on the core structure.
216 */
SARIsMenuAllocated(sar_core_struct * core_ptr,int n)217 int SARIsMenuAllocated(sar_core_struct *core_ptr, int n)
218 {
219 if(core_ptr == NULL)
220 return(0);
221 else if((n < 0) || (n >= core_ptr->total_menus))
222 return(0);
223 else if(core_ptr->menu[n] == NULL)
224 return(0);
225 else
226 return(1);
227 }
228
229 /*
230 * Returns the index number of the menu who's name matches the
231 * given name (case insensitive).
232 *
233 * Can return -1 for no match or error.
234 */
SARMatchMenuByName(sar_core_struct * core_ptr,const char * name)235 int SARMatchMenuByName(
236 sar_core_struct *core_ptr, const char *name
237 )
238 {
239 int i;
240 sar_menu_struct *m;
241
242 if((core_ptr == NULL) || (name == NULL))
243 return(-1);
244
245 for(i = 0; i < core_ptr->total_menus; i++)
246 {
247 m = core_ptr->menu[i];
248 if(m == NULL)
249 continue;
250
251 if(m->name == NULL)
252 continue;
253
254 if(!strcasecmp(m->name, name))
255 return(i);
256 }
257
258 return(-1);
259 }
260
261 /*
262 * Returns the pointer to the menu who's name matches the
263 * given name (case insensitive).
264 *
265 * Can return NULL for no match or error.
266 */
SARMatchMenuByNamePtr(sar_core_struct * core_ptr,const char * name)267 sar_menu_struct *SARMatchMenuByNamePtr(
268 sar_core_struct *core_ptr, const char *name
269 )
270 {
271 int i;
272 sar_menu_struct *m;
273
274 if((core_ptr == NULL) || (name == NULL))
275 return(NULL);
276
277 for(i = 0; i < core_ptr->total_menus; i++)
278 {
279 m = core_ptr->menu[i];
280 if(m == NULL)
281 continue;
282
283 if(m->name == NULL)
284 continue;
285
286 if(!strcasecmp(m->name, name))
287 return(m);
288 }
289
290 return(NULL);
291 }
292
293 /*
294 * Returns the pointer to the current menu or NULL if there
295 * is no current menu.
296 */
SARGetCurrentMenuPtr(sar_core_struct * core_ptr)297 sar_menu_struct *SARGetCurrentMenuPtr(sar_core_struct *core_ptr)
298 {
299 int n = (core_ptr != NULL) ? core_ptr->cur_menu : -1;
300 if(n < 0)
301 return(NULL);
302 else if(n >= core_ptr->total_menus)
303 return(NULL);
304 else
305 return(core_ptr->menu[n]);
306 }
307
308
309 /*
310 * Returns the player stats for the player specified by index i.
311 */
SARGetPlayerStatPtr(sar_core_struct * core_ptr,int i)312 sar_player_stat_struct *SARGetPlayerStatPtr(
313 sar_core_struct *core_ptr, int i
314 )
315 {
316 if(core_ptr == NULL)
317 return(NULL);
318 else if((i < 0) || (i >= core_ptr->total_player_stats))
319 return(NULL);
320 else
321 return(core_ptr->player_stat[i]);
322 }
323
324 /*
325 * Creates a new player stat.
326 */
SARPlayerStatNew(const char * name,int score)327 sar_player_stat_struct *SARPlayerStatNew(
328 const char *name,
329 int score
330 )
331 {
332 sar_player_stat_struct *pstat = SAR_PLAYER_STAT(calloc(
333 1, sizeof(sar_player_stat_struct)
334 ));
335 if(pstat == NULL)
336 return(NULL);
337
338 pstat->name = STRDUP(name);
339 pstat->score = score;
340
341 return(pstat);
342 }
343
344 /*
345 * Deletes the player stat.
346 */
SARPlayerStatDelete(sar_player_stat_struct * pstat)347 void SARPlayerStatDelete(sar_player_stat_struct *pstat)
348 {
349 free(pstat->name);
350 free(pstat);
351 }
352
353 /*
354 * Resorts the list of player stats.
355 */
SARPlayerStatResort(sar_player_stat_struct ** list,int total)356 void SARPlayerStatResort(sar_player_stat_struct **list, int total)
357 {
358 int i, n;
359 char **names, *name;
360 sar_player_stat_struct **tmp_list, *pstat;
361
362 if((list == NULL) || (total <= 0))
363 return;
364
365 /* Create tempory list for sorting */
366 names = (char **)calloc(
367 total, sizeof(char *)
368 );
369 tmp_list = (sar_player_stat_struct **)calloc(
370 total, sizeof(sar_player_stat_struct *)
371 );
372 if((names == NULL) || (tmp_list == NULL))
373 {
374 free(names);
375 free(tmp_list);
376 return;
377 }
378
379 /* Get list of names */
380 for(i = 0; i < total; i++)
381 names[i] = (list[i] != NULL) ? list[i]->name : NULL;
382
383 /* Sort names list */
384 StringQSort(names, total);
385
386 /* Iterate through sorted names */
387 for(i = 0; i < total; i++)
388 {
389 name = names[i];
390 if(name == NULL)
391 continue;
392
393 /* Iterate through given list, looking for the item who's
394 * name matches the current one in the sorted names list
395 */
396 for(n = 0; n < total; n++)
397 {
398 pstat = list[n];
399 if(pstat == NULL)
400 continue;
401
402 if(pstat->name == NULL)
403 continue;
404
405 if(!strcmp(name, pstat->name))
406 {
407 tmp_list[i] = pstat;
408 list[n] = NULL;
409 break;
410 }
411 }
412 if(n >= total)
413 {
414 /* Unable to find match */
415 tmp_list[i] = NULL;
416 }
417
418 }
419
420 /* Copy sorted list to the specified list */
421 memcpy(list, tmp_list, total * sizeof(sar_player_stat_struct *));
422
423 /* Delete tempory list */
424 free(names);
425 free(tmp_list);
426 }
427
428 /*
429 * Returns the current selected player stat.
430 */
SARPlayerStatCurrent(sar_core_struct * core_ptr,int * n)431 sar_player_stat_struct *SARPlayerStatCurrent(
432 sar_core_struct *core_ptr, int *n
433 )
434 {
435 int i = (core_ptr != NULL) ?
436 core_ptr->option.last_selected_player : -1;
437 if(i < 0)
438 {
439 if(n != NULL)
440 *n = -1;
441 return(NULL);
442 }
443
444 if(i < core_ptr->total_player_stats)
445 {
446 if(n != NULL)
447 *n = i;
448 return(core_ptr->player_stat[i]);
449 }
450 else
451 {
452 if(n != NULL)
453 *n = -1;
454 return(NULL);
455 }
456 }
457
458
459 /*
460 * Deletes the client data structure specified on the menu
461 * list object item pointer.
462 */
SARDeleteListItemData(sar_menu_list_item_struct * item_ptr)463 void SARDeleteListItemData(sar_menu_list_item_struct *item_ptr)
464 {
465 sar_menu_list_item_data_struct *d = SAR_MENU_LIST_ITEM_DATA(
466 (item_ptr != NULL) ? item_ptr->client_data : NULL
467 );
468 if(d == NULL)
469 return;
470
471 free(d->filename);
472 free(d->name);
473 free(d);
474
475 item_ptr->client_data = NULL;
476 }
477
478 /*
479 * Returns a statically allocated string containing the time
480 * of day in %h:%m format or by whatever format specified on the
481 * core structure if the core_ptr is not NULL.
482 *
483 * Time t is given in seconds from midnight.
484 */
SARTimeOfDayString(sar_core_struct * core_ptr,float t)485 char *SARTimeOfDayString(sar_core_struct *core_ptr, float t)
486 {
487 static char str[80];
488
489 #define HTOS(h) ((h) * 3600.0f)
490
491 /* Sanitize time. */
492 while(t >= HTOS(24.0f))
493 t -= HTOS(24.0f);
494 while(t < HTOS(0.0f))
495 t += HTOS(24.0f);
496
497 *str = '\0';
498
499 /* No core structure given? */
500 if(core_ptr == NULL)
501 {
502 int h = (int)MAX((t / 3600.0f), 0.0f),
503 m = (int)MAX(((int)((int)t / 60) % 60), 0.0f);
504
505 sprintf(str, "%i:%2.2i", h, m);
506 }
507 else
508 {
509 int h = (int)MAX((t / 3600.0f), 0.0f),
510 m = (int)MAX(((int)((int)t / 60) % 60), 0.0f);
511
512 sprintf(str, "%i:%2.2i", h, m);
513 }
514
515 #undef HTOS
516 return(str);
517 }
518
519 /*
520 * Returns a statically allocated string verbosly stating the
521 * delta time t in accordance to the format specified by the
522 * core_ptr. If core_ptr is NULL then a generic format will be
523 * assumed.
524 *
525 * This function never returns NULL.
526 */
SARDeltaTimeString(sar_core_struct * core_ptr,time_t t)527 char *SARDeltaTimeString(sar_core_struct *core_ptr, time_t t)
528 {
529 #define len 256
530 static char s[len];
531
532 if(t <= 0)
533 return("none");
534
535 if(t < 60)
536 {
537 sprintf(s, "%ld second%s",
538 t,
539 (t == 1) ? "" : "s"
540 );
541 }
542 else if(t < 3600)
543 {
544 time_t min = t / 60,
545 sec = t % 60;
546 if(sec != 0)
547 sprintf(
548 s, "%ld minute%s %ld second%s",
549 min,
550 (min == 1) ? "" : "s",
551 sec,
552 (sec == 1) ? "" : "s"
553 );
554 else
555 sprintf(
556 s, "%ld minute%s",
557 min,
558 (min == 1) ? "" : "s"
559 );
560 }
561 else if(t < 86400)
562 {
563 time_t hr = t / 3600,
564 min = (t / 60) % 60;
565 if(min != 0)
566 sprintf(
567 s, "%ld hour%s %ld minute%s",
568 hr,
569 (hr == 1) ? "" : "s",
570 min,
571 (min == 1) ? "" : "s"
572 );
573 else
574 sprintf(
575 s, "%ld hour%s",
576 hr,
577 (hr == 1) ? "" : "s"
578 );
579 }
580
581 return(s);
582 #undef len
583 }
584
585
586 /*
587 * Updates the global hud and message text color based on the
588 * given gamma g which must be in the domain of 0.0 to 1.0.
589 */
SARSetGlobalTextColorBrightness(sar_core_struct * core_ptr,float g)590 void SARSetGlobalTextColorBrightness(
591 sar_core_struct *core_ptr, float g
592 )
593 {
594 sar_color_struct *c;
595 sar_option_struct *opt;
596
597 if(core_ptr == NULL)
598 return;
599
600 opt = &core_ptr->option;
601
602 /* Set message text color. */
603 c = &opt->message_color;
604 c->a = 1.0f;
605 c->r = g;
606 c->g = g;
607 c->b = g;
608
609 /* Set new hud color. */
610 c = &opt->hud_color;
611 if(g > 0.5f)
612 {
613 float ng = (g - 0.5f) / 0.5f;
614 c->a = 1.0f;
615 c->r = ng;
616 c->g = 1.0f;
617 c->b = ng;
618 }
619 else
620 {
621 c->a = 1.0f;
622 c->r = 0.0f;
623 c->g = g * 2.0f;
624 c->b = 0.0f;
625 }
626 }
627
628 /*
629 * Reports the given GL error code, does not check if the
630 * error is actually an error and prints explicitly even if
631 * global options specify not to print errors.
632 */
SARReportGLError(sar_core_struct * core_ptr,GLenum error_code)633 void SARReportGLError(
634 sar_core_struct *core_ptr, GLenum error_code
635 )
636 {
637 const char *error_mesg = NULL, *error_type = NULL;
638
639 switch(error_code)
640 {
641 case GL_INVALID_ENUM:
642 error_type = "GL_INVALID_ENUM";
643 error_mesg =
644 "Invalid GLenum argument (possibly out of range)";
645 break;
646
647 case GL_INVALID_VALUE:
648 error_type = "GL_INVALID_VALUE";
649 error_mesg =
650 "Numeric argument out of range";
651 break;
652
653 case GL_INVALID_OPERATION:
654 error_type = "GL_INVALID_OPERATION";
655 error_mesg =
656 "Operation illegal in current state";
657 break;
658
659 case GL_STACK_OVERFLOW:
660 error_type = "GL_STACK_OVERFLOW";
661 error_mesg =
662 "Command would cause stack overflow";
663 break;
664
665 case GL_STACK_UNDERFLOW:
666 error_type = "GL_STACK_UNDERFLOW";
667 error_mesg =
668 "Command would cause a stack underflow";
669 break;
670
671 case GL_OUT_OF_MEMORY:
672 error_type = "GL_OUT_OF_MEMORY";
673 error_mesg =
674 "Not enough memory left to execute command";
675 break;
676
677 default:
678 error_type = "*UNKNOWN*";
679 error_mesg = "Undefined GL error";
680 break;
681 }
682
683 fprintf(
684 stderr,
685 "GL Error code %i: %s: %s\n",
686 error_code, error_type, error_mesg
687 );
688 }
689