1 /*
2  * util.c - utilities
3  * Copyright (C) 2008-2010  Alexandre Martins <alemartf(at)gmail(dot)com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <allegro.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <math.h>
25 #include "v2d.h"
26 #include "util.h"
27 #include "timer.h"
28 #include "logfile.h"
29 
30 
31 
32 /* private stuff */
33 static volatile int game_over = FALSE;
34 static void merge_sort_recursive(void *base, size_t size, int (*comparator)(const void*,const void*), int p, int q);
35 static void merge_sort_mix(void *base, size_t size, int (*comparator)(const void*,const void*), int p, int q, int m);
36 
37 
38 
39 
40 /* Memory management */
41 
42 
43 /*
44  * mallocx()
45  * Similar to malloc(), but aborts the
46  * program if it does not succeed.
47  */
mallocx(size_t bytes)48 void *mallocx(size_t bytes)
49 {
50     void *p = malloc(bytes);
51 
52     if(!p)
53         fatal_error("FATAL ERROR: mallocx() failed.\n");
54 
55     return p;
56 }
57 
58 
59 /*
60  * relloacx()
61  * Similar to realloc(), but abots the
62  * program if it does not succeed.
63  */
reallocx(void * ptr,size_t bytes)64 void* reallocx(void *ptr, size_t bytes)
65 {
66     void *p = realloc(ptr, bytes);
67 
68     if(!p)
69         fatal_error("FATAL ERROR: reallocx() failed.\n");
70 
71     return p;
72 }
73 
74 
75 
76 /* Game routines */
77 
78 /*
79  * game_quit()
80  * Quit game?
81  */
game_quit(void)82 void game_quit(void)
83 {
84     game_over = TRUE;
85 }
END_OF_FUNCTION(game_quit)86 END_OF_FUNCTION(game_quit)
87 
88 
89 /*
90  * game_is_over()
91  * Game over?
92  */
93 int game_is_over()
94 {
95     return game_over;
96 }
97 
98 
99 /*
100  * game_version_compare()
101  * Compares the given parameters to the version
102  * of the game. Returns:
103  * < 0 (game version is inferior),
104  * = 0 (same version),
105  * > 0 (game version is superior)
106  */
game_version_compare(int version,int sub_version,int wip_version)107 int game_version_compare(int version, int sub_version, int wip_version)
108 {
109     int game_version = (GAME_VERSION*10000 + GAME_SUB_VERSION*100 + GAME_WIP_VERSION);
110     int other_version = (version*10000 + sub_version*100 + wip_version);
111 
112     return game_version - other_version;
113 }
114 
115 
116 /* Other */
117 
118 
119 /*
120  * bounding_box()
121  * bounding box collision method
122  * r[4] = x1, y1, x2(=x1+w), y2(=y1+h)
123  */
bounding_box(float a[4],float b[4])124 int bounding_box(float a[4], float b[4])
125 {
126     return (a[0]<b[2] && a[2]>b[0] && a[1]<b[3] && a[3]>b[1]);
127 }
128 
129 
130 
131 /*
132  * circular_collision()
133  * Circular collision method
134  * a, b = points to test
135  * r_a = radius of a
136  * r_b = radius of b
137  */
circular_collision(v2d_t a,float r_a,v2d_t b,float r_b)138 int circular_collision(v2d_t a, float r_a, v2d_t b, float r_b)
139 {
140     return ( v2d_magnitude(v2d_subtract(a,b)) <= r_a + r_b );
141 }
142 
143 
144 
145 /*
146  * swap_ex()
147  * Swaps two variables. Use the
148  * swap() macro instead of this.
149  */
swap_ex(void * a,void * b,size_t size)150 void swap_ex(void *a, void *b, size_t size)
151 {
152     uint8 *sa=a, *sb=b, c;
153     size_t i;
154 
155     for(i=0; i<size; i++) {
156         c = sa[i];
157         sa[i] = sb[i];
158         sb[i] = c;
159     }
160 }
161 
162 
163 
164 
165 
166 /*
167  * fatal_error()
168  * Displays a fatal error and aborts the application
169  * (printf() format)
170  */
fatal_error(const char * fmt,...)171 void fatal_error(const char *fmt, ...)
172 {
173     char buf[1024];
174     va_list args;
175 
176     va_start(args, fmt);
177     vsprintf(buf, fmt, args);
178     va_end(args);
179 
180     logfile_message(buf);
181     set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
182     allegro_message("%s", buf);
183     exit(1);
184 }
185 
186 
187 /*
188  * old_school_angle()
189  * Old school angle
190  */
old_school_angle(float angle)191 float old_school_angle(float angle)
192 {
193     if(angle >= 0 && angle < PI/4-EPSILON)
194         return 0;
195     else if(angle >= PI/4-EPSILON && angle < PI/2-EPSILON)
196         return PI/4;
197     else if(angle >= PI/2-EPSILON && angle < PI/2+EPSILON)
198         return PI/2;
199     else if(angle >= PI/2+EPSILON && angle < PI-EPSILON)
200         return 3*PI/4;
201     else if(angle >= PI-EPSILON && angle < PI+EPSILON)
202         return PI;
203     else if(angle >= PI+EPSILON && angle < 3*PI/2-EPSILON)
204         return 5*PI/4;
205     else if(angle >= 3*PI/2-EPSILON && angle < 3*PI/2+EPSILON)
206         return 3*PI/2;
207     else if(angle > 3*PI/2+EPSILON && angle <= 7*PI/4+EPSILON)
208         return 7*PI/4;
209     else
210         return 0;
211 }
212 
213 /*
214  * merge_sort()
215  * Similar to stdlib's qsort, but merge_sort is
216  * a stable sorting algorithm
217  *
218  * base       - Pointer to the first element of the array to be sorted
219  * num        - Number of elements in the array pointed by base
220  * size       - Size in bytes of each element in the array
221  * comparator - The return value of this function should represent
222  *              whether elem1 is considered less than, equal to,
223  *              or greater than elem2 by returning, respectively,
224  *              a negative value, zero or a positive value
225  *              int comparator(const void *elem1, const void *elem2)
226  */
merge_sort(void * base,size_t num,size_t size,int (* comparator)(const void *,const void *))227 void merge_sort(void *base, size_t num, size_t size, int (*comparator)(const void*,const void*))
228 {
229     merge_sort_recursive(base, size, comparator, 0, num-1);
230 }
231 
232 
233 
234 /* private stuff */
merge_sort_recursive(void * base,size_t size,int (* comparator)(const void *,const void *),int p,int q)235 void merge_sort_recursive(void *base, size_t size, int (*comparator)(const void*,const void*), int p, int q)
236 {
237     if(q > p) {
238         int m = (p+q)/2;
239         merge_sort_recursive(base, size, comparator, p, m);
240         merge_sort_recursive(base, size, comparator, m+1, q);
241         merge_sort_mix(base, size, comparator, p, q, m);
242     }
243 }
244 
merge_sort_mix(void * base,size_t size,int (* comparator)(const void *,const void *),int p,int q,int m)245 void merge_sort_mix(void *base, size_t size, int (*comparator)(const void*,const void*), int p, int q, int m)
246 {
247     uint8 *arr = mallocx((q-p+1) * size);
248     uint8 *i = arr;
249     uint8 *j = arr + (m+1-p) * size;
250     int k = p;
251 
252     memcpy(arr, (uint8*)base + p * size, (q-p+1) * size);
253 
254     while(i < arr + (m+1-p) * size && j <= arr + (q-p) * size) {
255         int cmp = comparator((const void*)i, (const void*)j);
256         if(cmp <= 0) {
257             memcpy((uint8*)base + (k++) * size, i, size);
258             i += size;
259         }
260         else {
261             memcpy((uint8*)base + (k++) * size, j, size);
262             j += size;
263         }
264     }
265 
266     while(i < arr + (m+1-p) * size) {
267         memcpy((uint8*)base + (k++) * size, i, size);
268         i += size;
269     }
270 
271     while(j <= arr + (q-p) * size) {
272         memcpy((uint8*)base + (k++) * size, j, size);
273         j += size;
274     }
275 
276     free(arr);
277 }
278 
279