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