1 #include <stdlib.h>
2 #include <math.h>
3 #include <string.h>
4 #include <SDL.h>
5 #include "3d_objects.h"
6 #include "2d_objects.h"
7 #include "asc.h"
8 #include "cursors.h"
9 #include "draw_scene.h"
10 #include "e3d.h"
11 #include "elconfig.h"
12 #include "errors.h"
13 #include "events.h"
14 #include "map.h"
15 #include "particles.h"
16 #include "platform.h"
17 #include "shadows.h"
18 #include "textures.h"
19 #include "tiles.h"
20 #include "translate.h"
21 #include "io/e3d_io.h"
22 #ifdef CLUSTER_INSIDES
23 #include "cluster.h"
24 #endif
25 #ifdef FSAA
26 #include "fsaa/fsaa.h"
27 #endif /* FSAA */
28 
29 int use_3d_alpha_blend= 1;
30 #ifndef FASTER_MAP_LOAD
31 static int objects_list_placeholders = 0;
32 #endif
33 object3d *objects_list[MAX_OBJ_3D];
34 
35 #include "eye_candy_wrapper.h"
36 
37 e3d_object *load_e3d (const char *file_name);
38 void compute_clouds_map(object3d * object_id);
39 e3d_object *cur_e3d;
40 #ifdef  DEBUG
41 int cur_e3d_count;
42 int e3d_count, e3d_total;
43 #endif  //DEBUG
44 
45 static int next_obj_3d = 0;
46 
47 #ifdef FASTER_MAP_LOAD
inc_objects_list_placeholders(void)48 void inc_objects_list_placeholders(void)
49 {
50 	next_obj_3d++;
51 }
52 #else
clear_objects_list_placeholders(void)53 void clear_objects_list_placeholders(void)
54 {
55 	objects_list_placeholders = 0;
56 }
57 
inc_objects_list_placeholders(void)58 void inc_objects_list_placeholders(void)
59 {
60 	objects_list_placeholders++;
61 }
62 #endif
63 
build_clouds_planes(object3d * obj)64 static __inline__ void build_clouds_planes(object3d* obj)
65 {
66 	float w, cos_w, sin_w;
67 
68 	w = -obj->z_rot * M_PI / 180.0f;
69 	cos_w = cos(w);
70 	sin_w = sin(w);
71 
72 	obj->clouds_planes[0][0] = cos_w / texture_scale;
73 	obj->clouds_planes[0][1] = sin_w / texture_scale;
74 	obj->clouds_planes[0][2] = 1.0f / texture_scale;
75 	obj->clouds_planes[0][3] = obj->x_pos / texture_scale;
76 	obj->clouds_planes[1][0] = -sin_w / texture_scale;
77 	obj->clouds_planes[1][1] = cos_w / texture_scale;
78 	obj->clouds_planes[1][2] = 1.0f / texture_scale;
79 	obj->clouds_planes[1][3] = obj->y_pos / texture_scale;
80 }
81 
disable_buffer_arrays(void)82 void disable_buffer_arrays(void)
83 {
84 	if (use_vertex_buffers)
85 	{
86 		ELglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
87 		ELglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
88 	}
89 	if (use_compiled_vertex_array && (cur_e3d != NULL))
90 	{
91 		ELglUnlockArraysEXT();
92 	}
93 	cur_e3d = NULL;
94 }
95 
draw_3d_object_detail(object3d * object_id,Uint32 material_index,Uint32 use_lightning,Uint32 use_textures,Uint32 use_extra_textures)96 void draw_3d_object_detail(object3d * object_id, Uint32 material_index, Uint32 use_lightning,
97 	Uint32 use_textures, Uint32 use_extra_textures)
98 {
99 	e3d_vertex_data* vertex_layout;
100 	Uint8 * data_ptr;
101 
102 	// check for having to load the arrays
103 	load_e3d_detail_if_needed(object_id->e3d_data);
104 
105 	CHECK_GL_ERRORS();
106 	//also, update the last time this object was used
107 	object_id->last_acessed_time = cur_time;
108 
109 	//debug
110 
111 	if (object_id->self_lit && (!is_day || dungeon) && use_lightning)
112 	{
113 		glColor3fv(object_id->color);
114 	}
115 
116 	CHECK_GL_ERRORS();
117 
118 	glPushMatrix();//we don't want to affect the rest of the scene
119 
120 	glMultMatrixf(object_id->matrix);
121 
122 	CHECK_GL_ERRORS();
123 
124 	if (!dungeon && (clouds_shadows || use_shadow_mapping) && use_extra_textures)
125 	{
126 		VECTOR4 plane;
127 
128 		ELglActiveTextureARB(detail_unit);
129 		memcpy(plane, object_id->clouds_planes[0], sizeof(VECTOR4));
130 		plane[3] += clouds_movement_u;
131 		glTexGenfv(GL_S, GL_EYE_PLANE, plane);
132 		memcpy(plane, object_id->clouds_planes[1], sizeof(VECTOR4));
133 		plane[3] += clouds_movement_v;
134 		glTexGenfv(GL_T, GL_EYE_PLANE, plane);
135 		ELglActiveTextureARB(base_unit);
136 	}
137 
138 	// watch for a change
139 	if (object_id->e3d_data != cur_e3d)
140 	{
141 		if ((cur_e3d != NULL) && (use_compiled_vertex_array))
142 		{
143 			ELglUnlockArraysEXT();
144 		}
145 
146 		if (use_vertex_buffers)
147 		{
148 			ELglBindBufferARB(GL_ARRAY_BUFFER_ARB,
149 				object_id->e3d_data->vertex_vbo);
150 			data_ptr = 0;
151 		}
152 		else
153 		{
154 			data_ptr = object_id->e3d_data->vertex_data;
155 		}
156 
157 		vertex_layout = object_id->e3d_data->vertex_layout;
158 
159 		if ((vertex_layout->normal_count > 0) && use_lightning)
160 		{
161 			glEnableClientState(GL_NORMAL_ARRAY);
162 			glNormalPointer(vertex_layout->normal_type, vertex_layout->size,
163 				data_ptr + vertex_layout->normal_offset);
164 		}
165 		else
166 		{
167 			glDisableClientState(GL_NORMAL_ARRAY);
168 			glNormal3f(0.0f, 0.0f, 1.0f);
169 		}
170 
171 		if (use_textures)
172 		{
173 			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
174 			glTexCoordPointer(vertex_layout->texture_count, vertex_layout->texture_type,
175 				vertex_layout->size, data_ptr + vertex_layout->texture_offset);
176 		}
177 		else
178 		{
179 			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
180 		}
181 
182 		glVertexPointer(vertex_layout->position_count, vertex_layout->position_type,
183 			vertex_layout->size, data_ptr + vertex_layout->position_offset);
184 
185 		if (use_vertex_buffers)
186 		{
187 			ELglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
188 				object_id->e3d_data->indices_vbo);
189 		}
190 
191 		// lock this new one
192 		if (use_compiled_vertex_array)
193 		{
194 			ELglLockArraysEXT(0, object_id->e3d_data->vertex_no);
195 		}
196 		// gather statistics
197 		if (object_id->e3d_data != cur_e3d)
198 		{
199 #ifdef  DEBUG
200 			if ((cur_e3d_count > 0) && (cur_e3d != NULL))
201 			{
202 				e3d_count++;
203 				e3d_total += cur_e3d_count;
204 			}
205 			cur_e3d_count = 0;
206 #endif    //DEBUG
207 			cur_e3d = object_id->e3d_data;
208 		}
209 	}
210 #ifdef  DEBUG
211 	cur_e3d_count++;
212 #endif  //DEBUG
213 
214 	if (use_textures)
215 	{
216 		glEnable(GL_TEXTURE_2D);
217 		bind_texture(object_id->e3d_data->materials[material_index].texture);
218 	}
219 	else
220 	{
221 		glDisable(GL_TEXTURE_2D);
222 	}
223 
224 
225 	if (use_draw_range_elements && ELglDrawRangeElementsEXT)
226 		ELglDrawRangeElementsEXT(GL_TRIANGLES,
227 			object_id->e3d_data->materials[material_index].triangles_indices_min,
228 			object_id->e3d_data->materials[material_index].triangles_indices_max,
229 			object_id->e3d_data->materials[material_index].triangles_indices_count,
230 			object_id->e3d_data->index_type,
231 			object_id->e3d_data->materials[material_index].triangles_indices_index);
232 	else
233 		glDrawElements(GL_TRIANGLES,
234 			object_id->e3d_data->materials[material_index].triangles_indices_count,
235 			object_id->e3d_data->index_type,
236 			object_id->e3d_data->materials[material_index].triangles_indices_index);
237 
238 	glPopMatrix();//restore the scene
239 	CHECK_GL_ERRORS();
240 
241 	//OK, let's check if our mouse is over...
242 #ifdef MAP_EDITOR2
243 	if (selected_3d_object == -1 && read_mouse_now && mouse_in_sphere(object_id->x_pos, object_id->y_pos, object_id->z_pos, object_id->e3d_data->radius))
244 		anything_under_the_mouse(object_id->id, UNDER_MOUSE_3D_OBJ);
245 #endif
246 }
247 
draw_3d_objects(unsigned int object_type)248 void draw_3d_objects(unsigned int object_type)
249 {
250 	unsigned int    start, stop;
251 	unsigned int    i, l;
252 	int is_selflit, is_transparent, is_ground;
253 #ifdef  SIMPLE_LOD
254 	int x, y, dist;
255 #endif
256 #ifdef CLUSTER_INSIDES_OLD
257 	short cluster = get_actor_cluster ();
258 #endif
259 
260 #ifdef SIMPLE_LOD
261 	x= -camera_x;
262 	y= -camera_y;
263 #endif
264 
265  	cur_e3d= NULL;
266 #ifdef  DEBUG
267 	cur_e3d_count= 0;
268 #endif  //DEBUG
269 
270 	get_intersect_start_stop(main_bbox_tree, object_type, &start, &stop);
271 	// nothing to draw?
272 	if(start >= stop){
273 		return;
274 	}
275 
276 	// find the modes we need
277 	is_selflit= is_self_lit_3d_object(object_type);
278 	is_transparent= is_alpha_3d_object(object_type);
279 	is_ground= is_ground_3d_object(object_type);
280 	// set the modes we need
281 	if (is_selflit && (!is_day || dungeon))
282 	{
283 		glDisable(GL_LIGHTING);
284 	}
285 
286 #ifdef	FSAA
287 	if (fsaa > 1)
288 	{
289 		glEnable(GL_MULTISAMPLE);
290 	}
291 #endif	/* FSAA */
292 	if(is_transparent) {
293 #ifdef	NEW_ALPHA
294 		if(use_3d_alpha_blend){
295 			glEnable(GL_BLEND);
296 			glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
297 		}
298 #endif	//NEW_ALPHA
299 		//enable alpha filtering, so we have some alpha key
300 		glEnable(GL_ALPHA_TEST);
301 		if(is_ground)glAlphaFunc(GL_GREATER,0.23f);
302 		else glAlphaFunc(GL_GREATER,0.3f);
303 		glDisable(GL_CULL_FACE);
304 	}
305 
306 /*
307 	// NOTICE: The below code is an ASSUMPTION that appropriate client
308 	// states will be used!
309 */
310 	if (!dungeon && (clouds_shadows||use_shadow_mapping))
311 	{
312 		ELglActiveTextureARB(detail_unit);
313 		glEnable(GL_TEXTURE_GEN_S);
314 		glEnable(GL_TEXTURE_GEN_T);
315 		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
316 		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
317 		ELglActiveTextureARB(base_unit);
318 	}
319 	// now loop through each object
320 	for (i=start; i<stop; i++)
321 	{
322 		int	j;
323 
324 		j = get_intersect_item_ID(main_bbox_tree, i);
325 		l = get_3dobject_index(j);
326 		if (objects_list[l] == NULL) continue;
327 		//track the usage
328 		cache_use(objects_list[l]->e3d_data->cache_ptr);
329 		if(!objects_list[l]->display) continue;	// not currently on the map, ignore it
330 #ifdef CLUSTER_INSIDES_OLD
331 		if (objects_list[l]->cluster && objects_list[l]->cluster != cluster)
332 			// Object is in another cluster as actor, don't show it
333 			continue;
334 #endif // CLUSTER_INSIDES_OLD
335 #ifdef  SIMPLE_LOD
336 		// simple size/distance culling
337 		dist= (x-objects_list[l]->x_pos)*(x-objects_list[l]->x_pos) + (y-objects_list[l]->y_pos)*(y-objects_list[l]->y_pos);
338 		if(objects_list[l]->e3d_data->materials && (10000*objects_list[l]->e3d_data->materials[get_3dobject_material(j)].max_size)/(dist) < ((is_transparent)?15:10)) continue;
339 #endif  //SIMPLE_LOD
340 
341 		draw_3d_object_detail(objects_list[l], get_3dobject_material(j), 1, 1, 1);
342 
343 #ifdef MAP_EDITOR2
344 		if ((selected_3d_object == -1) && read_mouse_now && (get_cur_intersect_type(main_bbox_tree) == INTERSECTION_TYPE_DEFAULT))
345 #else
346 		if (read_mouse_now && (get_cur_intersect_type(main_bbox_tree) == INTERSECTION_TYPE_DEFAULT))
347 #endif
348 		{
349 			anything_under_the_mouse(objects_list[l]->id, UNDER_MOUSE_3D_OBJ);
350 		}
351 	}
352 
353 	if (!dungeon && (clouds_shadows || use_shadow_mapping))
354 	{
355 		ELglActiveTextureARB(detail_unit);
356 		glDisable(GL_TEXTURE_GEN_S);
357 		glDisable(GL_TEXTURE_GEN_T);
358 		ELglActiveTextureARB(base_unit);
359 	}
360 
361 	disable_buffer_arrays();
362 
363 	// restore the settings
364 	if (is_selflit && (!is_day || dungeon))
365 	{
366 		glEnable(GL_LIGHTING);
367 		glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
368 	}
369 	if(is_transparent) {
370 		glEnable(GL_CULL_FACE);
371 #ifdef	NEW_ALPHA
372 		if(use_3d_alpha_blend){
373 			glDisable(GL_BLEND);
374 		}
375 #endif	//NEW_ALPHA
376 		glDisable(GL_ALPHA_TEST);
377 	}
378 #ifdef	FSAA
379 	if (fsaa > 1)
380 	{
381 		glDisable(GL_MULTISAMPLE);
382 	}
383 #endif	/* FSAA */
384 
385 	CHECK_GL_ERRORS();
386 
387 #ifdef  DEBUG
388 	// final statistics
389 	if(cur_e3d_count > 0){
390 		e3d_count++;
391 		e3d_total+= cur_e3d_count;
392 	}
393 	cur_e3d_count= 0;
394 #endif  //DEBUG
395 }
396 
397 //Tests to see if an e3d object is already loaded. If it is, return the handle.
398 //If not, load it, and return the handle
load_e3d_cache(const char * file_name)399 static e3d_object *load_e3d_cache(const char* file_name)
400 {
401 	e3d_object *e3d_id;
402 
403 	//do we have it already?
404 	e3d_id = cache_find_item(cache_e3d, file_name);
405 	if (e3d_id) return e3d_id;
406 
407 	//e3d not found in the cache, so load it, and store it
408 	// allocate the memory
409 	e3d_id = calloc(1, sizeof(e3d_object));
410 	if (!e3d_id)
411 	{
412 		LOG_ERROR("Can't allocate data for file \"%s\"!", file_name);
413 		return NULL;
414 	}
415 	// and fill in the data
416 	safe_strncpy(e3d_id->file_name, file_name, sizeof(e3d_id->file_name));
417 
418 	e3d_id = load_e3d_detail(e3d_id);
419 	if (!e3d_id)
420 	{
421 		LOG_ERROR("Can't load file \"%s\"!", file_name);
422 		return NULL;
423 	}
424 
425 	// Note, doing this after load_e3d_detail() means the cache size is not calculated correctly
426 	// but doing it before load_e3d_detail() puts invalid objects into the cache if they fail to load.
427 	// This needs fixing properly, but for now this works without other issues.
428 	// see https://github.com/raduprv/Eternal-Lands/commit/1796c7944f4b11f67595e84ba42fa8e036621de5
429 	e3d_id->cache_ptr = cache_add_item(cache_e3d, e3d_id->file_name,
430 		e3d_id, sizeof(*e3d_id));
431 
432 	return e3d_id;
433 }
434 
add_e3d_at_id(int id,const char * file_name,float x_pos,float y_pos,float z_pos,float x_rot,float y_rot,float z_rot,char self_lit,char blended,float r,float g,float b,unsigned int dynamic)435 int add_e3d_at_id(int id, const char* file_name,
436 	float x_pos, float y_pos, float z_pos,
437 	float x_rot, float y_rot, float z_rot, char self_lit, char blended,
438 	float r, float g, float b, unsigned int dynamic)
439 {
440 	char fname[128];
441 #ifdef FASTER_MAP_LOAD
442 	const char *fbase;
443 #endif
444 	e3d_object *returned_e3d;
445 	object3d *our_object;
446 	int i;
447 	AABBOX bbox;
448 	unsigned int texture_id;
449 	unsigned int is_transparent, ground;
450 
451 	if (id < 0 || id >= MAX_OBJ_3D)
452 	{
453 		LOG_ERROR("Invalid object id %d", id);
454 		return -1;
455 	}
456 
457 	if (objects_list[id])
458 	{
459 		LOG_ERROR("There's already an object with ID %d", id);
460 		return -1;
461 	}
462 
463 	// convert to lower case and replace any '\' by '/'
464 	clean_file_name(fname, file_name, sizeof(fname));
465 #ifdef FASTER_MAP_LOAD
466 	fbase = strrchr(fname, '/');
467 	if (fbase)
468 		fbase++;
469 	else
470 		fbase = fname;
471 #endif
472 
473 	returned_e3d = load_e3d_cache(fname);
474 	if (!returned_e3d)
475 	{
476 		LOG_ERROR(nasty_error_str, fname);
477 		//replace it with the null object, to avoid object IDs corruption
478 		safe_strncpy(fname, "./3dobjects/badobject.e3d", sizeof(fname));
479 		returned_e3d = load_e3d_cache(fname);
480 		if (!returned_e3d)
481 			return -1; // umm, not even found the place holder, this is teh SUCK!!!
482 	}
483 	// now, allocate the memory
484 	our_object = calloc(1, sizeof (object3d));
485 
486 	// and fill it in
487 	safe_strncpy(our_object->file_name, fname, sizeof(our_object->file_name));
488 	our_object->x_pos = x_pos;
489 	our_object->y_pos = y_pos;
490 	our_object->z_pos = z_pos;
491 
492 	our_object->x_rot = x_rot;
493 	our_object->y_rot = y_rot;
494 	our_object->z_rot = z_rot;
495 
496 	our_object->color[0] = r;
497 	our_object->color[1] = g;
498 	our_object->color[2] = b;
499 	our_object->color[3] = 0.0f;
500 
501 	our_object->self_lit = self_lit;
502 	our_object->blended = blended;
503 	our_object->display = 1;
504 	our_object->state = 0;
505 
506 	build_clouds_planes(our_object);
507 
508 	our_object->e3d_data = returned_e3d;
509 
510 	our_object->id = id;
511 
512 	our_object->flags = 0;
513 
514 #ifdef FASTER_MAP_LOAD
515 	if (is_harvestable(fbase))
516 		our_object->flags |= OBJ_3D_HARVESTABLE;
517 	if (is_entrable(fbase))
518 		our_object->flags |= OBJ_3D_ENTRABLE;
519 	if (*fbase && strcasecmp(fbase, "bag1.e3d") == 0)
520 		our_object->flags |= OBJ_3D_BAG;
521 	if (*fbase && strcasecmp(fbase, "branch1.e3d") == 0)
522 		our_object->flags |= OBJ_3D_MINE;
523 #else  // FASTER_MAP_LOAD
524 	for(i = 0; i < sizeof(harvestable_objects)/sizeof(harvestable_objects[0]); i++) {
525 		if(*harvestable_objects[i] && strstr(file_name, harvestable_objects[i]) != NULL) {
526 			our_object->flags |= OBJ_3D_HARVESTABLE;
527 			break;
528 		}
529 	}
530 	for(i = 0; i < sizeof(entrable_objects)/sizeof(entrable_objects[0]); i++) {
531 		if(*(entrable_objects[i]) && strstr(file_name, entrable_objects[i]) != NULL) {
532 			our_object->flags |= OBJ_3D_ENTRABLE;
533 			break;
534 		}
535 	}
536 	if (strcasecmp(file_name, "") && strcasecmp(strrchr(file_name, '/')+1, "bag1.e3d") == 0) {
537 		our_object->flags |= OBJ_3D_BAG;
538 	}
539 	if (strcasecmp(file_name, "") && strcasecmp(strrchr(file_name, '/')+1, "branch1.e3d") == 0) {
540 		our_object->flags |= OBJ_3D_MINE;
541 	}
542 #endif // FASTER_MAP_LOAD
543 
544 #ifdef CLUSTER_INSIDES
545 	our_object->cluster = get_cluster ((int)(x_pos/0.5f), (int)(y_pos/0.5f));
546 	current_cluster = our_object->cluster;
547 #endif
548 
549 	objects_list[id] = our_object;
550 	// watch the top end
551 	if (id >= next_obj_3d)
552 		next_obj_3d = id+1;
553 
554 	calc_rotation_and_translation_matrix(our_object->matrix, x_pos, y_pos, z_pos, x_rot, y_rot, z_rot);
555 
556 	// watch for needing to load the detailed information
557 	//load_e3d_detail_if_needed(returned_e3d);
558 
559 	ground = returned_e3d->vertex_layout->normal_count == 0;
560 
561 	for (i = 0; i < returned_e3d->material_no; i++)
562 	{
563 		bbox.bbmin[X] = returned_e3d->materials[i].min_x;
564 		bbox.bbmax[X] = returned_e3d->materials[i].max_x;
565 		bbox.bbmin[Y] = returned_e3d->materials[i].min_y;
566 		bbox.bbmax[Y] = returned_e3d->materials[i].max_y;
567 		bbox.bbmin[Z] = returned_e3d->materials[i].min_z;
568 		bbox.bbmax[Z] = returned_e3d->materials[i].max_z;
569 
570 		matrix_mul_aabb(&bbox, our_object->matrix);
571 		texture_id = returned_e3d->materials[i].texture;
572 		is_transparent = returned_e3d->materials[i].options != 0;
573 		if (main_bbox_tree_items != NULL && dynamic == 0)
574 			add_3dobject_to_list(main_bbox_tree_items,
575 				get_3dobject_id(id, i), bbox, blended, ground,
576 				is_transparent, self_lit, texture_id);
577 		else
578 			add_3dobject_to_abt(main_bbox_tree,
579 				get_3dobject_id(id, i), bbox, blended, ground,
580 				is_transparent, self_lit, texture_id, dynamic);
581 	}
582 
583 	add_ec_effect_to_e3d(our_object);
584 	ec_add_object_obstruction(our_object, returned_e3d, 2.0);
585 //	LOG_DEBUG_VERBOSE("Bounding: %f, %f, %f -> %f, %f, %f\n", returned_e3d->min_x, returned_e3d->min_y, returned_e3d->min_z, returned_e3d->max_x, returned_e3d->max_y, returned_e3d->max_z);
586 //	LOG_DEBUG_VERBOSE("Rotation: %f, %f, %f\n", our_object->x_rot, our_object->y_rot, our_object->z_rot);
587 
588 	return id;
589 }
590 
add_e3d(const char * file_name,float x_pos,float y_pos,float z_pos,float x_rot,float y_rot,float z_rot,char self_lit,char blended,float r,float g,float b,unsigned int dynamic)591 int add_e3d(const char* file_name, float x_pos, float y_pos, float z_pos,
592 	float x_rot, float y_rot, float z_rot, char self_lit, char blended,
593 	float r, float g, float b, unsigned int dynamic)
594 {
595 	int i;
596 #ifndef FASTER_MAP_LOAD
597 	int j = 0;
598 #endif
599 
600 #ifdef FASTER_MAP_LOAD
601 	if (next_obj_3d < MAX_OBJ_3D && !objects_list[next_obj_3d])
602 		return add_e3d_at_id(next_obj_3d, file_name, x_pos, y_pos, z_pos,
603 			x_rot, y_rot, z_rot, self_lit, blended,
604 			r, g, b, dynamic);
605 
606 	// Oh my, next_obj_3d is not free. Find a free spot in the e3d_list,
607 	// but don't count on IDs being correct.
608 #endif
609 	for (i = 0; i < MAX_OBJ_3D; i++)
610 	{
611 		if (!objects_list[i])
612 		{
613 #ifndef FASTER_MAP_LOAD
614 			if (j < objects_list_placeholders)
615 				j++;
616 			else
617 #endif
618 			return add_e3d_at_id(i, file_name, x_pos, y_pos, z_pos,
619 				x_rot, y_rot, z_rot, self_lit, blended,
620 				r, g, b, dynamic);
621 		}
622 	}
623 
624 	// No free spot available
625 	return -1;
626 }
627 
628 #ifdef NEW_SOUND
get_3dobject_at_location(float x_pos,float y_pos)629 char * get_3dobject_at_location(float x_pos, float y_pos)
630 {
631 	int i;
632 	float offset = 0.5f;
633 	for (i = 0; i < MAX_OBJ_3D; i++)
634 	{
635 		if (objects_list[i]
636 			&& objects_list[i]->x_pos > (x_pos - offset) && objects_list[i]->x_pos < (x_pos + offset)
637 			&& objects_list[i]->y_pos > (y_pos - offset) && objects_list[i]->y_pos < (y_pos + offset)
638 			&& objects_list[i]->display)
639 		{
640 			return objects_list[i]->file_name;
641 		}
642 	}
643 	return "";
644 }
645 #endif // NEW_SOUND
646 
display_objects(void)647 void display_objects(void)
648 {
649 	CHECK_GL_ERRORS();
650 	glEnable(GL_CULL_FACE);
651 	glEnable(GL_COLOR_MATERIAL);
652 	glEnableClientState(GL_VERTEX_ARRAY);
653 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
654 
655 	if (!dungeon && clouds_shadows)
656 	{
657 		//bind the detail texture
658 		ELglActiveTextureARB(detail_unit);
659 		glEnable(GL_TEXTURE_2D);
660 		bind_texture_unbuffered(ground_detail_text);
661 		ELglActiveTextureARB(base_unit);
662 		glEnable(GL_TEXTURE_2D);
663 	}
664 
665 	CHECK_GL_ERRORS();
666 
667 	draw_3d_objects(TYPE_3D_NO_BLEND_NO_GROUND_NO_ALPHA_SELF_LIT_OBJECT);
668 	draw_3d_objects(TYPE_3D_NO_BLEND_NO_GROUND_NO_ALPHA_NO_SELF_LIT_OBJECT);
669 	draw_3d_objects(TYPE_3D_NO_BLEND_GROUND_NO_ALPHA_SELF_LIT_OBJECT);
670 	draw_3d_objects(TYPE_3D_NO_BLEND_GROUND_NO_ALPHA_NO_SELF_LIT_OBJECT);
671 
672 	CHECK_GL_ERRORS();
673 	glDisable(GL_CULL_FACE);
674 	glDisable(GL_COLOR_MATERIAL);
675 	glDisableClientState(GL_VERTEX_ARRAY);
676 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
677 	glDisableClientState(GL_COLOR_ARRAY);
678 	glDisableClientState(GL_NORMAL_ARRAY);
679 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
680 	if (!dungeon && clouds_shadows)
681 	{
682 		//disable the second texture unit
683 		ELglActiveTextureARB(detail_unit);
684 		glDisable(GL_TEXTURE_2D);
685 		ELglActiveTextureARB(base_unit);
686 	}
687 	CHECK_GL_ERRORS();
688 }
689 
display_ground_objects(void)690 void display_ground_objects(void)
691 {
692 	CHECK_GL_ERRORS();
693 	glEnable(GL_CULL_FACE);
694 	glEnable(GL_COLOR_MATERIAL);
695 	glEnableClientState(GL_VERTEX_ARRAY);
696 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
697 
698 	if (!dungeon && clouds_shadows)
699 	{
700 		//bind the detail texture
701 		ELglActiveTextureARB(detail_unit);
702 		glEnable(GL_TEXTURE_2D);
703 		bind_texture_unbuffered(ground_detail_text);
704 		ELglActiveTextureARB(base_unit);
705 		glEnable(GL_TEXTURE_2D);
706 	}
707 
708 	CHECK_GL_ERRORS();
709 
710 	draw_3d_objects(TYPE_3D_NO_BLEND_GROUND_ALPHA_SELF_LIT_OBJECT);
711 	draw_3d_objects(TYPE_3D_NO_BLEND_GROUND_ALPHA_NO_SELF_LIT_OBJECT);
712 
713 	CHECK_GL_ERRORS();
714 	glDisable(GL_CULL_FACE);
715 	glDisable(GL_COLOR_MATERIAL);
716 	glDisableClientState(GL_VERTEX_ARRAY);
717 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
718 	glDisableClientState(GL_COLOR_ARRAY);
719 	glDisableClientState(GL_NORMAL_ARRAY);
720 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
721 	if (!dungeon && clouds_shadows)
722 	{
723 		//disable the second texture unit
724 		ELglActiveTextureARB(detail_unit);
725 		glDisable(GL_TEXTURE_2D);
726 		ELglActiveTextureARB(base_unit);
727 	}
728 	CHECK_GL_ERRORS();
729 }
730 
display_alpha_objects(void)731 void display_alpha_objects(void)
732 {
733 	CHECK_GL_ERRORS();
734 	glEnable(GL_COLOR_MATERIAL);
735 	glEnableClientState(GL_VERTEX_ARRAY);
736 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
737 
738 	if (!dungeon && clouds_shadows)
739 	{
740 		//bind the detail texture
741 		ELglActiveTextureARB(detail_unit);
742 		glEnable(GL_TEXTURE_2D);
743 		bind_texture_unbuffered(ground_detail_text);
744 		ELglActiveTextureARB(base_unit);
745 		glEnable(GL_TEXTURE_2D);
746 	}
747 
748 	CHECK_GL_ERRORS();
749 
750 	draw_3d_objects(TYPE_3D_NO_BLEND_NO_GROUND_ALPHA_SELF_LIT_OBJECT);
751 	draw_3d_objects(TYPE_3D_NO_BLEND_NO_GROUND_ALPHA_NO_SELF_LIT_OBJECT);
752 
753 	CHECK_GL_ERRORS();
754 	glDisable(GL_COLOR_MATERIAL);
755 	glDisableClientState(GL_VERTEX_ARRAY);
756 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
757 	glDisableClientState(GL_COLOR_ARRAY);
758 	glDisableClientState(GL_NORMAL_ARRAY);
759 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
760 	if (!dungeon && clouds_shadows)
761 	{
762 		//disable the second texture unit
763 		ELglActiveTextureARB(detail_unit);
764 		glDisable(GL_TEXTURE_2D);
765 		ELglActiveTextureARB(base_unit);
766 	}
767 	CHECK_GL_ERRORS();
768 }
769 
display_blended_objects(void)770 void display_blended_objects(void)
771 {
772 	CHECK_GL_ERRORS();
773 	glEnable(GL_CULL_FACE);
774 	glEnable(GL_BLEND);
775 	glBlendFunc(GL_ONE,GL_ONE);
776 	glEnable(GL_COLOR_MATERIAL);
777 	glEnableClientState(GL_VERTEX_ARRAY);
778 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
779 
780 	if (!dungeon && clouds_shadows)
781 	{
782 		//bind the detail texture
783 		ELglActiveTextureARB(detail_unit);
784 		glEnable(GL_TEXTURE_2D);
785 		bind_texture_unbuffered(ground_detail_text);
786 		ELglActiveTextureARB(base_unit);
787 		glEnable(GL_TEXTURE_2D);
788 	}
789 
790 	CHECK_GL_ERRORS();
791 
792 	draw_3d_objects(TYPE_3D_BLEND_GROUND_NO_ALPHA_SELF_LIT_OBJECT);
793 	draw_3d_objects(TYPE_3D_BLEND_GROUND_NO_ALPHA_NO_SELF_LIT_OBJECT);
794 	draw_3d_objects(TYPE_3D_BLEND_GROUND_ALPHA_SELF_LIT_OBJECT);
795 	draw_3d_objects(TYPE_3D_BLEND_GROUND_ALPHA_NO_SELF_LIT_OBJECT);
796 
797 	draw_3d_objects(TYPE_3D_BLEND_NO_GROUND_NO_ALPHA_SELF_LIT_OBJECT);
798 	draw_3d_objects(TYPE_3D_BLEND_NO_GROUND_NO_ALPHA_NO_SELF_LIT_OBJECT);
799 	draw_3d_objects(TYPE_3D_BLEND_NO_GROUND_ALPHA_SELF_LIT_OBJECT);
800 	draw_3d_objects(TYPE_3D_BLEND_NO_GROUND_ALPHA_NO_SELF_LIT_OBJECT);
801 
802 	CHECK_GL_ERRORS();
803 	glDisable(GL_CULL_FACE);
804 	glDisable(GL_COLOR_MATERIAL);
805 	glDisableClientState(GL_VERTEX_ARRAY);
806 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
807 	glDisableClientState(GL_COLOR_ARRAY);
808 	glDisableClientState(GL_NORMAL_ARRAY);
809 	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
810 	glDisable(GL_BLEND);
811 	if (!dungeon && clouds_shadows)
812 	{
813 		//disable the second texture unit
814 		ELglActiveTextureARB(detail_unit);
815 		glDisable(GL_TEXTURE_2D);
816 		ELglActiveTextureARB(base_unit);
817 	}
818 	CHECK_GL_ERRORS();
819 }
820 
destroy_3d_object(int i)821 void destroy_3d_object(int i)
822 {
823 	if (i < 0 || i >= MAX_OBJ_3D || !objects_list[i])
824 		return;
825 
826 	ec_remove_obstruction_by_object3d(objects_list[i]);
827 
828 	delete_3dobject_from_abt(main_bbox_tree, i, objects_list[i]->blended, objects_list[i]->self_lit);
829 	free(objects_list[i]);
830 	objects_list[i] = NULL;
831 	if (i == next_obj_3d-1)
832 	{
833 		while (next_obj_3d > 0 && !objects_list[next_obj_3d-1])
834 			next_obj_3d--;
835 	}
836 }
837 
destroy_all_3d_objects(void)838 void destroy_all_3d_objects(void)
839 {
840 	int i;
841 
842 	for (i = 0; i < MAX_OBJ_3D; i++)
843 	{
844 		if (objects_list[i])
845 		{
846 			ec_remove_obstruction_by_object3d(objects_list[i]);
847 			if(!cache_find_item(cache_e3d, objects_list[i]->file_name))
848 				destroy_e3d(objects_list[i]->e3d_data);
849 			free(objects_list[i]);
850 			objects_list[i] = NULL; // kill any reference to it
851 		}
852 	}
853 
854 	// reset the top pointer
855 	next_obj_3d = 0;
856 }
857 
free_e3d_va(e3d_object * e3d_id)858 Uint32 free_e3d_va(e3d_object *e3d_id)
859 {
860 	set_all_intersect_update_needed(main_bbox_tree);
861 
862 	if (e3d_id == NULL)
863 		return 0;
864 
865 	if (e3d_id->vertex_data != NULL)
866 	{
867 		free(e3d_id->vertex_data);
868 		e3d_id->vertex_data = NULL;
869 	}
870 	if (e3d_id->indices != NULL)
871 	{
872 		free(e3d_id->indices);
873 		e3d_id->indices = NULL;
874 	}
875 	if (e3d_id->vertex_vbo != 0)
876 	{
877 		ELglDeleteBuffersARB(1, &e3d_id->vertex_vbo);
878 		e3d_id->vertex_vbo = 0;
879 	}
880 	if (e3d_id->indices_vbo != 0)
881 	{
882 		ELglDeleteBuffersARB(1, &e3d_id->indices_vbo);
883 		e3d_id->indices_vbo = 0;
884 	}
885 
886 	if (e3d_id->cache_ptr != NULL)
887 		return (e3d_id->cache_ptr->size - sizeof(*e3d_id));
888 	else
889 		return sizeof(*e3d_id);
890 }
891 
destroy_e3d(e3d_object * e3d_id)892 void destroy_e3d(e3d_object *e3d_id)
893 {
894 	// release the detailed data
895 	free_e3d_va(e3d_id);
896 	// free the materials (not free'd in free_e3d_va)
897 	if(e3d_id->materials) free(e3d_id->materials);
898 	e3d_id->materials= NULL;
899 	// and finally free the main object
900 
901 	ec_remove_obstruction_by_e3d_object(e3d_id);
902 
903 	free(e3d_id);
904 }
905 
906 // for support of the 1.0.3 server, change if an object is to be displayed or not
set_3d_object(Uint8 display,const void * ptr,int len)907 void set_3d_object (Uint8 display, const void *ptr, int len)
908 {
909 	const Uint32 *id_ptr = ptr;
910 
911 	// first look for the override to process ALL objects
912 	if (len < sizeof(*id_ptr))
913 	{
914 		int i;
915 		for (i = 0; i < next_obj_3d; i++)
916 		{
917 			if (objects_list[i])
918 				objects_list[i]->display = display;
919 		}
920 	}
921 	else
922 	{
923 		int idx = 0;
924 		while (len >= sizeof(*id_ptr))
925 		{
926 			int obj_id = SDL_SwapLE32(id_ptr[idx]);
927 			if (obj_id < next_obj_3d && objects_list[obj_id])
928 				objects_list[obj_id]->display = display;
929 			idx++;
930 			len -= sizeof (*id_ptr);
931 		}
932 	}
933 }
934 
935 // for future expansion
state_3d_object(Uint8 state,const void * ptr,int len)936 void state_3d_object (Uint8 state, const void *ptr, int len)
937 {
938 	const Uint32 *id_ptr = ptr;
939 
940 	// first look for the override to process ALL objects
941 	if (len < sizeof(*id_ptr))
942 	{
943 		int i;
944 		for (i = 0; i < next_obj_3d; i++)
945 		{
946 			if (objects_list[i])
947 				objects_list[i]->state= state;
948 		}
949 	}
950 	else
951 	{
952 		int idx = 0;
953 
954 		while (len >= sizeof(*id_ptr))
955 		{
956 			int obj_id = SDL_SwapLE32(id_ptr[idx]);
957 			if (obj_id < next_obj_3d && objects_list[obj_id])
958 				objects_list[obj_id]->state = state;
959 			idx++;
960 			len -= sizeof (*id_ptr);
961 		}
962 	}
963 }
964