1 #ifdef CLUSTER_INSIDES
2 
3 #ifndef CLUSTER_H
4 #define CLUSTER_H
5 
6 #include "tiles.h"
7 #include "bbox_tree.h"
8 #include "e3d.h"
9 #include "lights.h"
10 #include "particles.h"
11 #ifdef MAP_EDITOR
12 #include "map_editor/2d_objects.h"
13 #include "map_editor/3d_objects.h"
14 #else
15 #include "2d_objects.h"
16 #include "3d_objects.h"
17 #endif
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 /*!
24  * \ingroup maps
25  * \brief Update the occupation array with the height map
26  *
27  *	Mark the fields in the occupation array that are walkable.
28  *
29  * \param occupied   The occupation array
30  * \param height_map The height map
31  */
update_occupied_with_height_map(char * occupied,const unsigned char * height_map)32 static __inline__ void update_occupied_with_height_map (char* occupied, const unsigned char* height_map)
33 {
34 	int i;
35 
36 	for (i = 0; i < tile_map_size_x*tile_map_size_y*6*6; i++)
37 		if (height_map[i]) occupied[i] = 1;
38 }
39 
40 /*!
41  * \ingroup maps
42  * \brief Update the occupation array with the tile map
43  *
44  *	Mark the fields in the occupation array that are occupied by
45  *	ground tiles
46  *
47  * \param occupied The occupation array
48  * \param tile_map The tile map
49  */
update_occupied_with_tile_map(char * occupied,const unsigned char * tile_map)50 static __inline__ void update_occupied_with_tile_map (char* occupied, const unsigned char* tile_map)
51 {
52 	int nx = tile_map_size_x * 6;
53 	int ny = tile_map_size_y * 6;
54 	int x, y, idx;
55 
56 	idx = 0;
57 	for (y = 0; y < ny; y += 6)
58 	{
59 		for (x = 0; x < nx; x += 6, idx++)
60 		{
61 			if (tile_map[idx] != 255)
62 			{
63 				int offset = y*nx + x;
64 				int i, j;
65 
66 				for (j = 0; j < 6; j++)
67 					for (i = 0; i < 6; i++)
68 						occupied[offset+j*nx+i] = 1;
69 			}
70 		}
71 	}
72 }
73 
74 /*!
75  * \ingroup maps
76  * \brief Update the occupation array with a bounding box
77  *
78  *	Mark the fields in the occupation array that are included in
79  *	the bounding box.
80  *
81  * \param occupied The occupation array
82  * \param box      The axis aligned bounding box
83  */
update_occupied_with_bbox(char * occupied,const AABBOX * box)84 static __inline__ void update_occupied_with_bbox (char* occupied, const AABBOX* box)
85 {
86 	int xs = (int) (box->bbmin[X] / 0.5f);
87 	int ys = (int) (box->bbmin[Y] / 0.5f);
88 	int xe = (int) (box->bbmax[X] / 0.5f) + 1;
89 	int ye = (int) (box->bbmax[Y] / 0.5f) + 1;
90 	int x, y;
91 
92 	if (xs < 0) xs = 0;
93 	if (ys < 0) ys = 0;
94 	if (xe > tile_map_size_x*6) xe = tile_map_size_x*6;
95 	if (ye > tile_map_size_y*6) ye = tile_map_size_y*6;
96 
97 	for (y = ys; y < ye; y++)
98 	{
99 		for (x = xs; x < xe; x++)
100 			occupied[y*tile_map_size_x*6+x] = 1;
101 	}
102 }
103 
104 /*!
105  * \ingroup maps
106  * \brief Update the occupation array with a 3D objec t
107  *
108  *      Mark the fields in the occupation array that are included in
109  *      the bounding box of the 3D object.
110  *
111  * \param occupied The occupation array
112  * \param id       The position in objects_list of the 3D object
113  */
114 
update_occupied_with_3d(char * occupied,int id)115 static __inline__ void update_occupied_with_3d (char* occupied, int id)
116 {
117 	const e3d_object* obj;
118 	int i;
119 	AABBOX box;
120 #ifdef MAP_EDITOR
121 	MATRIX4x4 matrix;
122 #endif
123 
124 	if (id < 0 || id >= MAX_OBJ_3D || !objects_list[id])
125 		return;
126 
127 	obj = objects_list[id]->e3d_data;
128 	if (!obj)
129 		return;
130 
131 	for (i = 0; i < obj->material_no; i++)
132 	{
133 		box.bbmin[X] = obj->materials[i].min_x;
134 		box.bbmin[Y] = obj->materials[i].min_y;
135 		box.bbmin[Z] = obj->materials[i].min_z;
136 		box.bbmax[X] = obj->materials[i].max_x;
137 		box.bbmax[Y] = obj->materials[i].max_y;
138 		box.bbmax[Z] = obj->materials[i].max_z;
139 #ifdef MAP_EDITOR
140 		// the map editor doesn't store the object transformation matrices
141 		calc_rotation_and_translation_matrix (matrix,
142 		                                      objects_list[id]->x_pos, objects_list[id]->y_pos, objects_list[id]->z_pos,
143 		                                      objects_list[id]->x_rot, objects_list[id]->y_rot, objects_list[id]->z_rot);
144 		matrix_mul_aabb (&box, matrix);
145 #else
146 		matrix_mul_aabb (&box, objects_list[id]->matrix);
147 #endif
148 
149 		update_occupied_with_bbox (occupied, &box);
150 	}
151 }
152 
153 /*!
154  * \ingroup maps
155  * \brief Update the occupation array with a 2D object
156  *
157  *      Mark the fields in the occupation array that are included in
158  *      the bounding box of the 2D object.
159  *
160  * \param occupied The occupation array
161  * \param id       The index in obj_2d_list of the 2D object
162  */
update_occupied_with_2d(char * occupied,int id)163 static __inline__ void update_occupied_with_2d (char* occupied, int id)
164 {
165 	AABBOX box;
166 
167 	if (get_2d_bbox (id, &box))
168 		update_occupied_with_bbox (occupied, &box);
169 }
170 
171 /*!
172  * \ingroup maps
173  * \brief Update the occupation array with a light
174  *
175  *      Mark the position of the light as occupied
176  *
177  * \param occupied The occupation array
178  * \param id       The index in lights_list of the light
179  */
update_occupied_with_light(char * occupied,int id)180 static __inline__  void update_occupied_with_light (char* occupied, int id)
181 {
182 	int x, y;
183 
184 	if (id < 0 || id >= MAX_LIGHTS)
185 		return;
186 
187 	x = (int) (lights_list[id]->pos_x / 0.5f);
188 	y = (int) (lights_list[id]->pos_y / 0.5f);
189 
190 	if (x >= 0 && x < tile_map_size_x*6 && y >= 0 && y < tile_map_size_y*6)
191 		occupied[y*tile_map_size_x*6+x] = 1;
192 }
193 
194 /*!
195  * \ingroup maps
196  * \brief Update the occupation array with a particle system
197  *
198  *      Mark the fields in the occupation array that are included in
199  *      the bounding box of the particle system.
200  *
201  * \param occupied The occupation array
202  * \param id       The index in particles_list of the particle system
203  */
update_occupied_with_particle_system(char * occupied,int id)204 static __inline__ void update_occupied_with_particle_system (char* occupied, int id)
205 {
206 	AABBOX box;
207 
208 	if (id < 0 || id >= MAX_PARTICLE_SYSTEMS || !particles_list[id])
209 		return;
210 
211 	calc_bounding_box_for_particle_sys (&box, particles_list[id]);
212 	update_occupied_with_bbox (occupied, &box);
213 }
214 
215 /*!
216  * \ingroup maps
217  * \brief Set the cluster map from file data
218  *
219  *	Allocate and read the cluster map from file data.
220  *
221  * \param data The cluster data from the map file
222  * \note Either this function should be used, or when no cluster data is
223  *       present in the file, compute_clusters() should be used. Doing
224  *       both will lead to memory leaks and unnecesary CPU usage.
225  */
226 void set_clusters (const char* data);
227 
228 #ifdef MAP_EDITOR
229 /*!
230  * \ingroup maps
231  * \brief Get file data for the cluster map
232  *
233  *	Serialize the cluster map data, and return it through
234  *	character array \a data of length \a len.
235  *
236  * \param data Address where to store the pointer to the data
237  * \param len  The length of the data in bytes
238  * \note The array in \a *data will be dynamically allocated, and should
239  *       be \c free'd by the caller.
240  */
241 void get_clusters (char** data, int *len);
242 #endif
243 
244 /*!
245  * \ingroup maps
246  * \brief Group occupied areas into clusters
247  *
248  *	Detect and number contiguous occupied areas in the occupation array.
249  *
250  * \param occupied The occupation array
251  * \note When reading maps, this function should only be used when the
252  *       cluster map is not present in the file, otherwise
253  *       set_clusters() should be used. Doing both will lead to memory
254  *       leaks and unnecesary CPU usage.
255  */
256 void compute_clusters (const char* occupied);
257 
258 /*!
259  * \ingroup maps
260  * \brief Get the cluster number of a position
261  *
262  *      Get the number of the visibility cluster to which point
263  *      (\a x, \a y) belongs.
264  *
265  * \param x the x coordinate of the point to check
266  * \param y the y coordinate of the point to check
267  * \retval short The number of the visibility cluster, or 0 if the point
268  *               is not inside any cluster.
269  */
270 short get_cluster (int x, int y);
271 
272 /*!
273  * \ingroup maps
274  * \brief Destroy the clusters array
275  *
276  *	Free the memory associated with the clusters array, and clear
277  *	the pointer associated with it.
278  */
279 void destroy_clusters_array ();
280 
281 #ifndef MAP_EDITOR
282 /*!
283  * \ingroup maps
284  * \brief Get the cluster where the actor is currently on
285  *
286  *	Check the cluster map at the actor's current position, and
287  *	return the number of the cluster that he's currently in.
288  *
289  * \retval short The number of the actor's current visibility cluster
290  */
291 short get_actor_cluster ();
292 #endif
293 
294 extern short current_cluster;
295 
296 #ifdef __cplusplus
297 } // extern "C"
298 #endif
299 
300 #endif // CLUSTER_H
301 
302 #endif // CLUSTER_INSIDES
303