/*
 * Copyright (c) 2016-2019 Marco Hladik <marco@icculus.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/* We need to save trace infos temporarily in order to figure out what to
 * project the decal against. Half-Life's infodecal entity only stores origin,
 * but not angles. So we have to figure them out ourselves. */
.string texture;

typedef struct {
	float fraction;
	vector normal;
	vector endpos;
} traced_t;

float infodecal_send(entity pvsent, float cflags)
{
	WriteByte(MSG_ENTITY, ENT_DECAL);
	WriteCoord(MSG_ENTITY, self.origin[0]);
	WriteCoord(MSG_ENTITY, self.origin[1]);
	WriteCoord(MSG_ENTITY, self.origin[2]);
	WriteCoord(MSG_ENTITY, self.angles[0]);
	WriteCoord(MSG_ENTITY, self.angles[1]);
	WriteCoord(MSG_ENTITY, self.angles[2]);
	WriteString(MSG_ENTITY, self.texture);
	return TRUE;
}

void infodecal(void)
{
	traced_t tmp[6];
	int i = 0;
	int b = 0;
	float frac = 1.0f;
	vector vpos = self.origin;
	
	if (serverkeyfloat("*bspversion") != 30) {
#if 1
		remove(self);
		return;
#else
		/* Source Engine Material support */
		self.texture = sprintf( "materials/%s", self.texture );
#endif
	}

	if (!self.texture) {
		dprint("^1ERROR:^7 infodecal with no .texture\n");		
		/* Tempdecals == decals that are not spawned by the map, but by the
		 * decal-que (see shared/decals.c), so you can't remove them without
		 * causing a pointer error - just abort. */
		if (self.classname != "tempdecal") {
			remove(self);
		}
		return;
	}
	
	/* Some maps have everything set to full-on uppercase */
	self.texture = strtolower(self.texture);
	
	/*self.origin[0] = rint(self.origin[0]);
	self.origin[1] = rint(self.origin[1]);
	self.origin[2] = rint(self.origin[2]);*/

	/* Unrolled because I'm lazy */
	makevectors([0, 0, 0]);
	traceline(vpos + (v_forward * -1), vpos + (v_forward * 128), 1, self);
	tmp[0].fraction = trace_fraction;
	tmp[0].normal = trace_plane_normal;
	tmp[0].endpos = trace_endpos;
	traceline(vpos + (v_forward * 1), vpos + (v_forward * -128), 1, self);
	tmp[1].fraction = trace_fraction;
	tmp[1].normal = trace_plane_normal;
	tmp[1].endpos = trace_endpos;
	traceline(vpos + (v_right * -1), vpos + (v_right * 128), 1, self);
	tmp[2].fraction = trace_fraction;
	tmp[2].normal = trace_plane_normal;
	tmp[2].endpos = trace_endpos;
	traceline(vpos + (v_right * 1), vpos + (v_right * -128), 1, self);
	tmp[3].fraction = trace_fraction;
	tmp[3].normal = trace_plane_normal;
	tmp[3].endpos = trace_endpos;
	traceline(vpos + (v_up * -1), vpos + (v_up * 128), 1, self);
	tmp[4].fraction = trace_fraction;
	tmp[4].normal = trace_plane_normal;
	tmp[4].endpos = trace_endpos;
	traceline(vpos + (v_up * 1), vpos + (v_up * -128), 1, self);
	tmp[5].fraction = trace_fraction;
	tmp[5].normal = trace_plane_normal;
	tmp[5].endpos = trace_endpos;

	for (i = 0; i < 6; i++) {
		if ( tmp[i].fraction < frac ) {
			frac = tmp[i].fraction;
			b = i;
		}
	}

	if (frac == 1.0f) {
		dprint(sprintf("infodecal tracing failed at %v\n", self.origin));

		if (self.classname != "tempdecal") {
			remove(self);
		}
		return;
	}

	makevectors(vectoangles(tmp[b].endpos - self.origin ));
	vector cpl = v_forward - (v_forward * tmp[b].normal) * tmp[b].normal;

	if (tmp[b].normal[2] == 0) {
		cpl = [0, 0, 1];
	}

	self.angles = vectoangles(cpl, tmp[b].normal);
	self.solid = SOLID_NOT;
	self.pvsflags = PVSF_NOREMOVE | PVSF_IGNOREPVS;
	self.SendEntity = infodecal_send;
	self.SendFlags = 1;
}
