
#include "qe3.h"

#define	PAGEFLIPS	2

vec3_t	yz_shearPoint[3];
int		yz_shearState;
int		yz_shearPos;

void CSG_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back);

/*
============
YZ_Init
============
*/
void YZ_Init (void)
{
	g_qeglobals.d_yz.origin[0] = 0;
	g_qeglobals.d_yz.origin[1] = 20;
	g_qeglobals.d_yz.origin[2] = 46;

	g_qeglobals.d_yz.scale = 1;

	g_qeglobals.d_viewList[g_qeglobals.d_currentView++] = g_qeglobals.d_hwndYZ;

	if (g_qeglobals.d_currentView > 2)
		g_qeglobals.d_currentView = 0;
}


/*
============================================================================

  MOUSE ACTIONS

============================================================================
*/

static	int	cursorx, cursory, cursorz;
static	int	buttonstate;
static	int	pressx, pressy;
static	vec3_t	pressdelta;
static	qboolean	press_selection;

void YZ_ToPoint (int x, int y, vec3_t point)
{
	point[0] = 0;
	point[1] = g_qeglobals.d_yz.origin[1] + (x - g_qeglobals.d_yz.width/2)/g_qeglobals.d_yz.scale;
	point[2] = g_qeglobals.d_yz.origin[2] + (y - g_qeglobals.d_yz.height/2)/g_qeglobals.d_yz.scale;
}

void YZ_ToGridPoint (int x, int y, vec3_t point)
{
	point[0] = 0;
	point[1] = g_qeglobals.d_yz.origin[1] + (x - g_qeglobals.d_yz.width/2)/g_qeglobals.d_yz.scale;
	point[2] = g_qeglobals.d_yz.origin[2] + (y - g_qeglobals.d_yz.height/2)/g_qeglobals.d_yz.scale;
	point[1] = floor(point[1]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
	point[2] = floor(point[2]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
}

/*
==============
YZ_MouseDown
==============
*/
void YZ_MouseDown (int x, int y, int buttons)
{
	vec3_t	point;
	vec3_t	origin, dir, right, up;

	buttonstate = buttons;
	pressx = x;
	pressy = y;
	VectorCopy (vec3_origin, pressdelta);

	YZ_ToPoint (x, y, point);

	VectorCopy (point, origin);
	origin[0] = 8192;

	dir[0] = -1; dir[1] = 0; dir[2] = 0;
	right[0] = 0; right[1] = 1/g_qeglobals.d_yz.scale; right[2] = 0;
	up[0] = 0; up[1] = 0; up[2] = 1/g_qeglobals.d_yz.scale;

	press_selection = (selected_brushes.next != &selected_brushes);

	Sys_GetCursorPos (&cursorx, &cursory);


	// lbutton = manipulate selection
	// shift-LBUTTON = select
	if ( (buttons == MK_LBUTTON)
		|| (buttons == (MK_LBUTTON | MK_SHIFT))
		|| (buttons == (MK_LBUTTON | MK_CONTROL))
		|| (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) )
	{	
		Drag_Begin (x, y, buttons, 
			right, up,
			origin, dir);
		return;
	}

	// rbutton = shear
	if (buttonstate == (MK_RBUTTON | MK_SHIFT))
	{
		if (yz_shearState < 2)
			YZ_ShearButton(x, y);
		else
			YZ_ShearPointMove (x, y);

		return;
	}

	// control mbutton = move camera
	if (buttonstate == (MK_CONTROL|MK_MBUTTON) )
	{	
		camera.origin[1] = point[1];
		camera.origin[2] = point[2];
		Sys_UpdateWindows (W_CAMERA|W_YZ_OVERLAY|W_XY_OVERLAY|W_XZ_OVERLAY);
	}

	// mbutton = angle camera
	if (buttonstate == MK_MBUTTON)
	{	
		VectorSubtract (point, camera.origin, point);
		if (point[1] || point[0])
		{
			camera.angles[YAW] = 180/Q_PI*atan2 (point[1], point[0]);
			Sys_UpdateWindows (W_CAMERA|W_YZ_OVERLAY|W_XY_OVERLAY|W_XZ_OVERLAY);
		}
	}

	// shift mbutton = move z checker
	if (buttonstate == (MK_SHIFT|MK_MBUTTON) )
	{
		YZ_ToPoint (x, y, point);
		z.origin[0] = point[0];
		z.origin[1] = point[1];
		Sys_UpdateWindows (W_XY_OVERLAY|W_YZ_OVERLAY|W_XZ_OVERLAY|W_Z);
		return;
	}
}

/*
==============
YZ_MouseUp
==============
*/
void YZ_MouseUp (int x, int y, int buttons)
{
	Drag_MouseUp ();

	if (!press_selection)
		Sys_UpdateWindows (W_ALL);

	buttonstate = 0;
}

qboolean YZ_DragDelta (int x, int y, vec3_t move)
{
	vec3_t	xvec, yvec, delta;
	int		i;

	xvec[0] = xvec[2] = 0;
	xvec[1] = 1/g_qeglobals.d_yz.scale;
	yvec[0] = yvec[1] = 0;
	yvec[2] = 1/g_qeglobals.d_yz.scale;

	for (i=0 ; i<3 ; i++)
	{
		delta[i] = xvec[i]*(x - pressx) + yvec[i]*(y - pressy);
		delta[i] = floor(delta[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
	}
	VectorSubtract (delta, pressdelta, move);
	VectorCopy (delta, pressdelta);

	if (move[0] || move[1] || move[2])
		return true;
	return false;
}

/*
==============
YZ_NewBrushDrag
==============
*/
void YZ_NewBrushDrag (int x, int y)
{
	vec3_t	mins, maxs, junk;
	int		i;
	float	temp;
	brush_t	*n;

	if (!YZ_DragDelta (x,y, junk))
		return;

	selected_face = NULL;

	// delete the current selection
	if (selected_brushes.next != &selected_brushes)
		Brush_Free (selected_brushes.next);
	YZ_ToGridPoint (pressx, pressy, mins);
	mins[0] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_x/g_qeglobals.d_gridsize));
	YZ_ToGridPoint (x, y, maxs);
	maxs[0] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_x/g_qeglobals.d_gridsize));
	if (maxs[0] <= mins[0])
		maxs[0] = mins[0] + g_qeglobals.d_gridsize;

	for (i=0 ; i<3 ; i++)
	{
		if (mins[i] == maxs[i])
			return;	// don't create a degenerate brush
		if (mins[i] > maxs[i])
		{
			temp = mins[i];
			mins[i] = maxs[i];
			maxs[i] = temp;
		}
	}

	n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef);
	if (!n)
		return;

	Brush_AddToList (n, &selected_brushes);

	Entity_LinkBrush (world_entity, n);

	Brush_Build( n );

	Sys_UpdateWindows (W_ALL);
}

/*
==============
YZ_MouseMoved
==============
*/
void YZ_MouseMoved (int x, int y, int buttons)
{
	vec3_t	point;

	if (!buttonstate)
		return;

	// lbutton without selection = drag new brush
	if (buttonstate == MK_LBUTTON && !press_selection)
	{
		YZ_NewBrushDrag (x, y);
		return;
	}

	// lbutton (possibly with control and or shift)
	// with selection = drag selection
	if (buttonstate & MK_LBUTTON)
	{
		Drag_MouseMoved (x, y, buttons);
		Sys_UpdateWindows (W_XY_OVERLAY | W_XZ_OVERLAY | W_YZ_OVERLAY | W_CAMERA);
		return;
	}

	// control mbutton = move camera
	if (buttonstate == (MK_CONTROL|MK_MBUTTON) )
	{
		YZ_ToPoint (x, y, point);
		camera.origin[1] = point[1];
		camera.origin[2] = point[2];
		Sys_UpdateWindows (W_XY_OVERLAY | W_XZ_OVERLAY | W_YZ_OVERLAY | W_CAMERA);
		return;
	}

	// shift mbutton = move z checker
	if (buttonstate == (MK_SHIFT|MK_MBUTTON) )
	{
		YZ_ToPoint (x, y, point);
		z.origin[0] = point[0];
		z.origin[1] = point[1];
		Sys_UpdateWindows (W_XY_OVERLAY | W_XZ_OVERLAY | W_YZ_OVERLAY | W_Z);
		return;
	}

	// mbutton = angle camera
	if (buttonstate == MK_MBUTTON )
	{	
		YZ_ToPoint (x, y, point);
		VectorSubtract (point, camera.origin, point);
		if (point[2] || point[1])
		{
			camera.angles[ROLL] = 180/Q_PI*atan2 (point[1], point[0]);
			Sys_UpdateWindows (W_XY_OVERLAY | W_XZ_OVERLAY | W_YZ_OVERLAY | W_CAMERA);
		}
		return;
	}

	// rbutton = drag yz origin
	if (buttonstate == MK_RBUTTON)
	{
		Sys_GetCursorPos (&x, &y);
		if (x != cursorx || y != cursory)
		{
			g_qeglobals.d_yz.origin[1] -= (x-cursorx)/g_qeglobals.d_yz.scale;
			g_qeglobals.d_yz.origin[2] += (y-cursory)/g_qeglobals.d_yz.scale;
			Sys_SetCursorPos (cursorx, cursory);
			Sys_UpdateWindows (W_XY | W_XY_OVERLAY | W_XZ | W_XZ_OVERLAY | W_YZ | W_YZ_OVERLAY);
		}
		return;
	}
}


/*
============================================================================

DRAWING

============================================================================
*/


/*
==============
YZ_DrawGrid
==============
*/
void YZ_DrawGrid (void)
{
	float	x, y, xb, xe, yb, ye;
	int		w, h;
	char	text[32];

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_TEXTURE_1D);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);

	w = g_qeglobals.d_yz.width/2 / g_qeglobals.d_yz.scale;
	h = g_qeglobals.d_yz.height/2 / g_qeglobals.d_yz.scale;

	xb = g_qeglobals.d_yz.origin[1] - w;
	if (xb < region_mins[1])
		xb = region_mins[1];
	xb = 64 * floor (xb/64);

	xe = g_qeglobals.d_yz.origin[1] + w;
	if (xe > region_maxs[1])
		xe = region_maxs[1];
	xe = 64 * ceil (xe/64);

	yb = g_qeglobals.d_yz.origin[2] - h;
	if (yb < region_mins[2])
		yb = region_mins[2];
	yb = 64 * floor (yb/64);

	ye = g_qeglobals.d_yz.origin[2] + h;
	if (ye > region_maxs[2])
		ye = region_maxs[2];
	ye = 64 * ceil (ye/64);

	// draw major blocks

	glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]);

	if ( g_qeglobals.d_showgrid )
	{
		
		glBegin (GL_LINES);
		
		for (x=xb ; x<=xe ; x+=64)
		{
			glVertex2f (x, yb);
			glVertex2f (x, ye);
		}
		for (y=yb ; y<=ye ; y+=64)
		{
			glVertex2f (xb, y);
			glVertex2f (xe, y);
		}
		
		glEnd ();
		
	}

	// draw minor blocks
	if ( g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*g_qeglobals.d_yz.scale >= 4)
	{
		glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]);

		glBegin (GL_LINES);
		for (x=xb ; x<xe ; x += g_qeglobals.d_gridsize)
		{
			if ( ! ((int)x & 63) )
				continue;
			glVertex2f (x, yb);
			glVertex2f (x, ye);
		}
		for (y=yb ; y<ye ; y+=g_qeglobals.d_gridsize)
		{
			if ( ! ((int)y & 63) )
				continue;
			glVertex2f (xb, y);
			glVertex2f (xe, y);
		}
		glEnd ();
	}

	// draw coordinate text if needed

	if ( g_qeglobals.d_savedinfo.show_coordinates)
	{
		glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDTXT]);

		for (x=xb ; x<xe ; x+=64)
		{
			glRasterPos2f (x, g_qeglobals.d_yz.origin[2] + h - 6/g_qeglobals.d_yz.scale);
			sprintf (text, "%i",(int)x);
			glCallLists (strlen(text), GL_UNSIGNED_BYTE, text);
		}
		for (y=yb ; y<ye ; y+=64)
		{
			glRasterPos2f (g_qeglobals.d_yz.origin[1] - w + 1, y);
			sprintf (text, "%i",(int)y);
			glCallLists (strlen(text), GL_UNSIGNED_BYTE, text);
		}
	}
}

#define CAM_HEIGHT		48 // height of main part
#define CAM_GIZMO		8	// height of the gizmo

/*
==============
YZ_DrawCameraIcon
==============
*/
void YZ_DrawCameraIcon (void)
{
	float	x, y;
	int	xCam = 8;

	x = camera.origin[1];
	y = camera.origin[2];

	glColor3f (0.0, 0.0, 1.0);
	glBegin(GL_LINE_STRIP);
	glVertex3f (x-xCam,y,0);
	glVertex3f (x,y+CAM_GIZMO,0);
	glVertex3f (x+xCam,y,0);
	glVertex3f (x,y-CAM_GIZMO,0);
	glVertex3f (x-xCam,y,0);
	glVertex3f (x+xCam,y,0);
	glVertex3f (x+xCam,y-CAM_HEIGHT,0);
	glVertex3f (x-xCam,y-CAM_HEIGHT,0);
	glVertex3f (x-xCam,y,0);
	glEnd ();
}

/*
==============
YZ_DrawBlockGrid
==============
*/
void YZ_DrawBlockGrid (void)
{
	float	x, y, xb, xe, yb, ye;
	int		w, h;
	char	text[32];

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_TEXTURE_1D);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);

	w = g_qeglobals.d_yz.width/2 / g_qeglobals.d_yz.scale;
	h = g_qeglobals.d_yz.height/2 / g_qeglobals.d_yz.scale;

	xb = g_qeglobals.d_yz.origin[1] - w;
	if (xb < region_mins[1])
		xb = region_mins[1];
	xb = 1024 * floor (xb/1024);

	xe = g_qeglobals.d_yz.origin[1] + w;
	if (xe > region_maxs[1])
		xe = region_maxs[1];
	xe = 1024 * ceil (xe/1024);

	yb = g_qeglobals.d_yz.origin[2] - h;
	if (yb < region_mins[2])
		yb = region_mins[2];
	yb = 1024 * floor (yb/1024);

	ye = g_qeglobals.d_yz.origin[2] + h;
	if (ye > region_maxs[2])
		ye = region_maxs[2];
	ye = 1024 * ceil (ye/1024);

	// draw major blocks

	glColor3f(0,0,1);
	glLineWidth (2);

	glBegin (GL_LINES);
	
	for (x=xb ; x<=xe ; x+=1024)
	{
		glVertex2f (x, yb);
		glVertex2f (x, ye);
	}
	for (y=yb ; y<=ye ; y+=1024)
	{
		glVertex2f (xb, y);
		glVertex2f (xe, y);
	}
	
	glEnd ();
	glLineWidth (1);

	// draw coordinate text if needed

	for (x=xb ; x<xe ; x+=1024)
		for (y=yb ; y<ye ; y+=1024)
		{
			glRasterPos2f (x+512, y+512);
			sprintf (text, "%i,%i",(int)floor(x/1024), (int)floor(y/1024) );
			glCallLists (strlen(text), GL_UNSIGNED_BYTE, text);
		}

	glColor4f(0, 0, 0, 0);
}

/*
=============================================================

  PATH LINES

=============================================================
*/

/*
==================
YZ_DrawPathLines

Draws connections between entities.
Needs to consider all entities, not just ones on screen,
because the lines can be visible when neither end is.
Called for both camera view and yz view.
==================
*/
void YZ_DrawPathLines (void)
{
	int		i, j, k;
	vec3_t	mid, mid1;
	entity_t *se, *te;
	brush_t	*sb, *tb;
	char	*psz;
	vec3_t	dir, s1, s2;
	vec_t	len, f;
	int		arrows;
	int			num_entities;
	char		*ent_target[MAX_MAP_ENTITIES];
	entity_t	*ent_entity[MAX_MAP_ENTITIES];


	num_entities = 0;
	for (te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next)
	{
		ent_target[num_entities] = ValueForKey (te, "target");
		if (ent_target[num_entities][0])
		{
			ent_entity[num_entities] = te;
			num_entities++;
		}
	}

	for (se = entities.next ; se != &entities ; se = se->next)
	{
		psz = ValueForKey(se, "targetname");
	
		if (psz == NULL || psz[0] == '\0')
			continue;
		
		sb = se->brushes.onext;
		if (sb == &se->brushes)
			continue;

		for (k=0 ; k<num_entities ; k++)
		{
			if (strcmp (ent_target[k], psz))
				continue;

			te = ent_entity[k];
			tb = te->brushes.onext;
			if (tb == &te->brushes)
				continue;

			for (i=0 ; i<3 ; i++)
				mid[i] = (sb->mins[i] + sb->maxs[i])*0.5; 

			for (i=0 ; i<3 ; i++)
				mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5; 

			VectorSubtract (mid1, mid, dir);
			len = VectorNormalize (dir);
			s1[0] = -dir[1]*8 + dir[0]*8;
			s2[0] = dir[1]*8 + dir[0]*8;
			s1[1] = dir[0]*8 + dir[1]*8;
			s2[1] = -dir[0]*8 + dir[1]*8;

			glColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]);

			glBegin(GL_LINES);
			glVertex3fv(mid);
			glVertex3fv(mid1);

			arrows = (int)(len / 256) + 1;

			for (i=0 ; i<arrows ; i++)
			{
				f = len * (i + 0.5) / arrows;

				for (j=0 ; j<3 ; j++)
					mid1[j] = mid[j] + f*dir[j];
				glVertex3fv (mid1);
				glVertex3f (mid1[0] + s1[0], mid1[1] + s1[1], mid1[2]);
				glVertex3fv (mid1);
				glVertex3f (mid1[0] + s2[0], mid1[1] + s2[1], mid1[2]);
			}

			glEnd();
		}
	}

	return;
}

//=============================================================


/*
==============
YZ_Draw
==============
*/
void YZ_Draw (void)
{
    brush_t	*brush;
	float	w, h;
	entity_t	*e;
	double	start, end;
	vec3_t	mins, maxs;
	int		drawn, culled;
	int		i;

	if (!active_brushes.next)
		return;	// not valid yet

	if (g_qeglobals.d_yz.timing)
		start = Sys_DoubleTime ();

	//
	// clear
	//
	g_qeglobals.d_yz.d_dirty = false;

	glViewport(0, 0, g_qeglobals.d_yz.width, g_qeglobals.d_yz.height);
	glClearColor (
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
		g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],
		0);

    glClear(GL_COLOR_BUFFER_BIT);

	//
	// set up viewpoint
	//
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity ();

	w = g_qeglobals.d_yz.width/2 / g_qeglobals.d_yz.scale;
	h = g_qeglobals.d_yz.height/2 / g_qeglobals.d_yz.scale;
	mins[1] = g_qeglobals.d_yz.origin[1] - w;
	maxs[1] = g_qeglobals.d_yz.origin[1] + w;
	mins[2] = g_qeglobals.d_yz.origin[2] - h;
	maxs[2] = g_qeglobals.d_yz.origin[2] + h;

	glOrtho (mins[1], maxs[1], mins[2], maxs[2], -8000, 8000);
	
	//
	// now draw the grid
	//
	YZ_DrawGrid ();

	YZ_DrawCameraIcon ();

	glRotatef (-90, 1, 0, 0);
	glRotatef (-90, 0, 0, 1);

	//
	// draw stuff
	//
    glShadeModel (GL_FLAT);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_TEXTURE_1D);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);
	glColor3f(0, 0, 0);
//		glEnable (GL_LINE_SMOOTH);

	drawn = culled = 0;

	e = NULL;
	for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
	{
		if (brush->mins[1] > maxs[1]
			|| brush->mins[2] > maxs[2]
			|| brush->maxs[1] < mins[1]
			|| brush->maxs[2] < mins[2]	)
		{
			culled++;
			continue;		// off screen
		}

		if (FilterBrush (brush))
			continue;
		drawn++;
		if (brush->owner != e)
		{
			e = brush->owner;
			glColor3fv(e->eclass->color);
		}
		if (brush->owner == world_entity)
            glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSH]);

		Brush_DrawYZ( brush );
	}

	YZ_DrawPathLines ();

	//
	// draw pointfile
	//
	if ( g_qeglobals.d_pointfile_display_list)
		glCallList (g_qeglobals.d_pointfile_display_list);

	//
	// draw block grid
	//
	if ( g_qeglobals.show_blocks)
		YZ_DrawBlockGrid ();

	//
	// now draw selected brushes
	//
	glTranslatef( g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]);

	glColor3f(1.0, 0.0, 0.0);
	glEnable (GL_LINE_STIPPLE);
	glLineStipple (3, 0xaaaa);
	glLineWidth (2);

	for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
	{
		drawn++;
		Brush_DrawYZ( brush );
	}

	glDisable (GL_LINE_STIPPLE);
	glLineWidth (1);

	// edge / vertex flags

	if (g_qeglobals.d_select_mode == sel_vertex)
	{
		glPointSize (4);
		glColor3f (0,1,0);
		glBegin (GL_POINTS);
		for (i=0 ; i<g_qeglobals.d_numpoints ; i++)
			glVertex3fv (g_qeglobals.d_points[i]);
		glEnd ();
		glPointSize (1);
	}
	else if (g_qeglobals.d_select_mode == sel_edge)
	{
		float	*v1, *v2;

		glPointSize (4);
		glColor3f (0,0,1);
		glBegin (GL_POINTS);
		for (i=0 ; i<g_qeglobals.d_numedges ; i++)
		{
			v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1];
			v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2];
			glVertex3f ( (v1[0]+v2[0])*0.5,(v1[1]+v2[1])*0.5,(v1[2]+v2[2])*0.5);
		}
		glEnd ();
		glPointSize (1);
	}
	glTranslatef (-g_qeglobals.d_select_translate[0], -g_qeglobals.d_select_translate[1], -g_qeglobals.d_select_translate[2]);

	// draw shear points
	YZ_ShearDraw();

	//
	// now draw camera point
	//
//	YZ_DrawCameraIcon ();

    glFinish();
	QE_CheckOpenGLForErrors();

	if (g_qeglobals.d_yz.timing)
	{
		end = Sys_DoubleTime ();
		Sys_Printf ("yz: %i ms\n", (int)(1000*(end-start)));
	}
}

/*
==============
YZ_Overlay
==============
*/
void YZ_Overlay (void)
{
	int	w, h;
	int	r[4];
	static	vec3_t	lastz;
	static	vec3_t	lastcamera;

	glViewport(0, 0, g_qeglobals.d_yz.width, g_qeglobals.d_yz.height);

	//
	// set up viewpoint
	//
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity ();

	w = g_qeglobals.d_yz.width/2 / g_qeglobals.d_yz.scale;
	h = g_qeglobals.d_yz.height/2 / g_qeglobals.d_yz.scale;
	glOrtho (g_qeglobals.d_yz.origin[1] - w, g_qeglobals.d_yz.origin[1] + w
		, g_qeglobals.d_yz.origin[2] - h, g_qeglobals.d_yz.origin[2] + h, -8000, 8000);

	YZ_DrawCameraIcon ();

	glRotatef (-90, 1, 0, 0);
	glRotatef (-90, 0, 0, 1);

	//
	// erase the old camera and z checker positions
	// if the entire yz hasn't been redrawn
	//
	if (g_qeglobals.d_yz.d_dirty)
	{
		glReadBuffer (GL_BACK);
		glDrawBuffer (GL_FRONT);

		glRasterPos2f (lastz[0]-9, lastz[1]-9);
		glGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
		glCopyPixels(r[0], r[1], 18,18, GL_COLOR);

		glRasterPos2f (lastcamera[0]-50, lastcamera[1]-50);
		glGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
		glCopyPixels(r[0], r[1], 100,100, GL_COLOR);
	}
	g_qeglobals.d_yz.d_dirty = true;

	//
	// save off underneath where we are about to draw
	//

	VectorCopy (z.origin, lastz);
	VectorCopy (camera.origin, lastcamera);

	glReadBuffer (GL_FRONT);
	glDrawBuffer (GL_BACK);

	glRasterPos2f (lastz[0]-9, lastz[1]-9);
	glGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
	glCopyPixels(r[0], r[1], 18,18, GL_COLOR);

	glRasterPos2f (lastcamera[0]-50, lastcamera[1]-50);
	glGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
	glCopyPixels(r[0], r[1], 100,100, GL_COLOR);

	//
	// draw the new icons
	//
	glDrawBuffer (GL_FRONT);

    glShadeModel (GL_FLAT);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_TEXTURE_1D);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);
	glColor3f(0, 0, 0);

//	YZ_DrawCameraIcon ();
//	DrawZIcon ();

	glDrawBuffer (GL_BACK);
    glFinish();
}

/*
=============================================================

  SHEARING

=============================================================
*/

/*
==============
YZ_ShearButton
==============
*/
void YZ_ShearButton (int x, int y)
{
	vec3_t  pt;

	if (yz_shearState > 1)
		return;

	YZ_ToGridPoint (x, y, pt);

	VectorCopy(pt, yz_shearPoint[0]);
	yz_shearPoint[0][0] = 100.0;

	switch (yz_shearPos)
	{
	case 0:
		VectorCopy(pt, yz_shearPoint[1]);
		yz_shearPos = 1;
		yz_shearState++;
		break;

	case 1:
		VectorCopy(pt, yz_shearPoint[2]);
		yz_shearPos = 2;
		yz_shearState++;
		break;
	}
	
	Sys_UpdateWindows (W_XY_OVERLAY|W_XZ_OVERLAY|W_YZ_OVERLAY);
}


/*
==============
YZ_ShearDraw
==============
*/
void YZ_ShearDraw (void)
{
	glPointSize (8);

	if (yz_shearState)
	{
		if (yz_shearPos == 1)
			glColor3f (1,0,0);
		else
			glColor3f (0,0,1);

		glBegin (GL_POINTS);
		glVertex3f(0, yz_shearPoint[1][1], yz_shearPoint[1][2]);
		glEnd ();
	}

	if (yz_shearState > 1)
	{
		if (yz_shearPos == 2)
			glColor3f (1,0,0);
		else
			glColor3f (0,0,1);
		glBegin (GL_POINTS);
		glVertex3f(0, yz_shearPoint[2][1], yz_shearPoint[2][2]);
		glEnd ();
	}

	glPointSize (1);
}



/*
==============
YZ_ShearDrawPlane
==============
*/
void YZ_ShearDrawPlane (void)
{
    if (yz_shearState != 2)
		return;

	glColor3f (0,0,1);

	glShadeModel (GL_FLAT);
	glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
	glDisable(GL_CULL_FACE);

	glBegin (GL_TRIANGLES);
	glVertex3f(yz_shearPoint[0][0], yz_shearPoint[0][1], yz_shearPoint[0][2]);
	glVertex3f(yz_shearPoint[1][0], yz_shearPoint[1][1], yz_shearPoint[1][2]);
	glVertex3f(yz_shearPoint[2][0], yz_shearPoint[2][1], yz_shearPoint[2][2]);
	glEnd ();

	glEnable(GL_CULL_FACE);

	glPointSize (8);
	glColor3f (0,1,1);

	glBegin (GL_POINTS);
	glVertex3f(yz_shearPoint[yz_shearPos][0], 
		yz_shearPoint[yz_shearPos][1], 
		yz_shearPoint[yz_shearPos][2]);
	glEnd ();

	glPointSize (1);
}


/*
==============
YZ_ShearExecute
==============
*/
void YZ_ShearExecute (void)
{
	brush_t	*b, *front, *back, *snext;
	face_t   face;

	if (yz_shearState != 2) 
		return;

	// we need to create a face for CSG_SplitBrushByFace

	// get a vector between two shear points
	VectorCopy(yz_shearPoint[0], face.planepts[0]);
	VectorCopy(yz_shearPoint[1], face.planepts[1]);
	VectorCopy(yz_shearPoint[2], face.planepts[2]);

	// go through brushes and find brush to shear
	for (b=selected_brushes.next ; b != &selected_brushes ; b=snext)
	{
	    snext = b->next;

		// copy the face
		face.texdef = b->brush_faces->texdef;

		CSG_SplitBrushByFace (b, &face, &front, &back);

		if (front)
		    Brush_Free (front);

		if (back)
		{
			Brush_Free(b);
			Brush_AddToList (back, &selected_brushes);
		}
	}

	yz_shearPos = 0;
	yz_shearState = 0;

	Sys_UpdateWindows (W_XY_OVERLAY | W_XZ_OVERLAY | W_YZ_OVERLAY | W_CAMERA);
	Sys_Printf("Shear Execute\n");
}



/*
==============
YZ_ShearSelectPoint
==============
*/
void YZ_ShearSelectPoint (void)
{
	char	string[128];

	Sys_Printf("SelectPoint\n");

	switch (yz_shearPos)
	{
	case 1:
		yz_shearPos = 2;
		break;
	case 2:
		yz_shearPos = 1;
		break;
	}


	Sys_UpdateWindows (W_XY_OVERLAY | W_XZ_OVERLAY | W_YZ_OVERLAY | W_CAMERA);

	sprintf(string,"Selected point:%d", yz_shearPos + 1);
	Sys_Status (string, 2);
}

/*
==============
YZ_ShearPointMove
==============
*/
void YZ_ShearPointMove (int x, int y)
{
	vec3_t  pt;

	YZ_ToGridPoint (x, y, pt);

	VectorCopy(pt, yz_shearPoint[yz_shearPos]);

	VectorCopy(pt, yz_shearPoint[0]);
	yz_shearPoint[0][0] = 100.0;

	Sys_UpdateWindows (W_XY_OVERLAY | W_XZ_OVERLAY | W_YZ_OVERLAY | W_CAMERA);
}
