1 /* $Id: util.c,v 1.57 2005/07/11 21:23:12 oohara Exp $ */
2
3 /* NOT_HAVE_POSIX */
4 #include <config.h>
5
6 #include <stdio.h>
7 /* malloc, strtol */
8 #include <stdlib.h>
9 /* errno */
10 #include <errno.h>
11 /* INT_MIN, INT_MAX */
12 #include <limits.h>
13
14 #include "tenm_graphic.h"
15 #include "tenm_table.h"
16 #include "tenm_primitive.h"
17 #include "tenm_collision.h"
18 #include "tenm_object.h"
19 #include "tenm_math.h"
20 #include "const.h"
21 #include "explosion.h"
22
23 #include "util.h"
24
25 #define NEAR_ZERO 0.0001
26
27 #ifdef NOT_HAVE_POSIX
28 #define FONTDIR "spqr/image/"
29 #else /* not NOT_HAVE_POSIX */
30 #define FONTDIR DATADIR "/dangen/image/"
31 #endif
32
33 static tenm_image *font = NULL;
34 static tenm_primitive *window = NULL;
35 static double window_width = 0.0;
36 static double window_height = 0.0;
37 static char *buffer = NULL;
38 static int buffer_size = 0;
39
40 static int in_window_point(double x, double y);
41
42 /* return 0 on success, 1 on error */
43 int
util_init(int width,int height)44 util_init(int width, int height)
45 {
46 font = tenm_load_image(1, FONTDIR "/" "font.png",
47 1, 95,
48 tenm_map_color(255, 255, 255));
49
50 window= (tenm_primitive *) tenm_polygon_new(4,
51 0.0, 0.0,
52 0.0, (double) height,
53 (double) width, 0.0,
54 (double) width, (double) height);
55 if (window == NULL)
56 {
57 tenm_image_delete(font);
58 fprintf(stderr, "util_init: tenm_polygon_new failed\n");
59 return 1;
60 }
61 window_width = width;
62 window_height = height;
63
64 return 0;
65 }
66
67 void
util_quit(void)68 util_quit(void)
69 {
70 if (font != NULL)
71 {
72 tenm_image_delete(font);
73 font = NULL;
74 }
75 if (window != NULL)
76 {
77 (window->delete)(window);
78 window = NULL;
79 }
80 window_width = 0.0;
81 window_height = 0.0;
82 if (buffer != NULL)
83 {
84 free(buffer);
85 buffer = NULL;
86 }
87 buffer_size = 0;
88 }
89
90 int
draw_string(int x,int y,const char * string,int length)91 draw_string(int x, int y, const char *string, int length)
92 {
93 /* sanity check */
94 if (font == NULL)
95 return 0;
96 if (string == NULL)
97 return 0;
98 if (length <= 0)
99 return 0;
100
101 if (tenm_draw_string(x, y, font, string, length) != 0)
102 {
103 fprintf(stderr, "draw_string: tenm_draw_string failed\n");
104 return 1;
105 }
106 return 0;
107 }
108
109 int
draw_string_int(int x,int y,const int * string,int length)110 draw_string_int(int x, int y, const int *string, int length)
111 {
112 int i;
113 char *buffer_temp;
114
115 /* sanity check */
116 if (font == NULL)
117 return 0;
118 if (string == NULL)
119 return 0;
120 if (length <= 0)
121 return 0;
122
123 /* don't substitute buffer directly, or you will be in a trouble
124 * if realloc fails (you don't need data in buffer, but you still
125 * need to free buffer in any case) */
126 if ((buffer == NULL) || (length + 1 > buffer_size))
127 {
128 if (buffer == NULL)
129 buffer_temp = (char *) malloc(sizeof(char) * (length + 1));
130 else
131 buffer_temp = (char *) realloc(buffer, sizeof(char) * (length + 1));
132 if (buffer_temp == NULL)
133 {
134 fprintf(stderr, "draw_string_int: memory allocation to buffer failed\n");
135 return 1;
136 }
137 buffer = buffer_temp;
138 buffer_size = length + 1;
139 }
140
141 /* stupid way to get a pointer to char
142 * (char * and int * are incompatible)
143 */
144 for (i = 0; i < length; i++)
145 buffer[i] = (char) string[i];
146 buffer[length] = '\0';
147
148 if (tenm_draw_string(x, y, font, buffer, length) != 0)
149 {
150 fprintf(stderr, "draw_string_int: tenm_draw_string failed\n");
151 return 1;
152 }
153 return 0;
154 }
155
156 /* return 1 (true) or 0 (false) */
157 int
in_window_object(const tenm_object * p)158 in_window_object(const tenm_object *p)
159 {
160 int i;
161
162 if (window == NULL)
163 {
164 fprintf(stderr, "in_window_primitive: window is NULL\n");
165 return 0;
166 }
167 if (p == NULL)
168 {
169 fprintf(stderr, "in_window_primitive: p is NULL\n");
170 return 0;
171 }
172 if (p->mass == NULL)
173 {
174 fprintf(stderr, "in_window_primitive: p->mass is NULL\n");
175 return 0;
176 }
177 for (i = 0; i < p->mass->n; i++)
178 if (in_window_primitive(p->mass->p[i]))
179 return 1;
180 return 0;
181 }
182
183 /* optimized under the assumption that p is usually in the window
184 * return 1 (true) or 0 (false) */
185 int
in_window_primitive(const tenm_primitive * p)186 in_window_primitive(const tenm_primitive *p)
187 {
188 double temp_x;
189 double temp_y;
190 double temp_r;
191 int i;
192
193 if (window == NULL)
194 {
195 fprintf(stderr, "in_window_primitive: window is NULL\n");
196 return 0;
197 }
198 if (p == NULL)
199 {
200 fprintf(stderr, "in_window_primitive: p is NULL\n");
201 return 0;
202 }
203
204 switch (p->klass)
205 {
206 case TENM_POINT:
207 return in_window_point(((const tenm_point *) p)->x,
208 ((const tenm_point *) p)->y);
209 break;
210 case TENM_CIRCLE:
211 temp_x = ((const tenm_circle *) p)->center->x;
212 temp_y = ((const tenm_circle *) p)->center->y;
213 temp_r = ((const tenm_circle *) p)->r;
214 if ((temp_x + temp_r >= 0.0) && (temp_x - temp_r < window_width)
215 && (temp_y >= 0.0) && (temp_y < window_height))
216 return 1;
217 if ((temp_y + temp_r >= 0.0) && (temp_y - temp_r < window_height)
218 && (temp_x >= 0.0) && (temp_x < window_width))
219 return 1;
220 return tenm_collided_primitive(p, window);
221 break;
222 case TENM_SEGMENT:
223 temp_x = ((const tenm_segment *) p)->a->x;
224 temp_y = ((const tenm_segment *) p)->a->y;
225 if (in_window_point(temp_x, temp_y))
226 return 1;
227 temp_x = ((const tenm_segment *) p)->b->x;
228 temp_y = ((const tenm_segment *) p)->b->y;
229 if (in_window_point(temp_x, temp_y))
230 return 1;
231 return tenm_collided_primitive(p, window);
232 break;
233 case TENM_POLYGON:
234 for (i = 0; i < ((const tenm_polygon *) p)->n; i++)
235 {
236 temp_x = ((const tenm_polygon *) p)->v[i]->x;
237 temp_y = ((const tenm_polygon *) p)->v[i]->y;
238 if (in_window_point(temp_x, temp_y))
239 return 1;
240 }
241 return tenm_collided_primitive(p, window);
242 break;
243 default:
244 fprintf(stderr, "primitive_in_window: strange primitive found (%d)\n",
245 p->klass);
246 return 0;
247 break;
248 }
249 /* should not reach here */
250 return 0;
251 }
252
253 /* return 1 (true) or 0 (false) */
254 static int
in_window_point(double x,double y)255 in_window_point(double x, double y)
256 {
257 /* sanity check */
258 if (window == NULL)
259 {
260 fprintf(stderr, "point_in_window: window is NULL\n");
261 return 0;
262 }
263
264 if ((x < 0) || (x >= window_width))
265 return 0;
266 if ((y < 0) || (y >= window_height))
267 return 0;
268 return 1;
269 }
270
271 /* rotate the vector v (arg 2) by theta (arg 3) degree
272 * result (arg 1) and v (arg 2) must be double[2] (you must allocate enough
273 * memory before calling this function)
274 * the result is undefined if result (arg 1) and v (arg 2) overlap
275 */
276 void
vector_rotate(double * result,const double * v,int theta)277 vector_rotate(double *result, const double *v, int theta)
278 {
279 /* sanity check */
280 if (result == NULL)
281 {
282 fprintf(stderr, "vector_rotate: result is NULL\n");
283 return;
284 }
285 if (v == NULL)
286 {
287 fprintf(stderr, "vector_rotate: v is NULL\n");
288 return;
289 }
290
291 result[0] = tenm_cos(theta) * v[0] - tenm_sin(theta) * v[1];
292 result[1] = tenm_sin(theta) * v[0] + tenm_cos(theta) * v[1];
293 }
294
295 /* rotate the vector v (arg 2) to the vector a (arg 4)
296 * by at most theta (arg 3) degree
297 * result (arg 1), v (arg 2) and a(arg 3) must be double[2]
298 * (you must allocate enough memory before calling this function)
299 * the result is undefined if any pair of result (arg 1), v (arg 2)
300 * and a (arg 3) overlap
301 */
302 void
vector_rotate_bounded(double * result,const double * v,const double * a,int theta)303 vector_rotate_bounded(double *result, const double *v,
304 const double *a, int theta)
305 {
306 double length_v;
307 double length_a;
308 double dot;
309 double c;
310 double r1[2];
311 double r2[2];
312 double dot_r1;
313 double dot_r2;
314
315 /* sanity check */
316 if (result == NULL)
317 {
318 fprintf(stderr, "vector_rotate_bounded: result is NULL\n");
319 return;
320 }
321 if (v == NULL)
322 {
323 fprintf(stderr, "vector_rotate_bounded: v is NULL\n");
324 return;
325 }
326 if (a == NULL)
327 {
328 fprintf(stderr, "vector_rotate_bounded: a is NULL\n");
329 return;
330 }
331
332 if (theta <= 0)
333 {
334 result[0] = v[0];
335 result[1] = v[1];
336 return;
337 }
338
339 length_v = tenm_sqrt((int) (v[0] * v[0] + v[1] * v[1]));
340 length_a = tenm_sqrt((int) (a[0] * a[0] + a[1] * a[1]));
341 if (length_v < NEAR_ZERO)
342 length_v = 1.0;
343 if (length_a < NEAR_ZERO)
344 length_a = 1.0;
345
346 if (theta >= 180)
347 {
348 result[0] = a[0] * length_v / length_a;
349 result[1] = a[1] * length_v / length_a;
350 return;
351 }
352
353 dot = v[0] * a[0] + v[1] * a[1];
354 c = dot / (length_v * length_a);
355
356 if (c > tenm_cos(theta))
357 {
358 result[0] = a[0] * length_v / length_a;
359 result[1] = a[1] * length_v / length_a;
360 return;
361 }
362
363 r1[0] = 0.0;
364 r1[1] = 0.0;
365 vector_rotate(r1, v, theta);
366 r2[0] = 0.0;
367 r2[1] = 0.0;
368 vector_rotate(r2, v, -theta);
369 dot_r1 = r1[0] * a[0] + r1[1] * a[1];
370 dot_r2 = r2[0] * a[0] + r2[1] * a[1];
371
372 if (dot_r1 >= dot_r2)
373 {
374 result[0] = r1[0];
375 result[1] = r1[1];
376 return;
377 }
378
379 result[0] = r2[0];
380 result[1] = r2[1];
381 }
382
383 int
delete_enemy_shot(tenm_object * my,int n)384 delete_enemy_shot(tenm_object *my, int n)
385 {
386 if (my == NULL)
387 return 0;
388 if (!(my->attr & ATTR_ENEMY_SHOT))
389 return 0;
390
391 tenm_table_add(explosion_new(my->x, my->y,
392 0.0, 0.0,
393 1, 20, my->count[0], 2.0, 8));
394
395 return 1;
396 }
397
398 int
delete_enemy(tenm_object * my,int n)399 delete_enemy(tenm_object *my, int n)
400 {
401 if (my == NULL)
402 return 0;
403 if (my->attr & ATTR_BOSS)
404 return 0;
405 if (!(my->attr & (ATTR_ENEMY | ATTR_OBSTACLE | ATTR_OPAQUE)))
406 return 0;
407
408 return 1;
409 }
410