/**
 * $Id: drawobject.c,v 1.137 2004/12/03 23:22:21 ton Exp $
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

#include <string.h>
#include <math.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef _WIN32
#include "BLI_winstuff.h"
#endif
#include "MEM_guardedalloc.h"

#include "BMF_Api.h"

#include "IMB_imbuf.h"


#include "MTC_matrixops.h"

#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_constraint_types.h" // for drawing constraint
#include "DNA_effect_types.h"
#include "DNA_ipo_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_meta_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"

#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"

#include "BKE_utildefines.h"
#include "BKE_curve.h"
#include "BKE_constraint.h" // for the get_constraint_target function
#include "BKE_deform.h"		// lattice_modifier()
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_ipo.h"
#include "BKE_lattice.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_object.h"

#include "BIF_gl.h"
#include "BIF_mywindow.h"
#include "BIF_screen.h"
#include "BIF_space.h"
#include "BIF_editarmature.h"
#include "BIF_editika.h"
#include "BIF_editmesh.h"
#include "BIF_glutil.h"
#include "BIF_resources.h"

#include "BDR_drawmesh.h"
#include "BDR_drawobject.h"
#include "BDR_editobject.h"

#include "BSE_view.h"
#include "BSE_drawview.h"
#include "BSE_trans_types.h"

#include "blendef.h"
#include "mydevice.h"
#include "nla.h"

#include "BKE_deform.h"

/* pretty stupid */
/*  extern Lattice *editLatt; already in BKE_lattice.h  */
/* editcurve.c */
extern ListBase editNurb;
/* editmball.c */
extern ListBase editelems;

/* more or less needed forwards */
static void drawmeshwire(Object *ob);

	/***/

// Materials start counting at # one....
#define MAXMATBUF (MAXMAT + 1)
static float matbuf[MAXMATBUF][2][4];

static void init_gl_materials(Object *ob)
{
 	extern Material defmaterial;
	Material *ma;
	int a;
	
	if(ob->totcol==0) {
		matbuf[0][0][0]= defmaterial.r;
		matbuf[0][0][1]= defmaterial.g;
		matbuf[0][0][2]= defmaterial.b;
		matbuf[0][0][3]= 1.0;

		matbuf[0][1][0]= defmaterial.specr;
		matbuf[0][1][1]= defmaterial.specg;
		matbuf[0][1][2]= defmaterial.specb;
		matbuf[0][1][3]= 1.0;
		
		/* do material 1 too, for displists! */
		VECCOPY(matbuf[1][0], matbuf[0][0]);
		VECCOPY(matbuf[1][1], matbuf[0][1]);
	}
	
	for(a=1; a<=ob->totcol; a++) {
		ma= give_current_material(ob, a);
		if(ma==NULL) ma= &defmaterial;
		if(a<MAXMATBUF) {
			matbuf[a][0][0]= (ma->ref+ma->emit)*ma->r;
			matbuf[a][0][1]= (ma->ref+ma->emit)*ma->g;
			matbuf[a][0][2]= (ma->ref+ma->emit)*ma->b;
			matbuf[a][0][3]= 1.0;
			
			matbuf[a][1][0]= ma->spec*ma->specr;
			matbuf[a][1][1]= ma->spec*ma->specg;
			matbuf[a][1][2]= ma->spec*ma->specb;
			matbuf[a][1][3]= 1.0;
		}
	}
}

static void set_gl_material(int nr)
{
	if(nr<MAXMATBUF) {
		glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matbuf[nr][0]);
		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matbuf[nr][1]);
	}
}

	/***/
	
unsigned int rect_desel[16]= {0x707070,0x0,0x0,0x707070,0x407070,0x70cccc,0x407070,0x0,0xaaffff,0xffffff,0x70cccc,0x0,0x70cccc,0xaaffff,0x407070,0x707070};
unsigned int rect_sel[16]= {0x707070,0x0,0x0,0x707070,0x702070,0xcc50cc,0x702070,0x0,0xff80ff,0xffffff,0xcc50cc,0x0,0xcc50cc,0xff80ff,0x702070,0x707070};

unsigned int rectu_desel[16]= {0xff4e4e4e,0xff5c2309,0xff000000,0xff4e4f4d,0xff000000,0xffff9d72,0xffff601c,0xff000000,0xff5d2409,0xffffffff,0xffff9d72,0xff5b2209,0xff4e4e4e,0xff5c2309,0xff010100,0xff4f4f4f};
unsigned int rectu_sel[16]= {0xff4e4e4e,0xff403c00,0xff000000,0xff4e4e4d,0xff000000,0xfffff64c,0xffaaa100,0xff000000,0xff403c00,0xffffffff,0xfffff64c,0xff403c00,0xff4f4f4f,0xff403c00,0xff010100,0xff4e4e4e};

unsigned int rectl_desel[81]= {0x777777,0x777777,0xa9fefe,0xaaffff,0xaaffff,0xaaffff,0xaaffff,0x777777,0x777777,0x777777,0xa9fefe,0xaafefe,0x777777,0x777777,0x777777,0xa9fefe,0xa9fefe,0x777777,0xaaffff,0xa9fefe,0x4e4e4e,0x0,0x124040,0x0,0x4e4e4e,0xaafefe,0xaaffff,0xaaffff,0x777777,0x0,0x227777,0x55cccc,0x227777,0x0,0x777777,0xaaffff,0xaaffff,0x777777,0x124040,0x88ffff,0xffffff,0x55cccc,0x124040,0x777777,0xaaffff,0xaaffff,0x777777,0x0,0x55cccc,0x88ffff,0x227777,0x0,0x777777,0xaaffff,0xaafefe,0xaafefe,0x4f4f4f,0x0,0x124040,0x0,0x4e4e4e,0xa9fefe,0xaaffff,0x777777,0xa9fefe,0xa9fefe,0x777777,0x777777,0x777777,0xa9fefe,0xa9fefe,0x777777,0x777777,0x777777,0xa9fefe,0xa9fefe,0xaaffff,0xaaffff,0xaaffff,0x777777,0x777777};
unsigned int rectl_sel[81]= {0x777777,0x777777,0xffaaff,0xffaaff,0xffaaff,0xffaaff,0xffaaff,0x777777,0x777777,0x777777,0xffaaff,0xffaaff,0x777777,0x777777,0x777777,0xffaaff,0xffaaff,0x777777,0xffaaff,0xffaaff,0x4e4e4e,0x10101,0x402440,0x0,0x4e4e4e,0xffaaff,0xffaaff,0xffaaff,0x777777,0x0,0x774477,0xcc77cc,0x774477,0x0,0x777777,0xffaaff,0xffaaff,0x777777,0x402440,0xffaaff,0xffffff,0xcc77cc,0x412541,0x777777,0xffaaff,0xffaaff,0x777777,0x10101,0xcc77cc,0xffaaff,0x774477,0x0,0x777777,0xffaaff,0xffaaff,0xffaaff,0x4e4e4e,0x10101,0x402440,0x0,0x4e4e4e,0xffaaff,0xffaaff,0x777777,0xffaaff,0xffaaff,0x777777,0x777777,0x777777,0xffaaff,0xffaaff,0x777777,0x777777,0x777777,0xffaaff,0xffaaff,0xffaaff,0xffaaff,0xffaaff,0x777777,0x777777};
unsigned int rectlus_desel[81]= {0x777777,0x777777,0xa9fefe,0xaaffff,0xaaffff,0xaaffff,0xaaffff,0x777777,0x777777,0x777777,0xa9fefe,0xaafefe,0x777777,0x777777,0x777777,0xa9fefe,0xa9fefe,0x777777,0xaaffff,0xa9fefe,0x4e4e4e,0x0,0x5c2309,0x0,0x4e4f4d,0xaafefe,0xaaffff,0xaaffff,0x777777,0x0,0xff601c,0xff9d72,0xff601c,0x0,0x777777,0xaaffff,0xaaffff,0x777777,0x5d2409,0xffceb8,0xff9d72,0xff9d72,0x5b2209,0x777777,0xaaffff,0xaaffff,0x777777,0x10100,0xffceb8,0xffceb8,0xff601c,0x0,0x777777,0xaaffff,0xaafefe,0xaafefe,0x4e4e4e,0x0,0x5c2309,0x10100,0x4f4f4f,0xa9fefe,0xaaffff,0x777777,0xa9fefe,0xa9fefe,0x777777,0x777777,0x777777,0xa9fefe,0xa9fefe,0x777777,0x777777,0x777777,0xa9fefe,0xa9fefe,0xaaffff,0xaaffff,0xaaffff,0x777777,0x777777};
unsigned int rectlus_sel[81]= {0x777777,0x777777,0xffaaff,0xffaaff,0xffaaff,0xffaaff,0xffaaff,0x777777,0x777777,0x777777,0xffaaff,0xffaaff,0x777777,0x777777,0x777777,0xffaaff,0xffaaff,0x777777,0xffaaff,0xffaaff,0x4e4e4e,0x10100,0x403c00,0x0,0x4e4e4d,0xffaaff,0xffaaff,0xffaaff,0x777777,0x0,0xaaa100,0xfff64c,0xaaa100,0x0,0x777777,0xffaaff,0xffaaff,0x777777,0x403c00,0xfffde2,0xffffff,0xfff64c,0x403c00,0x777777,0xffaaff,0xffaaff,0x777777,0x10100,0xfff64c,0xfffde2,0xaaa100,0x0,0x777777,0xffaaff,0xffaaff,0xffaaff,0x4f4f4f,0x0,0x403c00,0x10100,0x4e4e4e,0xffaaff,0xffaaff,0x777777,0xffaaff,0xffaaff,0x777777,0x777777,0x777777,0xffaaff,0xffaaff,0x777777,0x777777,0x777777,0xffaaff,0xffaaff,0xffaaff,0xffaaff,0xffaaff,0x777777,0x777777};
unsigned int rectllib_desel[81]= {0xff777777,0xff777777,0xb9b237,0xb9b237,0xb9b237,0xb9b237,0xb9b237,0xff777777,0xff777777,0xff777777,0xb9b237,0xb9b237,0xff777777,0xff777777,0xff777777,0xb9b237,0xb9b237,0xff777777,0xb9b237,0xb9b237,0x4e4e4e,0x0,0x5c2309,0x0,0x4e4f4d,0xb9b237,0xb9b237,0xb9b237,0xff777777,0x0,0xff601c,0xff9d72,0xff601c,0x0,0xff777777,0xb9b237,0xb9b237,0xff777777,0x5d2409,0xffceb8,0xff9d72,0xff9d72,0x5b2209,0xff777777,0xb9b237,0xb9b237,0xff777777,0x10100,0xffceb8,0xffceb8,0xff601c,0x0,0xff777777,0xb9b237,0xb9b237,0xb9b237,0x4e4e4e,0x0,0x5c2309,0x10100,0x4f4f4f,0xb9b237,0xb9b237,0xff777777,0xb9b237,0xb9b237,0xff777777,0xff777777,0xff777777,0xb9b237,0xb9b237,0xff777777,0xff777777,0xff777777,0xb9b237,0xb9b237,0xb9b237,0xb9b237,0xb9b237,0xff777777,0xff777777};
unsigned int rectllib_sel[81]= {0xff777777,0xff777777,0xfff64c,0xfff64c,0xfff64c,0xfff64c,0xfff64c,0xff777777,0xff777777,0xff777777,0xfff64c,0xfff64c,0xff777777,0xff777777,0xff777777,0xfff64c,0xfff64c,0xff777777,0xfff64c,0xfff64c,0x4e4e4e,0x10100,0x403c00,0x0,0x4e4e4d,0xfff64c,0xfff64c,0xfff64c,0xff777777,0x0,0xaaa100,0xfff64c,0xaaa100,0x0,0xff777777,0xfff64c,0xfff64c,0xff777777,0x403c00,0xfffde2,0xffffff,0xfff64c,0x403c00,0xff777777,0xfff64c,0xfff64c,0xff777777,0x10100,0xfff64c,0xfffde2,0xaaa100,0x0,0xff777777,0xfff64c,0xfff64c,0xfff64c,0x4f4f4f,0x0,0x403c00,0x10100,0x4e4e4e,0xfff64c,0xfff64c,0xff777777,0xfff64c,0xfff64c,0xff777777,0xff777777,0xff777777,0xfff64c,0xfff64c,0xff777777,0xff777777,0xff777777,0xfff64c,0xfff64c,0xfff64c,0xfff64c,0xfff64c,0xff777777,0xff777777};

unsigned int rectl_set[81]= {0xff777777,0xff777777,0xaaaaaa,0xaaaaaa,0xaaaaaa,0xaaaaaa,0xaaaaaa,0xff777777,0xff777777,0xff777777,0xaaaaaa,0xaaaaaa,0xff777777,0xff777777,0xff777777,0xaaaaaa,0xaaaaaa,0xff777777,0xaaaaaa,0xaaaaaa,0x4e4e4e,0x10100,0x202020,0x0,0x4e4e4d,0xaaaaaa,0xaaaaaa,0xaaaaaa,0xff777777,0x0,0xaaa100,0xaaaaaa,0xaaa100,0x0,0xff777777,0xaaaaaa,0xaaaaaa,0xff777777,0x202020,0xfffde2,0xffffff,0xaaaaaa,0x202020,0xff777777,0xaaaaaa,0xaaaaaa,0xff777777,0x10100,0xaaaaaa,0xfffde2,0xaaa100,0x0,0xff777777,0xaaaaaa,0xaaaaaa,0xaaaaaa,0x4f4f4f,0x0,0x202020,0x10100,0x4e4e4e,0xaaaaaa,0xaaaaaa,0xff777777,0xaaaaaa,0xaaaaaa,0xff777777,0xff777777,0xff777777,0xaaaaaa,0xaaaaaa,0xff777777,0xff777777,0xff777777,0xaaaaaa,0xaaaaaa,0xaaaaaa,0xaaaaaa,0xaaaaaa,0xff777777,0xff777777};


static unsigned int colortab[24]=
	{0x0,		0xFF88FF, 0xFFBBFF, 
	 0x403000,	0xFFFF88, 0xFFFFBB, 
	 0x104040,	0x66CCCC, 0x77CCCC, 
	 0x101040,	0x5588FF, 0x88BBFF, 
	 0xFFFFFF
	};


static float cube[8][3] = {
	{-1.0, -1.0, -1.0},
	{-1.0, -1.0,  1.0},
	{-1.0,  1.0,  1.0},
	{-1.0,  1.0, -1.0},
	{ 1.0, -1.0, -1.0},
	{ 1.0, -1.0,  1.0},
	{ 1.0,  1.0,  1.0},
	{ 1.0,  1.0, -1.0},
};

void init_draw_rects(void)
{
	if(G.order==B_ENDIAN) {
		IMB_convert_rgba_to_abgr(16, rect_desel);
		IMB_convert_rgba_to_abgr(16, rect_sel);
		
		IMB_convert_rgba_to_abgr(16, rectu_desel);
		IMB_convert_rgba_to_abgr(16, rectu_sel);
		
		IMB_convert_rgba_to_abgr(81, rectl_desel);
		IMB_convert_rgba_to_abgr(81, rectl_sel);
	
		IMB_convert_rgba_to_abgr(81, rectlus_desel);
		IMB_convert_rgba_to_abgr(81, rectlus_sel);
	
		IMB_convert_rgba_to_abgr(81, rectllib_desel);
		IMB_convert_rgba_to_abgr(81, rectllib_sel);
				
		IMB_convert_rgba_to_abgr(81, rectl_set);
	}
}

static void draw_icon_centered(float *pos, unsigned int *rect, int rectsize) 
{
	float hsize= (float) rectsize/2.0;
	GLubyte dummy= 0;
	
	glRasterPos3fv(pos);
	
		/* use bitmap to shift rasterpos in pixels */
	glBitmap(0, 0, 0.0, 0.0, -hsize, -hsize, &dummy);
#if defined (__sun__) || defined ( __sun ) || defined (__sparc) || defined (__sparc__)
	glFlush(); 
#endif	
	glDrawPixels(rectsize, rectsize, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}

void helpline(float *vec)
{
	float vecrot[3], cent[2];
	short mval[2];

	VECCOPY(vecrot, vec);
	if(G.obedit) Mat4MulVecfl(G.obedit->obmat, vecrot);

	getmouseco_areawin(mval);
	project_float(vecrot, cent);	// no overflow in extreme cases

	persp(PERSP_WIN);
	
	glDrawBuffer(GL_FRONT);
	
	BIF_ThemeColor(TH_WIRE);

	setlinestyle(3);
	glBegin(GL_LINE_STRIP); 
		glVertex2sv(mval); 
		glVertex2fv(cent); 
	glEnd();
	setlinestyle(0);
	
	persp(PERSP_VIEW);
	glFlush(); // flush display for frontbuffer
	glDrawBuffer(GL_BACK);
}

void drawaxes(float size)
{
	int axis;

	for (axis=0; axis<3; axis++) {
		float v1[3]= {0.0, 0.0, 0.0};
		float v2[3]= {0.0, 0.0, 0.0};
		int arrow_axis= (axis==0)?1:0;
		
		glBegin(GL_LINES);

		v2[axis]= size;
		glVertex3fv(v1);
		glVertex3fv(v2);
			
		v1[axis]= size*0.8;
		v1[arrow_axis]= -size*0.125;
		glVertex3fv(v1);
		glVertex3fv(v2);
			
		v1[arrow_axis]= size*0.125;
		glVertex3fv(v1);
		glVertex3fv(v2);

		glEnd();
			
		v2[axis]+= size*0.125;
		glRasterPos3fv(v2);
		
		// patch for 3d cards crashing on glSelect for text drawing (IBM)
		if((G.f & G_PICKSEL) == 0) {
			if (axis==0)
				BMF_DrawString(G.font, "x");
			else if (axis==1)
				BMF_DrawString(G.font, "y");
			else
				BMF_DrawString(G.font, "z");
		}
	}
}

#if 0
static void drawgourcube(void)
{
	float n[3];

	n[0]=0; n[1]=0; n[2]=0;
	glBegin(GL_QUADS);
		n[0]= -1.0;
		glNormal3fv(n); 
		glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
		n[0]=0;
	glEnd();

	glBegin(GL_QUADS);
		n[1]= -1.0;
		glNormal3fv(n); 
		glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
		n[1]=0;
	glEnd();

	glBegin(GL_QUADS);
		n[0]= 1.0;
		glNormal3fv(n); 
		glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
		n[0]=0;
	glEnd();

	glBegin(GL_QUADS);
		n[1]= 1.0;
		glNormal3fv(n); 
		glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
		n[1]=0;
	glEnd();

	glBegin(GL_QUADS);
		n[2]= 1.0;
		glNormal3fv(n); 
		glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
		n[2]=0;
	glEnd();

	glBegin(GL_QUADS);
		n[2]= -1.0;
		glNormal3fv(n); 
		glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
	glEnd();
}
#endif

static void drawcube(void)
{

	glBegin(GL_LINE_STRIP);
		glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
		glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
		glVertex3fv(cube[7]); glVertex3fv(cube[4]);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(cube[1]); glVertex3fv(cube[5]);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(cube[2]); glVertex3fv(cube[6]);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(cube[3]); glVertex3fv(cube[7]);
	glEnd();
}

#if 0
static void drawcube_size(float *size)
{

	glPushMatrix();
	glScalef(size[0],  size[1],  size[2]);
	

	glBegin(GL_LINE_STRIP);
		glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
		glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
		glVertex3fv(cube[7]); glVertex3fv(cube[4]);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(cube[1]); glVertex3fv(cube[5]);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(cube[2]); glVertex3fv(cube[6]);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(cube[3]); glVertex3fv(cube[7]);
	glEnd();
	
	glPopMatrix();
}
#endif

static void tekenshadbuflimits(Lamp *la, float mat[][4])
{
	float sta[3], end[3], lavec[3];

	lavec[0]= -mat[2][0];
	lavec[1]= -mat[2][1];
	lavec[2]= -mat[2][2];
	Normalise(lavec);

	sta[0]= mat[3][0]+ la->clipsta*lavec[0];
	sta[1]= mat[3][1]+ la->clipsta*lavec[1];
	sta[2]= mat[3][2]+ la->clipsta*lavec[2];

	end[0]= mat[3][0]+ la->clipend*lavec[0];
	end[1]= mat[3][1]+ la->clipend*lavec[1];
	end[2]= mat[3][2]+ la->clipend*lavec[2];


	glBegin(GL_LINE_STRIP);
		glVertex3fv(sta);
		glVertex3fv(end);
	glEnd();

	glPointSize(3.0);
	bglBegin(GL_POINTS);
	bglVertex3fv(sta);
	bglVertex3fv(end);
	bglEnd();
	glPointSize(1.0);
}



static void spotvolume(float *lvec, float *vvec, float inp)
{
	/* camera is at 0,0,0 */
	float temp[3],plane[3],mat1[3][3],mat2[3][3],mat3[3][3],mat4[3][3],q[4],co,si,hoek;

	Normalise(lvec);
	Normalise(vvec);				/* is this the correct vector ? */

	Crossf(temp,vvec,lvec);		/* equation for a plane through vvec en lvec */
	Crossf(plane,lvec,temp);		/* a plane perpendicular to this, parrallel with lvec */

	Normalise(plane);

	/* now we've got two equations: one of a cone and one of a plane, but we have
	three unknowns. We remove one unkown by rotating the plane to z=0 (the plane normal) */

	/* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
	/* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/

	/* translating this comment to english didnt really help me understanding the math! :-) (ton) */
	
	q[1] = plane[1] ; 
	q[2] = -plane[0] ; 
	q[3] = 0 ;
	Normalise(&q[1]);

	hoek = saacos(plane[2])/2.0;
	co = cos(hoek);
	si = sqrt(1-co*co);

	q[0] =  co;
	q[1] *= si;
	q[2] *= si;
	q[3] =  0;

	QuatToMat3(q,mat1);

	/* rotate lamp vector now over acos(inp) degrees */

	vvec[0] = lvec[0] ; 
	vvec[1] = lvec[1] ; 
	vvec[2] = lvec[2] ;

	Mat3One(mat2);
	co = inp;
	si = sqrt(1-inp*inp);

	mat2[0][0] =  co;
	mat2[1][0] = -si;
	mat2[0][1] =  si;
	mat2[1][1] =  co;
	Mat3MulMat3(mat3,mat2,mat1);

	mat2[1][0] =  si;
	mat2[0][1] = -si;
	Mat3MulMat3(mat4,mat2,mat1);
	Mat3Transp(mat1);

	Mat3MulMat3(mat2,mat1,mat3);
	Mat3MulVecfl(mat2,lvec);
	Mat3MulMat3(mat2,mat1,mat4);
	Mat3MulVecfl(mat2,vvec);

	return;
}



static void drawlamp(Object *ob)
{
	Lamp *la;
	float vec[3], lvec[3], vvec[3],x,y,z;
	
	la= ob->data;
	vec[0]=vec[1]=vec[2]= 0.0;
	
	setlinestyle(4);
	
	/* yafray: for photonlight also draw lightcone as for spot */
	if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) {
		
		lvec[0]=lvec[1]= 0.0; 
		lvec[2] = 1.0;
		x = G.vd->persmat[0][2];
		y = G.vd->persmat[1][2];
		z = G.vd->persmat[2][2];
		vvec[0]= x*ob->obmat[0][0] + y*ob->obmat[0][1] + z*ob->obmat[0][2];
		vvec[1]= x*ob->obmat[1][0] + y*ob->obmat[1][1] + z*ob->obmat[1][2];
		vvec[2]= x*ob->obmat[2][0] + y*ob->obmat[2][1] + z*ob->obmat[2][2];

		y = cos( M_PI*la->spotsize/360.0 );
		spotvolume(lvec, vvec, y);
		x = -la->dist;
		lvec[0] *=  x ; 
		lvec[1] *=  x ; 
		lvec[2] *=  x;
		vvec[0] *= x ; 
		vvec[1] *= x ; 
		vvec[2] *= x;

		glBegin(GL_LINE_STRIP);
			glVertex3fv(vvec);
			glVertex3fv(vec);
			glVertex3fv(lvec);
		glEnd();
		
		z = x*sqrt(1.0 - y*y);
		x *= y;

		glTranslatef(0.0 ,  0.0 ,  x);
		if(la->mode & LA_SQUARE) {
			vvec[0]= fabs(z);
			vvec[1]= fabs(z);
			vvec[2]= 0.0;
			glBegin(GL_LINE_LOOP);
				glVertex3fv(vvec);
				vvec[1]= -fabs(z);
				glVertex3fv(vvec);
				vvec[0]= -fabs(z);
				glVertex3fv(vvec);
				vvec[1]= fabs(z);
				glVertex3fv(vvec);
			glEnd();
		}
		else circ(0.0, 0.0, fabs(z));
		
	}
	else if ELEM(la->type, LA_HEMI, LA_SUN) {
		glBegin(GL_LINE_STRIP);
			glVertex3fv(vec); 
			vec[2]= -la->dist; 
			glVertex3fv(vec);
		glEnd();
	}
	else {
		if(la->type==LA_AREA) {
			setlinestyle(0);
			if(la->area_shape==LA_AREA_SQUARE) 
				fdrawbox(-la->area_size*0.5, -la->area_size*0.5, la->area_size*0.5, la->area_size*0.5);
			else if(la->area_shape==LA_AREA_RECT) 
				fdrawbox(-la->area_size*0.5, -la->area_sizey*0.5, la->area_size*0.5, la->area_sizey*0.5);
			setlinestyle(3);
			glBegin(GL_LINE_STRIP); 
			glVertex3f(0.0,0.0,0.0);
			glVertex3f(0.0,0.0,-la->dist);
			glEnd();
			setlinestyle(0);
		}
		else if(la->mode & LA_SPHERE) {

			float tmat[4][4], imat[4][4];
			
			vec[0]= vec[1]= vec[2]= 0.0;
			mygetmatrix(tmat);
			Mat4Invert(imat, tmat);
			
			drawcircball(vec, la->dist, imat);

		}
	}
	myloadmatrix(G.vd->viewmat);
	
	VECCOPY(vec, ob->obmat[3]);
	
	setlinestyle(3);
	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec); 
		vec[2]= 0; 
		glVertex3fv(vec);
	glEnd();
	setlinestyle(0);
		
	if(la->type==LA_SPOT && (la->mode & LA_SHAD) ) {
		tekenshadbuflimits(la, ob->obmat);
	}
}

static void draw_limit_line(float sta, float end, unsigned int col)
{
	glBegin(GL_LINES);
	glVertex3f(0.0, 0.0, -sta);
	glVertex3f(0.0, 0.0, -end);
	glEnd();

	glPointSize(3.0);
	glBegin(GL_POINTS);
	cpack(col);
	glVertex3f(0.0, 0.0, -sta);
	glVertex3f(0.0, 0.0, -end);
	glEnd();
	glPointSize(1.0);
}		


/* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
static void draw_focus_cross(float dist, float size)
{
	glBegin(GL_LINES);
	glVertex3f(-size, 0.f, -dist);
	glVertex3f(size, 0.f, -dist);
	glVertex3f(0.f, -size, -dist);
	glVertex3f(0.f, size, -dist);
	glEnd();
}

void drawcamera(Object *ob)
{
	/* a standing up pyramid with (0,0,0) as top */
	Camera *cam;
	World *wrld;
	float vec[8][4], tmat[4][4], fac, facx, facy, depth;

	cam= ob->data;
	/* this code only works for perspective */
	if(G.vd->persp==2 && ob==G.vd->camera && cam->type==CAM_ORTHO) return;
	
	glDisable(GL_LIGHTING);
	glDisable(GL_CULL_FACE);
	
	/* that way it's always visible */
	fac= cam->drawsize;
	if(G.vd->persp>=2 && ob==G.vd->camera) fac= cam->clipsta+0.1;
	
	depth= - fac*cam->lens/16.0;
	facx= fac*1.28;
	facy= fac*1.024;
	
	vec[0][0]= 0; vec[0][1]= 0; vec[0][2]= 0.001;	/* GLBUG: for picking at iris Entry (well thats old!) */
	vec[1][0]= facx; vec[1][1]= facy; vec[1][2]= depth;
	vec[2][0]= facx; vec[2][1]= -facy; vec[2][2]= depth;
	vec[3][0]= -facx; vec[3][1]= -facy; vec[3][2]= depth;
	vec[4][0]= -facx; vec[4][1]= facy; vec[4][2]= depth;

	glBegin(GL_LINE_LOOP);
		glVertex3fv(vec[0]); 
		glVertex3fv(vec[1]); 
		glVertex3fv(vec[2]); 
		glVertex3fv(vec[0]); 
		glVertex3fv(vec[3]); 
		glVertex3fv(vec[4]);
	glEnd();

	glBegin(GL_LINES);
		glVertex3fv(vec[2]); 
		glVertex3fv(vec[3]);
	glEnd();

	glBegin(GL_LINES);
		glVertex3fv(vec[4]); 
		glVertex3fv(vec[1]);
	glEnd();

	if(G.vd->persp>=2) return;
	
	/* arrow on top */
	vec[0][2]= depth;

	glBegin(GL_QUADS);

		vec[0][0]= -0.2*cam->drawsize; 
		vec[0][1]= cam->drawsize;
		glVertex3fv(vec[0]);
		
		vec[0][0]= 0.2*cam->drawsize;
		glVertex3fv(vec[0]);
		
		vec[0][1]= 1.6*cam->drawsize;
		glVertex3fv(vec[0]);
		
		vec[0][0]= -0.2*cam->drawsize; 
		glVertex3fv(vec[0]);
	glEnd();

	glBegin(GL_TRIANGLES);
	
		vec[0][0]= -0.4*cam->drawsize;
		vec[0][1]= 1.6*cam->drawsize;
		glVertex3fv(vec[0]);
		
		vec[0][0]= 0.0; 
		vec[0][1]= 2.0*cam->drawsize;
		glVertex3fv(vec[0]);
		
		vec[0][0]= 0.4*cam->drawsize; 
		vec[0][1]= 1.6*cam->drawsize;
		glVertex3fv(vec[0]);
	
	glEnd();
	
	if(cam->flag & (CAM_SHOWLIMITS+CAM_SHOWMIST)) {
		myloadmatrix(G.vd->viewmat);
		Mat4CpyMat4(vec, ob->obmat);
		Mat4Ortho(vec);
		mymultmatrix(vec);

		MTC_Mat4SwapMat4(G.vd->persmat, tmat);
		mygetsingmatrix(G.vd->persmat);

		if(cam->flag & CAM_SHOWLIMITS) {
			draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
			/* yafray: dof focus point */
			if (G.scene->r.renderer==R_YAFRAY) draw_focus_cross(cam->YF_dofdist, cam->drawsize);
		}

		wrld= G.scene->world;
		if(cam->flag & CAM_SHOWMIST) 
			if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF);
			
		MTC_Mat4SwapMat4(G.vd->persmat, tmat);
	}
}

static void tekenvertslatt(short sel)
{
	Lattice *lt;
	BPoint *bp;
	float size;
	int a, uxt, u, vxt, v, wxt, w;

	size= BIF_GetThemeValuef(TH_VERTEX_SIZE);
	glPointSize(size);

	if(sel) BIF_ThemeColor(TH_VERTEX_SELECT);
	else BIF_ThemeColor(TH_VERTEX);

	bglBegin(GL_POINTS);

	bp= editLatt->def;
	lt= editLatt;
	
	if(lt->flag & LT_OUTSIDE) {
		
		for(w=0; w<lt->pntsw; w++) {
			if(w==0 || w==lt->pntsw-1) wxt= 1; else wxt= 0;
			for(v=0; v<lt->pntsv; v++) {
				if(v==0 || v==lt->pntsv-1) vxt= 1; else vxt= 0;
				
				for(u=0; u<lt->pntsu; u++, bp++) {
					if(u==0 || u==lt->pntsu-1) uxt= 1; else uxt= 0;
					if(uxt || vxt || wxt) {
						if(bp->hide==0) {
							if((bp->f1 & 1)==sel) bglVertex3fv(bp->vec);
						}
					}
				}
			}
		}
	}
	else {

		a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
		while(a--) {
			if(bp->hide==0) {
				if((bp->f1 & 1)==sel) bglVertex3fv(bp->vec);
			}
			bp++;
		}
	}
	
	glPointSize(1.0);
	bglEnd();	
}

static void calc_lattverts(void)
{
	BPoint *bp;
	float mat[4][4];
	int a;

	MTC_Mat4SwapMat4(G.vd->persmat, mat);
	mygetsingmatrix(G.vd->persmat);
	
	 bp= editLatt->def;
	
	a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
	while(a--) {
		project_short(bp->vec, bp->s);
		bp++;
	}

	MTC_Mat4SwapMat4(G.vd->persmat, mat);
}


void calc_lattverts_ext(void)
{

	areawinset(curarea->win);
	persp(PERSP_VIEW);
	mymultmatrix(G.obedit->obmat);
	calc_lattverts();
	myloadmatrix(G.vd->viewmat);
	
}


static void drawlattice(Object *ob)
{
	Lattice *lt;
	BPoint *bp, *bpu;
	int u, v, w, dv, dw, uxt, vxt, wxt;

	lt= ob->data;
	if(ob==G.obedit) {
		bp= editLatt->def;
		
		cpack(0x004000);
	}
	else {
		lattice_modifier(ob, 's');
		bp= lt->def;
	}
	
	dv= lt->pntsu;
	dw= dv*lt->pntsv;
	
	if(lt->flag & LT_OUTSIDE) {
		
		for(w=0; w<lt->pntsw; w++) {
			
			if(w==0 || w==lt->pntsw-1) wxt= 1; else wxt= 0;
			
			for(v=0; v<lt->pntsv; v++) {
				
				if(v==0 || v==lt->pntsv-1) vxt= 1; else vxt= 0;
				
				for(u=0, bpu=0; u<lt->pntsu; u++, bp++) {
				
					if(u==0 || u==lt->pntsu-1) uxt= 1; else uxt= 0;
					
					if(uxt || vxt || wxt) {
					
						if(w && (uxt || vxt)) {

							glBegin(GL_LINE_STRIP);
							glVertex3fv( (bp-dw)->vec ); glVertex3fv(bp->vec);
							glEnd();
						}
						if(v && (uxt || wxt)) {

							glBegin(GL_LINES);
							glVertex3fv( (bp-dv)->vec ); glVertex3fv(bp->vec);
							glEnd();
						}
						if(u && (vxt || wxt)) {

							glBegin(GL_LINES);
							glVertex3fv(bpu->vec); glVertex3fv(bp->vec);
							glEnd();
						}
					}
					
					bpu= bp;
				}
			}
		}		
	}
	else {
		for(w=0; w<lt->pntsw; w++) {
			
			for(v=0; v<lt->pntsv; v++) {
				
				for(u=0, bpu=0; u<lt->pntsu; u++, bp++) {
				
					if(w) {

						glBegin(GL_LINES);
						glVertex3fv( (bp-dw)->vec ); glVertex3fv(bp->vec);
						glEnd();
					}
					if(v) {

						glBegin(GL_LINES);
						glVertex3fv( (bp-dv)->vec ); glVertex3fv(bp->vec);
						glEnd();
					}
					if(u) {

						glBegin(GL_LINES);
						glVertex3fv(bpu->vec); glVertex3fv(bp->vec);
						glEnd();
					}
					bpu= bp;
				}
			}
		}
	}
	
	if(ob==G.obedit) {
		
		calc_lattverts();
		
		if(G.zbuf) glDisable(GL_DEPTH_TEST);
		
		tekenvertslatt(0);
		tekenvertslatt(1);
		
		if(G.zbuf) glEnable(GL_DEPTH_TEST); 
	}
	else lattice_modifier(ob, 'e');

}

/* ***************** ******************** */

int subsurf_optimal(Object *ob)
{
	if(ob->type==OB_MESH) {
		Mesh *me= ob->data;
		if( (me->flag & ME_OPT_EDGES) && (me->flag & ME_SUBSURF) && me->subdiv) return 1;
	}
	return 0;
}


void calc_mesh_facedots_ext(void)
{
	EditMesh *em = G.editMesh;
	EditFace *efa;
	float mat[4][4];

	if(em->faces.first==NULL) return;
	efa= em->faces.first;

	areawinset(curarea->win);
	persp(PERSP_VIEW);
	
	mymultmatrix(G.obedit->obmat);

	MTC_Mat4SwapMat4(G.vd->persmat, mat);
	mygetsingmatrix(G.vd->persmat);

	efa= em->faces.first;
	while(efa) {
		if( efa->h==0) {
			project_short(efa->cent, &(efa->xs));
		}
		efa= efa->next;
	}
	MTC_Mat4SwapMat4(G.vd->persmat, mat);

	myloadmatrix(G.vd->viewmat);
}

/* window coord, assuming all matrices are set OK */
static void calc_meshverts(void)
{
	EditMesh *em = G.editMesh;
	EditVert *eve;
	float mat[4][4];

	if(em->verts.first==0) return;
	eve= em->verts.first;

	MTC_Mat4SwapMat4(G.vd->persmat, mat);
	mygetsingmatrix(G.vd->persmat);

	if(subsurf_optimal(G.obedit)) { // separate loop for speed 
		for(eve= em->verts.first; eve; eve= eve->next) {
			if(eve->h==0 && eve->ssco) project_short(eve->ssco, &(eve->xs));
		}
	}
	else {
		for(eve= em->verts.first; eve; eve= eve->next) {
			if(eve->h==0) project_short(eve->co, &(eve->xs));
		}
	}
	MTC_Mat4SwapMat4(G.vd->persmat, mat);
}

/* window coord for current window, sets matrices temporal */
void calc_meshverts_ext(void)
{

	areawinset(curarea->win);
	persp(PERSP_VIEW);
	
	mymultmatrix(G.obedit->obmat);
	calc_meshverts();
	myloadmatrix(G.vd->viewmat);
	
}

/* window coord for current window, sets matrices temporal, sets (eve->f & 2) when not visible */
void calc_meshverts_ext_f2(void)
{
	EditMesh *em = G.editMesh;
	EditVert *eve;
	float mat[4][4];
	int optimal= subsurf_optimal(G.obedit);
	
	if(em->verts.first==0) return;
	eve= em->verts.first;

	/* matrices */
	areawinset(curarea->win);
	persp(PERSP_VIEW);
	mymultmatrix(G.obedit->obmat);
	
	MTC_Mat4SwapMat4(G.vd->persmat, mat);
	mygetsingmatrix(G.vd->persmat);

	for(eve= em->verts.first; eve; eve= eve->next) {
		eve->f &= ~2;
		if(eve->h==0) {
			if(optimal && eve->ssco) project_short_noclip(eve->ssco, &(eve->xs));
			else project_short_noclip(eve->co, &(eve->xs));
	
			if( eve->xs >= 0 && eve->ys >= 0 && eve->xs<curarea->winx && eve->ys<curarea->winy);
			else eve->f |= 2;
		}
	}
	
	/* restore */
	MTC_Mat4SwapMat4(G.vd->persmat, mat);
	myloadmatrix(G.vd->viewmat);
	
}


static void calc_Nurbverts(Nurb *nurb)
{
	Nurb *nu;
	BezTriple *bezt;
	BPoint *bp;
	float mat[4][4];
	int a;

	MTC_Mat4SwapMat4(G.vd->persmat, mat);
	mygetsingmatrix(G.vd->persmat);

	nu= nurb;
	while(nu) {
		if((nu->type & 7)==1) {
			bezt= nu->bezt;
			a= nu->pntsu;
			while(a--) {
				project_short(bezt->vec[0], bezt->s[0]);
				project_short(bezt->vec[1], bezt->s[1]);
				project_short(bezt->vec[2], bezt->s[2]);
				bezt++;
			}
		}
		else {
			bp= nu->bp;
			a= nu->pntsu*nu->pntsv;
			while(a--) {
				project_short(bp->vec, bp->s);
				bp++;
			}
		}
		nu= nu->next;
	}

	MTC_Mat4SwapMat4(G.vd->persmat, mat);
}

void calc_nurbverts_ext(void)
{

	areawinset(curarea->win);
	persp(PERSP_VIEW);
	mymultmatrix(G.obedit->obmat);
	calc_Nurbverts(editNurb.first);
	myloadmatrix(G.vd->viewmat);
	
}

static void draw_vertices(int optimal, int sel)
{
	EditMesh *em = G.editMesh;
	EditVert *eve;
	EditFace *efa;
	float size, fsize;
	char col[3], fcol[3];
	
	/* if not V3D_ZBUF_SELECT: */
	/* draws in zbuffer mode twice, to show invisible vertices transparent */

	if(G.zbuf) glDepthMask(0);		// disable write in zbuffer, zbuf select

	size= BIF_GetThemeValuef(TH_VERTEX_SIZE);
	fsize= BIF_GetThemeValuef(TH_FACEDOT_SIZE);
	if(sel) {
		BIF_GetThemeColor3ubv(TH_VERTEX_SELECT, col);
		BIF_GetThemeColor3ubv(TH_FACE_DOT, fcol);
	}
	else {
		BIF_GetThemeColor3ubv(TH_VERTEX, col);
		BIF_GetThemeColor3ubv(TH_WIRE, fcol);
	}

	if(G.zbuf) {
		if(G.vd->flag & V3D_ZBUF_SELECT);
		else {
			glDisable(GL_DEPTH_TEST);
			
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glEnable(GL_BLEND);
			
			if(G.scene->selectmode & SCE_SELECT_VERTEX) {
				glPointSize(size>2.1?size/2.0: size);
				glColor4ub(col[0], col[1], col[2], 100);
				
				bglBegin(GL_POINTS);
				if(optimal) {
					for(eve= em->verts.first; eve; eve= eve->next) {
						if(eve->h==0 && (eve->f & SELECT)==sel ) 
							if(eve->ssco) bglVertex3fv(eve->ssco);
					}
				}
				else {
					for(eve= em->verts.first; eve; eve= eve->next) {
						if(eve->h==0 && (eve->f & SELECT)==sel ) bglVertex3fv(eve->co);
					}
				}
				bglEnd();
			}
			
			if(G.scene->selectmode & SCE_SELECT_FACE) {
				glPointSize(fsize>2.1?fsize/2.0: fsize);
				glColor4ub(fcol[0], fcol[1], fcol[2], 100);
				
				bglBegin(GL_POINTS);
				for(efa= em->faces.first; efa; efa= efa->next) {
					if(efa->h==0) {
						if(efa->fgonf==EM_FGON);
						else if(sel == (efa->f & SELECT)) {
							bglVertex3fv(efa->cent);
						}
					}
				}
				bglEnd();
			}
			
			glDisable(GL_BLEND);
			glEnable(GL_DEPTH_TEST);
		}
	}

	if(G.scene->selectmode & SCE_SELECT_VERTEX) {

		glPointSize(size);
		glColor3ub(col[0], col[1], col[2]);

		bglBegin(GL_POINTS);
		if(optimal) {
			for(eve= em->verts.first; eve; eve= eve->next) {
				if(eve->h==0 && (eve->f & SELECT)==sel ) 
					if(eve->ssco) bglVertex3fv(eve->ssco);
			}
		}
		else {
			for(eve= em->verts.first; eve; eve= eve->next) {
				if(eve->h==0 && (eve->f & SELECT)==sel ) bglVertex3fv(eve->co);
			}
		}
		bglEnd();
		
	}
	
	if(G.scene->selectmode & SCE_SELECT_FACE) {		
		glPointSize(fsize);
		glColor3ub(fcol[0], fcol[1], fcol[2]);
		
		bglBegin(GL_POINTS);
		for(efa= em->faces.first; efa; efa= efa->next) {
			if(efa->h==0) {
				if(efa->fgonf==EM_FGON);
				else if(sel == (efa->f & SELECT)) {
					bglVertex3fv(efa->cent);
				}
			}
		}
		bglEnd();
	}

	if(G.zbuf) glDepthMask(1);
	glPointSize(1.0);
}


/* ************** DRAW DISPLIST ****************** */

/* DispListMesh, comes from subsurf or decimator */

static void displistmesh_draw_wire(DispListMesh *dlm) 
{
	MVert *mvert= dlm->mvert;
	MEdge *medge;
	int i, optim;
	
	if(dlm->medge) {
		optim= dlm->flag & ME_OPT_EDGES;
		medge= dlm->medge;
	
		glBegin(GL_LINES);
		for (i=0; i<dlm->totedge; i++, medge++) {
			if(optim==0 || (medge->flag & ME_EDGEDRAW)) {
				glVertex3fv(mvert[medge->v1].co); 
				glVertex3fv(mvert[medge->v2].co);
			}
	
		}
		glEnd();
	}
	else {
		for (i=0; i<dlm->totface; i++) {
			MFace *mf= &dlm->mface[i];
			
			glBegin(GL_LINE_LOOP);
			glVertex3fv(dlm->mvert[mf->v1].co);
			glVertex3fv(dlm->mvert[mf->v2].co);
			if (mf->v3) {
				glVertex3fv(dlm->mvert[mf->v3].co);
				if (mf->v4)
					glVertex3fv(dlm->mvert[mf->v4].co);
			}
			glEnd();
		}
	}
}

static void displistmesh_draw_solid(DispListMesh *dlm, float *nors) 
{
	int lmode, lshademodel= -1, lmat_nr= -1;
	int i;

#define PASSVERT(ind) {									\
	if (lshademodel==GL_SMOOTH)				\
		glNormal3sv(dlm->mvert[(ind)].no);					\
	glVertex3fv(dlm->mvert[(ind)].co);						\
}

	glBegin(lmode= GL_QUADS);
	for (i=0; i<dlm->totface; i++) {
		MFace *mf= &dlm->mface[i];
		
		if (mf->v3) {
			int nmode= mf->v4?GL_QUADS:GL_TRIANGLES;
			int nshademodel= (mf->flag&ME_SMOOTH)?GL_SMOOTH:GL_FLAT;
			
			if (nmode!=lmode) {
				glEnd();
				glBegin(lmode= nmode);
			}
			
			if (nshademodel!=lshademodel) {
				glEnd();
				glShadeModel(lshademodel= nshademodel);
				glBegin(lmode);
			}
			
			if (mf->mat_nr!=lmat_nr) {
				glEnd();
				set_gl_material((lmat_nr= mf->mat_nr)+1);
				glBegin(lmode);
			}
			
			if (lshademodel==GL_FLAT)
				glNormal3fv(&nors[i*3]);
				
			PASSVERT(mf->v1);
			PASSVERT(mf->v2);
			PASSVERT(mf->v3);
			if (mf->v4)
				PASSVERT(mf->v4);
		}
	}
	glEnd();
	
#undef PASSVERT
}

static void displistmesh_draw_shaded(DispListMesh *dlm, unsigned char *vcols1, unsigned char *vcols2) 
{
	int i, lmode;
	
	glShadeModel(GL_SMOOTH);
	if (vcols2)
		glEnable(GL_CULL_FACE);
		
#define PASSVERT(vidx, fidx) {				\
	unsigned char *col= &colbase[fidx*4];		\
	glColor3ub(col[3], col[2], col[1]);			\
	glVertex3fv(dlm->mvert[(vidx)].co);			\
}

	glBegin(lmode= GL_QUADS);
	for (i=0; i<dlm->totface; i++) {
		MFace *mf= &dlm->mface[i];
		
		if (mf->v3) {
			int nmode= mf->v4?GL_QUADS:GL_TRIANGLES;
			unsigned char *colbase= &vcols1[i*16];
			
			if (nmode!=lmode) {
				glEnd();
				glBegin(lmode= nmode);
			}
			
			PASSVERT(mf->v1, 0);
			PASSVERT(mf->v2, 1);
			PASSVERT(mf->v3, 2);
			if (mf->v4)
				PASSVERT(mf->v4, 3);
			
			if (vcols2) {
				unsigned char *colbase= &vcols2[i*16];

				if (mf->v4)
					PASSVERT(mf->v4, 3);
				PASSVERT(mf->v3, 2);
				PASSVERT(mf->v2, 1);
				PASSVERT(mf->v1, 0);
			}
		}
	}
	glEnd();

	if (vcols2)
		glDisable(GL_CULL_FACE);
	
#undef PASSVERT
}

	/***/
	
static int draw_index_wire= 1;
static int index3_nors_incr= 1;

static void drawDispListwire(ListBase *dlbase)
{
	DispList *dl;
	int parts, nr, ofs, *index;
	float *data;

	if(dlbase==0) return;

	dl= dlbase->first;
	while(dl) {
		data= dl->verts;
	
		switch(dl->type) {
		case DL_SEGM:
			parts= dl->parts;
			while(parts--) {
				nr= dl->nr;
				glBegin(GL_LINE_STRIP);
				while(nr--) {
					glVertex3fv(data);
					data+=3;
				}
				glEnd();
			}
			break;
		case DL_POLY:
			parts= dl->parts;
			while(parts--) {
				nr= dl->nr;
				glBegin(GL_LINE_LOOP);
				while(nr--) {
					glVertex3fv(data);
					data+=3;
				}
				glEnd();
			}
			break;
		case DL_SURF:
			parts= dl->parts;
			while(parts--) {
				nr= dl->nr;
				if(dl->flag & DL_CYCL_U) glBegin(GL_LINE_LOOP);
				else glBegin(GL_LINE_STRIP);

				while(nr--) {
					glVertex3fv(data);
					data+=3;
				}
				glEnd();
			}
			ofs= 3*dl->nr;
			nr= dl->nr;
			while(nr--) {
				data= (  dl->verts )+3*nr;
				parts= dl->parts;
				if(dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP);
				else glBegin(GL_LINE_STRIP);
				
				while(parts--) {
					glVertex3fv(data);
					data+=ofs;
				}
				glEnd();
			}
			break;
			
		case DL_INDEX3:
			if(draw_index_wire) {
				parts= dl->parts;
				data= dl->verts;
				index= dl->index;
				while(parts--) {

					glBegin(GL_LINE_LOOP);
						glVertex3fv(data+3*index[0]);
						glVertex3fv(data+3*index[1]);
						glVertex3fv(data+3*index[2]);
					glEnd();
					index+= 3;
				}
			}
			break;
			
		case DL_INDEX4:
			if(draw_index_wire) {
				parts= dl->parts;
				data= dl->verts;
				index= dl->index;
				while(parts--) {

					glBegin(GL_LINE_LOOP);
						glVertex3fv(data+3*index[0]);
						glVertex3fv(data+3*index[1]);
						glVertex3fv(data+3*index[2]);
						if(index[3]) glVertex3fv(data+3*index[3]);
					glEnd();
					index+= 4;
				}
			}
			break;
			
		case DL_MESH:
			displistmesh_draw_wire(dl->mesh);
			break;
		}
		dl= dl->next;
	}
}

static void drawDispListsolid(ListBase *lb, Object *ob)
{
	DispList *dl;
	int parts, ofs, p1, p2, p3, p4, a, b, *index;
	float *data, *v1, *v2, *v3, *v4;
	float *ndata, *n1, *n2, *n3, *n4;
	
	if(lb==0) return;
	
	glEnable(GL_LIGHTING);
	
	if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
	else glFrontFace(GL_CCW);
	
	if(ob->type==OB_MBALL) {	// mball always smooth shaded
		glShadeModel(GL_SMOOTH);
	}
	
	dl= lb->first;
	while(dl) {
		data= dl->verts;
		ndata= dl->nors;

		switch(dl->type) {
		case DL_SURF:

			set_gl_material(dl->col+1);
			
			if(dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH);
			else glShadeModel(GL_FLAT);

			for(a=0; a<dl->parts; a++) {
				
				DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
				
				v1= data+ 3*p1; 
				v2= data+ 3*p2;
				v3= data+ 3*p3; 
				v4= data+ 3*p4;
				n1= ndata+ 3*p1; 
				n2= ndata+ 3*p2;
				n3= ndata+ 3*p3; 
				n4= ndata+ 3*p4;
				
				glBegin(GL_QUAD_STRIP);
				
				glNormal3fv(n2); glVertex3fv(v2);
				glNormal3fv(n4); glVertex3fv(v4);

				for(; b<dl->nr; b++) {
					
					glNormal3fv(n1); glVertex3fv(v1);
					glNormal3fv(n3); glVertex3fv(v3);

					v2= v1; v1+= 3;
					v4= v3; v3+= 3;
					n2= n1; n1+= 3;
					n4= n3; n3+= 3;
				}
				
				
				glEnd();
			}
			break;

		case DL_INDEX3:
		
			parts= dl->parts;
			data= dl->verts;
			ndata= dl->nors;
			index= dl->index;

			set_gl_material(dl->col+1);
							
			/* voor polys only one normal needed */
			if(index3_nors_incr==0) {
				while(parts--) {

					glBegin(GL_TRIANGLES);
						glNormal3fv(ndata);
						glVertex3fv(data+3*index[0]);
						glVertex3fv(data+3*index[1]);
						glVertex3fv(data+3*index[2]);
					glEnd();
					index+= 3;
				}
			}
			else {
				while(parts--) {

					glBegin(GL_TRIANGLES);
						ofs= 3*index[0];
						glNormal3fv(ndata+ofs); glVertex3fv(data+ofs);
						ofs= 3*index[1];
						glNormal3fv(ndata+ofs); glVertex3fv(data+ofs);
						ofs= 3*index[2];
						glNormal3fv(ndata+ofs); glVertex3fv(data+ofs);
					glEnd();
					index+= 3;
				}
			}
			break;

		case DL_INDEX4:

			parts= dl->parts;
			data= dl->verts;
			ndata= dl->nors;
			index= dl->index;

			set_gl_material(dl->col+1);
		
			while(parts--) {

				glBegin(index[3]?GL_QUADS:GL_TRIANGLES);
					ofs= 3*index[0];
					glNormal3fv(ndata+ofs); glVertex3fv(data+ofs);
					ofs= 3*index[1];
					glNormal3fv(ndata+ofs); glVertex3fv(data+ofs);
					ofs= 3*index[2];
					glNormal3fv(ndata+ofs); glVertex3fv(data+ofs);
					if(index[3]) {
						ofs= 3*index[3];
						glNormal3fv(ndata+ofs); glVertex3fv(data+ofs);
					}
				glEnd();
				index+= 4;
			}
			break;
		
		case DL_MESH:
			if (!dl->nors)
				addnormalsDispList(ob, lb);
			displistmesh_draw_solid(dl->mesh, dl->nors);
			break;
				
		}
		dl= dl->next;
	}

	glShadeModel(GL_FLAT);
	glDisable(GL_LIGHTING);
	glFrontFace(GL_CCW);
}

static void drawDispListshaded(ListBase *lb, Object *ob)
{
	DispList *dl, *dlob;
	int parts, p1, p2, p3, p4, a, b, *index;
	float *data, *v1, *v2, *v3, *v4;/*  , *extverts=0 */
	unsigned int *cdata, *c1, *c2, *c3, *c4;
	char *cp;

	if(lb==0) return;

	glShadeModel(GL_SMOOTH);

	dl= lb->first;
	dlob= ob->disp.first;
	while(dl && dlob) {
		
		cdata= dlob->col1;
		data= dl->verts;
		if(cdata==0) break;
		
		switch(dl->type) {
		case DL_SURF:

			for(a=0; a<dl->parts; a++) {

				DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);

				v1= data+ 3*p1; 
				v2= data+ 3*p2;
				v3= data+ 3*p3; 
				v4= data+ 3*p4;
				c1= cdata+ p1; 
				c2= cdata+ p2;
				c3= cdata+ p3; 
				c4= cdata+ p4;

				for(; b<dl->nr; b++) {

					glBegin(GL_QUADS);
						cp= (char *)c1;
						glColor3ub(cp[3], cp[2], cp[1]);
						glVertex3fv(v1);
						cp= (char *)c2;
						glColor3ub(cp[3], cp[2], cp[1]);
						glVertex3fv(v2);
						cp= (char *)c4;
						glColor3ub(cp[3], cp[2], cp[1]);
						glVertex3fv(v4);
						cp= (char *)c3;
						glColor3ub(cp[3], cp[2], cp[1]);
						glVertex3fv(v3);
					glEnd();

					v2= v1; v1+= 3;
					v4= v3; v3+= 3;
					c2= c1; c1++;
					c4= c3; c3++;
				}
			}
			break;

		case DL_INDEX3:
			
			parts= dl->parts;
			index= dl->index;
			
			while(parts--) {

				glBegin(GL_TRIANGLES);
					cp= (char *)(cdata+index[0]);
					glColor3ub(cp[3], cp[2], cp[1]);					
					glVertex3fv(data+3*index[0]);

					cp= (char *)(cdata+index[1]);
					glColor3ub(cp[3], cp[2], cp[1]);					
					glVertex3fv(data+3*index[1]);

					cp= (char *)(cdata+index[2]);
					glColor3ub(cp[3], cp[2], cp[1]);					
					glVertex3fv(data+3*index[2]);
				glEnd();
				index+= 3;
			}
			break;

		case DL_INDEX4:
		
			parts= dl->parts;
			index= dl->index;
			while(parts--) {

				glBegin(index[3]?GL_QUADS:GL_TRIANGLES);
					cp= (char *)(cdata+index[0]);
					glColor3ub(cp[3], cp[2], cp[1]);					
					glVertex3fv(data+3*index[0]);

					cp= (char *)(cdata+index[1]);
					glColor3ub(cp[3], cp[2], cp[1]);					
					glVertex3fv(data+3*index[1]);

					cp= (char *)(cdata+index[2]);
					glColor3ub(cp[3], cp[2], cp[1]);					
					glVertex3fv(data+3*index[2]);
					
					if(index[3]) {
					
						cp= (char *)(cdata+index[3]);
						glColor3ub(cp[3], cp[2], cp[1]);	
						glVertex3fv(data+3*index[3]);
					}
				glEnd();
				index+= 4;
			}
			break;

		case DL_MESH:
			displistmesh_draw_shaded(dl->mesh, (unsigned char*) dlob->col1, (unsigned char*) dlob->col2);
			break;
			
		}
		dl= dl->next;
		dlob= dlob->next;
	}
	
	glShadeModel(GL_FLAT);
}


static void drawmeshsolid(Object *ob, float *nors)
{
	EditMesh *em = G.editMesh;
	Mesh *me;
	DispList *dl;
	MVert *mvert;
	TFace *tface;
	MFace *mface;
	EditFace *efa;
	float *extverts=0, *v1, *v2, *v3, *v4;
	int glmode, setsmooth=0, a, start, end, matnr= -1, vertexpaint, do_wire=0;
	short no[3], *n1, *n2, *n3, *n4 = NULL;
	
	vertexpaint= (G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT)) && (ob==((G.scene->basact) ? (G.scene->basact->object) : 0));

	me= get_mesh(ob);
	if(me==0) return;

	glShadeModel(GL_FLAT);

	glEnable(GL_LIGHTING);
	init_gl_materials(ob);

	two_sided( me->flag & ME_TWOSIDED );

	if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
	else glFrontFace(GL_CCW);

	mface= me->mface;
	if( (G.f & G_FACESELECT) && ob==((G.scene->basact) ? (G.scene->basact->object) : 0)) tface= me->tface;
	else tface= 0;

	mvert= me->mvert;
	a= me->totface;

	/* SOLVE */
	/* if ELEM(ob->type, OB_SECTOR, OB_LIFE) glEnable(GL_CULL_FACE); */

	if(ob==G.obedit || (G.obedit && ob->data==G.obedit->data)) {
		
		efa= em->faces.first;
		while(efa) {
			if(efa->h==0) {
				
				if(efa->mat_nr!=matnr) {
					matnr= efa->mat_nr;
					set_gl_material(matnr+1);
				}
				
				if(efa->v4) {
				
					glBegin(GL_QUADS);
						glNormal3fv(efa->n);
						glVertex3fv(efa->v1->co);
						glVertex3fv(efa->v2->co);
						glVertex3fv(efa->v3->co);
						glVertex3fv(efa->v4->co);
					glEnd();
				}
				else {

					glBegin(GL_TRIANGLES);
						glNormal3fv(efa->n);
						glVertex3fv(efa->v1->co);
						glVertex3fv(efa->v2->co);
						glVertex3fv(efa->v3->co);
					glEnd();
				}
			}
			efa= efa->next;
		}
		
		glDisable(GL_LIGHTING);
		glShadeModel(GL_FLAT);
	}
	else {		/* [nors] should never be zero, but is weak code... the displist 
				   system needs a make over (ton)
		          
				   Face select and vertex paint calls drawmeshsolid() with nors = NULL!
				   It's still weak code but hey, as ton says, the whole system needs 
		           a good thrashing! ;) (aphex) */

		start= 0; end= me->totface;
		set_buildvars(ob, &start, &end);
		mface+= start;
		if(tface) tface+= start;
		
		dl= find_displist(&ob->disp, DL_VERTS);
		if(dl) extverts= dl->verts;
	
		glBegin(GL_QUADS);
		glmode= GL_QUADS;
		
		for(a=start; a<end; a++, mface++, nors+=3) {
			if(mface->v3==0) do_wire= 1;
			else {
				if(tface && (tface->flag & TF_HIDE)) {
					glBegin(GL_LINE_LOOP);
					glVertex3fv( (mvert+mface->v1)->co);
					glVertex3fv( (mvert+mface->v2)->co);
					glVertex3fv( (mvert+mface->v3)->co);
					if(mface->v4) glVertex3fv( (mvert+mface->v1)->co);
					glEnd();
					tface++;
				}
				else {
					if(extverts) {
						v1= extverts+3*mface->v1;
						v2= extverts+3*mface->v2;
						v3= extverts+3*mface->v3;
						if(mface->v4) v4= extverts+3*mface->v4;
						else v4= 0;
					}
					else {
						v1= (mvert+mface->v1)->co;
						v2= (mvert+mface->v2)->co;
						v3= (mvert+mface->v3)->co;
						if(mface->v4) v4= (mvert+mface->v4)->co;
						else v4= 0;
					}
					
					
					if(tface) {
						if(tface->mode & TF_TWOSIDE) glEnable(GL_CULL_FACE);
						else glDisable(GL_CULL_FACE);
					}
					
	
					/* this GL_QUADS joke below was tested for speed: a factor 2! */
						
					if(v4) {if(glmode==GL_TRIANGLES) {glmode= GL_QUADS; glEnd(); glBegin(GL_QUADS);}}
					else {if(glmode==GL_QUADS) {glmode= GL_TRIANGLES; glEnd(); glBegin(GL_TRIANGLES);}}
						
					if(mface->mat_nr!=matnr) {
						glEnd();

						matnr= mface->mat_nr;
						set_gl_material(matnr+1);

						glBegin(glmode);
					}

					if( (me->flag & ME_AUTOSMOOTH)==0 && (mface->flag & ME_SMOOTH)) {
						if(setsmooth==0) {
							glEnd();
							glShadeModel(GL_SMOOTH);
							glBegin(glmode);
							setsmooth= 1;
						}
						n1= (mvert+mface->v1)->no;
						n2= (mvert+mface->v2)->no;
						n3= (mvert+mface->v3)->no;
						if(v4) n4= (mvert+mface->v4)->no;
					
						if(mface->puno & ME_FLIPV1) {
							no[0]= -n1[0]; no[1]= -n1[1]; no[2]= -n1[2];
							glNormal3sv(no);
						}
						else glNormal3sv(n1);
						glVertex3fv( v1 );
						
						if(mface->puno & ME_FLIPV2) {
							no[0]= -n2[0]; no[1]= -n2[1]; no[2]= -n2[2];
							glNormal3sv(no);
						}
						else glNormal3sv(n2);
						glVertex3fv( v2 );
						
						if(mface->puno & ME_FLIPV3) {
							no[0]= -n3[0]; no[1]= -n3[1]; no[2]= -n3[2];
							glNormal3sv(no);
						}
						else glNormal3sv(n3);
						glVertex3fv( v3 );
						
						if(v4) {
							if(mface->puno & ME_FLIPV4) {
								no[0]= -n4[0]; no[1]= -n4[1]; no[2]= -n4[2];
								glNormal3sv(no);
							}
							else glNormal3sv(n4);
							glVertex3fv( v4 );
						}
					}
					else {
						if(setsmooth==1) {
							glEnd();
							glShadeModel(GL_FLAT);
							glBegin(glmode);
							setsmooth= 0;
						}
						glNormal3fv(nors);
						glVertex3fv( v1 );
						glVertex3fv( v2 );
						glVertex3fv( v3 );
						if(v4) glVertex3fv( v4 );
					}
				}
				if(tface) tface++;
			}
		}
		
		glEnd();
		
		if(do_wire) {
			start= 0; end= me->totface;
			set_buildvars(ob, &start, &end);
			mface= ((MFace *)me->mface)+start;
			BIF_ThemeColor(TH_WIRE);
			glBegin(GL_LINES);
			for(a=0; a<end; a++, mface++) {
				if(mface->v3==0) {
					glVertex3fv((mvert+mface->v1)->co);
					glVertex3fv((mvert+mface->v2)->co);
				}
			}
			glEnd();
		}
	}
	
	glDisable(GL_LIGHTING);
	glFrontFace(GL_CCW);
}

#if 0
// WIP: experiment with cleaner draw, but cant make it for this release (ton)
static void drawmesh_vpaint(Object *ob)
{
	Mesh *me= ob->data;
	MVert *mvert;
	MFace *mface;
	TFace *tface;
	int totface, a, glmode;
	char *mcol;
	
	if(mesh_uses_displist(me)) {
		DispList *dl= find_displist(&me->disp, DL_MESH);
		DispListMesh *dlm= dl->mesh;
		
		if(dlm==NULL) return;
		if(dlm->tface==NULL && dlm->mcol==NULL) return;
		
		mvert= dlm->mvert;
		mface= dlm->mface;
		totface= dlm->totface;
		mcol= (char *)dlm->mcol;
		tface= dlm->tface;
	}
	else {

		if(me->tface==NULL && me->mcol==NULL) return;
		
		mvert= me->mvert;
		mface= me->mface;
		totface= me->totface;
		mcol= (char *)me->mcol;
		tface= me->tface;
	}
	
	glShadeModel(GL_SMOOTH);
	glBegin(GL_QUADS);
	glmode= GL_QUADS;
	
	for(a=0; a<totface; a++, mface++) {
		if(mcol) {
			for(a=0; a<totface; a++, mface++) {
				if(mface->v3) {
					
					if(mface->v4) {if(glmode==GL_TRIANGLES) {glmode= GL_QUADS; glEnd(); glBegin(GL_QUADS);}}
					else {if(glmode==GL_QUADS) {glmode= GL_TRIANGLES; glEnd(); glBegin(GL_TRIANGLES);}}
					
					glColor3ub(mcol[3], mcol[2], mcol[1]);
					glVertex3fv( (mvert+mface->v1)->co );
					glColor3ub(mcol[7], mcol[6], mcol[5]);
					glVertex3fv( (mvert+mface->v2)->co );
					glColor3ub(mcol[11], mcol[10], mcol[9]);
					glVertex3fv( (mvert+mface->v3)->co );
					if(mface->v4) {
						glColor3ub(mcol[15], mcol[14], mcol[13]);
						glVertex3fv( (mvert+mface->v4)->co );
					}
				}
				mcol+=16;
			}
		}
		else {
			
			tface++;
		}
	}
	glEnd();
	glShadeModel(GL_FLAT);
}
#endif

static void drawmeshshaded(Object *ob, unsigned int *col1, unsigned int *col2)
{
	Mesh *me;
	MVert *mvert;
	MFace *mface;
	TFace *tface;
	DispList *dl;
	float *extverts=0, *v1, *v2, *v3, *v4;
	int a, start, end, twoside;
	char *cp1, *cp2 = NULL;
	int lglmode;
	
	glShadeModel(GL_SMOOTH);
	glDisable(GL_LIGHTING);

	me= ob->data;
	mface= me->mface;
	
	/* then it does not draw hide */
	if( (G.f & G_FACESELECT) && ob==((G.scene->basact) ? (G.scene->basact->object) : 0)) tface= me->tface;
	else tface= 0;
	
	mvert= me->mvert;
	a= me->totface;
	
	twoside= me->flag & ME_TWOSIDED;
	if(col2==0) twoside= 0;
	
	if(twoside) glEnable(GL_CULL_FACE);
	
	start= 0; end= me->totface;
	set_buildvars(ob, &start, &end);
	mface+= start;
	if(tface) tface+= start;
	col1+= 4*start;
	if(col2) col2+= 4*start;
	
	dl= find_displist(&ob->disp, DL_VERTS);
	if(dl) extverts= dl->verts;

	glBegin(lglmode= GL_QUADS);
	
	cp1= (char *)col1;
	if(col2) cp2= (char *)col2;

	for(a=start; a<end; a++, mface++, cp1+= 16) {
		if(mface->v3) {
			if(tface && (tface->flag & TF_HIDE)) tface++;
			else {
				int nglmode= mface->v4?GL_QUADS:GL_TRIANGLES;
				
				if (nglmode!=lglmode) {
					glEnd();
					glBegin(lglmode= nglmode);
				}
				
				if(extverts) {
					v1= extverts+3*mface->v1;
					v2= extverts+3*mface->v2;
					v3= extverts+3*mface->v3;
					if(mface->v4) v4= extverts+3*mface->v4;
					else v4= 0;
				}
				else {
					v1= (mvert+mface->v1)->co;
					v2= (mvert+mface->v2)->co;
					v3= (mvert+mface->v3)->co;
					if(mface->v4) v4= (mvert+mface->v4)->co;
					else v4= 0;
				}

				if(tface) {
					if(tface->mode & TF_TWOSIDE) glEnable(GL_CULL_FACE);
					else glDisable(GL_CULL_FACE);
				}
				
				glColor3ub(cp1[3], cp1[2], cp1[1]);
				glVertex3fv( v1 );
				glColor3ub(cp1[7], cp1[6], cp1[5]);
				glVertex3fv( v2 );
				glColor3ub(cp1[11], cp1[10], cp1[9]);
				glVertex3fv( v3 );
				if(v4) {
					glColor3ub(cp1[15], cp1[14], cp1[13]);
					glVertex3fv( v4 );
				}
				
				if(twoside) {

					glColor3ub(cp2[11], cp2[10], cp2[9]);
					glVertex3fv( v3 );
					glColor3ub(cp2[7], cp2[6], cp2[5]);
					glVertex3fv( v2 );
					glColor3ub(cp2[3], cp2[2], cp2[1]);
					glVertex3fv( v1 );
					if(mface->v4) {
						glColor3ub(cp2[15], cp2[14], cp2[13]);
						glVertex3fv( v4 );
					}
				}
			}
		}
		if(col2) cp2+= 16;
	}
	
	glEnd();
	glShadeModel(GL_FLAT);
	if(twoside) glDisable(GL_CULL_FACE);
}

static void drawDispList(Object *ob, int dt)
{
	ListBase *lb=0;
	DispList *dl;
	Mesh *me;
	Curve *cu;
	int solid;

	
	solid= (dt > OB_WIRE);

	switch(ob->type) {
	case OB_MESH:
		
		me= get_mesh(ob);
		if(me==0) return;
		
		if(me->bb==0) tex_space_mesh(me);
		if(me->totface>4) if(boundbox_clip(ob->obmat, me->bb)==0) return;
		
		
		
		if(dt==OB_SOLID ) {
			
			lb= &me->disp;
			if(lb->first==NULL) addnormalsDispList(ob, lb);
			
			dl= lb->first;
			if(dl==NULL) return;
			if(dl->nors==NULL) addnormalsDispList(ob, lb);
			
			if(mesh_uses_displist(me)) {
				int vertexpaint= (G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT)) && (ob==((G.scene->basact) ? (G.scene->basact->object) : 0));

					/* vertexpaint only true when selecting */
				if (vertexpaint) {
					drawmeshsolid(ob, NULL);
				} else {
					init_gl_materials(ob);
					two_sided(me->flag & ME_TWOSIDED);
					drawDispListsolid(lb, ob);
				}
			}
			else {
				drawmeshsolid(ob, dl->nors);
			}
			
		}
		else if(dt==OB_SHADED) {
			if( G.f & G_WEIGHTPAINT && me->dvert) {
				unsigned char *wtcol, *curwt;
				MFace *curface;
				int i;
				unsigned char r,g,b;
				float val1,val2,val3,val4=0;
				
				wtcol = curwt= MEM_callocN (sizeof (unsigned char) * me->totface*4*4, "weightmap");
				
				memset (wtcol, 0x55, sizeof (unsigned char) * me->totface*4*4);
				for (i=0, curface=(MFace*)me->mface; i<me->totface; i++, curface++){
					
					val1 = get_mvert_weight (ob, curface->v1, ob->actdef-1);
					val2 = get_mvert_weight (ob, curface->v2, ob->actdef-1);
					val3 = get_mvert_weight (ob, curface->v3, ob->actdef-1);
					if (curface->v4)
						val4 = get_mvert_weight (ob, curface->v4, ob->actdef-1);
					
					color_temperature (val1, &r, &g, &b);
					*curwt++=0; *curwt++=b; *curwt++=g; *curwt++=r;
					color_temperature (val2, &r, &g, &b);
					*curwt++=0; *curwt++=b; *curwt++=g; *curwt++=r;
					color_temperature (val3, &r, &g, &b);
					*curwt++=0; *curwt++=b; *curwt++=g; *curwt++=r;
					color_temperature (val4, &r, &g, &b);
					*curwt++=0; *curwt++=b; *curwt++=g; *curwt++=r;
					
				}
				
				drawmeshshaded(ob, (unsigned int*)wtcol, 0);
				
				MEM_freeN (wtcol);
				
			}
			else

			if( G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) {
				/* in order: vertexpaint already made mcol */
				if(me->mcol) {
					drawmeshshaded(ob, (unsigned int *)me->mcol, 0);
				} else if(me->tface) {
					tface_to_mcol(me);
					drawmeshshaded(ob, (unsigned int *)me->mcol, 0);	
					MEM_freeN(me->mcol); me->mcol= 0;
				}
				else 
					drawmeshwire(ob);
				
			}
			else {
				dl= ob->disp.first;
				
				if(dl==0 || dl->col1==0) {
					shadeDispList(ob);
					dl= ob->disp.first;
				}
				if(dl) {
					if(mesh_uses_displist(me)) {
						drawDispListshaded(&me->disp, ob);
					} else {
						drawmeshshaded(ob, dl->col1, dl->col2);
					}
				}
			}
		}
		
		if(ob==((G.scene->basact) ? (G.scene->basact->object) : 0) && (G.f & G_FACESELECT)) {
			draw_tfaces3D(ob, me);
		}
		
		break;
		
	case OB_FONT:
	case OB_CURVE:
		cu= ob->data;
		
		lb= &cu->disp;
		if(lb->first==0) makeDispList(ob);
		
		if(solid) {
			dl= lb->first;
			if(dl==0) return;
			
			/* rule: dl->type INDEX3 is always first in list */
			if(dl->type!=DL_INDEX3) {
				if(ob==G.obedit) curve_to_filledpoly(ob->data, &editNurb, lb);
				else curve_to_filledpoly(ob->data, &cu->nurb, lb);
				
				dl= lb->first;
			}
			if(dl->nors==0) addnormalsDispList(ob, lb);
			
			index3_nors_incr= 0;
			
			if( displist_has_faces(lb)==0) {
				draw_index_wire= 0;
				drawDispListwire(lb);
				draw_index_wire= 1;
			}
			else {
				if(dt==OB_SHADED) {
					if(ob->disp.first==0) shadeDispList(ob);
					drawDispListshaded(lb, ob);
				}
				else {
					init_gl_materials(ob);
					two_sided(0);
					drawDispListsolid(lb, ob);
				}
				if(ob==G.obedit) {
					cpack(0);
					draw_index_wire= 0;
					drawDispListwire(lb);
					draw_index_wire= 1;
				}
			}
			index3_nors_incr= 1;
		}
		else {
			draw_index_wire= 0;
			drawDispListwire(lb);
			draw_index_wire= 1;
		}
		break;
	case OB_SURF:
	
		lb= &((Curve *)ob->data)->disp;
		if(lb->first==0) makeDispList(ob);
		
		if(solid) {
			dl= lb->first;
			if(dl==0) return;
			
			if(dl->nors==0) addnormalsDispList(ob, lb);
			
			if(dt==OB_SHADED) {
				if(ob->disp.first==0) shadeDispList(ob);
				drawDispListshaded(lb, ob);
			}
			else {
				init_gl_materials(ob);
				two_sided(0);
			
				drawDispListsolid(lb, ob);
			}
		}
		else {
			drawDispListwire(lb);
		}
		break;
	case OB_MBALL:
		
		if( is_basis_mball(ob)) {
			lb= &ob->disp;
			if(lb->first==0) makeDispList(ob);
	
			if(solid) {
				
				if(dt==OB_SHADED) {
					dl= lb->first;
					if(dl && dl->col1==0) shadeDispList(ob);
					drawDispListshaded(lb, ob);
				}
				else {
					init_gl_materials(ob);
					two_sided(0);
				
					drawDispListsolid(lb, ob);	
				}
			}
			else{
				/* MetaBalls use DL_INDEX4 type of DispList */
				drawDispListwire(lb);
			}
		}
		break;
	}
	
}

/* ******************************** */


static void draw_particle_system(Object *ob, PartEff *paf)
{
	Particle *pa;
	float ptime, ctime, vec[3], vec1[3];
	int a;
	
	pa= paf->keys;
	if(pa==0) {
		build_particle_system(ob);
		pa= paf->keys;
		if(pa==0) return;
	}
	
	myloadmatrix(G.vd->viewmat);
	
	if(ob->ipoflag & OB_OFFS_PARTICLE) ptime= ob->sf;
	else ptime= 0.0;
	ctime= bsystem_time(ob, 0, (float)(G.scene->r.cfra), ptime);

	glPointSize(1.0);
	if(paf->stype!=PAF_VECT) glBegin(GL_POINTS);

	for(a=0; a<paf->totpart; a++, pa+=paf->totkey) {
		
		if(ctime > pa->time) {
			if(ctime < pa->time+pa->lifetime) {
			
				if(paf->stype==PAF_VECT) {
					where_is_particle(paf, pa, ctime, vec);
					where_is_particle(paf, pa, ctime+1.0, vec1);
		

					glBegin(GL_LINE_STRIP);
						glVertex3fv(vec);
						glVertex3fv(vec1);
					glEnd();
					
				}
				else {
					where_is_particle(paf, pa, ctime, vec);
					
					glVertex3fv(vec);
						
				}
			}
		}
	}
	if(paf->stype!=PAF_VECT) glEnd();
	
	mymultmatrix(ob->obmat);	// bring back local matrix for dtx
}

static void draw_static_particle_system(Object *ob, PartEff *paf)
{
	Particle *pa;
	float ctime, mtime, vec[3], vec1[3];
	int a;
	
	pa= paf->keys;
	if(pa==0) {
		build_particle_system(ob);
		pa= paf->keys;
		if(pa==0) return;
	}
	
	glPointSize(1.0);
	if(paf->stype!=PAF_VECT) glBegin(GL_POINTS);

	for(a=0; a<paf->totpart; a++, pa+=paf->totkey) {
		
		where_is_particle(paf, pa, pa->time, vec1);
		
		mtime= pa->time+pa->lifetime+paf->staticstep-1;
		
		for(ctime= pa->time; ctime<mtime; ctime+=paf->staticstep) {
			
			/* make sure hair grows until the end.. */ 
			if(ctime>pa->time+pa->lifetime) ctime= pa->time+pa->lifetime;
			
			if(paf->stype==PAF_VECT) {
				where_is_particle(paf, pa, ctime+1, vec);

				glBegin(GL_LINE_STRIP);
					glVertex3fv(vec);
					glVertex3fv(vec1);
				glEnd();
				
				VECCOPY(vec1, vec);
			}
			else {
				where_is_particle(paf, pa, ctime, vec);
				
				glVertex3fv(vec);
					
			}
		}
	}
	if(paf->stype!=PAF_VECT) glEnd();

}

/* edges are supposed to be drawn already */
static void drawmeshwire_creases(void)
{
	EditMesh *em = G.editMesh;
	EditEdge *eed;
	float fac, *v1, *v2, vec[3];
	
	glLineWidth(3.0);
	glBegin(GL_LINES);
	for(eed= em->edges.first; eed; eed= eed->next) {
		if(eed->h==0 && eed->crease!=0.0) {
			if(eed->f & SELECT) BIF_ThemeColor(TH_EDGE_SELECT);
			else BIF_ThemeColor(TH_WIRE);
			
			v1= eed->v1->co; v2= eed->v2->co;
			VECSUB(vec, v2, v1);
			fac= 0.5 + eed->crease/2.0;
			glVertex3f(v1[0] + fac*vec[0], v1[1] + fac*vec[1], v1[2] + fac*vec[2] );
			glVertex3f(v2[0] - fac*vec[0], v2[1] - fac*vec[1], v2[2] - fac*vec[2] );
		}
	}
	glEnd();
	glLineWidth(1.0);
	
}

static void glVertex_efa_edges(EditFace *efa)
{
	if(efa->e1->h==0) {
		glVertex3fv(efa->v1->co);
		glVertex3fv(efa->v2->co);
	}
	if(efa->e2->h==0) {
		glVertex3fv(efa->v2->co);
		glVertex3fv(efa->v3->co);
	}
	if(efa->e3->h==0) {
		glVertex3fv(efa->e3->v1->co);
		glVertex3fv(efa->e3->v2->co);
	}
	if(efa->e4 && efa->e4->h==0) {
		glVertex3fv(efa->e4->v1->co);
		glVertex3fv(efa->e4->v2->co);
	}
}

static void drawmeshwire_wirextra(DispListMesh *dlm, int optimal, char alpha)
{
	EditMesh *em= G.editMesh;
	EditFace *efa;
	EditEdge *eed;
	int a;
	char wire[4], sel[4];

	/* since this function does transparant... */
	BIF_GetThemeColor3ubv(TH_EDGE_SELECT, sel);
	BIF_GetThemeColor3ubv(TH_WIRE, wire);

	wire[3]= alpha;
	sel[3]= alpha;
	
	if(G.scene->selectmode == SCE_SELECT_FACE) {
		
		glBegin(GL_LINES);
		if(dlm && optimal) {
			MEdge *medge= dlm->medge;
			MVert *mvert= dlm->mvert;
			
			for (a=0; a<dlm->totedge; a++, medge++) {
				if(medge->flag & ME_EDGEDRAW) {
					eed= dlm->editedge[a];
					if(eed && eed->h==0) {
						if(eed->f & SELECT) glColor4ubv(sel);
						else glColor4ubv(wire);
						glVertex3fv(mvert[medge->v1].co); 
						glVertex3fv(mvert[medge->v2].co);
					}
				}
			}
		}
		else {
			/* draw faces twice, to have selected ones on top */
			/* we draw unselected the edges though, so they show in face mode */
			glColor4ubv(wire);
			for(eed= em->edges.first; eed; eed= eed->next) {
				if(eed->h==0) { 
					glVertex3fv(eed->v1->co);
					glVertex3fv(eed->v2->co);
				}
			}
			glColor4ubv(sel);
			for(efa= em->faces.first; efa; efa= efa->next) {
				if(efa->h==0 && (efa->f & SELECT)) { 
					glVertex_efa_edges(efa);
				}
			}
		}
		glEnd();
	}	
	else if( (G.f & G_DRAWEDGES) || (G.scene->selectmode & SCE_SELECT_EDGE) ) {	
		/* Use edge highlighting */
		
		/* (bleeding edges) to illustrate selection is defined on vertex basis */
		/* but cannot do with subdivided edges... */
		if( (dlm==NULL || optimal==0) && (G.scene->selectmode & SCE_SELECT_VERTEX)) {
			glShadeModel(GL_SMOOTH);
			glBegin(GL_LINES);
			
			for(eed= em->edges.first; eed; eed= eed->next) {
				if(eed->h==0) {
					if(eed->v1->f & SELECT) glColor4ubv(sel);
					else glColor4ubv(wire);
					glVertex3fv(eed->v1->co);
					if(eed->v2->f & SELECT) glColor4ubv(sel);
					else glColor4ubv(wire);
					glVertex3fv(eed->v2->co);
				}
			}
			glEnd();
			glShadeModel(GL_FLAT);
		}
		else {
			glBegin(GL_LINES);
			if(dlm && optimal) {
				MEdge *medge= dlm->medge;
				MVert *mvert= dlm->mvert;
				
				for (a=0; a<dlm->totedge; a++, medge++) {
					if(medge->flag & ME_EDGEDRAW) {
						eed= dlm->editedge[a];
						if(eed && eed->h==0) {
							if(eed->f & SELECT) glColor4ubv(sel);
							else glColor4ubv(wire);
							glVertex3fv(mvert[medge->v1].co); 
							glVertex3fv(mvert[medge->v2].co);
						}
					}
				}
			}
			else {
				glBegin(GL_LINES);
				for(eed= em->edges.first; eed; eed= eed->next) {
					if(eed->h==0) {
						if(eed->f & SELECT) glColor4ubv(sel);
						else glColor4ubv(wire);
						glVertex3fv(eed->v1->co);
						glVertex3fv(eed->v2->co);
					}
				}
			}
			glEnd();
		}
	}
	else {
		glColor4ubv(wire);
		glBegin(GL_LINES);
		if(dlm && optimal) {
			MEdge *medge= dlm->medge;
			MVert *mvert= dlm->mvert;
			
			for (a=0; a<dlm->totedge; a++, medge++) {
				if(medge->flag & ME_EDGEDRAW) {
					eed= dlm->editedge[a];
					if(eed && eed->h==0) {
						glVertex3fv(mvert[medge->v1].co); 
						glVertex3fv(mvert[medge->v2].co);
					}
				}
			}
		}
		else {
			for(eed= em->edges.first; eed; eed= eed->next) {
				if(eed->h==0) {
					glVertex3fv(eed->v1->co);
					glVertex3fv(eed->v2->co);
				}
			}
		}
		glEnd();
	}
}	

static void drawmeshwire_seams(DispListMesh *dlm, int optimal)
{
	EditMesh *em= G.editMesh;
	EditEdge *eed;

	BIF_ThemeColor(TH_EDGE_SEAM);
	glLineWidth(2);

	if(dlm && optimal) {
		MEdge *medge= dlm->medge;
		MVert *mvert= dlm->mvert;
		int a;
	
		glBegin(GL_LINES);
		for (a=0; a<dlm->totedge; a++, medge++) {
			if(medge->flag & ME_EDGEDRAW) {
				eed= dlm->editedge[a];
				if(eed && eed->h==0 && eed->seam) {
					glVertex3fv(mvert[medge->v1].co); 
					glVertex3fv(mvert[medge->v2].co);
				}
			}
		}
		glEnd();
	}
	else {
		glBegin(GL_LINES);
		for(eed= em->edges.first; eed; eed= eed->next) {
			if(eed->h==0 && eed->seam) {
				glVertex3fv(eed->v1->co);
				glVertex3fv(eed->v2->co);
			}
		}
		glEnd();
	}

	cpack(0x0);
	glLineWidth(1);
}

static void drawmeshwire(Object *ob)
{
	EditMesh *em = G.editMesh;
	extern float editbutsize;	/* buttons.c */
	Mesh *me;
	MVert *mvert;
	MFace *mface;
	DispList *dl;
	Material *ma;
	EditFace *efa;
	float fvec[3], *f1, *f2, *f3, *f4, *extverts=NULL;
	int a, start, end, test, ok, optimal=0;

	me= get_mesh(ob);

	if(ob==G.obedit || (G.obedit && ob->data==G.obedit->data)) {
		DispList *dl= find_displist(&me->disp, DL_MESH);
		DispListMesh *dlm= NULL;
		if(dl) dlm= dl->mesh;
		
		optimal= subsurf_optimal(ob);
		
		if( (G.f & (G_FACESELECT+G_DRAWFACES))) {	/* transp faces */
			char col1[4], col2[4];
			
			BIF_GetThemeColor4ubv(TH_FACE, col1);
			BIF_GetThemeColor4ubv(TH_FACE_SELECT, col2);
			
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glEnable(GL_BLEND);
			glDepthMask(0);		// disable write in zbuffer, needed for nice transp
			
			if(dlm && optimal) {
				for(a=0, mface= dlm->mface; a<dlm->totface; a++, mface++) {
					if(mface->v3) {
						efa= dlm->editface[a];
						if(efa->f & SELECT) glColor4ub(col2[0], col2[1], col2[2], col2[3]); 
						else glColor4ub(col1[0], col1[1], col1[2], col1[3]);
						
						glBegin(mface->v4?GL_QUADS:GL_TRIANGLES);
						glVertex3fv(dlm->mvert[mface->v1].co);
						glVertex3fv(dlm->mvert[mface->v2].co);
						glVertex3fv(dlm->mvert[mface->v3].co);
						if (mface->v4) glVertex3fv(dlm->mvert[mface->v4].co);
						glEnd();
					}
				}
			}
			else {
				for(efa= em->faces.first; efa; efa= efa->next) {
					if(efa->h==0) {
						
						if(efa->f & SELECT) glColor4ub(col2[0], col2[1], col2[2], col2[3]); 
						else glColor4ub(col1[0], col1[1], col1[2], col1[3]);
						
						glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
						glVertex3fv(efa->v1->co);
						glVertex3fv(efa->v2->co);
						glVertex3fv(efa->v3->co);
						if(efa->v4) glVertex3fv(efa->v4->co);
						glEnd();
					}
				}
			}

			glDisable(GL_BLEND);
			glDepthMask(1);		// restore write in zbuffer
		}
		
		// in editmode it now draws the greyed out part, or optimized 
		if(mesh_uses_displist(me)) {
			
			/* dont draw the subsurf when solid... then this is a 'drawextra' */
			if(ob->dt>OB_WIRE && G.vd->drawtype>OB_WIRE);
			else {
				BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
				drawDispListwire(&me->disp);
			}
		}
		
		/* here starts all fancy draw-extra over */
		
		if(G.f & G_DRAWSEAMS)
			drawmeshwire_seams(dlm, optimal);

		/* show wires in transparant when no zbuf clipping for select */
		if(G.zbuf && (G.vd->flag & V3D_ZBUF_SELECT)==0) {
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glEnable(GL_BLEND);
			glDisable(GL_DEPTH_TEST);
			drawmeshwire_wirextra(dlm, optimal, 85);
			glDisable(GL_BLEND);
			glEnable(GL_DEPTH_TEST);
		}
		drawmeshwire_wirextra(dlm, optimal, 255);

		if(G.f & G_DRAWCREASES) drawmeshwire_creases();

		if(ob!=G.obedit) return;
		
		calc_meshverts();

		draw_vertices(optimal, 0);
		draw_vertices(optimal, 1);

		if(G.f & G_DRAWNORMALS) {	/* normals */
			/*cpack(0xDDDD22);*/
			BIF_ThemeColor(TH_NORMAL);

			glBegin(GL_LINES);
			
			efa= em->faces.first;
			while(efa) {
				if(efa->h==0 && efa->fgonf!=EM_FGON) {
					VECCOPY(fvec, efa->cent);
					glVertex3fv(fvec);
					fvec[0]+= editbutsize*efa->n[0];
					fvec[1]+= editbutsize*efa->n[1];
					fvec[2]+= editbutsize*efa->n[2];
					glVertex3fv(fvec);
					
				}
				efa= efa->next;
			}

			glEnd();
		}
	}
	else { /* Object mode draw */
		
		if(me==NULL) return;
		
		if(me->bb==NULL) tex_space_mesh(me);
		if(me->totface>4) if(boundbox_clip(ob->obmat, me->bb)==0) return;
		
		/* check for drawing vertices only */
		ok= 0;
		if(me->totface==0 && me->totedge==0) ok= 1;
		else {
			ma= give_current_material(ob, 1);
			if(ma && (ma->mode & MA_HALO)) ok= 1;
		}
		mvert= me->mvert;
		mface= me->mface;
		
		dl= find_displist(&ob->disp, DL_VERTS);
		if(dl) extverts= dl->verts;
					
		if(ok) {
			start= 0; end= me->totvert;
			set_buildvars(ob, &start, &end);
			
			glPointSize(1.5);
			glBegin(GL_POINTS);
		
			if(extverts) {
				extverts+= 3*start;
				for(a= start; a<end; a++, extverts+=3) { /* DispList found, Draw displist */
					glVertex3fv(extverts);
				}
			}
			else {
				mvert+= start;
				for(a= start; a<end; a++, mvert++) { /* else Draw mesh verts directly */
					glVertex3fv(mvert->co);
				}
			}
			glEnd();
			glPointSize(1.0);
		}
		else {
	
			if(mesh_uses_displist(me)) drawDispListwire(&me->disp); /* Subsurf */
			else {
				
				/* build effect only works on faces */
				start= 0; end= me->totface;
				set_buildvars(ob, &start, &end);
				mface+= start;
				
				/* now decide whether to draw edges block */
				if(me->medge && start==0 && end==me->totface) {
					MEdge *medge= me->medge;
					
					glBegin(GL_LINES);
					for(a=me->totedge; a>0; a--, medge++) {
						if(medge->flag & ME_EDGEDRAW) {
							if(extverts) {
								f1= extverts+3*medge->v1;
								f2= extverts+3*medge->v2;
							}
							else {
								f1= (mvert+medge->v1)->co;
								f2= (mvert+medge->v2)->co;
							}
							glVertex3fv(f1); glVertex3fv(f2); 
						}
					}
					glEnd();
				}
				else {
				
					for(a=start; a<end; a++, mface++) {
						test= mface->edcode;
						
						if(test) {
							if(extverts) {
								f1= extverts+3*mface->v1;
								f2= extverts+3*mface->v2;
							}
							else {
								f1= (mvert+mface->v1)->co;
								f2= (mvert+mface->v2)->co;
							}
							
							if(mface->v4) {
								if(extverts) {
									f3= extverts+3*mface->v3;
									f4= extverts+3*mface->v4;
								}
								else {
									f3= (mvert+mface->v3)->co;
									f4= (mvert+mface->v4)->co;
								}
								
								if(test== ME_V1V2+ME_V2V3+ME_V3V4+ME_V4V1) {
									glBegin(GL_LINE_LOOP);
										glVertex3fv(f1); glVertex3fv(f2); glVertex3fv(f3); glVertex3fv(f4);
									glEnd();
								}
								else if(test== ME_V1V2+ME_V2V3+ME_V3V4) {
		
									glBegin(GL_LINE_STRIP);
										glVertex3fv(f1); glVertex3fv(f2); glVertex3fv(f3); glVertex3fv(f4);
									glEnd();
								}
								else if(test== ME_V2V3+ME_V3V4+ME_V4V1) {
		
									glBegin(GL_LINE_STRIP);
										glVertex3fv(f2); glVertex3fv(f3); glVertex3fv(f4); glVertex3fv(f1);
									glEnd();
								}
								else if(test== ME_V3V4+ME_V4V1+ME_V1V2) {
		
									glBegin(GL_LINE_STRIP);
										glVertex3fv(f3); glVertex3fv(f4); glVertex3fv(f1); glVertex3fv(f2);
									glEnd();
								}
								else if(test== ME_V4V1+ME_V1V2+ME_V2V3) {
		
									glBegin(GL_LINE_STRIP);
										glVertex3fv(f4); glVertex3fv(f1); glVertex3fv(f2); glVertex3fv(f3);
									glEnd();
								}
								else {
									if(test & ME_V1V2) {
		
										glBegin(GL_LINE_STRIP);
											glVertex3fv(f1); glVertex3fv(f2);
										glEnd();
									}
									if(test & ME_V2V3) {
		
										glBegin(GL_LINE_STRIP);
											glVertex3fv(f2); glVertex3fv(f3);
										glEnd();
									}
									if(test & ME_V3V4) {
		
										glBegin(GL_LINE_STRIP);
											glVertex3fv(f3); glVertex3fv(f4);
										glEnd();
									}
									if(test & ME_V4V1) {
		
										glBegin(GL_LINE_STRIP);
											glVertex3fv(f4); glVertex3fv(f1);
										glEnd();
									}
								}
							}
							else if(mface->v3) {
								if(extverts) f3= extverts+3*mface->v3;
								else f3= (mvert+mface->v3)->co;
			
								if(test== ME_V1V2+ME_V2V3+ME_V3V1) {
									glBegin(GL_LINE_LOOP);
										glVertex3fv(f1); glVertex3fv(f2); glVertex3fv(f3);
									glEnd();
								}
								else if(test== ME_V1V2+ME_V2V3) {
		
									glBegin(GL_LINE_STRIP);
										glVertex3fv(f1); glVertex3fv(f2); glVertex3fv(f3);
									glEnd();
								}
								else if(test== ME_V2V3+ME_V3V1) {
		
									glBegin(GL_LINE_STRIP);
										glVertex3fv(f2); glVertex3fv(f3); glVertex3fv(f1);
									glEnd();
								}
								else if(test== ME_V1V2+ME_V3V1) {
		
									glBegin(GL_LINE_STRIP);
										glVertex3fv(f3); glVertex3fv(f1); glVertex3fv(f2);
									glEnd();
								}
								else {
									if(test & ME_V1V2) {
		
										glBegin(GL_LINE_STRIP);
											glVertex3fv(f1); glVertex3fv(f2);
										glEnd();
									}
									if(test & ME_V2V3) {
		
										glBegin(GL_LINE_STRIP);
											glVertex3fv(f2); glVertex3fv(f3);
										glEnd();
									}
									if(test & ME_V3V1) {
		
										glBegin(GL_LINE_STRIP);
											glVertex3fv(f3); glVertex3fv(f1);
										glEnd();
									}
								}
							}
							else if(test & ME_V1V2) {
		
								glBegin(GL_LINE_STRIP);
									glVertex3fv(f1); glVertex3fv(f2);
								glEnd();
							}
						}
					}
				}
			}
		}
	}
}

unsigned int nurbcol[8]= {
	0, 0x9090, 0x409030, 0x603080, 0, 0x40fff0, 0x40c033, 0xA090F0 };

static void tekenhandlesN(Nurb *nu, short sel)
{
	BezTriple *bezt;
	float *fp;
	unsigned int *col;
	int a;

	if(nu->hide) return;
	if( (nu->type & 7)==1) {
		if(sel) col= nurbcol+4;
		else col= nurbcol;

		bezt= nu->bezt;
		a= nu->pntsu;
		while(a--) {
			if(bezt->hide==0) {
				if( (bezt->f2 & 1)==sel) {
					fp= bezt->vec[0];
					cpack(col[bezt->h1]);

					glBegin(GL_LINE_STRIP); 
					glVertex3fv(fp);
					glVertex3fv(fp+3); 
					glEnd();
					cpack(col[bezt->h2]);

					glBegin(GL_LINE_STRIP); 
					glVertex3fv(fp+3); 
					glVertex3fv(fp+6); 
					glEnd();
				}
				else if( (bezt->f1 & 1)==sel) {
					fp= bezt->vec[0];
					cpack(col[bezt->h1]);

					glBegin(GL_LINE_STRIP); 
					glVertex3fv(fp); 
					glVertex3fv(fp+3); 
					glEnd();
				}
				else if( (bezt->f3 & 1)==sel) {
					fp= bezt->vec[1];
					cpack(col[bezt->h2]);

					glBegin(GL_LINE_STRIP); 
					glVertex3fv(fp); 
					glVertex3fv(fp+3); 
					glEnd();
				}
			}
			bezt++;
		}
	}
}

static void tekenvertsN(Nurb *nu, short sel)
{
	BezTriple *bezt;
	BPoint *bp;
	float size;
	int a;

	if(nu->hide) return;

	if(sel) BIF_ThemeColor(TH_VERTEX_SELECT);
	else BIF_ThemeColor(TH_VERTEX);

	size= BIF_GetThemeValuef(TH_VERTEX_SIZE);
	glPointSize(size);
	
	bglBegin(GL_POINTS);
	
	if((nu->type & 7)==1) {

		bezt= nu->bezt;
		a= nu->pntsu;
		while(a--) {
			if(bezt->hide==0) {
				if((bezt->f1 & 1)==sel) bglVertex3fv(bezt->vec[0]);
				if((bezt->f2 & 1)==sel) bglVertex3fv(bezt->vec[1]);
				if((bezt->f3 & 1)==sel) bglVertex3fv(bezt->vec[2]);
			}
			bezt++;
		}
	}
	else {
		bp= nu->bp;
		a= nu->pntsu*nu->pntsv;
		while(a--) {
			if(bp->hide==0) {
				if((bp->f1 & 1)==sel) bglVertex3fv(bp->vec);
			}
			bp++;
		}
	}
	
	bglEnd();
	glPointSize(1.0);
}

static void draw_editnurb(Object *ob, Nurb *nurb, int sel)
{
	Nurb *nu;
	BPoint *bp, *bp1;
	int a, b, ofs;
	
	nu= nurb;
	while(nu) {
		if(nu->hide==0) {
			switch(nu->type & 7) {
			case CU_POLY:
				cpack(nurbcol[3]);
				bp= nu->bp;
				for(b=0; b<nu->pntsv; b++) {
					if(nu->flagu & 1) glBegin(GL_LINE_LOOP);

					else glBegin(GL_LINE_STRIP);

					for(a=0; a<nu->pntsu; a++, bp++) {
						glVertex3fv(bp->vec);
					}

					if(nu->flagu & 1) glEnd();
					else glEnd();
				}
				break;
			case CU_NURBS:

				bp= nu->bp;
				for(b=0; b<nu->pntsv; b++) {
					bp1= bp;
					bp++;
					for(a=nu->pntsu-1; a>0; a--, bp++) {
						if(bp->hide==0 && bp1->hide==0) {
							if(sel) {
								if( (bp->f1 & 1) && ( bp1->f1 & 1) ) {
									cpack(nurbcol[5]);
		
									glBegin(GL_LINE_STRIP);
									glVertex3fv(bp->vec); 
									glVertex3fv(bp1->vec);
									glEnd();
								}
							}
							else {
								if( (bp->f1 & 1) && ( bp1->f1 & 1) );
								else {
									cpack(nurbcol[1]);
		
									glBegin(GL_LINE_STRIP);
									glVertex3fv(bp->vec); 
									glVertex3fv(bp1->vec);
									glEnd();
								}
							}
						}
						bp1= bp;
					}
				}
				if(nu->pntsv > 1) {	/* surface */

					ofs= nu->pntsu;
					for(b=0; b<nu->pntsu; b++) {
						bp1= nu->bp+b;
						bp= bp1+ofs;
						for(a=nu->pntsv-1; a>0; a--, bp+=ofs) {
							if(bp->hide==0 && bp1->hide==0) {
								if(sel) {
									if( (bp->f1 & 1) && ( bp1->f1 & 1) ) {
										cpack(nurbcol[7]);
			
										glBegin(GL_LINE_STRIP);
										glVertex3fv(bp->vec); 
										glVertex3fv(bp1->vec);
										glEnd();
									}
								}
								else {
									if( (bp->f1 & 1) && ( bp1->f1 & 1) );
									else {
										cpack(nurbcol[3]);
			
										glBegin(GL_LINE_STRIP);
										glVertex3fv(bp->vec); 
										glVertex3fv(bp1->vec);
										glEnd();
									}
								}
							}
							bp1= bp;
						}
					}

				}
				break;
			}
		}
		nu= nu->next;
	}
}

static void drawnurb(Object *ob, Nurb *nurb, int dt)
{
	extern float editbutsize;	/* buttons.c */
	Curve *cu;
	Nurb *nu;
	BevPoint *bevp;
	BevList *bl;
	float vec[3];
	int a, nr, skip;

	/* first non-selected handles */
	nu= nurb;
	while(nu) {
		if((nu->type & 7)==CU_BEZIER) {
			tekenhandlesN(nu, 0);
		}
		nu= nu->next;
	}
	
	/* then DispList */
	
	BIF_ThemeColor(TH_WIRE);
	cu= ob->data;
	drawDispList(ob, dt);

	draw_editnurb(ob, nurb, 0);
	draw_editnurb(ob, nurb, 1);

	if(cu->flag & CU_3D) {
	
		if(cu->bev.first==0) makeBevelList(ob);
		
		BIF_ThemeColor(TH_WIRE);
		bl= cu->bev.first;
		nu= nurb;
		while(nu && bl) {
			bevp= (BevPoint *)(bl+1);		
			nr= bl->nr;
			
			skip= nu->resolu/16;
			
			while(nr-- > 0) {
				
				glBegin(GL_LINE_STRIP);
				vec[0]= bevp->x-editbutsize*bevp->mat[0][0];
				vec[1]= bevp->y-editbutsize*bevp->mat[0][1];
				vec[2]= bevp->z-editbutsize*bevp->mat[0][2];
				glVertex3fv(vec);
				vec[0]= bevp->x+editbutsize*bevp->mat[0][0];
				vec[1]= bevp->y+editbutsize*bevp->mat[0][1];
				vec[2]= bevp->z+editbutsize*bevp->mat[0][2];
				glVertex3fv(vec);

				glEnd();
				
				bevp++;
				
				a= skip;
				while(a--) {
					bevp++;
					nr--;
				}
			}

			bl= bl->next;
			nu= nu->next;
		}
	}

	calc_Nurbverts(nurb);

	if(G.zbuf) glDisable(GL_DEPTH_TEST);
	
	nu= nurb;
	while(nu) {
		if((nu->type & 7)==1) tekenhandlesN(nu, 1);
		tekenvertsN(nu, 0);
		nu= nu->next;
	}

	nu= nurb;
	while(nu) {
		tekenvertsN(nu, 1);
		nu= nu->next;
	}
	
	if(G.zbuf) glEnable(GL_DEPTH_TEST); 
}

static void tekentextcurs(void)
{
	cpack(0);

	glBegin(GL_QUADS);
	glVertex2fv(G.textcurs[0]);
	glVertex2fv(G.textcurs[1]);
	glVertex2fv(G.textcurs[2]);
	glVertex2fv(G.textcurs[3]);
	glEnd();
}

void drawspiral(float *cent, float rad, float tmat[][4], int start)
{
	float vec[3], vx[3], vy[3];
	int a, tot=32;
	char inverse=0;
	/* 32 values of sin function (still same result!) */
	static float si[32] = {0.00000000,
		0.20129852,
		0.39435585,
		0.57126821,
		0.72479278,
		0.84864425,
		0.93775213,
		0.98846832,
		0.99871650,
		0.96807711,
		0.89780453,
		0.79077573,
		0.65137248,
		0.48530196,
		0.29936312,
		0.10116832,
		-0.10116832,
                -0.29936312,
                -0.48530196,
                -0.65137248,
                -0.79077573,
                -0.89780453,
                -0.96807711,
                -0.99871650,
                -0.98846832,
                -0.93775213,
                -0.84864425,
                -0.72479278,
                -0.57126821,
                -0.39435585,
                -0.20129852,
		0.00000000};
	/* 32 values of cos function (still same result!) */
	static float co[32] ={1.00000000,
                0.97952994,
                0.91895781,
                0.82076344,
                0.68896691,
                0.52896401,
                0.34730525,
                0.15142777,
                -0.05064916,
                -0.25065253,
                -0.44039415,
                -0.61210598,
                -0.75875812,
                -0.87434661,
                -0.95413925,
                -0.99486932,
                -0.99486932,
                -0.95413925,
                -0.87434661,
                -0.75875812,
                -0.61210598,
                -0.44039415,
                -0.25065253,
                -0.05064916,
                0.15142777,
                0.34730525,
                0.52896401,
                0.68896691,
                0.82076344,
                0.91895781,
                0.97952994,
                1.00000000};
		
	if (start < 0) {
		inverse = 1;
		start *= -1;
	}

	VECCOPY(vx, tmat[0]);
	VECCOPY(vy, tmat[1]);
	VecMulf(vx, rad);
	VecMulf(vy, rad);

	VECCOPY(vec, cent);

	if (inverse==0) {
		for(a=0; a<tot; a++) {
			if (a+start>31)
				start=-a + 1;
			glBegin(GL_LINES);							
			glVertex3fv(vec);
			vec[0]= cent[0] + *(si+a+start) * (vx[0] * (float)a/(float)tot) + *(co+a+start) * (vy[0] * (float)a/(float)tot);
			vec[1]= cent[1] + *(si+a+start) * (vx[1] * (float)a/(float)tot) + *(co+a+start) * (vy[1] * (float)a/(float)tot);
			vec[2]= cent[2] + *(si+a+start) * (vx[2] * (float)a/(float)tot) + *(co+a+start) * (vy[2] * (float)a/(float)tot);
			glVertex3fv(vec);
			glEnd();
		}
	}
	else {
		a=0;
		vec[0]= cent[0] + *(si+a+start) * (vx[0] * (float)(-a+31)/(float)tot) + *(co+a+start) * (vy[0] * (float)(-a+31)/(float)tot);
		vec[1]= cent[1] + *(si+a+start) * (vx[1] * (float)(-a+31)/(float)tot) + *(co+a+start) * (vy[1] * (float)(-a+31)/(float)tot);
		vec[2]= cent[2] + *(si+a+start) * (vx[2] * (float)(-a+31)/(float)tot) + *(co+a+start) * (vy[2] * (float)(-a+31)/(float)tot);
		for(a=0; a<tot; a++) {
			if (a+start>31)
				start=-a + 1;
			glBegin(GL_LINES);							
			glVertex3fv(vec);
			vec[0]= cent[0] + *(si+a+start) * (vx[0] * (float)(-a+31)/(float)tot) + *(co+a+start) * (vy[0] * (float)(-a+31)/(float)tot);
			vec[1]= cent[1] + *(si+a+start) * (vx[1] * (float)(-a+31)/(float)tot) + *(co+a+start) * (vy[1] * (float)(-a+31)/(float)tot);
			vec[2]= cent[2] + *(si+a+start) * (vx[2] * (float)(-a+31)/(float)tot) + *(co+a+start) * (vy[2] * (float)(-a+31)/(float)tot);
			glVertex3fv(vec);
			glEnd();
		}
	}
}

void drawcircball(float *cent, float rad, float tmat[][4])
{
	float vec[3], vx[3], vy[3];
	int a, tot=32;

	/* 32 values of sin function (still same result!) */
	static float si[32] = {0.00000000,
		0.20129852,
		0.39435585,
		0.57126821,
		0.72479278,
		0.84864425,
		0.93775213,
		0.98846832,
		0.99871650,
		0.96807711,
		0.89780453,
		0.79077573,
		0.65137248,
		0.48530196,
		0.29936312,
		0.10116832,
		-0.10116832,
                -0.29936312,
                -0.48530196,
                -0.65137248,
                -0.79077573,
                -0.89780453,
                -0.96807711,
                -0.99871650,
                -0.98846832,
                -0.93775213,
                -0.84864425,
                -0.72479278,
                -0.57126821,
                -0.39435585,
                -0.20129852,
		0.00000000};
	/* 32 values of cos function (still same result!) */
	static float co[32] ={1.00000000,
                0.97952994,
                0.91895781,
                0.82076344,
                0.68896691,
                0.52896401,
                0.34730525,
                0.15142777,
                -0.05064916,
                -0.25065253,
                -0.44039415,
                -0.61210598,
                -0.75875812,
                -0.87434661,
                -0.95413925,
                -0.99486932,
                -0.99486932,
                -0.95413925,
                -0.87434661,
                -0.75875812,
                -0.61210598,
                -0.44039415,
                -0.25065253,
                -0.05064916,
                0.15142777,
                0.34730525,
                0.52896401,
                0.68896691,
                0.82076344,
                0.91895781,
                0.97952994,
                1.00000000};
		
	VECCOPY(vx, tmat[0]);
	VECCOPY(vy, tmat[1]);
	VecMulf(vx, rad);
	VecMulf(vy, rad);
	
	glBegin(GL_LINE_LOOP);
	for(a=0; a<tot; a++) {
		vec[0]= cent[0] + *(si+a) * vx[0] + *(co+a) * vy[0];
		vec[1]= cent[1] + *(si+a) * vx[1] + *(co+a) * vy[1];
		vec[2]= cent[2] + *(si+a) * vx[2] + *(co+a) * vy[2];
		glVertex3fv(vec);
	}
	glEnd();
}

static void drawmball(Object *ob, int dt)
{
	MetaBall *mb;
	MetaElem *ml;
	float imat[4][4], tmat[4][4];
	int code= 1;
	
	mb= ob->data;

	if(ob==G.obedit) {
		BIF_ThemeColor(TH_WIRE);
		if((G.f & G_PICKSEL)==0 ) drawDispList(ob, dt);
		ml= editelems.first;
	}
	else {
		drawDispList(ob, dt);
		ml= mb->elems.first;
	}

	/* in case solid draw, reset wire colors */
	if(ob!=G.obedit && (ob->flag & SELECT)) {
		if(ob==OBACT) BIF_ThemeColor(TH_ACTIVE);
		else BIF_ThemeColor(TH_SELECT);
	}
	else BIF_ThemeColor(TH_WIRE);

	mygetmatrix(tmat);
	Mat4Invert(imat, tmat);
	Normalise(imat[0]);
	Normalise(imat[1]);
	
	while(ml) {
		
		if(ob==G.obedit) {
			if(ml->flag & SELECT) cpack(0xA0A0F0);
			else cpack(0x3030A0);
			
			if(G.f & G_PICKSEL) {
				ml->selcol= code;
				glLoadName(code++);
			}
		}
		drawcircball(&(ml->x), ml->rad, imat);
		
		ml= ml->next;
	}
}

static void draw_forcefield(Object *ob)
{
	float imat[4][4], tmat[4][4];
	float vec[3]= {0.0, 0.0, 0.0};
	
	if (ob->pd->forcefield == PFIELD_FORCE) {
		float ffall_val;

		mygetmatrix(tmat);
		Mat4Invert(imat, tmat);
		Normalise(imat[0]);
		Normalise(imat[1]);
		if (has_ipo_code(ob->ipo, OB_PD_FFALL)) 
			ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, G.scene->r.cfra);
		else 
			ffall_val = ob->pd->f_power;

		BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.5);
		drawcircball(vec, 1.0, imat);
		BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.9 - 0.4 / pow(1.5, (double)ffall_val));
		drawcircball(vec, 1.5, imat);
		BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.9 - 0.4 / pow(2.0, (double)ffall_val));
		drawcircball(vec, 2.0, imat);
	}
	else if (ob->pd->forcefield == PFIELD_VORTEX) {
		float ffall_val, force_val;

		Mat4One(imat);
		if (has_ipo_code(ob->ipo, OB_PD_FFALL)) 
			ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, G.scene->r.cfra);
		else 
			ffall_val = ob->pd->f_power;

		if (has_ipo_code(ob->ipo, OB_PD_FSTR))
			force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, G.scene->r.cfra);
		else 
			force_val = ob->pd->f_strength;

		BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
		if (force_val < 0) {
			drawspiral(vec, 1.0, imat, 1);
			drawspiral(vec, 1.0, imat, 16);
		}
		else {
			drawspiral(vec, 1.0, imat, -1);
			drawspiral(vec, 1.0, imat, -16);
		}
	}
	
}

static void draw_bb_box(BoundBox *bb)
{
	float *vec;

	vec= bb->vec[0];

	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec); glVertex3fv(vec+3);glVertex3fv(vec+6); glVertex3fv(vec+9);
		glVertex3fv(vec); glVertex3fv(vec+12);glVertex3fv(vec+15); glVertex3fv(vec+18);
		glVertex3fv(vec+21); glVertex3fv(vec+12);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec+3); glVertex3fv(vec+15);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec+6); glVertex3fv(vec+18);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec+9); glVertex3fv(vec+21);
	glEnd();
	
}

void get_local_bounds(Object *ob, float *centre, float *size)
{
	BoundBox *bb= NULL;
	/* uses boundbox, function used by Ketsji */
	
	if(ob->type==OB_MESH) {
		bb= ( (Mesh *)ob->data )->bb;
		if(bb==0) {
			tex_space_mesh(ob->data);
			bb= ( (Mesh *)ob->data )->bb;
		}
	}
	else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
		bb= ( (Curve *)ob->data )->bb;
	}
	else if(ob->type==OB_MBALL) {
		bb= ob->bb;
	}
	if(bb==NULL) {
		centre[0]= centre[1]= centre[2]= 0.0;
		VECCOPY(size, ob->size);
	}
	else {
		size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]);
		size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]);
		size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]);
		
		centre[0]= (bb->vec[0][0] + bb->vec[4][0])/2.0;
		centre[1]= (bb->vec[0][1] + bb->vec[2][1])/2.0;
		centre[2]= (bb->vec[0][2] + bb->vec[1][2])/2.0;
	}
}



static void draw_bb_quadric(BoundBox *bb, short type)
{
	float size[3], cent[3];
	GLUquadricObj *qobj = gluNewQuadric(); 
	
	gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); 
	
	size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]);
	size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]);
	size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]);
	
	cent[0]= (bb->vec[0][0] + bb->vec[4][0])/2.0;
	cent[1]= (bb->vec[0][1] + bb->vec[2][1])/2.0;
	cent[2]= (bb->vec[0][2] + bb->vec[1][2])/2.0;
	
	glPushMatrix();
	if(type==OB_BOUND_SPHERE) {
		glTranslatef(cent[0], cent[1], cent[2]);
		glScalef(size[0], size[1], size[2]);
		gluSphere(qobj, 1.0, 8, 5);
	}	
	else if(type==OB_BOUND_CYLINDER) {
		float radius = size[0] > size[1] ? size[0] : size[1];
		glTranslatef(cent[0], cent[1], cent[2]-size[2]);
		glScalef(radius, radius, 2.0*size[2]);
		gluCylinder(qobj, 1.0, 1.0, 1.0, 8, 1);
	}
	else if(type==OB_BOUND_CONE) {
		float radius = size[0] > size[1] ? size[0] : size[1];
		glTranslatef(cent[0], cent[2]-size[2], cent[1]);
		glScalef(radius, 2.0*size[2], radius);
		glRotatef(-90., 1.0, 0.0, 0.0);
		gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1);
	}
	glPopMatrix();
	
	gluDeleteQuadric(qobj); 
}

static void draw_bounding_volume(Object *ob)
{
	BoundBox *bb=0;
	
	if(ob->type==OB_MESH) {
		bb= ( (Mesh *)ob->data )->bb;
		if(bb==0) {
			tex_space_mesh(ob->data);
			bb= ( (Mesh *)ob->data )->bb;
		}
	}
	else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
		bb= ( (Curve *)ob->data )->bb;
		if(bb==0) {
			makeDispList(ob);
			bb= ( (Curve *)ob->data )->bb;
		}
	}
	else if(ob->type==OB_MBALL) {
		bb= ob->bb;
		if(bb==0) {
			makeDispList(ob);
			bb= ob->bb;
		}
	}
	else {
		drawcube();
		return;
	}
	
	if(bb==0) return;
	
	if(ob->boundtype==OB_BOUND_BOX) draw_bb_box(bb);
	else draw_bb_quadric(bb, ob->boundtype);
	
}

static void drawtexspace(Object *ob)
{
	Mesh *me;
	MetaBall *mb;
	Curve *cu;
	BoundBox bb;
	float *vec, *loc, *size;
	
	if(ob->type==OB_MESH) {
		me= ob->data;
		size= me->size;
		loc= me->loc;
	}
	else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
		cu= ob->data;
		size= cu->size;
		loc= cu->loc;
	}
	else if(ob->type==OB_MBALL) {
		mb= ob->data;
		size= mb->size;
		loc= mb->loc;
	}
	else return;
	
	bb.vec[0][0]=bb.vec[1][0]=bb.vec[2][0]=bb.vec[3][0]= loc[0]-size[0];
	bb.vec[4][0]=bb.vec[5][0]=bb.vec[6][0]=bb.vec[7][0]= loc[0]+size[0];
	
	bb.vec[0][1]=bb.vec[1][1]=bb.vec[4][1]=bb.vec[5][1]= loc[1]-size[1];
	bb.vec[2][1]=bb.vec[3][1]=bb.vec[6][1]=bb.vec[7][1]= loc[1]+size[1];

	bb.vec[0][2]=bb.vec[3][2]=bb.vec[4][2]=bb.vec[7][2]= loc[2]-size[2];
	bb.vec[1][2]=bb.vec[2][2]=bb.vec[5][2]=bb.vec[6][2]= loc[2]+size[2];
	
	setlinestyle(2);
		
	vec= bb.vec[0];

	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec); glVertex3fv(vec+3);glVertex3fv(vec+6); glVertex3fv(vec+9);
		glVertex3fv(vec); glVertex3fv(vec+12);glVertex3fv(vec+15); glVertex3fv(vec+18);
		glVertex3fv(vec+21); glVertex3fv(vec+12);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec+3); glVertex3fv(vec+15);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec+6); glVertex3fv(vec+18);
	glEnd();

	glBegin(GL_LINE_STRIP);
		glVertex3fv(vec+9); glVertex3fv(vec+21);
	glEnd();
	
	setlinestyle(0);
}

static int ob_from_decimator(Object *ob)
{
	/* note: this is a temporal solution, a reconstruction of the
	   displist system should take care of it (ton)
	*/
	DispList *dl;
	
	dl= ob->disp.first;

	if(dl && dl->mesh) return 1;
	
	return 0;
}

/* draws wire outline */
static void drawSolidSelect(Object *ob, ListBase *lb) 
{

	if(ob->flag & SELECT) {
	
		glLineWidth(2.0);
		glDepthMask(0);
		
		if(ob->type==OB_MESH) {
			/* optimal draw gives ugly outline, so we temporally disable it */
			Mesh *me= ob->data;
			
			if(me->totface) {
				DispList *dl= me->disp.first;
				DispListMesh *dlm=NULL;
				short flag= 0;
				
				if(dl && dl->mesh) {
					dlm= dl->mesh;
					flag= dlm->flag & ME_OPT_EDGES;
					dlm->flag &= ~ME_OPT_EDGES;
				}
				
				drawmeshwire(ob);

				if(dlm && flag) dlm->flag |= flag;
			}
		}
		else drawDispListwire(lb);
		
		glLineWidth(1.0);
		glDepthMask(1);
	}
}

static void draw_solid_select(Object *ob) 
{
	Curve *cu;

	if(ob->dtx & OB_DRAWWIRE) return;

	switch(ob->type) {
	case OB_MESH:
		drawSolidSelect(ob, NULL);
		break;
	case OB_FONT:
	case OB_CURVE:
	case OB_SURF:
		cu= ob->data;
		if(displist_has_faces(&cu->disp)) 
			if(boundbox_clip(ob->obmat, cu->bb)) drawSolidSelect(ob, &cu->disp);
		break;
	case OB_MBALL:
		drawSolidSelect(ob, &ob->disp);
		break;
	}
}


static void drawWireExtra(Object *ob, ListBase *lb) 
{

	if(ob!=G.obedit && (ob->flag & SELECT)) {
		if(ob==OBACT) BIF_ThemeColor(TH_ACTIVE);
		else BIF_ThemeColor(TH_SELECT);
	}
	else BIF_ThemeColor(TH_WIRE);

	bglPolygonOffset(1.0);
	glDepthMask(0);	// disable write in zbuffer, selected edge wires show better
	
	if(ob->type==OB_MESH) drawmeshwire(ob);
	else if(ob->type==OB_CURVE) {
		draw_index_wire= 0;
		drawDispListwire(lb);
		draw_index_wire= 1;
	}
	else drawDispListwire(lb); 

	glDepthMask(1);
	bglPolygonOffset(0.0);
}

static void draw_extra_wire(Object *ob) 
{
	Curve *cu;

	switch(ob->type) {
	case OB_MESH:
		drawWireExtra(ob, NULL);
		break;
	case OB_FONT:
	case OB_CURVE:
	case OB_SURF:
		cu= ob->data;
		if(boundbox_clip(ob->obmat, cu->bb)) drawWireExtra(ob, &cu->disp);
		break;
	case OB_MBALL:
		drawWireExtra(ob, &ob->disp);
		break;
	}
}

/* should be called in view space */
static void draw_hooks(Object *ob)
{
	ObHook *hook;
	float vec[3];
	
	for(hook= ob->hooks.first; hook; hook= hook->next) {
		
		VecMat4MulVecfl(vec, ob->obmat, hook->cent);
		if(hook->parent) {
			setlinestyle(3);
			glBegin(GL_LINES);
			glVertex3fv(hook->parent->obmat[3]);
			glVertex3fv(vec);
			glEnd();
			setlinestyle(0);
		}

		glPointSize(3.0);
		bglBegin(GL_POINTS);
		bglVertex3fv(vec);
		bglEnd();
		glPointSize(1.0);

	}
}

void draw_object(Base *base)
{
	PartEff *paf;
	Object *ob;
	Curve *cu;
	Mesh *me;
	ListBase elems;
	CfraElem *ce;
	float cfraont, axsize=1.0;
	unsigned int *rect, col=0;
	static int warning_recursive= 0;
	int sel, drawtype, colindex= 0, ipoflag;
	short dt, dtx, zbufoff= 0;
	
	ob= base->object;

	/* draw keys? */
	if(base==(G.scene->basact) || (base->flag & (SELECT+BA_WASSEL))) {
		if(warning_recursive==0 && ob!=G.obedit) {
			if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
				float temp[7][3];

				warning_recursive= 1;
				
				elems.first= elems.last= 0;
				make_cfra_list(ob->ipo, &elems);
		
				cfraont= (G.scene->r.cfra);
				drawtype= G.vd->drawtype;
				if(drawtype>OB_WIRE) G.vd->drawtype= OB_WIRE;
				sel= base->flag;
				memcpy(temp, &ob->loc, 7*3*sizeof(float));
				
				ipoflag= ob->ipoflag;
				ob->ipoflag &= ~OB_OFFS_OB;
				
				set_no_parent_ipo(1);
				disable_speed_curve(1);

				if ((ob->ipoflag & OB_DRAWKEYSEL)==0) {
					ce= elems.first;
					while(ce) {
						if(!ce->sel) {
							(G.scene->r.cfra)= ce->cfra/G.scene->r.framelen;
						
							base->flag= 0;
						
							where_is_object_time(ob, (G.scene->r.cfra));
							draw_object(base);
						}
						ce= ce->next;
					}
				}
				
				ce= elems.first;
				while(ce) {
					if(ce->sel) {
						(G.scene->r.cfra)= ce->cfra/G.scene->r.framelen;
						
						base->flag= SELECT;
						
						where_is_object_time(ob, (G.scene->r.cfra));
						draw_object(base);
					}
					ce= ce->next;
				}

				set_no_parent_ipo(0);
				disable_speed_curve(0);
				
				base->flag= sel;
				ob->ipoflag= ipoflag;
				
				/* restore icu->curval */
				(G.scene->r.cfra)= cfraont;
				
				memcpy(&ob->loc, temp, 7*3*sizeof(float));
				where_is_object(ob);
				G.vd->drawtype= drawtype;
				
				BLI_freelistN(&elems);

				warning_recursive= 0;
			}
		}
	}
	
	/* patch? children objects with a timeoffs change the parents. How to solve! */
	/* if( ((int)ob->ctime) != F_(G.scene->r.cfra)) where_is_object(ob); */

	mymultmatrix(ob->obmat);

	/* which wire color */
	if((G.f & G_PICKSEL) == 0) {
		project_short(ob->obmat[3], &base->sx);
		
		if(G.moving==1 && (base->flag & (SELECT+BA_PARSEL))) BIF_ThemeColor(TH_TRANSFORM);
		else {
		
			BIF_ThemeColor(TH_WIRE);
			if((G.scene->basact)==base) {
				if(base->flag & (SELECT+BA_WASSEL)) BIF_ThemeColor(TH_ACTIVE);
			}
			else {
				if(base->flag & (SELECT+BA_WASSEL)) BIF_ThemeColor(TH_SELECT);
			}
			
			// no theme yet
			if(ob->id.lib) {
				if(base->flag & (SELECT+BA_WASSEL)) colindex = 4;
				else colindex = 3;
			}
			else if(warning_recursive==1) {
				if(base->flag & (SELECT+BA_WASSEL)) colindex = 7;
				else colindex = 6;
			}

		}	
		
		if(colindex) {
			col= colortab[colindex];
			cpack(col);
		}
	}
	
	/* maximum drawtype */
	dt= MIN2(G.vd->drawtype, ob->dt);
	if(G.zbuf==0 && dt>OB_WIRE) dt= OB_WIRE;
	dtx= 0;
	
	/* faceselect exception: also draw solid when dt==wire, except in editmode */
	if(ob==((G.scene->basact) ? (G.scene->basact->object) : 0) && (G.f & (G_FACESELECT+G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT))) {
		if(ob->type==OB_MESH) {
			
			if(ob==G.obedit);
			else {
				dt= OB_SHADED;
		
				glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT);
				glEnable(GL_DEPTH_TEST);
				zbufoff= 1;
			}
		}
		else {
			if(dt<OB_SOLID) {
				dt= OB_SOLID;
				glClearDepth(1.); glClear(GL_DEPTH_BUFFER_BIT);
				glEnable(GL_DEPTH_TEST);
				zbufoff= 1;
			}
		}
	}
	if(dt>=OB_WIRE ) {

		dtx= ob->dtx;
		if(G.obedit==ob) {
			// the only 2 extra drawtypes alowed in editmode
			dtx= dtx & (OB_DRAWWIRE|OB_TEXSPACE);
		}
		else if(G.f & (G_FACESELECT)) {
			// unwanted combo
			dtx &= ~OB_DRAWWIRE;
		}
		
		if(G.f & G_DRAW_EXT) {
			if(ob->type==OB_EMPTY || ob->type==OB_CAMERA || ob->type==OB_LAMP) dt= OB_WIRE;
		}
	}

	/* exception for mesh..., needs to be here for outline draw */
	if(ob->type==OB_MESH) {
		me= ob->data;
		/* check for need for displist (it's zero when parent, key, or hook changed) */
		if(ob->disp.first==NULL) {
			if(ob->parent && ob->partype==PARSKEL) makeDispList(ob);
			else if(ob->parent && ob->parent->type==OB_LATTICE) makeDispList(ob);
			else if(ob->hooks.first) makeDispList(ob);
			else if(ob->softflag) makeDispList(ob);
			else if(me->disp.first==NULL && mesh_uses_displist(me)) makeDispList(ob);
			else if(ob->effect.first) {	// as last check
				Effect *eff= ob->effect.first;
				if(eff->type==EFF_WAVE) makeDispList(ob);
			}
		}
	}
	
	/* draw outline for selected solid objects */
	if(G.vd->flag & V3D_SELECT_OUTLINE) {
		if(dt>OB_WIRE && dt<OB_TEXTURE && ob!=G.obedit) {
			if((G.f & (G_VERTEXPAINT|G_FACESELECT|G_TEXTUREPAINT|G_WEIGHTPAINT))==0)
				draw_solid_select(ob);
		}
	}
	
	switch( ob->type) {
		
	case OB_MESH:
		me= ob->data;

		if(base->flag & OB_RADIO);
		else if(ob==G.obedit || (G.obedit && ob->data==G.obedit->data)) {
			if(dt<=OB_WIRE) drawmeshwire(ob);
			else {
				if(mesh_uses_displist(me)) {
					init_gl_materials(ob);
					two_sided( me->flag & ME_TWOSIDED );
					drawDispListsolid(&me->disp, ob);
				}
				else {
					drawmeshsolid(ob, 0);
				}
				dtx |= OB_DRAWWIRE;	// draws edges, transp faces, subsurf optimal, vertices
			}
			if(ob==G.obedit && (G.f & G_PROPORTIONAL)) draw_prop_circle();
		}
		else {
			Material *ma= give_current_material(ob, 1);

			if(ob_from_decimator(ob)) drawDispListwire(&ob->disp);
			else if(dt==OB_BOUNDBOX) draw_bounding_volume(ob);
			else if(dt==OB_WIRE || me->totface==0) drawmeshwire(ob);
			else if(ma && (ma->mode & MA_HALO)) drawmeshwire(ob);
			else if(G.f & G_FACESELECT || G.vd->drawtype==OB_TEXTURE) {
				draw_tface_mesh(ob, ob->data, dt);
			}
			else drawDispList(ob, dt);
		}
		
		if( ob!=G.obedit) {
			paf = give_parteff(ob);
			if( paf ) {
				if(col) cpack(0xFFFFFF);	/* for visibility */
				if(paf->flag & PAF_STATIC) draw_static_particle_system(ob, paf);
				else if((G.f & G_PICKSEL) == 0) draw_particle_system(ob, paf);	// selection errors happen to easy
				if(col) cpack(col);
			}
		}
		
		break;
	case OB_FONT:
		cu= ob->data;
		if(ob==G.obedit) {
			tekentextcurs();
			cpack(0xFFFF90);
			drawDispList(ob, OB_WIRE);
		}
		else if(dt==OB_BOUNDBOX) draw_bounding_volume(ob);
		else if(boundbox_clip(ob->obmat, cu->bb)) drawDispList(ob, dt);
			
		break;
	case OB_CURVE:
	case OB_SURF:
		cu= ob->data;
		
		if(ob==G.obedit) {
			drawnurb(ob, editNurb.first, dt);
			if((G.f & G_PROPORTIONAL)) draw_prop_circle();
		}
		else if(dt==OB_BOUNDBOX) draw_bounding_volume(ob);
		else if(boundbox_clip(ob->obmat, cu->bb)) drawDispList(ob, dt);
		
		break;
	case OB_MBALL:
		if(ob==G.obedit) drawmball(ob, dt);
		else if(dt==OB_BOUNDBOX) draw_bounding_volume(ob);
		else drawmball(ob, dt);
		break;
	case OB_EMPTY:
		drawaxes(1.0);
		break;
	case OB_LAMP:
		/* does a myloadmatrix */
		drawlamp(ob);
		if(dtx) mymultmatrix(ob->obmat);
		break;
	case OB_CAMERA:
		drawcamera(ob);
		break;
	case OB_LATTICE:
		drawlattice(ob);
		if(ob==G.obedit && (G.f & G_PROPORTIONAL)) draw_prop_circle();
		break;
	case OB_ARMATURE:
		draw_armature (ob);
		break;
	default:
		drawaxes(1.0);
	}
	if(ob->pd && ob->pd->forcefield) draw_forcefield(ob);


	/* draw extra: after normal draw because of makeDispList */
	if(dtx) {
		if(G.f & G_SIMULATION);
		else if(dtx & OB_AXIS) {
			drawaxes(axsize);
		}
		if(dtx & OB_BOUNDBOX) draw_bounding_volume(ob);
		if(dtx & OB_TEXSPACE) drawtexspace(ob);
		if(dtx & OB_DRAWNAME) {
			// patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing
			if((G.f & G_PICKSEL) == 0) {
				glRasterPos3f(0.0,  0.0,  0.0);
				
				BMF_DrawString(G.font, " ");
				BMF_DrawString(G.font, ob->id.name+2);
			}
		}
		if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);
		if((dtx & OB_DRAWWIRE) && dt>=OB_SOLID) draw_extra_wire(ob);
	}
	
	if(dt<OB_SHADED) {
		if((ob->gameflag & OB_ACTOR) && (ob->gameflag & OB_DYNAMIC)) {
			float tmat[4][4], imat[4][4], vec[3];
			
			vec[0]= vec[1]= vec[2]= 0.0;
			mygetmatrix(tmat);
			Mat4Invert(imat, tmat);
			
			setlinestyle(2);
			drawcircball(vec, ob->inertia, imat);
			setlinestyle(0);
		}
	}

	myloadmatrix(G.vd->viewmat);

	if(zbufoff) glDisable(GL_DEPTH_TEST);

	if(warning_recursive) return;
	if(base->flag & OB_FROMDUPLI) return;
	if(base->flag & OB_RADIO) return;
	if(G.f & G_SIMULATION) return;

	if((G.f & (G_PICKSEL))==0) {
		ListBase *list;

		/* draw hook center and offset line */
		if(ob->hooks.first && ob!=G.obedit) draw_hooks(ob);

		/* help lines and so */
		if(ob!=G.obedit && ob->parent && (ob->parent->lay & G.vd->lay)) {
			setlinestyle(3);
			glBegin(GL_LINES);
			glVertex3fv(ob->obmat[3]);
			glVertex3fv(ob->orig);
			glEnd();
			setlinestyle(0);
		}
		
		/* Drawing the constraint lines */
		list = &ob->constraints;
		if (list){
			extern void make_axis_color(char *col, char *col2, char axis);	// drawview.c
			bConstraint *curcon;
			float size[3], tmat[4][4];
			char col[4], col2[4];
			
			BIF_GetThemeColor3ubv(TH_GRID, col);
			make_axis_color(col, col2, 'z');
			glColor3ubv(col2);
			
			for (curcon = list->first; curcon; curcon=curcon->next){
				if ((curcon->flag & CONSTRAINT_EXPAND)&&(curcon->type!=CONSTRAINT_TYPE_NULL)&&(constraint_has_target(curcon))){
					get_constraint_target_matrix(curcon, TARGET_OBJECT, NULL, tmat, size, bsystem_time(ob, 0, (float)(G.scene->r.cfra), ob->sf));
					setlinestyle(3);
					glBegin(GL_LINES);
					glVertex3fv(tmat[3]);
					glVertex3fv(ob->obmat[3]);
					glEnd();
					setlinestyle(0);
				}
			}
		}

		/* object centers */
		if(G.zbuf) glDisable(GL_DEPTH_TEST);
		if(ob->type == OB_LAMP) {
			if(ob->id.lib) {
				if(base->flag & SELECT) rect= rectllib_sel;
				else rect= rectllib_desel;
			}
			else if(ob->id.us>1) {
				if(base->flag & SELECT) rect= rectlus_sel;
				else rect= rectlus_desel;
			}
			else {
				if(base->flag & SELECT) rect= rectl_sel;
				else rect= rectl_desel;
			}
			draw_icon_centered(ob->obmat[3], rect, 9);
		}
		else {
			if(ob->id.lib || ob->id.us>1) {
				if(base->flag & SELECT) rect= rectu_sel;
				else rect= rectu_desel;
			}
			else {
				if(base->flag & SELECT) rect= rect_sel;
				/* The center of the active object (which need not 
				 * be selected) gets drawn as if it were selected
				 */
				else if(base==(G.scene->basact)) rect= rect_sel;
				else rect= rect_desel;
			}
			draw_icon_centered(ob->obmat[3], rect, 4);
		}
		if(G.zbuf) glEnable(GL_DEPTH_TEST);
		
	}
	else if((G.f & (G_VERTEXPAINT|G_FACESELECT|G_TEXTUREPAINT|G_WEIGHTPAINT))==0) {
	
		glBegin(GL_POINTS);
			glVertex3fv(ob->obmat[3]);
		glEnd();
		
	}
}

void draw_object_ext(Base *base)
{
	
	if(G.vd==NULL || base==NULL) return;
	
	if(G.vd->drawtype > OB_WIRE) {
		G.zbuf= 1;
		glEnable(GL_DEPTH_TEST);
	}
	
	G.f |= G_DRAW_EXT;

	glDrawBuffer(GL_FRONT);
	persp(PERSP_VIEW);

	draw_object(base);

	G.f &= ~G_DRAW_EXT;

	glFlush();		/* reveil frontbuffer drawing */
	glDrawBuffer(GL_BACK);
	
	if(G.zbuf) {
		G.zbuf= 0;
		glDisable(GL_DEPTH_TEST);
	}
	curarea->win_swap= WIN_FRONT_OK;
}

/* ***************** BACKBUF SEL (BBS) ********* */

static int bbs_mesh_verts(Object *ob, int offset)
{
	EditVert *eve;
	int a= offset, optimal= subsurf_optimal(ob);
	
	glPointSize( BIF_GetThemeValuef(TH_VERTEX_SIZE) );
	
	bglBegin(GL_POINTS);
	for(eve= G.editMesh->verts.first; eve; eve= eve->next, a++) {
		if(eve->h==0) {
			cpack( index_to_framebuffer(a) );
			if(optimal && eve->ssco) bglVertex3fv(eve->ssco);
			else bglVertex3fv(eve->co);
		}
	}
	bglEnd();
	
	glPointSize(1.0);
	return a;
}		

/* two options, edgecolors or black */
static int bbs_mesh_wire(Object *ob, int offset)
{
	EditEdge *eed;
	Mesh *me= ob->data;
	DispList *dl= find_displist(&me->disp, DL_MESH);
	DispListMesh *dlm= NULL;
	int index, b, retval, optimal=0;

	if(dl) dlm= dl->mesh;
	optimal= subsurf_optimal(ob);
	
	if(dlm && optimal) {
		MEdge *medge= dlm->medge;
		MVert *mvert= dlm->mvert;
		
		// tuck original indices in vn
		for(b=0, eed= G.editMesh->edges.first; eed; eed= eed->next, b++) eed->vn= (EditVert *)(b+offset);
		retval= b+offset;
		glBegin(GL_LINES);
		for (b=0; b<dlm->totedge; b++, medge++) {
			if(medge->flag & ME_EDGEDRAW) {
				eed= dlm->editedge[b];
				if(eed && eed->h==0) {
					
					index= (int)eed->vn;
					cpack(index_to_framebuffer(index));
					
					glVertex3fv(mvert[medge->v1].co); 
					glVertex3fv(mvert[medge->v2].co);
				}
			}
		}
		glEnd();
	}
	else {
		index= offset;
		cpack(0);
		glBegin(GL_LINES);
		for(eed= G.editMesh->edges.first; eed; eed= eed->next, index++) {
			if(eed->h==0) {

				cpack(index_to_framebuffer(index));

				glVertex3fv(eed->v1->co);
				glVertex3fv(eed->v2->co);
			}
		}
		glEnd();
		retval= index;
	}
	return retval;
}		
		
/* two options, facecolors or black */
static int bbs_mesh_solid(Object *ob, int facecol)
{
	int glmode, a;
	
	cpack(0);

	if(ob==G.obedit) {
		Mesh *me= ob->data;
		EditFace *efa;
		DispList *dl= find_displist(&me->disp, DL_MESH);
		DispListMesh *dlm= NULL;
		int b;
		
		if(dl) dlm= dl->mesh;
		a= 0; 

		if(dlm && dlm->editface) {
			EditFace *prevefa;
			MFace *mface;
			efa= NULL;
			
			// tuck original indices in efa->prev
			for(b=1, efa= G.editMesh->faces.first; efa; efa= efa->next, b++) efa->prev= (EditFace *)(b);
			a= b+1;	// correct return value, next loop excludes hidden faces

			for(b=0, mface= dlm->mface; b<dlm->totface; b++, mface++) {
				if(mface->v3) {
					if(facecol) {
						efa= dlm->editface[b];
						cpack(index_to_framebuffer((int)efa->prev));
					}
					
					glBegin(mface->v4?GL_QUADS:GL_TRIANGLES);
					glVertex3fv(dlm->mvert[mface->v1].co);
					glVertex3fv(dlm->mvert[mface->v2].co);
					glVertex3fv(dlm->mvert[mface->v3].co);
					if (mface->v4) glVertex3fv(dlm->mvert[mface->v4].co);
					glEnd();
				}
			}
			
			if(facecol && (G.scene->selectmode & SCE_SELECT_FACE)) {		
				glPointSize(BIF_GetThemeValuef(TH_FACEDOT_SIZE));
				
				bglBegin(GL_POINTS);
				for(efa= G.editMesh->faces.first; efa; efa= efa->next) {
					if(efa->h==0) {
						if(efa->fgonf==EM_FGON);
						else {
							cpack(index_to_framebuffer((int)efa->prev));
							bglVertex3fv(efa->cent);
						}
					}
				}
				bglEnd();
			}
			
			for (prevefa= NULL, efa= G.editMesh->faces.first; efa; prevefa= efa, efa= efa->next)
				efa->prev= prevefa;

		}
		else {
			a= 1;
			glBegin(GL_QUADS);
			glmode= GL_QUADS;
			for(efa= G.editMesh->faces.first; efa; efa= efa->next, a++) {
				if(efa->h==0) {
					if(efa->v4) {if(glmode==GL_TRIANGLES) {glmode= GL_QUADS; glEnd(); glBegin(GL_QUADS);}}
					else {if(glmode==GL_QUADS) {glmode= GL_TRIANGLES; glEnd(); glBegin(GL_TRIANGLES);}}

					if(facecol) {
						int i= index_to_framebuffer(a);
						cpack(i);
					}
					glVertex3fv(efa->v1->co);
					glVertex3fv(efa->v2->co);
					glVertex3fv(efa->v3->co);
					if(efa->v4) glVertex3fv(efa->v4->co);
				}
			}
			glEnd();
		}
		if(facecol) return a;
	}
	else {
		Mesh *me= ob->data;
		MVert *mvert;
		MFace *mface;
		TFace *tface;
		DispList *dl;
		float *extverts=NULL;
		int a, totface, hastface, i;
		
		mvert= me->mvert;
		mface= me->mface;
		tface= me->tface;
		hastface = (me->tface != NULL);
		totface= me->totface;

		dl= find_displist(&ob->disp, DL_VERTS);
		if(dl) extverts= dl->verts;
		
		glBegin(GL_QUADS);
		glmode= GL_QUADS;
		
		for(a=0; a<totface; a++, mface++, tface++) {
			if(mface->v3) {
				if(facecol) {
					if(hastface && tface->flag & TF_HIDE) continue;
					i= index_to_framebuffer(a+1);
					cpack(i);
				}

				if(mface->v4) {if(glmode==GL_TRIANGLES) {glmode= GL_QUADS; glEnd(); glBegin(GL_QUADS);}}
				else {if(glmode==GL_QUADS) {glmode= GL_TRIANGLES; glEnd(); glBegin(GL_TRIANGLES);}}
				
				if(extverts) {
					glVertex3fv( extverts+3*mface->v1 );
					glVertex3fv( extverts+3*mface->v2 );
					glVertex3fv( extverts+3*mface->v3 );
					if(mface->v4) glVertex3fv( extverts+3*mface->v4 );
				}
				else {
					glVertex3fv( (mvert+mface->v1)->co );
					glVertex3fv( (mvert+mface->v2)->co );
					glVertex3fv( (mvert+mface->v3)->co );
					if(mface->v4) glVertex3fv( (mvert+mface->v4)->co );
				}
			}
		}
		glEnd();
	}
	return 1;
}

void draw_object_backbufsel(Object *ob)
{
	extern int em_solidoffs, em_wireoffs, em_vertoffs;	// let linker solve it... from editmesh_mods.c 
	
	mymultmatrix(ob->obmat);

	glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);

	switch( ob->type) {
	case OB_MESH:
		if(G.obedit) {

			em_solidoffs= bbs_mesh_solid(ob, G.scene->selectmode & SCE_SELECT_FACE);
			
			bglPolygonOffset(1.0);
			
			// we draw edges always, for loop (select) tools
			em_wireoffs= bbs_mesh_wire(ob, em_solidoffs);
			
			if(G.scene->selectmode & SCE_SELECT_VERTEX) 
				em_vertoffs= bbs_mesh_verts(ob, em_wireoffs);
			else em_vertoffs= em_wireoffs;
			
			bglPolygonOffset(0.0);
		}
		else bbs_mesh_solid(ob, 1);	// 1= facecol, faceselect
		
		break;
	case OB_CURVE:
	case OB_SURF:
		break;
	}

	myloadmatrix(G.vd->viewmat);

}
