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

	Title :                 Display module
	Filename :              display.c
	Author :                Thomas Szirtes
	Revision :              1.0

	Notes :                 Controls all the main display functions

	Copyright :             (C) SEGA Europe 1998

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

#include        "ftypes.h"

#ifdef  USING_SET4
 #include        <shinobi.h>
#else
 #include        <ninja.h>
#endif

#include        "particle.h"
#include        "future.h"
#include        "tools.h"
#include        "camera.h"


/*
 *              EXTERNAL DECLARATIONS
 */

extern          SHIP                *shipdb[];
extern          NJS_TEXLIST         texlist_ship1_ship1;
extern          NJS_LIGHT           flight;
extern          NJS_MATERIAL		mat_ship1_ship1_exhaust[];
extern          NJS_OBJECT          object_test_lazer_lazer[];
extern          NJS_MATRIX          mtest;
/* shield objects */
extern          NJS_OBJECT          object_shield_sphere_sphere[];
extern          NJS_TEXLIST         texlist_shield_sphere;
extern          NJS_MATERIAL		matlist_shield_sphere_sphere[];
/* sky */
extern          NJS_TEXLIST         texlist_sky_grid;

extern          CAMERA  mycam;
extern          myglobals;
extern          PDATABASE           particle_database;
extern			NJS_LIGHT       tlight;


/*
 *              DEFINITIONS
 */

#define         FLOOR_AREA                      37                              
#define         HALF_FLOOR_AREA                 (FLOOR_AREA>>1)
#define         FLOOR_NUM_PT                    ((FLOOR_AREA+1)*(FLOOR_AREA+1))

#define         LOD_DISTANCE                    19*(GRID_SIZE)
#define         SHIP_LOD_DISTANCE               6*(GRID_SIZE)


/*
 *              MODULE VARIABLES
 */



/*------------------------- BACKDROP -----------------------------// */

/* Scroll data for backdrop - this will probably be replaced with 3D hemisphere */
static NJS_SCROLL       scl;                    

/* Backdrop map data */
static Uint32           backmap[4][4] = {
	{NJM_MAP(0,0,0),NJM_MAP(1,0,0),NJM_MAP(2,0,0),NJM_MAP(3,0,0)},
	{NJM_MAP(4,0,0),NJM_MAP(5,0,0),NJM_MAP(6,0,0),NJM_MAP(7,0,0)},
	{NJM_MAP(0,0,0),NJM_MAP(0,0,0),NJM_MAP(0,0,0),NJM_MAP(0,0,0)},
	{NJM_MAP(0,0,0),NJM_MAP(0,0,0),NJM_MAP(0,0,0),NJM_MAP(0,0,0)},
};

/* Back drop texture */
static  NJS_TEXNAME     texname_backdrop[] = {
	{"sky11",0,0},
	{"sky12",0,0},
	{"sky13",0,0},
	{"sky14",0,0},
	{"sky21",0,0},
	{"sky22",0,0},
	{"sky23",0,0},
	{"sky24",0,0},
};

/* Backdrop texture list */
static  NJS_TEXLIST     texlist_backdrop = { texname_backdrop, 8 };


/*----------------------- SHIP EXHAUST ----------------------------// */
static  NJS_LIGHT               exhaust_light;
static  NJS_TEXANIM             exhaust_texanim[] = {
											 { 64,64,32,32,0,0,255, 255,5,0 },
											};
static  NJS_SPRITE              sprite;


static  NJS_TEXANIM             lazer_texanim[] =       {       
											 { 64,64,32,32,0,0,255, 255,3,0 }
											};

static  NJS_TEXANIM             lazerbullet_texanim[] = {       
											 { 64,64,32,32,0,0,255, 255,4,0 }
											};

static  Uint16                  instance_drawn_count;
static  Uint16                  instance_drawn[256];

static  NJS_POINT3              lazer_point[4]= {
										 {20.f,-32.f,-100.f},
										 {84.f,-32.f,-100.f},
										 {84.f,32.f,-100.f},
										 {20.f,32.f,-100.f}
										};
static  NJS_COLOR               lazer_color[4];
static  NJS_COLOR               lazer_uv[4];
static  NJS_POINT3COL			lazer_p;

/* fire sprite */
static	NJS_SPRITE				fire_spr;
static  NJS_TEXANIM             fire_texanim[] = {      
											 { 64,64,32,32,0,0,255, 255,3,0 }
											};


/*-------------------------- FLOOR DATA ----------------------------// */

/* generated arrays */
static  NJS_TEXNAME             texname_floor[2];
static  NJS_POINT3              floor_pts[FLOOR_NUM_PT];
static  Sint16                  floor_grid1[FLOOR_AREA*FLOOR_AREA*6];
static  long                    floor_uv1[FLOOR_AREA*FLOOR_AREA*4];     
static  long                    floor_col1[FLOOR_AREA*FLOOR_AREA*4];


/* pre-defined arrays */
static  NJS_TEXLIST             texlist_floor   = { texname_floor, 1 };
static  NJS_MATERIAL    floor_mat[]             = {
											{ARGB( 255, 255, 255, 255 ),ARGB( 255,255,255,255 ),0.0F,0,0x95210400}, /*bit23 */
										  };

static  NJS_MESHSET             floor_mesh[]    = {
											{0x0000,(FLOOR_AREA*FLOOR_AREA*2),floor_grid1,NULL,NULL,NULL,(NJS_COLOR *)floor_uv1},
										  };

static  NJS_MODEL               floor_mdl[]             = {
											{floor_pts,NULL,FLOOR_NUM_PT,floor_mesh,floor_mat,1,1,{0.f,0.f,0.f},.707106f}
										  };

static  NJS_OBJECT              floor_obj[]             = {
											{0x0017, floor_mdl, {0.f, 0.f, 0.f},{(Angle)0.f, (Angle)0.f, (Angle)0.f}, {1.f, 1.f, 1.f}, NULL,NULL}
										  };

static  int             use_textures_flag                               =       TRUE;


NJS_LIGHT               engine_light;


/*---------------------------------- PRIVATE FUNCTIONS ----------------------------------------// */

/*--------------------------------------------------------------------------
 
  void display_floorinit(void)
 
  Parameters:
 
  Returns:
 
  Notes:
		Generates a trianglar mesh for the floor and textures it
  
  --------------------------------------------------------------------------*/

static void display_floorinit()
{
	int i,j,n,m,k;

	/* Calculate vertex data - only one set of vertex data per model */
	k       =       0;
	for(j=0;j<=FLOOR_AREA;j++)
	{
		for(i=0;i<=FLOOR_AREA;i++)
		{
			floor_pts[k].x          =       (Float)((i-HALF_FLOOR_AREA)*GRID_SIZE);
			floor_pts[k].z          =       (Float)((j-HALF_FLOOR_AREA)*GRID_SIZE);
			floor_pts[k].y          =       0.f;
			k++;
		}
	}
	
	/* grid data and UV --- tops */
	n=0; m=0;
	for(j=0;j<FLOOR_AREA;j++)
	{
		for(i=0;i<FLOOR_AREA;i++)
		{
			/* tri 1 */
			/* A */
			floor_grid1[n]  =       i+(j*(FLOOR_AREA+1));
			floor_uv1[n++]  =       UV(0,0);
			/* B */
			floor_grid1[n]  =       i+((j+1)*(FLOOR_AREA+1));
			floor_uv1[n++]  =       UV(0,255);
			/* C */
			floor_grid1[n]  =       i+(j*(FLOOR_AREA+1))+1;
			floor_uv1[n++]  =       UV(255,0);
			m++;

			/* tri 2 */
			/* D */
			floor_grid1[n]  =       i+((j+1)*(FLOOR_AREA+1))+1;
			floor_uv1[n++]  =       UV(255,255);
			/* C */
			floor_grid1[n]  =       i+(j*(FLOOR_AREA+1))+1;
			floor_uv1[n++]  =       UV(255,0);
			/* B */
			floor_grid1[n]  =       i+((j+1)*(FLOOR_AREA+1));
			floor_uv1[n++]  =       UV(0,255);
		
			m++;
		}
	}

	floor_mesh[0].nbMesh    =       m;

}




/*--------------------------------------------------------------------------
 
  static void display_drawbuilding(Uint16 inst, Uint8 gnd, int light_state)
 
  Parameters:
		inst			building instance identifier
		gnd				ground height
		light_state		used for switching on off lights on buildings
  
  Returns:
 
  Notes:
		Checks to see it building is viewable at that particular position
		if so sets up textures and draws it.
 
  --------------------------------------------------------------------------*/

static void display_drawbuilding(Uint16 inst, Uint8 gnd, int light_state)
{
	static          NJS_POINT3      p3;
	Uint8           id;
	Uint8           orient;
	float           d;

	/* first lets check if in view */
	p3.x    =       (float)GRID2P(build_inst[inst].i);
	p3.y    =       0.0f;
	p3.z    =       (float)GRID2P(build_inst[inst].j);

	id              =       build_inst[inst].id;

	/* calculate distance */
	d               =       njDistanceP2P(&p3,&mycam.pos);

	if (d > LOD_DISTANCE )
	{
		if (buildings[id].lightobj != NULL)
			(buildings[id].lightobj)->evalflags     |= NJD_EVAL_BREAK;      
		/* switch off texture/alpha and lighting - this just a silohette */
		if ( use_textures_flag  !=      FALSE )
		{
			use_textures_flag       =       FALSE;
			/* this code is disabled for now */
/*          njSetConstantAttr( ~(NJD_FLAG_USE_TEXTURE|NJD_FLAG_USE_ALPHA), NJD_FLAG_IGNORE_LIGHT );
			njControl3D( NJD_CONTROL_3D_CONSTANT_ATTR | NJD_CONTROL_3D_CONSTANT_MATERIAL );
*/              }
	}
	else
	{
		if (buildings[id].lightobj != NULL)
			(buildings[id].lightobj)->evalflags     &= ~NJD_EVAL_BREAK;     
		if ( use_textures_flag  !=      TRUE )
		{
			/* switch on textures */
			use_textures_flag = TRUE;
			njSetConstantAttr( ~0 , NJD_FILTER_BILINEAR );
			/*
			njControl3D     ( NJD_CONTROL_3D_CONSTANT_ATTR |  NJD_CONTROL_3D_ENABLE_ALPHA );
			*/
		}
	}

	/* out of view then throw away */
	njPushMatrix    (NULL);
		njTranslate             (NULL, p3.x, gnd, p3.z);
	
		/* Do orientation ( in 90 degree units ) */
		orient  =       build_inst[inst].flag & INST_FLAG_ORIENT_MASK;
		switch (orient)
		{
		/* case 0 = no rotation */
		case(INST_FLAG_ORIENT1) : njRotateY ( NULL, NJM_DEG_ANG(90.f) );  break;
		case(INST_FLAG_ORIENT2) : njRotateY ( NULL, NJM_DEG_ANG(180.f) ); break;
		case(INST_FLAG_ORIENT3) : njRotateY ( NULL, NJM_DEG_ANG(270.f) ); break;
		}

		/* Work out what detail level to use - based on distance */
		njSetTexture    ( buildings[id].lotex );
		njFastDrawObject( buildings[id].loobj );        


		/* draw lights */
		if (light_state==1)
		{
			if(buildings[id].lighttemplate!=NULL)
			{
				/* lights are present on building */
				BLDLIGHTS_Draw( buildings[id].lighttemplate, build_inst[inst].lbdlightinst );
			}
		}

	njPopMatrix             (1);
}


/*--------------------------------------------------------------------------
 
  void display_lazer(float x, float y, float z, float radius, Uint8 alpha)

  Parameters:
		x,y,z                   position to place lazer
		radius                  size of lazer flare
		alpha                   translucency of lazer flare

  Returns:
 
  Notes:
 
  --------------------------------------------------------------------------*/
void display_lazer(float x, float y, float z, float radius, Uint8 alpha)
{
	
	/* set alpha */
	lazer_color[0].argb.a   =       alpha;
	lazer_color[1].argb.a   =       alpha;
	lazer_color[2].argb.a   =       alpha;
	lazer_color[3].argb.a   =       alpha;

	lazer_point[0].x                =       x-radius;
	lazer_point[0].y                =       y-radius;
	lazer_point[0].z                =       z;
	lazer_point[1].x                =       x+radius;
	lazer_point[1].y                =       y-radius;
	lazer_point[1].z                =       z;
	lazer_point[2].x                =       x+radius;
	lazer_point[2].y                =       y+radius;
	lazer_point[2].z                =       z;
	lazer_point[3].x                =       x-radius;
	lazer_point[3].y                =       y+radius;
	lazer_point[3].z                =       z;

	njSetTexture    ( &misc_texlist );
	njSetTextureNum ( 2 );
	njDrawPolygon3D ( &lazer_p, 4, NJD_TRANSPARENT|NJD_USE_TEXTURE|NJD_DRAW_NORMAL|NJD_FILL );
}


/*---------------------------  P U B L I C   F U N C T I O N S  ---------------------------------------// */


/*--------------------------------------------------------------------------
 
  void DISPLAY_Fire(FIRE *fire)

  Parameters:
		fire	fire object to display

  Returns:
 
  Notes:
 
  --------------------------------------------------------------------------*/
void DISPLAY_Fire(FIRE *fire)
{
	float   r;

	r       =       (float)(GenerateRandom()%5)*0.005f;
	/* consists of three sections *

	/* Head Ball - scalable sprite */
	fire_spr.tlist  =       &misc_texlist;
	fire_spr.tanim  =       fire_texanim;
	fire_spr.ang    =       NJM_DEG_ANG(0.0f);
	fire_spr.sx             =       0.14f+r; 
	fire_spr.sy             =       0.14f+r; 
	fire_spr.p.x    =       fire->pos.x; 
	fire_spr.p.y    =       fire->pos.y; 
	fire_spr.p.z    =       fire->pos.z; 
	njDrawSprite3D  ( &fire_spr, 0, NJD_SPRITE_SCALE | NJD_SPRITE_ALPHA );

	/* Tail - textured polygons */
	

	
	/* set alpha */
	
	lazer_color[0].argb.a   =       255;
	lazer_color[0].argb.r   =       230;
	lazer_color[0].argb.g   =       230;
	lazer_color[0].argb.b   =       255;

	lazer_color[1].argb.a   =       230;
	lazer_color[1].argb.r   =       230;
	lazer_color[1].argb.g   =       230;
	lazer_color[1].argb.b   =       255;

	lazer_color[2].argb.a   =       30;
	lazer_color[2].argb.r   =       0;
	lazer_color[2].argb.g   =       0;
	lazer_color[2].argb.b   =       255;
	njSetTexture    ( &misc_texlist );
	njSetTextureNum ( 7 );

	lazer_point[0].x                =       fire->pos.x-1.5f;
	lazer_point[0].y                =       fire->pos.y;
	lazer_point[0].z                =       fire->pos.z;
	lazer_point[1].x                =       fire->pos.x+1.5f;
	lazer_point[1].y                =       fire->pos.y;
	lazer_point[1].z                =       fire->pos.z;
	lazer_point[2].x                =       fire->pos.x-(fire->dir.x*3.f);
	lazer_point[2].y                =       fire->pos.y-(fire->dir.y*3.f);
	lazer_point[2].z                =       fire->pos.z-(fire->dir.z*3.f);

	njDrawTriangle3D        ( &lazer_p, 1, NJD_TRANSPARENT|NJD_USE_TEXTURE|NJD_DRAW_NORMAL|NJD_FILL );

	lazer_point[0].x                =       fire->pos.x;
	lazer_point[0].y                =       fire->pos.y-1.5f;
	lazer_point[0].z                =       fire->pos.z;
	lazer_point[1].x                =       fire->pos.x;
	lazer_point[1].y                =       fire->pos.y+1.5f;
	lazer_point[1].z                =       fire->pos.z;
	lazer_point[2].x                =       fire->pos.x-(fire->dir.x*3.f);
	lazer_point[2].y                =       fire->pos.y-(fire->dir.y*3.f);
	lazer_point[2].z                =       fire->pos.z-(fire->dir.z*3.f);

	njDrawTriangle3D        ( &lazer_p, 1, NJD_TRANSPARENT|NJD_USE_TEXTURE|NJD_DRAW_NORMAL|NJD_FILL );

}



/*--------------------------------------------------------------------------

  void DISPLAY_Init(void)
 
  Parameters:
	None
 
  Returns:
 
  Notes:
 
  --------------------------------------------------------------------------*/

void DISPLAY_Init() 
{
	int n;
	Sint32  r;

	/*------------- Load Building Textures ------------------// */

	for(n=0;n<MAX_BUILDINGS;n++)
	{
		if (buildings[n].lotex!=NULL)
			njLoadTexture   ( buildings[n].lotex );
	}

	njClipZ                         ( -1.f,         (float)-(65535) );

	/*------------- Load misc Textures -----------------*/

	njLoadTexture   ( &texlist_shield_sphere );
	njLoadTexture   ( &texlist_sky_grid );


    /*------------- Set up back drop --------------// */
    
	/* init scroll */
	scl.celps           =       128;							/* cell size */
    scl.mapw            =       4;                              /* map width (cell) */
    scl.maph            =       4;                              /* map height(cell) */
    scl.sx              =       1.0f;							/* horizontal scale */
    scl.sy              =       1.0f;							/* vertical scale   */
    scl.spx             =       320.f;                          /* scaling center x      */
    scl.spy             =       240.f;                          /* scaling center y  */
    scl.list            =       &texlist_backdrop;				/* texture list      */
    scl.map             =       (Uint32*)backmap;				/* map aray          */
    scl.mflag           =       ON;                             /* matrix flag */
    scl.sflag           =       ON;                             /* scaling flag */
    scl.pr              =       -((FLOOR_AREA-3)*GRID_SIZE);    /* priority     */
    scl.px              =       0.f;                            /* translate x  */
    scl.py              =       0.f;                            /* translate y  */
    scl.bx              =       0.f;                            /* map draw start x */
    scl.by              =       0.f;                            /* map draw start y */
    scl.cx              =       320.f;                          /* rotation center x */
    scl.cy              =       240.f;                          /* rotation center y */
    scl.clip[0].x       =       0.f;                            /* clip left-up x */
    scl.clip[0].y       =       0.f;                            /* clip left-up y */
    scl.clip[1].x       =       640.f;                          /* clip right-down x */
    scl.clip[1].y       =       480.f;                          /* clip right-down y */
    scl.sclc.argb.a     =       255;                            /* A */
    scl.sclc.argb.r     =       255;                            /* R */
    scl.sclc.argb.g     =       255;                            /* G */
    scl.sclc.argb.b     =       255;                            /* B */
    scl.colmode         =       NJD_COLOR_MODE_PACKED_TEXTURE;  /* color mode */
    scl.m[_SM00]        =       1.f;
    scl.m[_SM01]        =       0.f;
    scl.m[_SM10]        =       0.f;
    scl.m[_SM11]        =       1.f;
	


	/* --- Initialize Floor --- // */
	/* Load textures */
	njSetTextureName(&texname_floor[0],"floor3.pvr",0,NJD_TEXATTR_TYPE_FILE);
	r       =       njLoadTexture   ( &texlist_floor );

	r       =       njLoadTexture   ( &texlist_backdrop );

	/* Create object */
	display_floorinit();


	/* SHIP LAZER POLYGON INITIALIZE */
	lazer_p.p                               =       lazer_point;
	lazer_p.col                             =       lazer_color;
	lazer_p.tex                             =       lazer_uv;
	lazer_p.num                             =       4;

	lazer_uv[0].tex.u               =       0;      
	lazer_uv[0].tex.v               =       0;
	lazer_uv[1].tex.u               =       255;
	lazer_uv[1].tex.v               =       0;
	lazer_uv[2].tex.u               =       255;
	lazer_uv[2].tex.v               =       255;
	lazer_uv[3].tex.u               =       0;
	lazer_uv[3].tex.v               =       255;

	lazer_color[0].color    =       0xffffffff;     
	lazer_color[1].color    =       0xffffffff;
	lazer_color[2].color    =       0xffffffff;
	lazer_color[3].color    =       0xffffffff;
       
	njCreateLight           ( &engine_light, NJD_DIR_LIGHT );
	njSetLightColor         ( &engine_light, 0.6f, 0.6f, 1.0f);
	njSetLightIntensity     ( &engine_light, 2.0f, 2.0f, 2.0f);
	njLightOff              ( &engine_light );

}



/*--------------------------------------------------------------------------
 
  void DISPLAY_Backdrop(CAMERA *cam)
 
  Parameters:
	cam                     pointer to camera object on which to superimpose backdrop
 
  Returns:
 
  Notes:
		Superimposes the backdrop onto the specified camera view
		This code is really fudged... I hate fudged code so later I
		intend to organize a proper backdrop object
 
  --------------------------------------------------------------------------*/

void    DISPLAY_Backdrop(CAMERA *cam)
{
	NJS_POINT3      p3;
	NJS_POINT2      p2;


	/* Load up textures */
	njSetTexture(&texlist_backdrop);

	/* project background position = on ground level, 7000 units in distance */
	p3.y    =       0;
	p3.z    =       (njCos(cam->head_angle.yz)*7000.f)+cam->pos.z;
	p3.x    =       (njSin(cam->head_angle.yz)*7000.f)+cam->pos.x;
	njProjectScreen(NULL, &p3, &p2);

	/* Calculate position */
	scl.bx  =       (float) - ( 512.f * (NJM_ANG_DEG(cam->head_angle.yz) / 90.f) );
	scl.by  =        250 - p2.y;    
	/* set up rotation matrix */
	scl.m[_SM00] = njCos(-cam->head_angle.roll);
    scl.m[_SM01] = -njSin(-cam->head_angle.roll);
    scl.m[_SM10] = -scl.m[_SM01];
    scl.m[_SM11] = scl.m[_SM00];


	/* Disable fog whilst we draw the scroll otherwise we won't see it */
	camera_FogOff(cam);
	njDrawScroll( &scl );
	camera_FogOn(cam);
}

/*--------------------------------------------------------------------------
 
  void DISPLAY_Lava(CAMERA *cam)
 
  Parameters:
	cam             pointer to camera
 
  Returns:
 
  Notes:
 
  --------------------------------------------------------------------------*/
void DISPLAY_Lava(CAMERA *cam)
{
	extern  NJS_OBJECT      object_sky_grid_grid[];
	extern  NJS_MATERIAL    matlist_sky_grid_grid[];
	static  Uint8   bright  =       200;
	static  Uint8   bright_d=       1;

	
	bright  +=      bright_d;
	matlist_sky_grid_grid[0].diffuse.argb.r =       bright;
	matlist_sky_grid_grid[0].diffuse.argb.g =       bright;
	matlist_sky_grid_grid[0].diffuse.argb.b =       bright;

	if (bright>=255) bright_d               =       -2;
	if (bright<=200) bright_d               =       2;


	njPushMatrix    ( NULL );
		njTranslate             ( NULL, 0.f, 64.f, 0.f); 
		njSetTexture    ( &texlist_sky_grid );
		njDrawObject    ( object_sky_grid_grid );
	njPopMatrix             (1);

}


/*--------------------------------------------------------------------------
 
  void DISPLAY_Ship(CAMERA *cam)
 
  Parameters:
	ship            pointer to ship object to display
 
  Returns:
 
  Notes:
 
  --------------------------------------------------------------------------*/

void DISPLAY_Ship(SHIP *ship)
{
	static  float			flicker=0.0f;
	static int              n=0;
	static NJS_ARGB         argb;
	register                float   r;

	if (ship->exhaust>0.f) ship->exhaust    -=      0.06f;

	if (ship->move.acceleration!=0.f)
	{
		ship->exhaust   =       1.0f;
	}
	
	if (flicker=0.0f) flicker=3.0f; else flicker=0.0f;

	if (!(ship->flags&SHIP_FLAG_USER))
	{
		njFogDisable();
	}

	/* do engine light if user ship */
	if (ship->flags&SHIP_FLAG_USER)
	{
		r = 2.f - ((float)(GenerateRandom()%32767))/32767.f;
		njSetLightDirection ( &engine_light,
							njSin(NJM_DEG_ANG(ship->move.yaw)),
							njSin(NJM_DEG_ANG(ship->move.pitch)),
							njCos(NJM_DEG_ANG(ship->move.yaw)) );
		njSetLightIntensity     ( &engine_light, (ship->exhaust*r), (ship->exhaust*r), (ship->exhaust*r));

		if(ship->exhaust>0.f)
		{
			njLightOn(&engine_light);
		}
	}


	/* calculate appropiate level of detail */
	/* unfortunately I have supplied any LOD objects - so this is ineffective at the moment */
	if ( (njDistanceP2P( &ship->move.position, &mycam.pos ) < SHIP_LOD_DISTANCE) || (ship->loobj==NULL))
	{
		njSetTexture            (ship->tex);
		njDrawObject            (ship->obj);    
	}
	else
	{
		njSetTexture            (ship->lotex);
		njDrawObject            (ship->loobj);  
	}


	/* draw shield */
	if(ship->shield_anim>0) 
	{
		ship->shield_anim -= 10;
		matlist_shield_sphere_sphere[0].diffuse.argb.a  =       (unsigned char)ship->shield_anim; 

		object_shield_sphere_sphere[0].ang[0]           +=      NJM_DEG_ANG(10.f);
		object_shield_sphere_sphere[0].ang[1]           +=      NJM_DEG_ANG(5.f);
		njSetTexture            ( &texlist_shield_sphere );
		njDrawObject            ( object_shield_sphere_sphere );
	}

	njLightOff(&engine_light);

	if (!(ship->flags&SHIP_FLAG_USER))
	{
		njFogEnable();
		return;
	}

/*	DISPLAY_UserLazer(ship);
*/	
	sprite.tlist    =       &misc_texlist;
	sprite.tanim    =       exhaust_texanim;
	sprite.ang              =       0;

	for(n=6;n>=0;n--)
	{
		r       =       1.f - ((float)(GenerateRandom()%19735))/65535.f;

		argb.a          =       (float)ship->exhaust*r*((1.f-(n*0.1f)));
		argb.r          =       (float)(1.0f);
		argb.g          =       (float)(1.0f);
		argb.b          =       (float)(1.0f);
		njSetConstantMaterial( &argb );
		sprite.p.x      =       -2.34f; 
		sprite.p.y      =       0.21f; 
		sprite.p.z      =       8.23f+(n*0.6f*ship->exhaust); 
		sprite.sx       =       (float)(ship->exhaust*r*(0.07f-(n*0.006)));
		sprite.sy       =       (float)(ship->exhaust*r*(0.07f-(n*0.006)));
		njDrawSprite3D( &sprite, 0, NJD_SPRITE_ANGLE | NJD_SPRITE_SCALE | NJD_SPRITE_COLOR | NJD_SPRITE_ALPHA );
		sprite.p.x      =       2.34f; 
		njDrawSprite3D( &sprite, 0, NJD_SPRITE_ANGLE | NJD_SPRITE_SCALE | NJD_SPRITE_COLOR | NJD_SPRITE_ALPHA );
	}


	njFogEnable();

}



/*--------------------------------------------------------------------------
 
  void DISPLAY_Ships(Uint16 n)

  Parameters:
		n			ship identifier number

  Returns:
 
  Notes:
		Draw ships by identifier number

  --------------------------------------------------------------------------*/

void DISPLAY_Ships(Uint16 n)
{
	SHIP *sh;
	
	while   (n != NO_SHIP_ID)
	{
	njLightOn   ( &tlight );
		sh      =       shipdb[n];
		if (!(sh->flags&SHIP_FLAG_DISABLE))
		{
			njPushMatrix            ( NULL );
				njTranslate                     ( NULL, sh->move.position.x, sh->move.position.y, sh->move.position.z );
				njRotateY                       ( NULL, NJM_DEG_ANG(180.f+sh->move.yaw) );
				njRotateZ                       ( NULL, NJM_DEG_ANG(sh->move.roll) );
				njRotateX                       ( NULL, NJM_DEG_ANG(sh->move.pitch) );
				DISPLAY_Ship            ( sh );
			njPopMatrix                     ( 1 );
		}
		n       =       sh->next_ship;
	njLightOff   ( &tlight );
	}
	
}



/*--------------------------------------------------------------------------
 
  void DISPLAY_Map(MAP *map)
 
  Parameters:
	map		Map data pointer
	mode	debug mode on or off (for level editor)
 
  Returns:
 
  Notes:

  Issues :
	DRAW DETECTION - buildings can sit over many grid units, but as we scan
	the grid we do not want to trigger building more than once - therefore
	we need a tag that building as drawn. The problem is how to manage this
	in the fastest way possible. I have drawn a hybrid system - it stores the
    instance number in an array database, and then tags the instance as drawn.
    This means that we can use the array to quickly refresh the drawn flags
    afterwards.
  
  --------------------------------------------------------------------------*/
void DISPLAY_Map(MAP *map,int mode)
{
	
	Sint16                  i,j,k;
	Sint16                  ci,cj;
	Sint16                  gi,gj;
	extern  CAMERA			mycam;
	int                     n;
	int                     light_state;
	Uint16                  inst;
	NJS_ARGB				argb;


	argb.a		= -128.0f;
	argb.r		= 0.f;
	argb.g		= 0.f;
	argb.b		= 0.f;

	njSetConstantMaterial( &argb );


	/* for level editor mode */
	if (mode!=0) light_state=0; else light_state=1;

	instance_drawn_count            =               0;                      /* refresh array */

	
	/*---- PROCESS FLOOR -----// */

	/* Convert user position to map GROUND position */
	/* Places the floor grid always in front of camera and */
	/* adjusts floor data to match view area - thus 80% of polygons are always visible regardless of camera */
	/* Note ninja does a lot of this for you - but I give it a bit of extra help at no cost */

	ci      =       (Sint16)((int)P2GRID(mycam.pos.x)) + 
			(int)((HALF_FLOOR_AREA) * njSin(mycam.head_angle.yz)* njCos(mycam.head_angle.xz));

	cj      =       (Sint16)((int)P2GRID(mycam.pos.z)) + 
			(int)((HALF_FLOOR_AREA) * njCos(mycam.head_angle.yz) * njCos(mycam.head_angle.xz));


	
	/* Modify polygon mesh to fit current city view */
	k=0;
	for(j=0;j<=FLOOR_AREA;j++)
	{
		for(i=0;i<=FLOOR_AREA;i++)
		{
			gi = (ci + i - HALF_FLOOR_AREA) & 0x7f;
			gj = (cj + j - HALF_FLOOR_AREA) & 0x7f;

			floor_pts[k].y          =       map->map[ gi ][ gj ].gnd;

			k++;
		}
	}


	/* Draw floor  */
	if (mode==0)
	{
		njPushMatrix    ( NULL );
			njTranslate             ( NULL, (Float)ci*128, 0.f, (Float)cj*128 );
			njSetTexture    ( &texlist_floor );
			njDrawObject    ( floor_obj );
		njPopMatrix             ( 1 );
	}

	njLightOff                      ( &tlight );

	DISPLAY_Lava(&mycam);
	
	/* ----- PROCESS BUILDINGS ----- // */
	for(j=0; j<FLOOR_AREA; j++)
	{
		for(i=0; i<FLOOR_AREA; i++)
		{

			gi      =       (ci + (i - HALF_FLOOR_AREA))&0x7f;                      /* wrap around */
			gj      =       (cj + (j - HALF_FLOOR_AREA))&0x7f;

			if (map->map[gi][gj].ship!=NO_SHIP_ID)
			{
				DISPLAY_Ships ( map->map[gi][gj].ship );
			}
			
			inst    =       map->map[gi][gj].inst;

			if (inst <= instance_count)
			{
				/* check if building has been drawn? */
				if (!(build_inst[inst].flag & INST_FLAG_DRAWN)) 
				{
					/* no then set as drawn, save instance in array */
					build_inst[inst].flag                                   |=      INST_FLAG_DRAWN;
					instance_drawn[instance_drawn_count++]  =       inst;

					if (mode==0)
						display_drawbuilding( inst, map->map[gi][gj].gnd, light_state );
					else
						display_drawbuilding( inst, 0, light_state );
				
					/* This is a smoking chimney - hence draw particle system */
					if (buildings[build_inst[inst].id].particletemplate != NULL)
					{
						if (build_inst[inst].particleinst != 0xffff)
						{
							PARTICLE_Generator(particle_database.systems[build_inst[inst].particleinst]);
							PARTICLE_Update(particle_database.systems[build_inst[inst].particleinst]);
						}
					}

				}
			}

		}
	}

	/* make sure we switch textures back on if they have been disabled */
	use_textures_flag = TRUE;
	njSetConstantAttr( ~0 , NJD_FILTER_BILINEAR );
/*	njControl3D                     ( NJD_CONTROL_3D_CONSTANT_ATTR |
						  NJD_CONTROL_3D_ENABLE_ALPHA );
*/
	njLightOn                       ( &tlight );
	
	/* clear instance drawn flags */
	for(n=0;n<instance_drawn_count;n++)
		build_inst[instance_drawn[n]].flag      &=      ~INST_FLAG_DRAWN;

}
