void obj_find_overlap_colliders(SCP_vector<int> *overlap_list_out, SCP_vector<int> *list, int axis, bool collide)
{
	size_t i, j;
	bool overlapped;
	bool first_not_added = true;
	SCP_vector<int> overlappers;

	float min;
	float max;
	float overlap_min;
	float overlap_max;
	
	overlappers.clear();

	for ( i = 0; i < (*list).size(); ++i ) {
		overlapped = false;

		min = obj_get_collider_endpoint((*list)[i], axis, true);
		max = obj_get_collider_endpoint((*list)[i], axis, false);

		for ( j = 0; j < overlappers.size(); ) {
			overlap_min = obj_get_collider_endpoint(overlappers[j], axis, true);
			overlap_max = obj_get_collider_endpoint(overlappers[j], axis, false);
			if ( min <= overlap_max ) {
				overlapped = true;

				if ( overlappers.size() == 1 && first_not_added ) {
					first_not_added = false;
					overlap_list_out->push_back(overlappers[j]);
				}
				
				if ( collide ) {
					obj_collide_pair(&Objects[(*list)[i]], &Objects[overlappers[j]]);
				}
			} else {
				overlappers[j] = overlappers.back();
				overlappers.pop_back();
				continue;
			}

			++j;
		}

		if ( overlappers.size() == 0 ) {
			first_not_added = true;
		}

		if ( overlapped ) {
			overlap_list_out->push_back((*list)[i]);
		}

		overlappers.push_back((*list)[i]);
	}

	overlapped = true;
}
void obj_remove_collider(int obj_index)
{
#ifdef OBJECT_CHECK 
	CheckObjects[obj_index].flags |= OF_NOT_IN_COLL;
#endif	

	size_t i;

	for ( i = 0; i < Collision_sort_list.size(); ++i ) {
		if ( Collision_sort_list[i] == obj_index ) {
			Collision_sort_list[i] = Collision_sort_list.back();
			Collision_sort_list.pop_back();
			break;
		}
	}

	Objects[obj_index].flags |= OF_NOT_IN_COLL;	
}
void obj_remove_collider(int obj_index)
{
#ifdef OBJECT_CHECK 
    CheckObjects[obj_index].flags.set(Object::Object_Flags::Not_in_coll);
#endif	

	size_t i;

	for ( i = 0; i < Collision_sort_list.size(); ++i ) {
		if ( Collision_sort_list[i] == obj_index ) {
			Collision_sort_list[i] = Collision_sort_list.back();
			Collision_sort_list.pop_back();
			break;
		}
	}

	Objects[obj_index].flags.set(Object::Object_Flags::Not_in_coll);
}
/**
 * Given a set of flags, determine whether a shader with these flags exists within the GL_shader vector. If no shader with the requested flags exists, attempt to compile one.
 *
 * @param flags	Integer variable, holding a combination of SDR_* flags
 * @return 		Index into GL_shader, referencing a valid shader, or -1 if shader compilation failed
 */
int gr_opengl_maybe_create_shader(int flags)
{
	if (Use_GLSL < 2)
		return -1;

	size_t idx;
	size_t max = GL_shader.size();

	for (idx = 0; idx < max; idx++) {
		if (GL_shader[idx].flags == flags) {
			return idx;
		}
	}

	// If we are here, it means we need to compile a new shader
	opengl_compile_main_shader(flags);
	if (GL_shader.back().flags == flags)
		return (int)GL_shader.size() - 1;

	// If even that has failed, bail
	return -1;
}
// Creates a single particle. See the PARTICLE_?? defines for types.
particle *particle_create( particle_info *pinfo )
{
	if ( !Particles_enabled )
	{
		return NULL;
	}

	particle* new_particle = new particle();
	int fps = 1;
	
	new_particle->pos = pinfo->pos;
	new_particle->velocity = pinfo->vel;
	new_particle->age = 0.0f;
	new_particle->max_life = pinfo->lifetime;
	new_particle->radius = pinfo->rad;
	new_particle->type = pinfo->type;
	new_particle->optional_data = pinfo->optional_data;
	new_particle->tracer_length = pinfo->tracer_length;
	new_particle->attached_objnum = pinfo->attached_objnum;
	new_particle->attached_sig = pinfo->attached_sig;
	new_particle->reverse = pinfo->reverse;
	new_particle->particle_index = (int)Particles.size();

	switch (pinfo->type) {
		case PARTICLE_BITMAP:
		case PARTICLE_BITMAP_PERSISTENT: {
			if (pinfo->optional_data < 0) {
				Int3();
				delete new_particle;
				return NULL;
			}

			bm_get_info( pinfo->optional_data, NULL, NULL, NULL, &new_particle->nframes, &fps );

			if ( new_particle->nframes > 1 )	{
				// Recalculate max life for ani's
				new_particle->max_life = i2fl(new_particle->nframes) / i2fl(fps);
			}

			break;
		}

		case PARTICLE_FIRE: {
			if (Anim_bitmap_id_fire < 0) {
				delete new_particle;
				return NULL;
			}

			new_particle->optional_data = Anim_bitmap_id_fire;
			new_particle->nframes = Anim_num_frames_fire;

			break;
		}

		case PARTICLE_SMOKE: {
			if (Anim_bitmap_id_smoke < 0) {
				delete new_particle;
				return NULL;
			}

			new_particle->optional_data = Anim_bitmap_id_smoke;
			new_particle->nframes = Anim_num_frames_smoke;

			break;
		}

		case PARTICLE_SMOKE2: {
			if (Anim_bitmap_id_smoke2 < 0) {
				delete new_particle;
				return NULL;
			}

			new_particle->optional_data = Anim_bitmap_id_smoke2;
			new_particle->nframes = Anim_num_frames_smoke2;

			break;
		}

		default:
			new_particle->nframes = 1;
			break;
	}
	
	new_particle->signature = ++lastSignature;
	Particles.push_back( new_particle );

#ifndef NDEBUG
	if (Particles.size() > (uint)Num_particles_hwm) {
		Num_particles_hwm = (int)Particles.size();

		nprintf(("Particles", "Num_particles high water mark = %i\n", Num_particles_hwm));
	}
#endif

	return Particles.back();
}
void particle_move_all(float frametime)
{
	MONITOR_INC( NumParticles, Num_particles );	

	if ( !Particles_enabled )
		return;

	if ( Particles.empty() )
		return;

	for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); )
	{	
		particle* part = *p;
		if (part->age == 0.0f) {
			part->age = 0.00001f;
		} else {
			part->age += frametime;
		}

		bool remove_particle = false;

		// if its time expired, remove it
		if (part->age > part->max_life) {
			// special case, if max_life is 0 then we want it to render at least once
			if ( (part->age > frametime) || (part->max_life > 0.0f) ) {
				remove_particle = true;
			}
		}

		// if the particle is attached to an object which has become invalid, kill it
		if (part->attached_objnum >= 0) {
			// if the signature has changed, or it's bogus, kill it
			if ( (part->attached_objnum >= MAX_OBJECTS) || (part->attached_sig != Objects[part->attached_objnum].signature) ) {
				remove_particle = true;
			}
		}

		if (remove_particle)
		{
			part->signature = 0;
			delete part;

			// if we're sitting on the very last particle, popping-back will invalidate the iterator!
			if (p + 1 == Particles.end())
			{
				Particles.pop_back();
				break;
			}
			else
			{
				*p = Particles.back();
				Particles.pop_back();
				continue;
			}
		}

		// move as a regular particle
		vm_vec_scale_add2( &part->pos, &part->velocity, frametime );

		// next particle
		++p;
	}
}