/*	Each frame, update warping textures
*/
void R_UpdateWarpTextures (void)
{
	texture_t *tx;
	int i;
	float x, y, x2, warptess;

	if (r_oldwater.value || cl.bIsPaused || r_drawflat_cheatsafe || r_lightmap_cheatsafe)
		return;

	warptess = 128.0f / Math_Clamp(3.0f, floor(r_waterquality.value), 64.0f);

	for (i=0; i<cl.worldmodel->numtextures; i++)
	{
		tx = cl.worldmodel->textures[i];
		if(!tx)
			continue;

		if(!tx->update_warp)
			continue;

		//render warp
		GL_SetCanvas (CANVAS_WARPIMAGE);
		Video_SetTexture(tx->gltexture);
		for (x=0.0; x<128.0; x=x2)
		{
			x2 = x + warptess;
			glBegin (GL_TRIANGLE_STRIP);
			for (y=0.0; y<128.01; y+=warptess) // .01 for rounding errors
			{
				glTexCoord2f (WARPCALC(x,y), WARPCALC(y,x));
				glVertex2f (x,y);
				glTexCoord2f (WARPCALC(x2,y), WARPCALC(y,x2));
				glVertex2f (x2,y);
			}
			glEnd();
		}

		//copy to texture
		Video_SetTexture(tx->warpimage);
		glCopyTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, glx, gly+glheight-gl_warpimagesize, gl_warpimagesize, gl_warpimagesize);

		tx->update_warp = FALSE;
	}

	//if viewsize is less than 100, we need to redraw the frame around the viewport
	scr_tileclear_updates = 0;
}
void Sky_DrawSkyBox (void)
{
	int	i;

	for(i = 0; i < 6; i++)
	{
		if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i])
			continue;

		Video_SetTexture(gSkyBoxTexture[skytexorder[i]]);

#if 1 //FIXME: this is to avoid tjunctions until i can do it the right way
		skymins[0][i] = -1;
		skymins[1][i] = -1;
		skymaxs[0][i] = 1;
		skymaxs[1][i] = 1;
#endif

		glBegin(GL_QUADS);
		Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i);
		Sky_EmitSkyBoxVertex (skymins[0][i], skymaxs[1][i], i);
		Sky_EmitSkyBoxVertex (skymaxs[0][i], skymaxs[1][i], i);
		Sky_EmitSkyBoxVertex (skymaxs[0][i], skymins[1][i], i);
		glEnd();

		rs_skypolys++;
		rs_skypasses++;

		if (Fog_GetDensity() > 0 && r_skyfog.value > 0)
		{
			float *c;

			c = Fog_GetColor();

			VideoLayer_Enable(VIDEO_BLEND);
			VideoLayer_Disable(VIDEO_TEXTURE_2D);

			glColor4f(c[0], c[1], c[2], Math_Clamp(0, r_skyfog.value, 1.0f));

			glBegin(GL_QUADS);
			Sky_EmitSkyBoxVertex (skymins[0][i], skymins[1][i], i);
			Sky_EmitSkyBoxVertex (skymins[0][i], skymaxs[1][i], i);
			Sky_EmitSkyBoxVertex (skymaxs[0][i], skymaxs[1][i], i);
			Sky_EmitSkyBoxVertex (skymaxs[0][i], skymins[1][i], i);
			glEnd();

			glColor3f(1.0f,1.0f,1.0f);

			VideoLayer_Enable(VIDEO_TEXTURE_2D);
			VideoLayer_Disable(VIDEO_BLEND);

			rs_skypasses++;
		}
	}
}
void Sky_DrawFaceQuad(glpoly_t *p)
{
	float	s,t,
			*v;
	int		i;

	glColor3f(1.0f,1.0f,1.0f);

	Video_SetTexture(gCloudTexture);

	VideoLayer_Enable(VIDEO_BLEND);
	VideoLayer_BlendFunc(VIDEO_BLEND_ONE, VIDEO_BLEND_ONE);

	glBegin(GL_QUADS);

	for (i = 0, v = p->verts[0]; i < 4; i++, v += VERTEXSIZE)
	{
		Sky_GetTexCoord(v,cv_sky_scrollspeed.value,&s,&t);

		glTexCoord2f(s,t);
		glVertex3fv(v);
	}

	glEnd();

	VideoLayer_BlendFunc(VIDEO_BLEND_DEFAULT);

	rs_skypolys++;
	rs_skypasses++;

	if(Fog_GetDensity() > 0 && r_skyfog.value > 0)
	{
		float *c = Fog_GetColor();

		VideoLayer_Disable(VIDEO_TEXTURE_2D);

		glColor4f(c[0], c[1], c[2], Math_Clamp(0.0, r_skyfog.value, 1.0));

		glBegin(GL_QUADS);
		for(i = 0,v = p->verts[0]; i < 4; i++,v += VERTEXSIZE)
			glVertex3fv(v);
		glEnd();

		glColor3f(1.0f,1.0f,1.0f);

		VideoLayer_Enable(VIDEO_TEXTURE_2D);

		rs_skypasses++;
	}

	VideoLayer_Disable(VIDEO_BLEND);
}
/*	Typically called before an object is drawn.
*/
void Material_Draw(Material_t *Material, int Skin, 
	VideoVertex_t *ObjectVertex, VideoPrimitive_t ObjectPrimitive, unsigned int ObjectSize,
	bool ispost)
{
	if (r_drawflat_cheatsafe || !Material)
		return;

	if ((Material->override_wireframe && (r_showtris.iValue != 1) || !Material->override_wireframe) && (r_lightmap_cheatsafe || r_showtris.bValue))
	{
		if (!ispost)
		{
			// Select the first TMU.
			Video_SelectTexture(0);

			// Set it as white.
			Video_SetTexture(g_mGlobalColour->msSkin[MATERIAL_COLOUR_WHITE].mtTexture->gMap);
		}
		return;
	}

	MaterialSkin_t *msCurrentSkin;
	if (Material->iFlags & MATERIAL_FLAG_ANIMATED)
		msCurrentSkin = Material_GetAnimatedSkin(Material);
	else
		msCurrentSkin = Material_GetSkin(Material, Skin);
	if (!msCurrentSkin)
		Sys_Error("Failed to get valid skin! (%s)\n", Material->cName);

	// Handle any generic blending.
	if ((msCurrentSkin->uiFlags & MATERIAL_FLAG_BLEND) || (Material->fAlpha < 1))
	{
		if (!ispost)
		{
			vlDepthMask(false);

			VideoLayer_Enable(VIDEO_BLEND);

			if (msCurrentSkin->uiFlags & MATERIAL_FLAG_ADDITIVE)
				// Additive blending isn't done by default.
				VideoLayer_BlendFunc(VIDEO_BLEND_ADDITIVE);
		}
		else
		{
			vlDepthMask(true);

			VideoLayer_Disable(VIDEO_BLEND);

			if (msCurrentSkin->uiFlags & MATERIAL_FLAG_ADDITIVE)
				// Return blend mode to its default.
				VideoLayer_BlendFunc(VIDEO_BLEND_DEFAULT);
		}
	}

	unsigned int i, uiCurrentUnit;
	for (i = 0, uiCurrentUnit = 0; i < msCurrentSkin->uiTextures; i++, uiCurrentUnit++)
	{
#ifdef VIDEO_LIGHTMAP_HACKS
		// Skip the lightmap, since it's manually handled.
		if (uiCurrentUnit == VIDEO_TEXTURE_LIGHT)
			uiCurrentUnit++;
#endif

		// Attempt to select the unit (if it's already selected, then it'll just return).
		Video_SelectTexture(uiCurrentUnit);

		if (!ispost)
		{
			// Enable it.
			VideoLayer_Enable(VIDEO_TEXTURE_2D);

			// Bind it.
			Video_SetTexture(msCurrentSkin->mtTexture[i].gMap);

			// Allow us to manipulate the texture.
			if (msCurrentSkin->mtTexture[i].matrixmod)
			{
				glMatrixMode(GL_TEXTURE);
				glLoadIdentity();
				if ((msCurrentSkin->mtTexture[i].vScroll[0] > 0) || (msCurrentSkin->mtTexture[i].vScroll[0] < 0) ||
					(msCurrentSkin->mtTexture[i].vScroll[1] > 0) || (msCurrentSkin->mtTexture[i].vScroll[1] < 0))
					glTranslatef(
						msCurrentSkin->mtTexture[i].vScroll[0] * cl.time,
						msCurrentSkin->mtTexture[i].vScroll[1] * cl.time,
						0);
				if ((msCurrentSkin->mtTexture[i].fRotate > 0) || (msCurrentSkin->mtTexture[i].fRotate < 0))
					glRotatef(msCurrentSkin->mtTexture[i].fRotate*cl.time, 0, 0, 1.0f);
				glMatrixMode(GL_MODELVIEW);
			}
		}

		switch (msCurrentSkin->mtTexture[i].mttType)
		{
		case MATERIAL_TEXTURE_LIGHTMAP:
		case MATERIAL_TEXTURE_DIFFUSE:
			if (!ispost)
			{
#if 0 // TODO: Material shader assignments!!!!
				VideoShader_SetVariablei(iDiffuseUniform, Video.current_textureunit);
#endif

				if (uiCurrentUnit > 0)
				{
					VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_DECAL);

					// Check if we've been given a video object to use...
					if (ObjectVertex)
					{
						unsigned int j;

						// Go through the whole object.
						for (j = 0; j < ObjectSize; j++)
						{
							// Copy over original texture coords.
							Video_ObjectTexture(&ObjectVertex[j], uiCurrentUnit,
								// Use base texture coordinates as a reference.
								ObjectVertex[j].mvST[0][0],
								ObjectVertex[j].mvST[0][1]);
						}
					}
				}
				else
					VideoLayer_SetTextureEnvironmentMode(msCurrentSkin->mtTexture[i].EnvironmentMode);

				if ((msCurrentSkin->mtTexture[i].uiFlags & MATERIAL_FLAG_ALPHA) || (msCurrentSkin->uiFlags & MATERIAL_FLAG_ALPHA))
					VideoLayer_Enable(VIDEO_ALPHA_TEST);
			}
			else
			{
				if ((msCurrentSkin->mtTexture[i].uiFlags & MATERIAL_FLAG_ALPHA) || (msCurrentSkin->uiFlags & MATERIAL_FLAG_ALPHA))
				{
					VideoLayer_Disable(VIDEO_ALPHA_TEST);

					if ((msCurrentSkin->uiFlags & MATERIAL_FLAG_ALPHATRICK) && (cv_video_alphatrick.bValue && (ObjectSize > 0)))
					{
						vlDepthMask(false);
						VideoLayer_Enable(VIDEO_BLEND);

						// Draw the object again (don't bother passing material).
						Video_DrawObject(ObjectVertex, ObjectPrimitive, ObjectSize, NULL, 0);

						VideoLayer_Disable(VIDEO_BLEND);
						vlDepthMask(true);
					}
				}

				VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_MODULATE);
			}
			break;
		case MATERIAL_TEXTURE_DETAIL:
			if (!ispost)
			{
				if (!cv_video_drawdetail.bValue)
				{
					Video_DisableCapabilities(VIDEO_TEXTURE_2D);
					break;
				}

				VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_COMBINE);
				glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
				glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 2);

				// Check if we've been given a video object to use...
				if (ObjectVertex)
				{
					unsigned int j;

					// Go through the whole object.
					for (j = 0; j < ObjectSize; j++)
					{
						// Copy over original texture coords.
						Video_ObjectTexture(&ObjectVertex[j], uiCurrentUnit,
							// Use base texture coordinates as a reference.
							ObjectVertex[j].mvST[0][0] * cv_video_detailscale.value,
							ObjectVertex[j].mvST[0][1] * cv_video_detailscale.value);

						// TODO: Modify them to the appropriate scale.

					}
				}
			}
			else
			{
				VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_MODULATE);
				glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
			}
			break;
		case MATERIAL_TEXTURE_FULLBRIGHT:
			if (!ispost)
			{
				if (!gl_fullbrights.bValue)
				{
					Video_DisableCapabilities(VIDEO_TEXTURE_2D);
					break;
				}

				VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_ADD);

				if (uiCurrentUnit > 0)
				{
					// Check if we've been given a video object to use...
					if (ObjectVertex)
					{
						unsigned int j;

						// Go through the whole object.
						for (j = 0; j < ObjectSize; j++)
						{
							// Copy over original texture coords.
							Video_ObjectTexture(&ObjectVertex[j], uiCurrentUnit,
								// Use base texture coordinates as a reference.
								ObjectVertex[j].mvST[0][0],
								ObjectVertex[j].mvST[0][1]);
						}
					}
				}
			}
			else
				VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_MODULATE);
			break;
		case MATERIAL_TEXTURE_SPHERE:
			if (!ispost)
			{
				VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_COMBINE);

				Video_GenerateSphereCoordinates();

				VideoLayer_Enable(VIDEO_TEXTURE_GEN_S | VIDEO_TEXTURE_GEN_T);
			}
			else
			{
				VideoLayer_SetTextureEnvironmentMode(VIDEO_TEXTURE_MODE_MODULATE);
				VideoLayer_Disable(VIDEO_TEXTURE_GEN_S | VIDEO_TEXTURE_GEN_T);
			}
			break;
		default:
			Sys_Error("Invalid texture type for material! (%s) (%i)\n", Material->cPath, msCurrentSkin->mtTexture[i].mttType);
		}

		if (ispost)
		{
			// Reset any manipulation within the matrix.
			if (msCurrentSkin->mtTexture[i].matrixmod)
			{
				glMatrixMode(GL_TEXTURE);
				glLoadIdentity();
				glTranslatef(0, 0, 0);
				glRotatef(0, 0, 0, 0);
				glMatrixMode(GL_MODELVIEW);
			}

			// Disable the texture.
			VideoLayer_Disable(VIDEO_TEXTURE_2D);
		}
	}
}