/**
 * $Id: drawobject.c,v 1.15 2003/07/21 17:46:55 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 "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"

#include "MTC_matrixops.h"

#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#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_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 "BKE_utildefines.h"
#include "BKE_curve.h"
#include "BKE_object.h"
#include "BKE_global.h"
#include "BKE_displist.h"
#include "BKE_material.h"
#include "BKE_ipo.h"
#include "BKE_mesh.h"
#include "BKE_effect.h"
#include "BKE_lattice.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 "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"

#ifdef __NLA
#include "BKE_deform.h"
#endif

/* 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};

#define B_YELLOW	0x77FFFF
#define B_PURPLE	0xFF70FF


unsigned int selcol= 0xFF88FF;
unsigned int actselcol= 0xFFBBFF;

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);
#ifdef __sun__
	glFinish(); 
#endif	
	glDrawPixels(rectsize, rectsize, GL_RGBA, GL_UNSIGNED_BYTE, rect);
}

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

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

	getmouseco_areawin(mval);
	project_short_noclip(vecrot, mval1);

	persp(0);
	
	glDrawBuffer(GL_FRONT);
	
	cpack(0);

	setlinestyle(3);
	glBegin(GL_LINE_STRIP); 
		glVertex2sv(mval); 
		glVertex2sv(mval1); 
	glEnd();
	setlinestyle(0);
	
	persp(1);

	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);

		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);
	glBegin(GL_POINTS);
	cpack(0);
	glVertex3fv(sta);
	glVertex3fv(end);
	glEnd();
	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);
	
	if(la->type==LA_SPOT) {
		
		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->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]);
	
	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);
}		


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;
	glDisable(GL_LIGHTING);
	glDisable(GL_CULL_FACE);
	
	/* that way it's always visible */
	fac= cam->drawsize;
	if(G.vd->persp>=2) 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;
	if(G.f & G_BACKBUFSEL) 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, B_YELLOW);

		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;
	int a, uxt, u, vxt, v, wxt, w;

	glPointSize(3.0);

	if(sel) cpack(B_YELLOW);
	else cpack(B_PURPLE);

	glBegin(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) glVertex3fv(bp->vec);
						}
					}
				}
			}
		}
	}
	else {

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

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);
	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 {
		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); 
	}
}

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

/* window coord, assuming all matrices are set OK */
void calc_meshverts(void)
{
	EditVert *eve;
	float mat[4][4];

	if(G.edve.first==0) return;
	eve= G.edve.first;

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

	eve= G.edve.first;
	while(eve) {
		if(eve->h==0) {
			project_short(eve->co, &(eve->xs));
		}
		eve= eve->next;
	}
	MTC_Mat4SwapMat4(G.vd->persmat, mat);
}

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

	areawinset(curarea->win);
	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)
{
	EditVert *eve;
	float mat[4][4];
	
	/* matrices */
	areawinset(curarea->win);
	mymultmatrix(G.obedit->obmat);
	
	if(G.edve.first==0) return;
	eve= G.edve.first;

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

	eve= G.edve.first;
	while(eve) {
		eve->f &= ~2;
		if(eve->h==0) {
			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;
		}
		eve= eve->next;
	}
	
	/* 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);
	mymultmatrix(G.obedit->obmat);
	calc_Nurbverts(editNurb.first);
	myloadmatrix(G.vd->viewmat);
	
}

void tekenvertices(short sel)
{
	EditVert *eve;

	glPointSize(2.0);
	
	if(sel) cpack(B_YELLOW);
	else cpack(B_PURPLE);
#ifdef __NLA /* __TEKENTEST */
//	if (sel==2)
//		cpack (0x0000FF);
#endif	/* __TEKENTEST */
	glBegin(GL_POINTS);

	eve= (EditVert *)G.edve.first;
	while(eve) {
		if(eve->h==0 && (eve->f & 1)==sel ) {
			glVertex3fv(eve->co);
		}
#ifdef __NLA /* __TEKENTEST */
//	if (eve->totweight && sel==2)
//		glVertex3fv(eve->co);

#endif	/* __TEKENTEST */
		eve= eve->next;
	}
	glEnd();

	glPointSize(1.0);
}

void tekenvertices_ext(int mode)
{
	ScrArea *tempsa, *sa;
	View3D *vd;
	
	if(G.f & (G_FACESELECT+G_DRAWFACES)) {
		allqueue(REDRAWVIEW3D, 0);
		return;
	}
	
	if(G.zbuf) glDisable(GL_DEPTH_TEST);
	
	glDrawBuffer(GL_FRONT);

	/* check all views */
	tempsa= curarea;
	sa= G.curscreen->areabase.first;
	while(sa) {
		if(sa->spacetype==SPACE_VIEW3D) {
			vd= sa->spacedata.first;
			if(G.obedit->lay & vd->lay) {
				areawinset(sa->win);
				mymultmatrix(G.obedit->obmat);

				calc_meshverts();
				if(mode==0 || mode==2) tekenvertices(0);
				if(mode==1 || mode==2) tekenvertices(1);
				sa->win_swap= WIN_FRONT_OK;
				
				myloadmatrix(G.vd->viewmat);
			}
		}
		sa= sa->next;
	}
	if(curarea!=tempsa) areawinset(tempsa->win);
	
	glDrawBuffer(GL_BACK);
	if(G.zbuf) glEnable(GL_DEPTH_TEST);
}

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

	/* DispListMesh */
	
static void displistmesh_draw_wire(DispListMesh *dlm) {
	int i;
	
	for (i=0; i<dlm->totface; i++) {
		MFaceInt *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, int drawsmooth, float *nors) {
	int lmode, lshademodel= -1, lmat_nr= -1;
	int i;

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

	glBegin(lmode= GL_QUADS);
	for (i=0; i<dlm->totface; i++) {
		MFaceInt *mf= &dlm->mface[i];
		
		if (mf->v3) {
			int nmode= mf->v4?GL_QUADS:GL_TRIANGLES;
			
			if (nmode!=lmode) {
				glEnd();
				glBegin(lmode= nmode);
			}
			
			if (drawsmooth) {
				int nshademodel= (mf->flag&ME_SMOOTH)?GL_SMOOTH:GL_FLAT;

				if (nshademodel!=lshademodel) {
					glEnd();
					glShadeModel(lshademodel= nshademodel);
					glBegin(lmode);
				}
			
				if (mf->mat_nr!=lmat_nr)
					set_gl_material((lmat_nr= mf->mat_nr)+1);
			}
			
			if (drawsmooth && 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++) {
		MFaceInt *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 & 1) 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 & 2) 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;
	int drawsmooth= !(G.f & G_BACKBUFSEL);
	
	if(lb==0) return;
	if (drawsmooth) {
		glShadeModel(GL_SMOOTH);
		glEnable(GL_LIGHTING);
	}
	
	dl= lb->first;
	while(dl) {
		data= dl->verts;
		ndata= dl->nors;

		switch(dl->type) {
		case DL_SURF:
			if(!drawsmooth) {
				for(a=0; a<dl->parts; a++) {
	
					DL_SURFINDEX(dl->flag & 1, dl->flag & 2, dl->nr, dl->parts);
	
					v1= data+ 3*p1; 
					v2= data+ 3*p2;
					v3= data+ 3*p3; 
					v4= data+ 3*p4;
	
					glBegin(GL_QUAD_STRIP);
					
					glVertex3fv(v2);
					glVertex3fv(v4);

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

						v2= v1; v1+= 3;
						v4= v3; v3+= 3;
					}
					
					
					glEnd();
				}
			}
			else {

				set_gl_material(dl->col+1);
/*				
				glBegin(GL_LINES);
				for(a=0; a<dl->parts*dl->nr; a++) {
					float nor[3];
					
					VECCOPY(nor, data+3*a);
					glVertex3fv(nor);
					VecAddf(nor, nor, ndata+3*a);
					glVertex3fv(nor);
				}
				glEnd();
*/				
				for(a=0; a<dl->parts; a++) {
					
					DL_SURFINDEX(dl->flag & 1, dl->flag & 2, 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;
			
			if(!drawsmooth) {
				while(parts--) {

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

				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;

			if(!drawsmooth) {
				while(parts--) {

					glBegin(index[3]?GL_QUADS:GL_TRIANGLES);
						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;
				}
			}
			else {
				
				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, drawsmooth, dl->nors);
			break;
				
		}
		dl= dl->next;
	}

	if(drawsmooth) {
		glShadeModel(GL_FLAT);
		glDisable(GL_LIGHTING);
	}
}

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 & 1, dl->flag & 2, 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);
}

/* wrappers for shaded+wire and solid+wire */
static void drawMeshWireExtra(Object *ob) {
	GLfloat origwidth;
	GLint origcolor[4];
	
	glGetFloatv(GL_LINE_WIDTH, &origwidth);
	glGetIntegerv(GL_CURRENT_COLOR, origcolor);
	
	glLineWidth(1.2);

	cpack(0x4F4F4F);
	drawmeshwire(ob);

	glColor4iv(origcolor);
	glLineWidth(origwidth);
}

static void drawDispListWireExtra(ListBase *lb) {
	GLfloat origwidth;
	GLint origcolor[4];

	glGetFloatv(GL_LINE_WIDTH, &origwidth);
	glGetIntegerv(GL_CURRENT_COLOR, origcolor);

	glLineWidth(1.2);

	cpack(0x4F4F4F);
	drawDispListwire(lb);

	glLineWidth(origwidth);
	glColor4iv(origcolor);
}

static void drawmeshsolid(Object *ob, float *nors)
{
	Mesh *me;
	DispList *dl;
	MVert *mvert;
	TFace *tface;
	MFace *mface;
	EditVlak *evl;
	float *extverts=0, *v1, *v2, *v3, *v4;
	int glmode, setsmooth=0, a, start, end, matnr= -1, vertexpaint, i;
	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);

	if( (G.f & G_BACKBUFSEL)==0 ) {
		glEnable(GL_LIGHTING);
		init_gl_materials(ob);
		two_sided( me->flag & ME_TWOSIDED );
	}

	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)) {
		
		evl= G.edvl.first;
		while(evl) {
			if(evl->v1->h==0 && evl->v2->h==0 && evl->v3->h==0) {
				
				if(evl->mat_nr!=matnr) {
					matnr= evl->mat_nr;
					set_gl_material(matnr+1);
				}
				
				if(evl->v4 && evl->v4->h==0) {
				
					glBegin(GL_QUADS);
						glNormal3fv(evl->n);
						glVertex3fv(evl->v1->co);
						glVertex3fv(evl->v2->co);
						glVertex3fv(evl->v3->co);
						glVertex3fv(evl->v4->co);
					glEnd();
				}
				else {

					glBegin(GL_TRIANGLES);
						glNormal3fv(evl->n);
						glVertex3fv(evl->v1->co);
						glVertex3fv(evl->v2->co);
						glVertex3fv(evl->v3->co);
					glEnd();
				}
			}
			evl= evl->next;
		}
		
		glDisable(GL_LIGHTING);
		glShadeModel(GL_FLAT);
		
		if(ob==G.obedit) {
			calc_meshverts();
		
			if(G.zbuf) glDisable(GL_DEPTH_TEST);
			tekenvertices(0);
			tekenvertices(1);
			if(G.zbuf) glEnable(GL_DEPTH_TEST);
		}
		
		if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);

	}
	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) {
				if(tface && (tface->flag & TF_HIDE)) {
					if( (G.f & G_BACKBUFSEL)==0) {
						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(G.f & G_BACKBUFSEL) {
						if(vertexpaint) {
							i= index_to_framebuffer(a+1);
							cpack(i);
						}
	
						glVertex3fv( v1 );
						glVertex3fv( v2 );
						glVertex3fv( v3 );
						if(v4) glVertex3fv( v4 );
						
					}
					else {
						
						if(mface->mat_nr!=matnr) {
							matnr= mface->mat_nr;
							set_gl_material(matnr+1);
						}
	
						if( (me->flag & ME_AUTOSMOOTH)==0 && (mface->flag & ME_SMOOTH)) {
							if(setsmooth==0) {
								glEnd();
								glShadeModel(GL_SMOOTH);
								if(glmode==GL_TRIANGLES) glBegin(GL_TRIANGLES);
								else glBegin(GL_QUADS);
								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);
								if(glmode==GL_TRIANGLES) glBegin(GL_TRIANGLES);
								else glBegin(GL_QUADS);
								setsmooth= 0;
							}
							glNormal3fv(nors);
							glVertex3fv( v1 );
							glVertex3fv( v2 );
							glVertex3fv( v3 );
							if(v4) glVertex3fv( v4 );
						}
					}
				}
				if(tface) tface++;
			}
		}
		
		glEnd();
	}
	
	/* SOLVE */
/* 	if ELEM(ob->type, OB_SECTOR, OB_LIFE) glDisable(GL_CULL_FACE); */

	if(G.f & G_BACKBUFSEL) {
		glDisable(GL_CULL_FACE);
	}
	glDisable(GL_LIGHTING);

}

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);
	
	if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);
}

static void drawDispList(Object *ob, int dt)
{
	ListBase *lb=0;
	DispList *dl;
	Mesh *me;
	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==0) addnormalsDispList(ob, lb);
			
			dl= lb->first;
			if(dl==0) return;

			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);
					if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);					
				} else {
					init_gl_materials(ob);
					two_sided(me->flag & ME_TWOSIDED);
					drawDispListsolid(lb, ob);
					if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(lb);
				}
			}
			else {
				drawmeshsolid(ob, dl->nors);
				if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);
			}
			
		}
		else if(dt==OB_SHADED) {
#ifdef __NLA
			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);
				if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);
				
				MEM_freeN (wtcol);
				
			}
			else
#endif
			if( G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) {
				/* in order: vertexpaint already made mcol */
///*

//*/
				if(me->mcol) {
					drawmeshshaded(ob, (unsigned int *)me->mcol, 0);
					if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);
				} else if(me->tface) {
					tface_to_mcol(me);
					drawmeshshaded(ob, (unsigned int *)me->mcol, 0);	
					MEM_freeN(me->mcol); me->mcol= 0;
					if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);
				}
				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);
						if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(&me->disp);
					} else {
						drawmeshshaded(ob, dl->col1, dl->col2);
						if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);
					}
				}
			}
		}
		
		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:
	
		lb= &((Curve *)ob->data)->disp;
		if(lb->first==0) makeDispList(ob);
		
		if(solid && ob!=G.obedit) {
			dl= lb->first;
			if(dl==0) return;
			
			/* rule: dl->type INDEX3 is always first in list */
			if(dl->type!=DL_INDEX3) {
				curve_to_filledpoly(ob->data, lb);
				dl= lb->first;
			}
			if(dl->nors==0) addnormalsDispList(ob, lb);
			
			index3_nors_incr= 0;
			
			if(dt==OB_SHADED) {
				if(ob->disp.first==0) shadeDispList(ob);
				drawDispListshaded(lb, ob);
				if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(lb);
			}
			else {
				init_gl_materials(ob);
				two_sided(0);
				drawDispListsolid(lb, ob);
				if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(lb);

			}
			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);
				if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(lb);
			}
			else {
				init_gl_materials(ob);
				two_sided(0);
			
				drawDispListsolid(lb, ob);
				if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(lb);
			}
		}
		else {
			drawDispListwire(lb);
		}
		break;
	case OB_MBALL:

		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);
				if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(lb);
			}
			else {
				init_gl_materials(ob);
				two_sided(0);
			
				drawDispListsolid(lb, ob);	
				if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(lb);
			}
		}
		else 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();

}

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();

}

static void drawmeshwire(Object *ob)
{
	extern float editbutsize;	/* buttons.c */
	Mesh *me;
	MVert *mvert;
	MFace *mface;
	DispList *dl;
	Material *ma;
	EditEdge *eed;
	EditVlak *evl;
	float fvec[3], cent[3], *f1, *f2, *f3, *f4, *extverts=0;
	int a, start, end, test, /*  colbcol=0, */ ok;

	me= get_mesh(ob);

	if(ob==G.obedit || (G.obedit && ob->data==G.obedit->data)) {
		
		if(G.f & (G_FACESELECT+G_DRAWFACES)) {	/* faces */
			
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glEnable(GL_BLEND);

			evl= G.edvl.first;
			while(evl) {
				if(evl->v1->h==0 && evl->v2->h==0 && evl->v3->h==0) {
					
					if(1) {
						if(vlakselectedAND(evl, 1)) glColor4ub(200, 100, 200, 60);
						else glColor4ub(0, 50, 150, 30);
						
						glBegin(evl->v4?GL_QUADS:GL_TRIANGLES);
						glVertex3fv(evl->v1->co);
						glVertex3fv(evl->v2->co);
						glVertex3fv(evl->v3->co);
						if(evl->v4) glVertex3fv(evl->v4->co);
						glEnd();
						
					} else {
						if(vlakselectedAND(evl, 1)) cpack(0x559999);
						else cpack(0x664466);
					
						if(evl->v4 && evl->v4->h==0) {
						
							CalcCent4f(cent, evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co);
							glBegin(GL_LINE_LOOP);
								VecMidf(fvec, cent, evl->v1->co); glVertex3fv(fvec);
								VecMidf(fvec, cent, evl->v2->co); glVertex3fv(fvec);
								VecMidf(fvec, cent, evl->v3->co); glVertex3fv(fvec);
								VecMidf(fvec, cent, evl->v4->co); glVertex3fv(fvec);
							glEnd();
						}
						else {
	
							CalcCent3f(cent, evl->v1->co, evl->v2->co, evl->v3->co);
							glBegin(GL_LINE_LOOP);
								VecMidf(fvec, cent, evl->v1->co); glVertex3fv(fvec);
								VecMidf(fvec, cent, evl->v2->co); glVertex3fv(fvec);
								VecMidf(fvec, cent, evl->v3->co); glVertex3fv(fvec);
							glEnd();
						}
					}
				}
				evl= evl->next;
			}
			glDisable(GL_BLEND);
		}

		if(G.zbuf==0 && mesh_uses_displist(me)) {
			cpack(0x505050);
			drawDispListwire(&me->disp);
		}
		cpack(0x0);
		
		if(G.f & G_DRAWEDGES) {	/* Use edge Highlighting */
			glShadeModel(GL_SMOOTH);
			
			eed= G.eded.first;
			glBegin(GL_LINES);
			while(eed) {
				if(eed->h==0) {
					if(eed->v1->f & 1) cpack(0x559999); else cpack(0x0);
					glVertex3fv(eed->v1->co);
					if(eed->v2->f & 1) cpack(0x559999); else cpack(0x0);
					glVertex3fv(eed->v2->co);
				}
				eed= eed->next;
			}
			glEnd();
			glShadeModel(GL_FLAT);
		}
		else {
			eed= G.eded.first;
			glBegin(GL_LINES);
			while(eed) {
				if(eed->h==0) {
					glVertex3fv(eed->v1->co);
					glVertex3fv(eed->v2->co);
				}
				eed= eed->next;
			}
			glEnd();
		}
		if(ob!=G.obedit) return;
		
		calc_meshverts();

		if(G.zbuf) glDisable(GL_DEPTH_TEST);
		tekenvertices(0);
		tekenvertices(1);
#ifdef __NLA
		tekenvertices(2);	/* __TEKENTEST */
#endif
		if(G.zbuf) glEnable(GL_DEPTH_TEST);

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

			glBegin(GL_LINES);
			
			evl= G.edvl.first;
			while(evl) {
				if(evl->v1->h==0 && evl->v2->h==0 && evl->v3->h==0) {
					if(evl->v4) CalcCent4f(fvec, evl->v1->co, evl->v2->co, evl->v3->co, evl->v4->co);
					else CalcCent3f(fvec, evl->v1->co, evl->v2->co, evl->v3->co);

					glVertex3fv(fvec);
					fvec[0]+= editbutsize*evl->n[0];
					fvec[1]+= editbutsize*evl->n[1];
					fvec[2]+= editbutsize*evl->n[2];
					glVertex3fv(fvec);
					
				}
				evl= evl->next;
			}

			glEnd();
		}
	}
	else {
		
		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(mesh_uses_displist(me)) drawDispListwire(&me->disp);
		else {
			
			mvert= me->mvert;
			mface= me->mface;

			ok= 0;
			if(me->totface==0) ok= 1;
			else {
				ma= give_current_material(ob, 1);
				if(ma && (ma->mode & MA_HALO)) ok= 1;
			}
			
			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) {
						glVertex3fv(extverts);
					}
				}
				else {
					mvert+= start;
					for(a= start; a<end; a++, mvert++) {
						glVertex3fv(mvert->co);
					}
				}
				
				glEnd();
				glPointSize(1.0);
			}
			else {
				
				start= 0; end= me->totface;
				set_buildvars(ob, &start, &end);
				mface+= start;
				
				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;
	int a;

	if(nu->hide) return;

	if(sel) cpack(B_YELLOW);
	else cpack(B_PURPLE);
	glPointSize(3.0);
	
	glBegin(GL_POINTS);
	
	if((nu->type & 7)==1) {

		bezt= nu->bezt;
		a= nu->pntsu;
		while(a--) {
			if(bezt->hide==0) {
				if((bezt->f1 & 1)==sel) glVertex3fv(bezt->vec[0]);
				if((bezt->f2 & 1)==sel) glVertex3fv(bezt->vec[1]);
				if((bezt->f3 & 1)==sel) glVertex3fv(bezt->vec[2]);
			}
			bezt++;
		}
	}
	else {
		bp= nu->bp;
		a= nu->pntsu*nu->pntsv;
		while(a--) {
			if(bp->hide==0) {
				if((bp->f1 & 1)==sel) glVertex3fv(bp->vec);
			}
			bp++;
		}
	}
	
	glEnd();
	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 */
	
	cpack(0);
	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);
		
		cpack(0x0);
		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 drawcircball(float *cent, float rad, float tmat[][4])
{
	float si, co, phi, dphi, vec[3], vx[3], vy[3];
	int a, tot=32;
		
	VECCOPY(vx, tmat[0]);
	VECCOPY(vy, tmat[1]);
	VecMulf(vx, rad);
	VecMulf(vy, rad);
	
	dphi= 2.0*M_PI/tot;
	phi= 0.0;
	
	glBegin(GL_LINE_LOOP);
	for(a=0; a<tot; a++, phi+= dphi) {
		si= sin(phi);
		co= cos(phi);
		vec[0]= cent[0]+si*vx[0]+co*vy[0];
		vec[1]= cent[1]+si*vx[1]+co*vy[1];
		vec[2]= cent[2]+si*vx[2]+co*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) {
		cpack(0x0);
		if((G.f & G_PICKSEL)==0 ) drawDispList(ob, dt);
		ml= editelems.first;
	}
	else {
		drawDispList(ob, dt);
		ml= mb->elems.first;
	}

	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_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;
	
	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) {
		glTranslatef(cent[0], cent[1], cent[2]-size[2]);
		glScalef(size[0], size[1], 2.0*size[2]);
		gluCylinder(qobj, 1.0, 1.0, 1.0, 8, 1);
	}
	else if(type==OB_BOUND_CONE) {
		glTranslatef(cent[0], cent[1], cent[2]-size[2]);
		glScalef(size[0], size[1], 2.0*size[2]);
		gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1);
	}
	
	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;
}

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_BACKBUFSEL+G_PICKSEL)) == 0) {
		project_short(ob->obmat[3], &base->sx);
		
		if(G.moving==1 && (base->flag & (SELECT+BA_PARSEL))) colindex= 12;
		else {
			if((G.scene->basact)==base) {
				if(base->flag & (SELECT+BA_WASSEL)) colindex= 2;
			}
			else {
				if(base->flag & (SELECT+BA_WASSEL)) colindex= 1;
			}
			if(ob->id.lib) colindex+= 3;
			else if(warning_recursive==1) colindex+= 6;
			else if(ob->flag & OB_FROMGROUP) colindex+= 9;
		}	
		
		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) dt= OB_WIRE;
			else {
				if(G.f & G_BACKBUFSEL) dt= OB_SOLID;
				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;
			}
		}
	}
	else if(dt>=OB_WIRE ) {

		if(dt>OB_SOLID) if(G.f & G_BACKBUFSEL) dt= OB_SOLID;

		dtx= ob->dtx;
		if(G.obedit==ob) {
			if(dtx & OB_TEXSPACE) dtx= OB_TEXSPACE;
			else dtx= 0;
		}
		
		if(G.f & G_DRAW_EXT) {
			if(ob->type==OB_EMPTY || ob->type==OB_CAMERA || ob->type==OB_LAMP) dt= OB_WIRE;
		}
		
	}

	if( (G.f & G_DRAW_EXT) && dt>OB_WIRE) {
		
		switch( ob->type) {
		case OB_MBALL:
			drawmball(ob, dt);
			break;
		}
	}
	else {

		switch( ob->type) {
			
		case OB_MESH:
			me= ob->data;

#if 1
#ifdef __NLA
			/* Force a refresh of the display list if the parent is an armature */
			if (ob->parent && ob->parent->type==OB_ARMATURE && ob->partype==PARSKEL){
#if 0			/* Turn this on if there are problems with deformation lag */
				where_is_armature (ob->parent);
#endif
				if (ob != G.obedit)
					makeDispList (ob);
			}
#endif
#endif
			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);
						/* this seems to be the place where the wire for subsurfs 
						 * gets drawn.. so we draw an extra wire in grey here (editmode) */
						if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(&me->disp);
						drawmeshwire(ob);
					}
					else {
						drawmeshsolid(ob, 0);
						if(ob->dtx & OB_DRAWWIRE) drawDispListWireExtra(&me->disp);
					}
				}
				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) drawmeshwire(ob);
				else if(ma && (ma->mode & MA_HALO)) drawmeshwire(ob);
				else if(me->tface) {
					if(G.f & G_BACKBUFSEL) drawmeshsolid(ob, 0);					
					else if(G.f & G_FACESELECT || G.vd->drawtype==OB_TEXTURE) {
						draw_tface_mesh(ob, ob->data, dt);
						if(ob->dtx & OB_DRAWWIRE) drawMeshWireExtra(ob);
					}
					else drawDispList(ob, dt);
				}
				else drawDispList(ob, dt);
			}
			if( (ob!=G.obedit) 
				&& ((G.f & (G_BACKBUFSEL+G_PICKSEL)) == 0) ) {
				paf = give_parteff(ob);
				if( paf ) {
					if(col) cpack(0xFFFFFF);	/* for visibility */
					if(paf->flag & PAF_STATIC) draw_static_particle_system(ob, paf);
					else draw_particle_system(ob, paf);
					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);
			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_IKA:
			draw_ika(ob, base->flag & SELECT);
			break;
#ifdef __NLA
		case OB_ARMATURE:
			draw_armature (ob);
			break;
#endif
		default:
			drawaxes(1.0);
		}
	}

	/* 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) {
			if(ob->type==OB_LAMP) glRasterPos3fv(ob->obmat[3]);
			else 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(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_BACKBUFSEL+G_PICKSEL))==0) {
		/* help lines and so */
		if(ob->parent && (ob->parent->lay & G.vd->lay)) {
			setlinestyle(3);
			glBegin(GL_LINES);
			glVertex3fv(ob->obmat[3]);
			glVertex3fv(ob->orig);
			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)
{
	ScrArea *tempsa, *sa;
	View3D *vd;
	
	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);

	/* check all views */
	tempsa= curarea;
	sa= G.curscreen->areabase.first;
	while(sa) {
		if(sa->spacetype==SPACE_VIEW3D) {
			/* limited drawing in both buffers: selectbuffer! */
			
			vd= sa->spacedata.first;
			if(base->lay & vd->lay) {
				areawinset(sa->win);

				draw_object(base);

				sa->win_swap= WIN_FRONT_OK;
			}
		}
		sa= sa->next;
	}
	if(curarea!=tempsa) areawinset(tempsa->win);
	
	G.f &= ~G_DRAW_EXT;

	glDrawBuffer(GL_BACK);
	
	if(G.zbuf) {
		G.zbuf= 0;
		glDisable(GL_DEPTH_TEST);
	}
}
