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