// SauerMod - MODENGINE - Engine Extensions by Quinton Reeves
// This extends the engine rendering.

#include "pch.h"
#include "engine.h"

VARP(hudblend, 0, 60, 100);
VARP(showentdir, 0, 1, 1);

VARF(fullbrightlevel, 0, 128, 255, initlights());

VARP(thirdperson, 0, 0, 1);
VARP(thirdpersondistance, 1, 16, 1000);
VARP(thirdpersonheight, 0, 6, 1000);
VARP(thirdpersonscale, 0, 150, 1000);
VARP(thirdpersonstick, 0, 0, 1);

bool isthirdperson() { return cl->gamethirdperson() || (reflecting && !refracting); }

#define rendernearfar(r,g,b,f) \
	loopj(2) { \
		if (!j) { glDepthFunc(GL_GREATER); glColor3f(r*0.25f, g*0.25f, b*0.25f); } \
		else { glDepthFunc(GL_LESS); glColor3f(r, g, b); } \
		f; \
	}


void renderprimitive(bool on)
{
	if (on)
	{
		notextureshader->set();
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_CULL_FACE);
		glEnable(GL_BLEND);
		glBlendFunc(GL_ONE, GL_ONE);
	}
	else
	{
		defaultshader->set();
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_CULL_FACE);
		glDisable(GL_BLEND);
	}
}

void renderline(vec &fr, vec &to, float r, float g, float b)
{
	rendernearfar(r, g, b,
	{
		glBegin(GL_LINES);
		glVertex3f(fr.x, fr.y, fr.z);
		glVertex3f(to.x, to.y, to.z);
		glEnd();
		xtraverts += 2;
	});
}

void rendertris(vec &fr, float yaw, float pitch, float size, float r, float g, float b, bool fill)
{
	rendernearfar(r, g, b,
	{
		vec to;
		float ty;

		glBegin(GL_TRIANGLES);
		glPolygonMode(GL_FRONT_AND_BACK, fill ? GL_FILL : GL_LINE);

		glVertex3f(fr.x, fr.y, fr.z);

		ty = yaw - 45.f;
		if (ty < 0.f) ty += 360.f;
		else if (ty > 360.f) ty -= 360.f;

		vecfromyawpitch(ty, pitch, -1, 0, to);
		to.mul(size);
		to.add(fr);
		glVertex3f(to.x, to.y, to.z);

		ty = yaw + 45.f;
		if (ty < 0.f) ty += 360.f;
		else if (ty > 360.f) ty -= 360.f;

		vecfromyawpitch(ty, pitch, -1, 0, to);
		to.mul(size);
		to.add(fr);
		glVertex3f(to.x, to.y, to.z);

		glEnd();
		xtraverts += 3;
	});
}

void renderlineloop(vec &o, float height, float xradius, float yradius, float z, int type, float r, float g, float b)
{
	rendernearfar(r, g, b,
	{
		glBegin(GL_LINE_LOOP);
		loopi(16)
		{
			vec p;
			switch (type)
			{
				case 0:
					p = vec(xradius*cosf(2*M_PI*i/16.0f), height*sinf(2*M_PI*i/16.0f), 0);
					p.rotate_around_x((z+90)*RAD);
					break;
				case 1:
					p = vec(height*cosf(2*M_PI*i/16.0f), yradius*sinf(2*M_PI*i/16.0f), 0);
					p.rotate_around_y((z+90)*RAD);
					break;
				case 2:
				default:
					p = vec(xradius*cosf(2*M_PI*i/16.0f), yradius*sinf(2*M_PI*i/16.0f), 0);
					p.rotate_around_z((z+90)*RAD);
					break;
			}
			p.add(o);
			glVertex3fv(p.v);
		}
		xtraverts += 16;
		glEnd();
	});
}

void renderentdir(vec &o, float yaw, float pitch)
{
	vec fr = o, to, dr;

	vecfromyawpitch(yaw, pitch, 1, 0, dr);

	to = dr;
	to.mul(RENDERPUSHX);
	to.add(fr);
	fr.z += RENDERPUSHZ;
	to.z += RENDERPUSHZ;

	renderline(fr, to, 0.f, 0.f, 1.f);

	dr.mul(0.5f);
	to.add(dr);
	rendertris(to, yaw, pitch, 2.f, 0.f, 0.f, 1.f, true);
}

void renderentradius(vec &o, float height, float radius)
{
	renderlineloop(o, height, radius, radius, 0.f, 0, 0.f, 1.f, 1.f);
	renderlineloop(o, height, radius, radius, 0.f, 1, 0.f, 1.f, 1.f);
	renderlineloop(o, height, radius, radius, 0.f, 2, 0.f, 1.f, 1.f);
}

bool rendericon(const char *icon, int x, int y, int xs, int ys)
{
	Texture *t;

	if ((t = textureload(icon, 0, true, false)) != crosshair)
	{
		glBindTexture(GL_TEXTURE_2D, t->gl);
		glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex2i(x,	y);
		glTexCoord2f(1.0f, 0.0f); glVertex2i(x+xs, y);
		glTexCoord2f(1.0f, 1.0f); glVertex2i(x+xs, y+ys);
		glTexCoord2f(0.0f, 1.0f); glVertex2i(x,	y+ys);
		glEnd();
		return true;
	}
	return false;
}

extern int scr_w, scr_h, fov;

bool modlos(vec &o, vec &q, float yaw, float pitch, float mdist, float fx, float fy)
{
	float dist = o.dist(q);

	if (mdist <= 0.f || dist <= mdist)
	{
		float fovx = fx, fovy = fy;

		if (fovx <= 0.f) fovx = (float)fov;
		if (fovy <= 0.f) fovy = (float)fov*scr_h/scr_w;

		float x = fabs((asin((q.z - o.z) / dist) / RAD) - pitch);
		float y = fabs((-(float)atan2(q.x - o.x, q.y - o.y)/PI*180+180) - yaw);
		return x <= fovx && y <= fovy;
	}
	return false;
}

bool modsight(physent *d, vec &q, vec &v, float mdist, float fx, float fy)
{
	if (modlos(d->o, q, d->yaw, d->pitch, mdist, fx, fy)) return raycubelos(d->o, q, v);
	return false;
}

bool titlecard(int ox, int oy, int secs)
{
	if (secs <= CARDTIME+CARDFADE)
	{
		float fade = 1.f, amt = hudblend*0.01f;
		int x = ox;

		if (secs <= CARDTIME)
			x = int((float(secs)/float(CARDTIME))*(float)ox);
		else if (secs <= CARDTIME+CARDFADE)
			fade -= (float(secs-CARDTIME)/float(CARDFADE));

		const char *maptitle = modgettitle();
		if (!*maptitle) maptitle = "Untitled by Unknown";

		glColor4f(1.f, 1.f, 1.f, amt);

		rendericon("packages/icons/sauer.jpg", ox+20-x, oy-75, 64, 64);

		draw_textx("%s", ox+100-x, oy-75, 255, 255, 255, int(255.f*fade), AL_LEFT, maptitle);

		glColor4f(1.f, 1.f, 1.f, fade);
		rendericon("packages/icons/overlay.png", ox+20-x, oy-260, 144, 144);
		if(!rendericon(picname, ox+28-x, oy-252, 128, 128))
			rendericon("", ox+20-x, oy-260, 144, 144);

		draw_textx("%s", ox+180-x, oy-180, 255, 255, 255, int(255.f*fade), AL_LEFT, cl->gametitle());

		return true;
	}

	return false;
}
