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