MuckyFoot-UrbanChaos/fallen/DDEngine/Source/aeng.cpp
2017-05-20 11:14:17 +10:00

17085 lines
316 KiB
C++

//
// Another engine.
//
#include <MFStdLib.h>
#include <DDLib.h>
#include <math.h>
#include "game.h"
#include "aeng.h"
#include "font.h"
#include "ngamut.h"
#include "poly.h"
#include "texture.h"
#include "matrix.h"
#include "message.h"
#include "font2d.h"
#include "figure.h"
#include "build.h"
#include "mesh.h"
#include "dirt.h"
#include "sky.h"
#include "mist.h"
#include "id.h"
#include "shadow.h"
#include "puddle.h"
#include "az.h"
#include "aa.h"
#include "smap.h"
#include "sewer.h"
#include "drip.h"
#include "wibble.h"
#include "shape.h"
#include "bang.h"
#include "mav.h"
#include "fire.h"
#include "animtmap.h"
#include "sprite.h"
#include "spark.h"
#include "glitter.h"
#include "Text.h" // Guy.
#include "cone.h"
#include "ob.h"
#include "morph.h"
#include "trip.h"
#include "text.h"
#include "pap.h"
#include "night.h"
#include "c:\fallen\headers\supermap.h"
#include "hook.h"
#include "sm.h"
#include "ns.h"
#include "cloth.h"
#include "facet.h"
//#include "c:\fallen\sedit\headers\es.h"
#include "ic.h"
#include "comp.h"
#include "cam.h"
#include "c:\fallen\headers\tracks.h"
#include "pcom.h"
#include "drawxtra.h"
#include "balloon.h"
#include "snipe.h"
#include "c:\fallen\headers\inside2.h"
#include "psystem.h"
#include "fc.h"
#include "memory.h"
#include "ware.h"
#include "statedef.h"
#include "pow.h"
#include "FMatrix.h"
#include "eway.h"
#include "c:\fallen\headers\env.h"
#include "animate.h"
#include "oval.h"
#include "crinkle.h"
#include "sw.h"
#include "c:\fallen\headers\sound.h"
#include "vertexbuffer.h"
#include "BreakTimer.h"
#include "polypoint.h"
#include "grenade.h"
#include "superfacet.h"
#include "farfacet.h"
#include "interfac.h"
#include "polypage.h"
#include "DCLowLevel.h"
#ifdef TARGET_DC
#include <shsgintr.h>
#else
#define POLY_set_local_rotation_none() {}
#endif
#define AENG_MAX_BBOXES 8
#define AENG_BBOX_PUSH_IN 16
#define AENG_BBOX_PUSH_OUT 4
//#ifdef DEBUG
#if 0
#define ANNOYINGSCRIBBLECHECK ScribbleCheck()
static void ScribbleCheck ( void )
{
ASSERT ( prim_faces4[1].Points[0] >= 48 );
ASSERT ( prim_faces4[1].Points[0] < 62 );
ASSERT ( prim_faces4[1].Points[1] >= 48 );
ASSERT ( prim_faces4[1].Points[1] < 62 );
ASSERT ( prim_faces4[1].Points[2] >= 48 );
ASSERT ( prim_faces4[1].Points[2] < 62 );
ASSERT ( prim_faces4[1].Points[3] >= 48 );
ASSERT ( prim_faces4[1].Points[3] < 62 );
}
#else
#define ANNOYINGSCRIBBLECHECK
#endif
#ifndef TARGET_DC
#define LOG_ENTER(x) {}
#define LOG_EXIT(x) {}
#define LOG_EVENT(x) {}
#endif
#ifdef TARGET_DC
#define AENG_rdtsc() 0
#else
ULONG AENG_rdtsc()
{
ULONG hi;
ULONG lo;
_asm
{
rdtsc
mov hi, edx
mov lo, eax
}
ULONG ans;
ans = lo >> 16;
ans |= hi << 16;
ans = lo;
return ans;
}
#endif
void AENG_draw_far_facets(void);
void AENG_draw_box_around_recessed_door(DFacet *df, SLONG inside_out);
void AENG_get_rid_of_unused_dfcache_lighting(SLONG splitscreen);
void AENG_draw_inside_floor(UWORD inside_index,UWORD inside_room,UBYTE fade);
UBYTE aeng_draw_cloud_flag = 1;
UWORD light_inside=0;
UWORD fade_black=1;
#ifdef TARGET_DC
#define sw_hack FALSE
#else
UBYTE sw_hack;
#endif
#ifndef TARGET_DC
UBYTE cloud_data[32][32];
SLONG cloud_x,cloud_z;
#endif
extern SLONG FirstPersonMode;
SLONG FirstPersonAlpha = 255;
#define MAX_FPM_ALPHA 160
int AENG_total_polys_drawn;
int AENG_detail_stars = 1;
int AENG_detail_shadows = 1;
int AENG_detail_moon_reflection = 1;
int AENG_detail_people_reflection = 1;
int AENG_detail_puddles = 1;
int AENG_detail_dirt = 1;
int AENG_detail_mist = 1;
int AENG_detail_rain = 1;
int AENG_detail_skyline = 1;
int AENG_detail_filter = 1;
int AENG_detail_perspective = 1;
int AENG_detail_crinkles = 1;
#ifndef TARGET_DC
int AENG_estimate_detail_levels = 1;
#endif
SLONG AENG_cur_fc_cam;
#ifndef TARGET_DC
// Clouds?!?!?!?!?!?!? Madness.
void move_clouds(void)
{
cloud_x+=10;
cloud_z+=5;
}
SLONG global_b=0;
//
// calc a cloud shadow value for a world co-ord for reapeated use by prim or person or ...
//
void calc_global_cloud(SLONG x,SLONG y,SLONG z)
{
SLONG in,r,g,b;
SLONG in1,in2,in3,in0;
SLONG dx,dz,mx,mz;
if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME))
return;
y>>=1;
x=(x+(cloud_x)-y);//&0x1f;
z=(z+(cloud_z)-y);//&0x1f;
mx=(x>>8)&0x1f;
mz=(z>>8)&0x1f;
in0=cloud_data[mx][mz];
in1=cloud_data[(mx+1)&0x1f][mz];
in2=cloud_data[(mx)&0x1f][(mz+1)&0x1f];
in3=cloud_data[(mx+1)&0x1f][(mz+1)&0x1f];
// in0 in1
//
//
// in2 in3
dx=x&0xff;
dz=z&0xff;
if(dx+dz<256)
{
in=in0;
in+=((in1-in0)*dx)>>8;
in+=((in2-in0)*dz)>>8;
}
else
{
in=in3;
in+=((in2-in3)*(256-dx))>>8;
in+=((in1-in3)*(256-dz))>>8;
}
if(in<0)
in=0;
global_b=in;
}
//
// use pre-calced shadow value
//
void use_global_cloud(ULONG *col)
{
SLONG r,g,b;
SLONG in=global_b;
if (!aeng_draw_cloud_flag) return;
if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME))
return;
r=((*col)&0xff0000)>>16;
in=(in*(r))>>8;
{
r-=in;
if(r<0)
r=0;
}
g=((*col)&0xff00)>>8;
// if(g-global_bright>Mglobal_bright_CLOUD)
{
g-=in;
if(g<0)
g=0;
}
b=((*col)&0xff);
// if(b-global_bright>Mglobal_bright_CLOUD)
{
b-=in;//(global_bright*220)>>8;
if(b<0)
b=0;
}
*col=(*col&0xff000000)|(r<<16)|(g<<8)|(b);
}
//
// Take a co-ord in the world, calcultae how much shadow the clouds are producing at that point
// and darken the colour accordingly
#define MIN_CLOUD 48
inline void apply_cloud(SLONG x,SLONG y,SLONG z,ULONG *col)
{
return;
if (!aeng_draw_cloud_flag) return;
SLONG in,r,g,b;
SLONG in1,in2,in3,in0;
SLONG dx,dz,mx,mz;
if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME))
return;
y>>=1;
x=(x+(cloud_x)-y);//&0x1f;
z=(z+(cloud_z)-y);//&0x1f;
mx=(x>>8)&0x1f;
mz=(z>>8)&0x1f;
in0=cloud_data[mx][mz];
in1=cloud_data[(mx+1)&0x1f][mz];
in2=cloud_data[(mx)&0x1f][(mz+1)&0x1f];
in3=cloud_data[(mx+1)&0x1f][(mz+1)&0x1f];
// in0 in1
//
//
// in2 in3
dx=x&0xff;
dz=z&0xff;
if(dx+dz<256)
{
in=in0;
in+=((in1-in0)*dx)>>8;
in+=((in2-in0)*dz)>>8;
}
else
{
in=in3;
in+=((in2-in3)*(256-dx))>>8;
in+=((in1-in3)*(256-dz))>>8;
}
if(in<0)
in=0;
r=((*col)&0xff0000)>>16;
//
// use the redness that's there as a general brightness factor for the vertex
//
//
// adjust the shadow factor so dark things only get affected a little, & light things get affected a lot
//
in=(in*(r))>>8;
{
r-=in;
if(r<0)
r=0;
// if(r>255)
// r=255;
}
g=((*col)&0xff00)>>8;
// if(g-in>MIN_CLOUD)
{
g-=in;
if(g<0)
g=0;
// if(g>255)
// g=255;
}
b=((*col)&0xff);
// if(b-in>MIN_CLOUD)
{
b-=in;//(in*220)>>8;
if(b<0)
b=0;
// if(b>255)
// b=255;
}
*col=(*col&0xff000000)|(r<<16)|(g<<8)|(b);
}
void init_clouds(void)
{
MFFileHandle handle;
handle=FileOpen("data\\cloud.raw");
if(handle!=FILE_OPEN_ERROR)
{
FileRead(handle,cloud_data,1024);
FileClose(handle);
}
else
{
memset(cloud_data,0,1024);
}
}
#endif //#ifndef TARGET_DC
// GetShadowPixelMapping
//
// returns a UBYTE -> UWORD table for mapping
// from the shadow buffer to the shadow texture surface
UWORD* GetShadowPixelMapping()
{
static UWORD mapping[256];
static int mapping_state = -1;
//
// create mapping, if necessary
//
if ((mapping_state == -1) || (mapping_state != (int)the_display.GetDeviceInfo()->DestInvSourceColourSupported()))
{
// mapping must change
mapping_state = the_display.GetDeviceInfo()->DestInvSourceColourSupported();
if (mapping_state)
{
// density colourmap
for (int ii = 0; ii < 256; ii++)
{
int val = ii >> 1; // not too shadowy
mapping[ii] = ((val >> TEXTURE_shadow_mask_red) << TEXTURE_shadow_shift_red)
| ((val >> TEXTURE_shadow_mask_green) << TEXTURE_shadow_shift_green)
| ((val >> TEXTURE_shadow_mask_blue) << TEXTURE_shadow_shift_blue);
}
}
else
{
// density alphamap
for (int ii = 0; ii < 256; ii++)
{
int val = ii >> 1; // not too shadowy
mapping[ii] = (val >> TEXTURE_shadow_mask_alpha) << TEXTURE_shadow_shift_alpha;
}
}
}
return mapping;
}
extern SLONG dfacets_drawn_this_gameturn;
extern BOOL allow_debug_keys;
//
// The shift of the floor...
//
#define ALT_SHIFT (3)
//
// The maximum draw distance.
//
float AENG_lens = 4.0F;
//static SLONG NormalDrawDistance = 22<<8;
SLONG CurDrawDistance = 22<<8;
//#define AENG_DRAW_DIST ((FC_cam[1].focus) ? 16 : 22)
#define AENG_DRAW_DIST (CurDrawDistance>>8)
#define AENG_DRAW_DIST_PRECISE (CurDrawDistance)
#define AENG_DRAW_PEOPLE_DIST (CurDrawDistance + 128)
#define AENG_LENS (AENG_lens)
SLONG AENG_get_draw_distance()
{
return CurDrawDistance >> 8;
}
void AENG_set_draw_distance(SLONG dist)
{
#if 0
NormalDrawDistance = dist;
ENV_set_value_number("draw_distance", dist, "Render");
#endif
}
//
// The camera.
//
float AENG_cam_x;
float AENG_cam_y;
float AENG_cam_z;
float AENG_cam_yaw;
float AENG_cam_pitch;
float AENG_cam_roll;
float AENG_cam_matrix[9];
SLONG AENG_cam_vec[3];
//
// The floating point prim points.
//
SVector_F AENG_dx_prim_points[RMAX_PRIM_POINTS];
struct StoreLine
{
SLONG x1,y1,z1,x2,y2,z2;
ULONG col;
};
#define MAX_LINES 100
struct StoreLine Lines[MAX_LINES];
SLONG next_line=0;
void add_debug_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG colour)
{
SLONG line;
line=next_line%MAX_LINES;
Lines[line].x1=x1;
Lines[line].y1=y1;
Lines[line].z1=z1;
Lines[line].x2=x2;
Lines[line].y2=y2;
Lines[line].z2=z2;
Lines[line].col=colour;
next_line++;
}
#ifdef DEBUG
void draw_debug_lines(void)
{
SLONG c0,s,e;
if((!ControlFlag)||(!allow_debug_keys)) return;
s=next_line-MAX_LINES;
if(s<0)
s=0;
e=next_line;
for(c0=s;c0<e;c0++)
{
SLONG index;
index=c0%MAX_LINES;
AENG_world_line(Lines[index].x1,Lines[index].y1,Lines[index].z1,6,Lines[index].col,
Lines[index].x2,Lines[index].y2,Lines[index].z2,1,Lines[index].col,1);
}
}
#endif
//
// The sewer pages.
//
SLONG AENG_sewer_page[SEWER_PAGE_NUMBER] =
{
3,
4,
5,
POLY_PAGE_WATER
};
//
// Swaps two frames...
//
#define SWAP_FRAME(a,b) {COMP_Frame *spare; spare = (a); (a) = (b); (b) = spare;}
// ========================================================
//
// MOVIE STUFF
//
// ========================================================
#ifdef TARGET_DC
#define AENG_MAX_MOVIE_DATA (128 * 1024)
#else
#define AENG_MAX_MOVIE_DATA (512 * 1024)
#endif
UBYTE AENG_movie_data[AENG_MAX_MOVIE_DATA];
UBYTE *AENG_movie_upto;
COMP_Frame AENG_frame_one;
COMP_Frame AENG_frame_two;
COMP_Frame *AENG_frame_last = &AENG_frame_one;
COMP_Frame *AENG_frame_next = &AENG_frame_two;
SLONG AENG_frame_count;
SLONG AENG_frame_tick;
SLONG AENG_frame_number;
//
// Initialises the movie stuff.
//
void AENG_movie_init()
{
SLONG bytes_read;
FILE *handle;
//
// Load the movie in.
//
handle = MF_Fopen("movie\\bond.mmv", "rb");
if (!handle)
{
goto file_error;
}
bytes_read = fread(AENG_movie_data, sizeof(UBYTE), AENG_MAX_MOVIE_DATA, handle);
ASSERT ( bytes_read < AENG_MAX_MOVIE_DATA );
AENG_frame_last = &AENG_frame_one;
AENG_frame_next = &AENG_frame_two;
AENG_frame_count = 0;
AENG_frame_tick = 0;
AENG_frame_number = 200;
AENG_movie_upto = AENG_movie_data;
return;
file_error:;
AENG_frame_last = NULL;
AENG_frame_next = NULL;
AENG_frame_count = 0;
AENG_frame_tick = 0;
AENG_frame_number = 0;
return;
}
//
// Updates the movie texture page.
//
void AENG_movie_update()
{
return;
if (AENG_frame_number == 0)
{
//
// No movie!
//
return;
}
COMP_Delta *cd;
AENG_frame_tick += TICK_RATIO >> 1;
if (AENG_frame_tick >= (1 << TICK_SHIFT))
{
AENG_frame_tick -= (1 << TICK_SHIFT);
AENG_frame_tick &= (1 << TICK_SHIFT) - 1;
AENG_frame_count += 1;
if (AENG_frame_count >= AENG_frame_number)
{
if (AENG_frame_count < AENG_frame_number + 32)
{
//
// Wait a while at the end of the movie.
//
return;
}
AENG_frame_count = 0;
AENG_movie_upto = AENG_movie_data;
}
//
// Load in the new frame.
//
cd = (COMP_Delta *) AENG_movie_upto;
COMP_decomp(
AENG_frame_last,
cd,
AENG_frame_next);
AENG_movie_upto += cd->size + 4;
//
// Download the new frame.
//
ASSERT(TEXTURE_VIDEO_SIZE == COMP_SIZE);
if (TEXTURE_86_lock())
{
SLONG x;
SLONG y;
UWORD *data;
UWORD pixel;
TGA_Pixel *tp;
for (y = 0; y < TEXTURE_VIDEO_SIZE; y++)
{
tp = &AENG_frame_next->p[y][0];
data = TEXTURE_shadow_bitmap;
data += y * (TEXTURE_shadow_pitch >> 1);
for (x = 0; x < TEXTURE_VIDEO_SIZE; x++)
{
pixel = 0;
pixel |= (tp->red >> TEXTURE_shadow_mask_red ) << TEXTURE_shadow_shift_red;
pixel |= (tp->green >> TEXTURE_shadow_mask_green) << TEXTURE_shadow_shift_green;
pixel |= (tp->blue >> TEXTURE_shadow_mask_blue ) << TEXTURE_shadow_shift_blue;
*data = pixel;
tp += 1;
data += 1;
}
}
TEXTURE_86_unlock();
TEXTURE_86_update();
}
SWAP_FRAME(AENG_frame_last, AENG_frame_next);
}
}
/*
COMP_Frame cf1;
COMP_Frame cf2;
COMP_Frame cf3;
COMP_Frame cf4;
#define MAX_MOVIE_DATA (1024 * 512)
UBYTE movie_data[MAX_MOVIE_DATA];
UBYTE *movie_data_upto;
*/
void AENG_init(void)
{
extern void this_may_well_be_the_last_ever_function_call_put_into_the_game(void);
this_may_well_be_the_last_ever_function_call_put_into_the_game();
MESH_init();
// FONT2D_init();
#ifndef TARGET_DC
init_clouds();
#endif
SKY_init("stars\\poo");
POLY_init();
AENG_movie_init();
TEXTURE_choose_set(1);
INDOORS_INDEX_FADE=255;
//POLY_frame_init(FALSE, FALSE);
#if 0
//
// Create the movie.
//
{
SLONG i;
COMP_Frame *curr = &cf1;
COMP_Frame *last = &cf2;
COMP_Frame *next = &cf3;
COMP_Delta *cd;
SLONG load_ok;
CBYTE name[256];
movie_data_upto = movie_data;
for (i = 1; i <= 200; i++)
{
sprintf(name, "movie\\frames\\cin1%03d.tga", i);
load_ok = COMP_load(name, curr);
ASSERT(load_ok);
cd = COMP_calc(last, curr, next);
ASSERT(movie_data_upto + (cd->size + 4) <= &movie_data[MAX_MOVIE_DATA]);
memcpy(movie_data_upto, cd, cd->size + 4);
movie_data_upto += cd->size + 4;
sprintf(name, "movie\\comp\\comp%03d.tga", i);
TGA_save(
name,
COMP_SIZE,
COMP_SIZE,
(TGA_Pixel *) next->p,
FALSE);
SWAP_FRAME(last,next);
}
}
/*
SLONG cf1_ok = COMP_load("movie\\frames\\cin1040.tga", &cf1);
SLONG cf2_ok = COMP_load("movie\\frames\\cin1041.tga", &cf2);
COMP_Delta *cd = COMP_calc(&cf1, &cf2, &cf3);
COMP_decomp(&cf1, cd, &cf4);
TGA_save(
"movie\\test1.tga",
COMP_SIZE,
COMP_SIZE,
(TGA_Pixel *) cf1.p,
FALSE);
TGA_save(
"movie\\test2.tga",
COMP_SIZE,
COMP_SIZE,
(TGA_Pixel *) cf2.p,
FALSE);
TGA_save(
"movie\\test3.tga",
COMP_SIZE,
COMP_SIZE,
(TGA_Pixel *) cf3.p,
FALSE);
TGA_save(
"movie\\test4.tga",
COMP_SIZE,
COMP_SIZE,
(TGA_Pixel *) cf4.p,
FALSE);
IC_test();
*/
SLONG num_bytes;
num_bytes = movie_data_upto - movie_data;
FILE *handle = MF_Fopen("movie\\bond.mmv", "wb");
if (handle)
{
fwrite(movie_data, sizeof(UBYTE), num_bytes, handle);
MF_Fclose(handle);
}
exit(0);
#endif
//
// Load the fade palette for the bonfires
//
init_flames();
}
void AENG_fini()
{
TEXTURE_free();
}
void AENG_create_dx_prim_points()
{
SLONG i;
for (i = 0; i < MAX_PRIM_POINTS; i++)
{
AENG_dx_prim_points[i].X = float(prim_points[i].X);
AENG_dx_prim_points[i].Y = float(prim_points[i].Y);
AENG_dx_prim_points[i].Z = float(prim_points[i].Z);
}
}
void AENG_world_line(
SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1,
SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2,
SLONG sort_to_front)
{
#ifdef DEBUG
#ifdef TARGET_DC
ASSERT ( FALSE );
return;
#endif
#else
POLY_Point p1;
POLY_Point p2;
POLY_transform(float(x1), float(y1), float(z1), &p1);
POLY_transform(float(x2), float(y2), float(z2), &p2);
if (POLY_valid_line(&p1, &p2))
{
p1.colour = colour1;
p1.specular = 0xff000000;
p2.colour = colour2;
p2.specular = 0xff000000;
POLY_add_line(&p1, &p2, float(width1), float(width2), POLY_PAGE_COLOUR, sort_to_front);
}
#endif
}
void AENG_world_line_nondebug (
SLONG x1, SLONG y1, SLONG z1, SLONG width1, ULONG colour1,
SLONG x2, SLONG y2, SLONG z2, SLONG width2, ULONG colour2,
SLONG sort_to_front)
{
POLY_Point p1;
POLY_Point p2;
POLY_transform(float(x1), float(y1), float(z1), &p1);
POLY_transform(float(x2), float(y2), float(z2), &p2);
if (POLY_valid_line(&p1, &p2))
{
p1.colour = colour1;
p1.specular = 0xff000000;
p2.colour = colour2;
p2.specular = 0xff000000;
POLY_add_line(&p1, &p2, float(width1), float(width2), POLY_PAGE_COLOUR, sort_to_front);
}
}
void AENG_world_line_infinite(
SLONG ix1, SLONG iy1, SLONG iz1, SLONG iwidth1, ULONG colour1,
SLONG ix2, SLONG iy2, SLONG iz2, SLONG iwidth2, ULONG colour2,
SLONG sort_to_front)
{
#ifdef TARGET_DC
ASSERT ( FALSE );
return;
#else
float x1 = float(ix1);
float y1 = float(iy1);
float z1 = float(iz1);
float w1 = float(iwidth1);
float r1 = float((colour1 >> 16) & 0xff);
float g1 = float((colour1 >> 8) & 0xff);
float b1 = float((colour1 >> 0) & 0xff);
float x2 = float(ix2);
float y2 = float(iy2);
float z2 = float(iz2);
float w2 = float(iwidth2);
float r2 = float((colour2 >> 16) & 0xff);
float g2 = float((colour2 >> 8) & 0xff);
float b2 = float((colour2 >> 0) & 0xff);
float dx = x2 - x1;
float dy = y2 - y1;
float dz = z2 - z1;
float dr = r2 - r1;
float dg = g2 - g1;
float db = b2 - b1;
float dw = w2 - w1;
float dist = sqrt(dx*dx + dy*dy + dz*dz);
float steps = (float)floor(dist * (1.0F / 1024.0F)) + 1.0F;
float oversteps = 1.0F / steps;
float x = x1;
float y = y1;
float z = z1;
float w = w1;
float r = r1;
float g = g1;
float b = b1;
dx *= oversteps;
dy *= oversteps;
dz *= oversteps;
dw *= oversteps;
dr *= oversteps;
dg *= oversteps;
db *= oversteps;
float f;
for (f = 0.0F; f < steps; f += 1.0F)
{
colour1 = (SLONG(r ) << 16) | (SLONG(g ) << 8) | (SLONG(b ) << 0);
colour2 = (SLONG(r + dr) << 16) | (SLONG(g + dg) << 8) | (SLONG(b + db) << 0);
AENG_world_line(
SLONG(x),
SLONG(y),
SLONG(z),
SLONG(w),
colour1,
SLONG(x + dx),
SLONG(y + dy),
SLONG(z + dz),
SLONG(w + dw),
colour2,
sort_to_front);
x += dx;
y += dy;
z += dz;
w += dw;
r += dr;
g += dg;
b += db;
}
#endif
}
struct
{
float x;
float y;
float z;
} AENG_cone[5];
void AENG_calc_gamut(
float x,
float y,
float z,
float yaw,
float pitch,
float roll,
float draw_dist,
float lens)
{
float width;
float height;
float depth;
float aspect;
float matrix[9];
MATRIX_calc(
matrix,
yaw,
pitch,
roll);
//
// The dimensions of the view pyramid.
//
width = draw_dist;
height = draw_dist;
depth = draw_dist;
width *= POLY_screen_width;
width /= POLY_screen_height;
if (FC_cam[1].focus)
{
//
// We are in splitscreen mode.
//
width *= 2.0F;
}
width /= lens;
height /= lens;
//
// Finds the points of the cone in world space
//
AENG_cone[3].x = AENG_cone[4].x = x / 256.0f;
AENG_cone[3].y = AENG_cone[4].y = y / 256.0f;
AENG_cone[3].z = AENG_cone[4].z = z / 256.0f;
AENG_cone[3].x += depth * matrix[6];
AENG_cone[3].y += depth * matrix[7];
AENG_cone[3].z += depth * matrix[8];
//
// AENG_cone[0] is the top left corner...
//
AENG_cone[0].x = AENG_cone[3].x + height * matrix[3];
AENG_cone[0].y = AENG_cone[3].y + height * matrix[4];
AENG_cone[0].z = AENG_cone[3].z + height * matrix[5];
AENG_cone[0].x = AENG_cone[0].x - width * matrix[0];
AENG_cone[0].y = AENG_cone[0].y - width * matrix[1];
AENG_cone[0].z = AENG_cone[0].z - width * matrix[2];
//
// AENG_cone[1] is the top right corner...
//
AENG_cone[1].x = AENG_cone[3].x + height * matrix[3];
AENG_cone[1].y = AENG_cone[3].y + height * matrix[4];
AENG_cone[1].z = AENG_cone[3].z + height * matrix[5];
AENG_cone[1].x = AENG_cone[1].x + width * matrix[0];
AENG_cone[1].y = AENG_cone[1].y + width * matrix[1];
AENG_cone[1].z = AENG_cone[1].z + width * matrix[2];
//
// AENG_cone[2] is the bottom right corner...
//
AENG_cone[2].x = AENG_cone[3].x - height * matrix[3];
AENG_cone[2].y = AENG_cone[3].y - height * matrix[4];
AENG_cone[2].z = AENG_cone[3].z - height * matrix[5];
AENG_cone[2].x = AENG_cone[2].x + width * matrix[0];
AENG_cone[2].y = AENG_cone[2].y + width * matrix[1];
AENG_cone[2].z = AENG_cone[2].z + width * matrix[2];
//
// AENG_cone[3] is the bottom left corner...
//
AENG_cone[3].x = AENG_cone[3].x - height * matrix[3];
AENG_cone[3].y = AENG_cone[3].y - height * matrix[4];
AENG_cone[3].z = AENG_cone[3].z - height * matrix[5];
AENG_cone[3].x = AENG_cone[3].x - width * matrix[0];
AENG_cone[3].y = AENG_cone[3].y - width * matrix[1];
AENG_cone[3].z = AENG_cone[3].z - width * matrix[2];
//
// Create the gamut.
//
NGAMUT_init();
NGAMUT_add_line(AENG_cone[4].x, AENG_cone[4].z, AENG_cone[0].x, AENG_cone[0].z);
NGAMUT_add_line(AENG_cone[4].x, AENG_cone[4].z, AENG_cone[1].x, AENG_cone[1].z);
NGAMUT_add_line(AENG_cone[4].x, AENG_cone[4].z, AENG_cone[2].x, AENG_cone[2].z);
NGAMUT_add_line(AENG_cone[4].x, AENG_cone[4].z, AENG_cone[3].x, AENG_cone[3].z);
NGAMUT_add_line(AENG_cone[0].x, AENG_cone[0].z, AENG_cone[1].x, AENG_cone[1].z);
NGAMUT_add_line(AENG_cone[1].x, AENG_cone[1].z, AENG_cone[2].x, AENG_cone[2].z);
NGAMUT_add_line(AENG_cone[2].x, AENG_cone[2].z, AENG_cone[3].x, AENG_cone[3].z);
NGAMUT_add_line(AENG_cone[3].x, AENG_cone[3].z, AENG_cone[0].x, AENG_cone[0].z);
NGAMUT_calculate_point_gamut();
NGAMUT_calculate_out_gamut();
NGAMUT_calculate_lo_gamut();
}
// The gamut calculation for the skyline - lo-rez map only.
// This doesn't even do the gamut "properly" - there are only 32x32 squares,
// so it's much quicker to just find the bounding box. Much easier too.
// So, only these four are updated:
SLONG AENG_gamut_lo_xmin;
SLONG AENG_gamut_lo_xmax;
SLONG AENG_gamut_lo_zmin;
SLONG AENG_gamut_lo_zmax;
void AENG_calc_gamut_lo_only(
float x,
float y,
float z,
float yaw,
float pitch,
float roll,
float draw_dist,
float lens)
{
float width;
float height;
float depth;
float aspect;
float matrix[9];
MATRIX_calc(
matrix,
yaw,
pitch,
roll);
//
// The dimensions of the view pyramid.
//
width = draw_dist;
height = draw_dist;
depth = draw_dist;
width *= POLY_screen_width;
width /= POLY_screen_height;
if (FC_cam[1].focus)
{
//
// We are in splitscreen mode.
//
width *= 2.0F;
}
width /= lens;
height /= lens;
//
// Finds the points of the cone in world space
//
AENG_cone[3].x = AENG_cone[4].x = x / 256.0f;
//AENG_cone[3].y = AENG_cone[4].y = y / 256.0f;
AENG_cone[3].z = AENG_cone[4].z = z / 256.0f;
AENG_cone[3].x += depth * matrix[6];
//AENG_cone[3].y += depth * matrix[7];
AENG_cone[3].z += depth * matrix[8];
//
// AENG_cone[0] is the top left corner...
//
AENG_cone[0].x = ( AENG_cone[3].x + height * matrix[3] );
//AENG_cone[0].y = ( AENG_cone[3].y + height * matrix[4] );
AENG_cone[0].z = ( AENG_cone[3].z + height * matrix[5] );
AENG_cone[0].x = ( AENG_cone[0].x - width * matrix[0] );
//AENG_cone[0].y = ( AENG_cone[0].y - width * matrix[1] );
AENG_cone[0].z = ( AENG_cone[0].z - width * matrix[2] );
//
// AENG_cone[1] is the top right corner...
//
AENG_cone[1].x = ( AENG_cone[3].x + height * matrix[3] );
//AENG_cone[1].y = ( AENG_cone[3].y + height * matrix[4] );
AENG_cone[1].z = ( AENG_cone[3].z + height * matrix[5] );
AENG_cone[1].x = ( AENG_cone[1].x + width * matrix[0] );
//AENG_cone[1].y = ( AENG_cone[1].y + width * matrix[1] );
AENG_cone[1].z = ( AENG_cone[1].z + width * matrix[2] );
//
// AENG_cone[2] is the bottom right corner...
//
AENG_cone[2].x = ( AENG_cone[3].x - height * matrix[3] );
//AENG_cone[2].y = ( AENG_cone[3].y - height * matrix[4] );
AENG_cone[2].z = ( AENG_cone[3].z - height * matrix[5] );
AENG_cone[2].x = ( AENG_cone[2].x + width * matrix[0] );
//AENG_cone[2].y = ( AENG_cone[2].y + width * matrix[1] );
AENG_cone[2].z = ( AENG_cone[2].z + width * matrix[2] );
//
// AENG_cone[3] is the bottom left corner...
//
AENG_cone[3].x = ( AENG_cone[3].x - height * matrix[3] );
//AENG_cone[3].y = ( AENG_cone[3].y - height * matrix[4] );
AENG_cone[3].z = ( AENG_cone[3].z - height * matrix[5] );
AENG_cone[3].x = ( AENG_cone[3].x - width * matrix[0] );
//AENG_cone[3].y = ( AENG_cone[3].y - width * matrix[1] );
AENG_cone[3].z = ( AENG_cone[3].z - width * matrix[2] );
//
// Create the gamut.
//
// Clip the eight lines to the size of the map, then find their bounding box.
float gamut_lo_xmax = AENG_cone[4].x * 0.25f;
float gamut_lo_xmin = AENG_cone[4].x * 0.25f;
float gamut_lo_zmax = AENG_cone[4].z * 0.25f;
float gamut_lo_zmin = AENG_cone[4].z * 0.25f;
// Point 4 should always be on the map, AFAICS.
ASSERT ( ( gamut_lo_xmax < PAP_SIZE_LO ) && ( gamut_lo_xmin > 0 ) );
ASSERT ( ( gamut_lo_xmax < PAP_SIZE_LO ) && ( gamut_lo_xmin > 0 ) );
for ( int i = 0; i < 8; i++ )
{
int iPt1, iPt2;
switch ( i )
{
case 0: iPt1 = 4; iPt2 = 0; break;
case 1: iPt1 = 4; iPt2 = 1; break;
case 2: iPt1 = 4; iPt2 = 2; break;
case 3: iPt1 = 4; iPt2 = 3; break;
case 4: iPt1 = 0; iPt2 = 1; break;
case 5: iPt1 = 1; iPt2 = 2; break;
case 6: iPt1 = 2; iPt2 = 3; break;
case 7: iPt1 = 3; iPt2 = 4; break;
}
float fX1 = AENG_cone[iPt1].x * 0.25f;
float fZ1 = AENG_cone[iPt1].z * 0.25f;
float fX2 = AENG_cone[iPt2].x * 0.25f;
float fZ2 = AENG_cone[iPt2].z * 0.25f;
// Clip to +ve X
if ( fX1 >= PAP_SIZE_LO )
{
if ( fX2 >= PAP_SIZE_LO )
{
// Quick reject.
gamut_lo_xmax = PAP_SIZE_LO;
continue;
}
else
{
float lambda = ( (float)PAP_SIZE_LO - fX1 ) / ( fX2 - fX1 );
fZ1 = fZ1 + lambda * ( fZ2 - fZ1 );
fX1 = PAP_SIZE_LO;
}
}
else
{
if ( fX2 >= PAP_SIZE_LO )
{
float lambda = ( (float)PAP_SIZE_LO - fX1 ) / ( fX2 - fX1 );
fZ2 = fZ1 + lambda * ( fZ2 - fZ1 );
fX2 = PAP_SIZE_LO;
}
else
{
// Accept.
}
}
// Clip to 0 X
if ( fX1 <= 0.0f )
{
if ( fX2 <= 0.0f )
{
// Quick reject.
gamut_lo_xmin = 0;
continue;
}
else
{
float lambda = ( 0.0f - fX1 ) / ( fX2 - fX1 );
fZ1 = fZ1 + lambda * ( fZ2 - fZ1 );
fX1 = 0.0f;
}
}
else
{
if ( fX2 <= 0.0f )
{
float lambda = ( 0.0f - fX1 ) / ( fX2 - fX1 );
fZ2 = fZ1 + lambda * ( fZ2 - fZ1 );
fX2 = 0.0f;
}
else
{
// Accept.
}
}
// Clip to +ve Z
if ( fZ1 >= PAP_SIZE_LO )
{
if ( fZ2 >= PAP_SIZE_LO )
{
// Quick reject.
gamut_lo_zmax = PAP_SIZE_LO;
continue;
}
else
{
float lambda = ( (float)PAP_SIZE_LO - fZ1 ) / ( fZ2 - fZ1 );
fX1 = fX1 + lambda * ( fX2 - fX1 );
fZ1 = PAP_SIZE_LO;
}
}
else
{
if ( fZ2 >= PAP_SIZE_LO )
{
float lambda = ( (float)PAP_SIZE_LO - fZ1 ) / ( fZ2 - fZ1 );
fX2 = fX1 + lambda * ( fX2 - fX1 );
fZ2 = PAP_SIZE_LO;
}
else
{
// Accept.
}
}
// Clip to 0 Z
if ( fZ1 <= 0.0f )
{
if ( fZ2 <= 0.0f )
{
// Quick reject.
gamut_lo_zmin = 0;
continue;
}
else
{
float lambda = ( 0.0f - fZ1 ) / ( fZ2 - fZ1 );
fX1 = fX1 + lambda * ( fX2 - fX1 );
fZ1 = 0.0f;
}
}
else
{
if ( fZ2 <= 0.0f )
{
float lambda = ( 0.0f - fZ1 ) / ( fZ2 - fZ1 );
fX2 = fX1 + lambda * ( fX2 - fX1 );
fZ2 = 0.0f;
}
else
{
// Accept.
}
}
ASSERT ( ( fX1 <= PAP_SIZE_LO ) && ( fX1 >= 0.0f ) );
ASSERT ( ( fX2 <= PAP_SIZE_LO ) && ( fX2 >= 0.0f ) );
ASSERT ( ( fZ1 <= PAP_SIZE_LO ) && ( fZ1 >= 0.0f ) );
ASSERT ( ( fZ2 <= PAP_SIZE_LO ) && ( fZ2 >= 0.0f ) );
// Expand BB.
if ( gamut_lo_xmax < fX1 )
{
gamut_lo_xmax = fX1;
}
else if ( gamut_lo_xmin > fX1 )
{
gamut_lo_xmin = fX1;
}
if ( gamut_lo_zmax < fZ1 )
{
gamut_lo_zmax = fZ1;
}
else if ( gamut_lo_zmin > fZ1 )
{
gamut_lo_zmin = fZ1;
}
if ( gamut_lo_xmax < fX2 )
{
gamut_lo_xmax = fX2;
}
else if ( gamut_lo_xmin > fX2 )
{
gamut_lo_xmin = fX2;
}
if ( gamut_lo_zmax < fZ2 )
{
gamut_lo_zmax = fZ2;
}
else if ( gamut_lo_zmin > fZ2 )
{
gamut_lo_zmin = fZ2;
}
}
#if 0
float gamut_lo_xmax = AENG_cone[0].x;
float gamut_lo_xmin = AENG_cone[0].x;
float gamut_lo_zmax = AENG_cone[0].z;
float gamut_lo_zmin = AENG_cone[0].z;
for ( int i = 1; i <= 4; i++ )
{
if ( gamut_lo_xmax < AENG_cone[i].x )
{
gamut_lo_xmax = AENG_cone[i].x;
}
else if ( gamut_lo_xmin > AENG_cone[i].x )
{
gamut_lo_xmin = AENG_cone[i].x;
}
if ( gamut_lo_zmax < AENG_cone[i].z )
{
gamut_lo_zmax = AENG_cone[i].z;
}
else if ( gamut_lo_zmin > AENG_cone[i].z )
{
gamut_lo_zmin = AENG_cone[i].z;
}
}
#endif
#if 1
AENG_gamut_lo_xmin = (SLONG)( gamut_lo_xmin );
AENG_gamut_lo_xmax = (SLONG)( gamut_lo_xmax );
AENG_gamut_lo_zmin = (SLONG)( gamut_lo_zmin );
AENG_gamut_lo_zmax = (SLONG)( gamut_lo_zmax );
#else
AENG_gamut_lo_xmin = (SLONG)( gamut_lo_xmin * 0.25f );
AENG_gamut_lo_xmax = (SLONG)( gamut_lo_xmax * 0.25f );
AENG_gamut_lo_zmin = (SLONG)( gamut_lo_zmin * 0.25f );
AENG_gamut_lo_zmax = (SLONG)( gamut_lo_zmax * 0.25f );
#endif
// Just catch the dodgy edge condition.
if ( AENG_gamut_lo_xmax == PAP_SIZE_LO )
{
AENG_gamut_lo_xmax = PAP_SIZE_LO - 1;
}
if ( AENG_gamut_lo_xmin == PAP_SIZE_LO )
{
AENG_gamut_lo_xmin = PAP_SIZE_LO - 1;
}
if ( AENG_gamut_lo_zmax == PAP_SIZE_LO )
{
AENG_gamut_lo_zmax = PAP_SIZE_LO - 1;
}
if ( AENG_gamut_lo_zmin == PAP_SIZE_LO )
{
AENG_gamut_lo_zmin = PAP_SIZE_LO - 1;
}
#if 0
if ( AENG_gamut_lo_xmax < 0 )
{
AENG_gamut_lo_xmax = 0;
AENG_gamut_lo_xmin = 0;
}
else if ( AENG_gamut_lo_xmax >= PAP_SIZE_LO )
{
AENG_gamut_lo_xmax = PAP_SIZE_LO - 1;
}
if ( AENG_gamut_lo_xmin >= PAP_SIZE_LO )
{
AENG_gamut_lo_xmax = PAP_SIZE_LO - 1;
AENG_gamut_lo_xmin = PAP_SIZE_LO - 1;
}
else if ( AENG_gamut_lo_xmin < 0 )
{
AENG_gamut_lo_xmin = 0;
}
if ( AENG_gamut_lo_zmax < 0 )
{
AENG_gamut_lo_zmax = 0;
AENG_gamut_lo_zmin = 0;
}
else if ( AENG_gamut_lo_zmax >= PAP_SIZE_LO )
{
AENG_gamut_lo_zmax = PAP_SIZE_LO - 1;
}
if ( AENG_gamut_lo_zmin >= PAP_SIZE_LO )
{
AENG_gamut_lo_zmax = PAP_SIZE_LO - 1;
AENG_gamut_lo_zmin = PAP_SIZE_LO - 1;
}
else if ( AENG_gamut_lo_zmin < 0 )
{
AENG_gamut_lo_zmin = 0;
}
#endif
}
void AENG_set_camera_radians(
SLONG wx,
SLONG wy,
SLONG wz,
float y,
float p,
float r)
{
AENG_cam_x = float(wx);
AENG_cam_y = float(wy);
AENG_cam_z = float(wz);
AENG_cam_yaw = y;
AENG_cam_pitch = p;
AENG_cam_roll = r;
MATRIX_calc(
AENG_cam_matrix,
y,p,r);
POLY_camera_set(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
float(AENG_DRAW_DIST) * 256.0F,
AENG_LENS,
POLY_SPLITSCREEN_NONE);
FMATRIX_vector(AENG_cam_vec,(y*2048)/(2*PI),(p*2048)/(2*PI));
//
// Create the gamut
//
AENG_calc_gamut(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
AENG_DRAW_DIST,
AENG_LENS);
}
void AENG_set_camera_radians(
SLONG wx,
SLONG wy,
SLONG wz,
float y,
float p,
float r,
SLONG splitscreen)
{
AENG_cam_x = float(wx);
AENG_cam_y = float(wy);
AENG_cam_z = float(wz);
AENG_cam_yaw = y;
AENG_cam_pitch = p;
AENG_cam_roll = r;
MATRIX_calc(
AENG_cam_matrix,
y,p,r);
POLY_camera_set(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
float(AENG_DRAW_DIST) * 256.0F,
AENG_LENS,
splitscreen);
FMATRIX_vector(AENG_cam_vec,(y*2048)/(2*PI),(p*2048)/(2*PI));
//
// Create the gamut
//
AENG_calc_gamut(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
AENG_DRAW_DIST,
AENG_LENS);
}
void AENG_set_camera(
SLONG wx,
SLONG wy,
SLONG wz,
SLONG y,
SLONG p,
SLONG r)
{
float radians_yaw = float(y) * (2.0F * PI / 2048.0F);
float radians_pitch = float(p) * (2.0F * PI / 2048.0F);
float radians_roll = float(r) * (2.0F * PI / 2048.0F);
FC_cam[0].x=wx<<8;
FC_cam[0].y=wy<<8;
FC_cam[0].z=wz<<8;
FC_cam[0].yaw=y<<8;
FC_cam[0].pitch=p<<8;
FC_cam[0].roll=r<<8;
AENG_set_camera_radians(
wx,
wy,
wz,
radians_yaw,
radians_pitch,
radians_roll,
POLY_SPLITSCREEN_NONE);
}
void AENG_do_cached_lighting_old(void)
{
SLONG i;
SLONG x;
SLONG z;
SLONG kept=0,new_squares=0;
NIGHT_Square *nq;
extern SLONG HEAP_max_free(void);
if(HEAP_max_free()<4000 || Keys[KB_Q])
{
CBYTE str[100];
NIGHT_destroy_all_cached_info();
// sprintf(str," RECALC LIGHTING FREE = %d",HEAP_max_free());
// CONSOLE_text(str,10000);
}
else
{
//
// Get rid of any cached squares we dont need anymore.
//
for (i = 1; i < NIGHT_MAX_SQUARES; i++)
{
nq = &NIGHT_square[i];
if (nq->flag & NIGHT_SQUARE_FLAG_USED)
{
if (WITHIN(nq->lo_map_z, NGAMUT_lo_zmin, NGAMUT_lo_zmax) &&
WITHIN(
nq->lo_map_x,
NGAMUT_lo_gamut[nq->lo_map_z].xmin,
NGAMUT_lo_gamut[nq->lo_map_z].xmax))
{
//
// We still need this cache info.
//
kept++;
}
else
{
//
// We dont need this square any more.
//
NIGHT_cache_destroy(i);
}
}
}
}
if(INDOORS_INDEX)
{
if(light_inside!=INDOORS_INDEX)
{
//
// remove floor lighting
//
for (i = 1; i < NIGHT_MAX_SQUARES; i++)
{
nq = &NIGHT_square[i];
if (nq->flag & NIGHT_SQUARE_FLAG_USED)
NIGHT_cache_destroy(i);
}
}
light_inside=INDOORS_INDEX;
//
// create the squares we need for the inside bounding rect clipped with gamut
//
{
SLONG x,z,floor_y;
struct InsideStorey *p_inside;
SLONG in_width;
UBYTE *in_block;
SLONG min_z,max_z;
SLONG min_x,max_x;
p_inside=&inside_storeys[INDOORS_INDEX];
floor_y=p_inside->StoreyY;
min_z=MAX(NGAMUT_lo_zmin,p_inside->MinZ>>2);
max_z=MIN(NGAMUT_lo_zmax,p_inside->MaxZ>>2);
in_width=p_inside->MaxX-p_inside->MinX;
for (z = min_z; z <= max_z+1; z++)
{
min_x=MAX(NGAMUT_lo_gamut[z].xmin,p_inside->MinX>>2);
max_x=MIN(NGAMUT_lo_gamut[z].xmax,p_inside->MaxX>>2);
if(z>min_z)
{
min_x=MIN(NGAMUT_lo_gamut[z-1].xmin,min_x);
max_x=MAX(NGAMUT_lo_gamut[z-1].xmax,max_x);
}
for (x = min_x;x<=max_x+1;x++)
{
if (NIGHT_cache[x][z] == NULL)
{
//
// Creating cached lighting for this square.
//
NIGHT_cache_create_inside(x,z,floor_y);
new_squares++;
}
}
}
}
return;
}
else
if(light_inside)
{
light_inside=0;
for (i = 1; i < NIGHT_MAX_SQUARES; i++)
{
nq = &NIGHT_square[i];
if (nq->flag & NIGHT_SQUARE_FLAG_USED)
{
NIGHT_cache_destroy(i);
}
}
}
//
// Create any square we need.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
if (NIGHT_cache[x][z] == NULL)
{
//
// Creating cached lighting for this square.
//
NIGHT_cache_create(x,z);
}
}
}
}
//
// Marks all caches squares with 'DELETEME'. When a square is drawn
// its DELETEME flag is cleared.
//
void AENG_mark_night_squares_as_deleteme(void)
{
SLONG i;
NIGHT_Square *nq;
for (i = 1; i < NIGHT_MAX_SQUARES; i++)
{
nq = &NIGHT_square[i];
//
// Do this to all NIGHT_squares... not just the used ones.
//
nq->flag |= NIGHT_SQUARE_FLAG_DELETEME;
}
}
//
// Makes sure that all lo-res gamut squares have the right kind of
// lighting caching done for them. (In a warehouse or not).
//
void AENG_ensure_appropriate_caching(SLONG ware)
{
SLONG x;
SLONG z;
SLONG ok;
NIGHT_Square *nq;
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
if (NIGHT_cache[x][z] == NULL)
{
//
// Creating cached lighting for this square.
//
NIGHT_cache_create(x,z,ware);
}
else
{
//
// Make sure this square has the correct type.
//
nq = &NIGHT_square[NIGHT_cache[x][z]];
if (nq->flag & NIGHT_SQUARE_FLAG_WARE)
{
ok = ware;
}
else
{
ok = !ware;
}
if (!ok)
{
//
// The caching is the wrong sort!
//
NIGHT_cache_destroy(NIGHT_cache[x][z]);
NIGHT_cache_create(x,z,ware);
}
}
}
}
}
void AENG_get_rid_of_deleteme_squares()
{
SLONG i;
NIGHT_Square *nq;
for (i = 1; i < NIGHT_MAX_SQUARES; i++)
{
nq = &NIGHT_square[i];
if (nq->flag & NIGHT_SQUARE_FLAG_USED)
{
if (nq->flag & NIGHT_SQUARE_FLAG_DELETEME)
{
NIGHT_cache_destroy(i);
}
}
}
}
//
// Adds a projected shadow poly to the POLY module.
//
float AENG_project_offset_u;
float AENG_project_offset_v;
float AENG_project_mul_u;
float AENG_project_mul_v;
float AENG_project_lit_light_x;
float AENG_project_lit_light_y;
float AENG_project_lit_light_z;
float AENG_project_lit_light_range;
float AENG_project_fadeout_x;
float AENG_project_fadeout_z;
#define SHADOW_Z_BIAS_BODGE 0.0001f
void AENG_add_projected_shadow_poly(SMAP_Link *sl)
{
SLONG i;
POLY_Point *pp;
//
// Transform all the points into the poly buffer.
//
POLY_buffer_upto = 0;
while(sl)
{
ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1));
pp = &POLY_buffer[POLY_buffer_upto++];
POLY_transform(
sl->wx,
sl->wy,
sl->wz,
pp);
if (pp->MaybeValid())
{
pp->u = AENG_project_offset_u + sl->u * AENG_project_mul_u;
pp->v = AENG_project_offset_v + sl->v * AENG_project_mul_v;
pp->colour = 0xffffffff;
pp->specular = 0xff000000;
#ifdef TARGET_DC
// Stop Z fighting
pp->Z += SHADOW_Z_BIAS_BODGE;
#endif
}
else
{
//
// Abandon the whole shadow polygon.
//
return;
}
sl = sl->next;
}
//
// Add the triangles.
//
POLY_Point *tri[3];
tri[0] = &POLY_buffer[0];
for (i = 1; i < POLY_buffer_upto - 1; i++)
{
tri[1] = &POLY_buffer[i + 0];
tri[2] = &POLY_buffer[i + 1];
if (POLY_valid_triangle(tri))
{
POLY_add_triangle(tri, POLY_PAGE_SHADOW, TRUE);
}
}
}
void AENG_add_projected_fadeout_shadow_poly(SMAP_Link *sl)
{
float dx;
float dz;
float dist;
SLONG i;
SLONG alpha;
POLY_Point *pp;
//
// Transform all the points into the poly buffer.
//
POLY_buffer_upto = 0;
while(sl)
{
ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1));
pp = &POLY_buffer[POLY_buffer_upto++];
POLY_transform(
sl->wx,
sl->wy,
sl->wz,
pp);
if (pp->MaybeValid())
{
dx = sl->wx - AENG_project_fadeout_x;
dz = sl->wz - AENG_project_fadeout_z;
dist = fabs(dx) + fabs(dz);
if (dist < 64.0F)
{
alpha = 0xff;
}
else
{
if (dist > 256.0F)
{
alpha = 0;
}
else
{
alpha = 0xff - SLONG((dist - 64.0F) * (255.0F / 192.0F));
}
}
pp->u = AENG_project_offset_u + sl->u * AENG_project_mul_u;
pp->v = AENG_project_offset_v + sl->v * AENG_project_mul_v;
alpha |= alpha << 8;
alpha |= alpha << 16;
pp->colour = alpha;
pp->specular = 0xff000000;
#ifdef TARGET_DC
// Stop Z fighting
pp->Z += SHADOW_Z_BIAS_BODGE;
#endif
}
else
{
//
// Abandon the whole shadow polygon.
//
return;
}
sl = sl->next;
}
//
// Add the triangles.
//
POLY_Point *tri[3];
tri[0] = &POLY_buffer[0];
for (i = 1; i < POLY_buffer_upto - 1; i++)
{
tri[1] = &POLY_buffer[i + 0];
tri[2] = &POLY_buffer[i + 1];
if (POLY_valid_triangle(tri))
{
POLY_add_triangle(tri, POLY_PAGE_SHADOW, TRUE);
}
}
}
void AENG_add_projected_lit_shadow_poly(SMAP_Link *sl)
{
SLONG i;
float dx;
float dy;
float dz;
float dist;
float bright;
POLY_Point *pp;
//
// Transform all the points into the poly buffer.
//
POLY_buffer_upto = 0;
while(sl)
{
ASSERT(WITHIN(POLY_buffer_upto, 0, POLY_BUFFER_SIZE - 1));
pp = &POLY_buffer[POLY_buffer_upto++];
POLY_transform(
sl->wx,
sl->wy,
sl->wz,
pp);
if (pp->MaybeValid())
{
pp->u = AENG_project_offset_u + sl->u * AENG_project_mul_u;
pp->v = AENG_project_offset_v + sl->v * AENG_project_mul_v;
dx = sl->wx - AENG_project_lit_light_x;
dy = sl->wy - AENG_project_lit_light_y;
dz = sl->wz - AENG_project_lit_light_z;
dist = fabs(dx) + fabs(dy) + fabs(dz);
bright = dist / AENG_project_lit_light_range;
bright = 1.0F - bright;
bright *= 512.0F;
if (bright > 0.0F)
{
SLONG alpha = SLONG(bright);
if (alpha > 255) {alpha = 255;}
alpha |= alpha << 8;
alpha |= alpha << 16;
#ifdef TARGET_DC
alpha |= 0xff000000;
#endif
pp->colour = alpha;
pp->specular = 0xff000000;
}
else
{
#ifdef TARGET_DC
pp->colour = 0xff000000;
#else
pp->colour = 0x00000000;
#endif
pp->specular = 0xff000000;
}
#ifdef TARGET_DC
// Stop Z fighting
pp->Z += SHADOW_Z_BIAS_BODGE;
#endif
}
else
{
//
// Abandon the whole shadow polygon.
//
return;
}
sl = sl->next;
}
//
// Add the triangles.
//
POLY_Point *tri[3];
tri[0] = &POLY_buffer[0];
for (i = 1; i < POLY_buffer_upto - 1; i++)
{
tri[1] = &POLY_buffer[i + 0];
tri[2] = &POLY_buffer[i + 1];
if (POLY_valid_triangle(tri))
{
POLY_add_triangle(tri, POLY_PAGE_SHADOW, TRUE);
}
}
}
//
// Draws the rain.
//
void AENG_draw_rain_old(float angle)
{
SLONG i;
float vec1x;
float vec1y;
float vec2x;
float vec2y;
float z;
float X;
float Y;
float Z;
POLY_Point pp [3];
POLY_Point *tri[3];
tri[0] = &pp[0];
tri[1] = &pp[1];
tri[2] = &pp[2];
//
// Common to all poly points.
//
pp[0].colour = 0x00000000;
pp[1].colour = 0x88333344;
pp[2].colour = 0x88555577;
pp[0].specular = 0x00000000;
pp[1].specular = 0x00000000;
pp[2].specular = 0x00000000;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[1].u = 0.0F;
pp[1].v = 0.0F;
pp[2].u = 0.0F;
pp[2].v = 0.0F;
//
// Work out the vectors from the angle.
//
#define AENG_RAIN_SIZE (4.0F)
vec1x = (float)sin(angle) * (32.0F * AENG_RAIN_SIZE);
vec1y = -(float)cos(angle) * (32.0F * AENG_RAIN_SIZE);
vec2x = (float)cos(angle) * AENG_RAIN_SIZE;
vec2y = (float)sin(angle) * AENG_RAIN_SIZE;
#define AENG_NUM_RAINDROPS 128
for (i = 0; i < AENG_NUM_RAINDROPS; i++)
{
z = float(rand() & 0xff) * (0.5F / 256.0F) + POLY_ZCLIP_PLANE;
X = float(rand() % DisplayWidth);
Y = float(rand() % DisplayHeight);
Z = POLY_ZCLIP_PLANE / z;
pp[0].X = X;
pp[0].Y = Y;
pp[0].Z = Z;
pp[0].z = z;
pp[1].X = X + vec1x * Z;
pp[1].Y = Y + vec1y * Z;
pp[1].Z = Z;
pp[1].z = z;
pp[2].X = X + vec2x * Z;
pp[2].Y = Y + vec2y * Z;
pp[2].Z = Z;
pp[2].z = z;
POLY_add_triangle(tri, POLY_PAGE_ALPHA, FALSE, TRUE);
}
}
void AENG_draw_rain()
{
SLONG i;
float x1;
float y1;
float z1;
float x2;
float y2;
float z2;
float matrix[9];
float fade;
SLONG bright;
SLONG r;
SLONG g;
SLONG b;
ULONG colour;
//
// The cameras view matrix.
//
MATRIX_calc(
matrix,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll);
//
// Fiddle the matrix so multipling (a,b,c) by the matrix
// where a,b are between -1 and 1 and c is between 0 and 1
// gives a place in the world that the camera can see...
//
matrix[0] *= 640.0F / 480.0F;
matrix[1] *= 640.0F / 480.0F;
matrix[2] *= 640.0F / 480.0F;
matrix[0] /= AENG_LENS;
matrix[1] /= AENG_LENS;
matrix[2] /= AENG_LENS;
matrix[3] /= AENG_LENS;
matrix[4] /= AENG_LENS;
matrix[5] /= AENG_LENS;
//
// Rain lasts 8 squares into the distance.
//
//#undef AENG_NUM_RAINDROPS
//#define AENG_NUM_RAINDROPS 500
matrix[0] *= 256.0F * 8.0F;
matrix[1] *= 256.0F * 8.0F;
matrix[2] *= 256.0F * 8.0F;
matrix[3] *= 256.0F * 8.0F;
matrix[4] *= 256.0F * 8.0F;
matrix[5] *= 256.0F * 8.0F;
matrix[6] *= 256.0F * 8.0F;
matrix[7] *= 256.0F * 8.0F;
matrix[8] *= 256.0F * 8.0F;
for (i = 0; i < AENG_NUM_RAINDROPS; i++)
{
//
// Pick a random place in world space in front of the camera.
//
x1 = float(rand()) * (1.0F / float(RAND_MAX >> 1)) - 1.0F;
y1 = float(rand()) * (1.0F / float(RAND_MAX >> 1)) - 0.5F;
z1 = float(rand()) * (1.0F / float(RAND_MAX )) + 0.1F;
fade = 1.0F - z1 * 0.8F;
bright = SLONG(fade * 256.0F);
colour = (bright << 24) | ((69 << 16) | (74 << 8) | (98 << 0));
MATRIX_MUL_BY_TRANSPOSE(
matrix,
x1,
y1,
z1);
x1 += AENG_cam_x;
y1 += AENG_cam_y;
z1 += AENG_cam_z;
#if 1 // shade the rain
SLONG px = SLONG(x1) >> 10;
SLONG pz = SLONG(z1) >> 10;
SLONG dx = (SLONG(x1) >> 8) & 3;
SLONG dz = (SLONG(z1) >> 8) & 3;
if ((px < 0) || (px >= PAP_SIZE_LO)) continue;
if ((pz < 0) || (pz >= PAP_SIZE_LO)) continue;
SLONG square = NIGHT_cache[px][pz];
if (!square) continue;
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
NIGHT_Square* nq = &NIGHT_square[square];
ULONG col,spec;
NIGHT_get_d3d_colour(nq->colour[dx + dz * PAP_BLOCKS], &col, &spec);
colour = col;
#endif
SHAPE_droplet(
SLONG(x1),
SLONG(y1),
SLONG(z1),
8,
-64,
8,
colour,
POLY_PAGE_RAINDROP);
}
}
void AENG_draw_drips(UBYTE puddles_only)
{
//
// Draw the drips.
//
SLONG i;
float midx;
float midy;
float midz;
float px;
float pz;
float radius;
ULONG colour;
DRIP_Info *di;
POLY_Point pp[4];
POLY_Point *quad[4];
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
//
// The same for all drips.
//
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[1].u = 1.0F;
pp[1].v = 0.0F;
pp[2].u = 0.0F;
pp[2].v = 1.0F;
pp[3].u = 1.0F;
pp[3].v = 1.0F;
pp[0].specular = 0xff000000;
pp[1].specular = 0xff000000;
pp[2].specular = 0xff000000;
pp[3].specular = 0xff000000;
DRIP_get_start();
while(di = DRIP_get_next())
{
if (puddles_only != (di->flags&DRIP_FLAG_PUDDLES_ONLY))
continue; // Abandon this drip.
midx = float(di->x);
midy = float(di->y);
midz = float(di->z);
midy += 8.0F;
radius = float(di->size);
for (i = 0; i < 4; i++)
{
px = midx + ((i & 0x1) ? +radius : -radius);
pz = midz + ((i & 0x2) ? +radius : -radius);
POLY_transform(px, midy, pz, &pp[i]);
if (!pp[i].IsValid())
continue; // Abandon this drip.
}
if (POLY_valid_quad(quad))
{
colour = (di->fade << 16) | (di->fade << 8) | (di->fade << 0);
pp[0].colour = colour;
pp[1].colour = colour;
pp[2].colour = colour;
pp[3].colour = colour;
POLY_add_quad(quad, POLY_PAGE_DRIP, FALSE);
}
}
}
//
// Adds the bangs in the current gamut to the POLY module.
//
void AENG_draw_bangs()
{
float u_mid;
float v_mid;
#ifdef DOG_POO
SLONG z;
BANG_Info *bi;
for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++)
{
BANG_get_start(
NGAMUT_point_gamut[z].xmin,
NGAMUT_point_gamut[z].xmax,
z);
while(bi = BANG_get_next())
{
u_mid = (1.0F / 8.0F) + (1.0F / 4.0F) * float(bi->frame & 0x3);
v_mid = (1.0F / 8.0F) + (1.0F / 4.0F) * float(bi->frame >> 2);
#ifdef MAKE_THEM_FACE_THE_CAMERA
//
// Always make it face the camera.
//
float dx = AENG_cam_x - float(bi->x);
float dy = AENG_cam_y - float(bi->y);
float dz = AENG_cam_z - float(bi->z);
#ifdef TARGET_DC
float len = 256.0f * _InvSqrtA(dx*dx + dy*dy + dz*dz);
dx = dx * len;
dy = dy * len;
dz = dz * len;
#else
float len = sqrt(dx*dx + dy*dy + dz*dz);
dx = dx * (256.0F / len);
dy = dy * (256.0F / len);
dz = dz * (256.0F / len);
#endif
#endif
SHAPE_semisphere_textured(
bi->x,
bi->y,
bi->z,
bi->dx,
bi->dy,
bi->dz,
bi->radius,
u_mid,
v_mid,
1.0F / 8.0F,
POLY_PAGE_BANG,
bi->red,
bi->green,
bi->blue);
}
}
#endif
}
//
// Draws the cloth.
//
void AENG_draw_cloth(void)
{
#ifdef DOG_POO
SLONG i;
SLONG x;
SLONG z;
UBYTE cloth;
CLOTH_Info *ci;
POLY_Point pp[CLOTH_WIDTH * CLOTH_HEIGHT];
//
// Our lighting normal for each point. The normal's length is less
// than one so the dprod will always be in range. The normal from
// the CLOTH module is only approximately of length 1.0!
//
static float light_x = 0.55F;
static float light_y = 0.55F;
static float light_z = 0.55F;
float dprod;
SLONG bright;
SLONG r;
SLONG g;
SLONG b;
SLONG base_r;
SLONG base_g;
SLONG base_b;
SLONG px;
SLONG py;
POLY_Point *quad[4];
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
for (cloth = CLOTH_get_first(x,z); cloth; cloth = ci->next)
{
ci = CLOTH_get_info(cloth);
base_r = (ci->colour >> 16) & 0xff;
base_g = (ci->colour >> 8) & 0xff;
base_b = (ci->colour >> 0) & 0xff;
//
// Transform all the points.
//
for (i = 0; i < CLOTH_WIDTH * CLOTH_HEIGHT; i++)
{
POLY_transform(
ci->p[i].x,
ci->p[i].y,
ci->p[i].z,
&pp[i]);
if (!pp[i].MaybeValid())
{
goto abandon_this_cloth;
}
//
// Light the point.
//
dprod =
light_x * ci->p[i].nx +
light_y * ci->p[i].ny +
light_z * ci->p[i].nz;
dprod = fabs(dprod);
bright = SLONG(dprod * 255.0F);
r = bright * base_r >> 8;
g = bright * base_g >> 8;
b = bright * base_b >> 8;
pp[i].colour = (r << 16) | (g << 8) | (b << 0);
pp[i].specular = 0xff000000;
pp[i].u = 0.0F;
pp[i].v = 0.0F;
}
//
// Create all the faces.
//
for (px = 0; px < CLOTH_WIDTH - 1; px++)
for (py = 0; py < CLOTH_HEIGHT - 1; py++)
{
quad[0] = &pp[CLOTH_INDEX(px + 0, py + 0)];
quad[1] = &pp[CLOTH_INDEX(px + 1, py + 0)];
quad[2] = &pp[CLOTH_INDEX(px + 0, py + 1)];
quad[3] = &pp[CLOTH_INDEX(px + 1, py + 1)];
if (POLY_valid_quad(quad))
{
POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE);
}
}
abandon_this_cloth:;
}
}
}
#endif
}
//
// Adds the fire in the current gamut to the POLY module.
//
void AENG_draw_fire()
{
SLONG z;
FIRE_Info *fi;
FIRE_Point *fp;
for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++)
{
FIRE_get_start(
NGAMUT_point_gamut[z].xmin,
NGAMUT_point_gamut[z].xmax,
z);
}
}
void AENG_draw_sparks()
{
SLONG z;
SPARK_Info *si;
GLITTER_Info *gi;
// Internal gubbins.
POLY_flush_local_rot();
for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++)
{
SPARK_get_start(
NGAMUT_point_gamut[z].xmin,
NGAMUT_point_gamut[z].xmax,
z);
while(si = SPARK_get_next())
{
SHAPE_sparky_line(
si->num_points,
si->x,
si->y,
si->z,
si->colour,
float(si->size));
}
GLITTER_get_start(
NGAMUT_point_gamut[z].xmin,
NGAMUT_point_gamut[z].xmax,
z);
while(gi = GLITTER_get_next())
{
SHAPE_glitter(
gi->x1,
gi->y1,
gi->z1,
gi->x2,
gi->y2,
gi->z2,
gi->colour);
}
}
}
//
// Draws the hook.
//
void AENG_draw_hook(void)
{
#ifdef TARGET_DC
ASSERT ( FALSE );
#else //#ifdef TARGET_DC
SLONG i;
SLONG x;
SLONG y;
SLONG z;
SLONG yaw;
SLONG pitch;
SLONG roll;
SLONG x1;
SLONG y1;
SLONG z1;
SLONG x2;
SLONG y2;
SLONG z2;
SLONG red = 0x80;
SLONG green = 0x20;
SLONG blue = 0x00;
ULONG colour1;
ULONG colour2;
HOOK_pos_grapple(
&x,
&y,
&z,
&yaw,
&pitch,
&roll);
x >>= 8;
y >>= 8;
z >>= 8;
MESH_draw_poly(
PRIM_OBJ_HOOK,
x, y, z,
yaw,
pitch,
roll,
NULL,0xff,0);
for (i = HOOK_NUM_POINTS - 1; i >= 1; i--)
{
HOOK_pos_point(i + 0, &x1, &y1, &z1);
HOOK_pos_point(i - 1, &x2, &y2, &z2);
x1 >>= 8;
y1 >>= 8;
z1 >>= 8;
x2 >>= 8;
y2 >>= 8;
z2 >>= 8;
if (red < 250)
{
red += 2;
}
else
{
if (green < 250)
{
green += 2;
}
else
{
if (blue < 250)
{
blue += 3;
}
}
}
colour1 = (red << 16) | (green << 8) | (blue << 0);
colour2 = (red << 17) | (green << 8) | (blue >> 1);
AENG_world_line(
x1, y1, z1, 0x8, colour1,
x2, y2, z2, 0x6, colour2,
FALSE);
}
#endif //#else //#ifdef TARGET_DC
}
ULONG AENG_colour_mult(ULONG c1, ULONG c2)
{
SLONG r1 = (c1 >> 16) & 0xff;
SLONG g1 = (c1 >> 8) & 0xff;
SLONG b1 = (c1 >> 0) & 0xff;
SLONG r2 = (c2 >> 16) & 0xff;
SLONG g2 = (c2 >> 8) & 0xff;
SLONG b2 = (c2 >> 0) & 0xff;
SLONG ar = r1 * r2 >> 8;
SLONG ag = g1 * g2 >> 8;
SLONG ab = b1 * b2 >> 8;
ULONG ans = (ar << 16) | (ag << 8) | (ab << 0);
return ans;
}
//
// Draws the dirt.
//
extern UBYTE estate;
#define AENG_MAX_DIRT_LVERTS (64 * 3)
#define AENG_MAX_DIRT_INDICES (AENG_MAX_DIRT_LVERTS * 4 / 3)
D3DLVERTEX AENG_dirt_lvert_buffer[AENG_MAX_DIRT_LVERTS + 1];
D3DLVERTEX *AENG_dirt_lvert;
SLONG AENG_dirt_lvert_upto;
UWORD AENG_dirt_index[AENG_MAX_DIRT_INDICES];
SLONG AENG_dirt_index_upto;
UBYTE AENG_dirt_matrix_buffer[sizeof(D3DMATRIX) + 32];
D3DMATRIX *AENG_dirt_matrix;
#define AENG_MAX_DIRT_UVLOOKUP 16
struct
{
float u;
float v;
} AENG_dirt_uvlookup[AENG_MAX_DIRT_UVLOOKUP];
SLONG AENG_dirt_uvlookup_valid;
SWORD AENG_dirt_uvlookup_world_type;
void AENG_draw_dirt()
{
if (GAME_FLAGS & GF_NO_FLOOR)
{
//
// No dirt if there is no floor!
//
return;
}
SLONG i;
#define LEAF_PAGE (POLY_PAGE_LEAF)
#define LEAF_CENTRE_U (0.5F)
#define LEAF_CENTRE_V (0.5F)
#define LEAF_RADIUS (0.5F)
#define LEAF_U(a) (LEAF_CENTRE_U + LEAF_RADIUS * (float)sin(a))
#define LEAF_V(a) (LEAF_CENTRE_V + LEAF_RADIUS * (float)cos(a))
#define SNOW_CENTRE_U (0.5F)
#define SNOW_CENTRE_V (0.5F)
#define SNOW_RADIUS (1.0F)
//#ifdef TARGET_DC
// Slightly more for the DC - not sure why.
//#define LEAF_UP 12
//#else
#define LEAF_UP 8
//#endif
#define LEAF_SIZE (20.0F+(float)(i&15))
SLONG j;
float fyaw;
float fpitch;
float froll;
float ubase;
float vbase;
float matrix[9];
float angle;
SVector_F temp[4];
PolyPage *pp;
D3DLVERTEX *lv;
ULONG rubbish_colour;
#ifdef TARGET_DC
ULONG leaf_colour_choice_rgb[4] =
{
0xff332d1d,
0xff243224,
0xff123320,
0xff332f07
};
ULONG leaf_colour_choice_grey[4] =
{
0xff333333,
0xff444444,
0xff222222,
0xff383838
};
#else
ULONG leaf_colour_choice_rgb[4] =
{
0x332d1d,
0x243224,
0x123320,
0x332f07
};
ULONG leaf_colour_choice_grey[4] =
{
0x333333,
0x444444,
0x222222,
0x383838
};
#endif
if (AENG_dirt_uvlookup_valid && AENG_dirt_uvlookup_world_type == world_type)
{
//
// Valid lookup table.
//
}
else
{
//
// Calclate the uvlookup table.
//
for (i = 0; i < AENG_MAX_DIRT_UVLOOKUP; i++)
{
float angle = float(i) * (2.0F * PI / AENG_MAX_DIRT_UVLOOKUP);
float cangle;
float sangle;
#ifdef TARGET_DC
_SinCosA(&sangle, &cangle, angle);
#else
sangle = sinf(angle);
cangle = cosf(angle);
#endif
//
// Fix the uv's for texture paging.
//
#ifdef TEX_EMBED
if (world_type == WORLD_TYPE_SNOW)
{
pp = &POLY_Page[POLY_PAGE_SNOWFLAKE];
// And the snowflake texture is bigger and needs a bit of squishing.
AENG_dirt_uvlookup[i].u = SNOW_CENTRE_U + sangle * SNOW_RADIUS;
AENG_dirt_uvlookup[i].v = SNOW_CENTRE_V + cangle * SNOW_RADIUS;
}
else
{
pp = &POLY_Page[POLY_PAGE_LEAF];
AENG_dirt_uvlookup[i].u = LEAF_CENTRE_U + sangle * LEAF_RADIUS;
AENG_dirt_uvlookup[i].v = LEAF_CENTRE_V + cangle * LEAF_RADIUS;
}
AENG_dirt_uvlookup[i].u = AENG_dirt_uvlookup[i].u * pp->m_UScale + pp->m_UOffset;
AENG_dirt_uvlookup[i].v = AENG_dirt_uvlookup[i].v * pp->m_VScale + pp->m_VOffset;
#endif
}
AENG_dirt_uvlookup_valid = TRUE;
AENG_dirt_uvlookup_world_type = world_type;
}
for (i = 0; i < 4; i++)
{
leaf_colour_choice_rgb[i] = AENG_colour_mult(leaf_colour_choice_rgb[i], NIGHT_amb_d3d_colour);
}
ULONG flag[4];
ULONG leaf_colour;
ULONG leaf_specular;
// Cope with some wacky internals.
POLY_set_local_rotation_none();
POLY_flush_local_rot();
//
// Initialise the leaf page and MM stuff...
//
AENG_dirt_lvert_upto = 0;
AENG_dirt_index_upto = 0;
AENG_dirt_lvert = (D3DLVERTEX *) ((SLONG(AENG_dirt_lvert_buffer) + 31) & ~0x1f);
AENG_dirt_matrix = (D3DMATRIX *) ((SLONG(AENG_dirt_matrix_buffer) + 31) & ~0x1f);
//
// Draw the dirt.
//
DIRT_Dirt *dd;
#ifdef DEBUG
int iDrawnDirtCount = 0;
#endif
for (i = 0; i < DIRT_MAX_DIRT; i++)
{
dd = &DIRT_dirt[i];
if (dd->type == DIRT_TYPE_UNUSED)
{
continue;
}
dd->flag &= ~DIRT_FLAG_DELETE_OK;
//
// Is this bit of dirt behind the camera?
//
{
float dx;
float dy;
float dz;
dx = float(dd->x) - AENG_cam_x;
dy = float(dd->y) - AENG_cam_y;
dz = float(dd->z) - AENG_cam_z;
float dprod;
dprod =
dx * AENG_cam_matrix[6] +
dy * AENG_cam_matrix[7] +
dz * AENG_cam_matrix[8];
if (dprod < 64.0F)
{
//
// Offscreen...
//
DIRT_MARK_AS_OFFSCREEN_QUICK(i);
goto do_next_dirt;
}
}
#ifdef DEBUG
iDrawnDirtCount++;
#endif
switch(dd->type)
{
case DIRT_TYPE_LEAF:
case DIRT_TYPE_SNOW:
{
//
// Get four vertices from the leaf page.
//
if (AENG_dirt_lvert_upto + 4 > AENG_MAX_DIRT_LVERTS)
{
//
// Draw what we have so far...
//
// Cope with some wacky internals.
POLY_set_local_rotation_none();
if (world_type == WORLD_TYPE_SNOW)
{
POLY_Page[POLY_PAGE_SNOWFLAKE].RS.SetChanged();
}
else
{
POLY_Page[POLY_PAGE_LEAF].RS.SetChanged();
}
the_display.lp_D3D_Device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
D3DFVF_LVERTEX,
AENG_dirt_lvert,
AENG_dirt_lvert_upto,
AENG_dirt_index,
AENG_dirt_index_upto,
0);
AENG_dirt_lvert_upto = 0;
AENG_dirt_index_upto = 0;
lv = AENG_dirt_lvert;
}
else
{
lv = &AENG_dirt_lvert[AENG_dirt_lvert_upto];
}
if ((i & 0xf) == 0 && !estate && world_type != WORLD_TYPE_SNOW)
{
//
// This is some rubbish...
//
fpitch = float(dd->pitch) * (PI / 1024.0F);
froll = float(dd->roll) * (PI / 1024.0F);
//
// Copied from MATRIX_calc then fucked with...
//
float cy, cp, cr;
float sy, sp, sr;
#ifdef TARGET_DC
// Use the fast intrinsics.
// Error is 2e-21 at most.
sy = 0.0F; // sin(0)
cy = 1.0F; // cos(0)
_SinCosA ( &sr, &cr, froll );
_SinCosA ( &sp, &cp, fpitch );
#else
sy = 0.0F; // sin(0)
cy = 1.0F; // cos(0)
sp = sin(fpitch);
sr = sin(froll);
cp = cos(fpitch);
cr = cos(froll);
#endif
//
// (matrix[3],matrix[4],matrix[5]) remains undefined...
//
matrix[0] = cy * cr + sy * sp * sr;
matrix[6] = sy * cp;
matrix[1] = -cp * sr;
matrix[7] = sp;
matrix[2] = -sy * cr + cy * sp * sr;
matrix[8] = cy * cp;
matrix[0] *= 24.0F;
matrix[1] *= 24.0F;
matrix[2] *= 24.0F;
matrix[6] *= 24.0F;
matrix[7] *= 24.0F;
matrix[8] *= 24.0F;
//
// Work out the position of the points.
//
float base_x = float(dd->x);
float base_y = float(dd->y + LEAF_UP);
float base_z = float(dd->z);
lv[0].x = base_x + matrix[6] + matrix[0];
lv[0].y = base_y + matrix[7] + matrix[1];
lv[0].z = base_z + matrix[8] + matrix[2];
lv[1].x = base_x + matrix[6] - matrix[0];
lv[1].y = base_y + matrix[7] - matrix[1];
lv[1].z = base_z + matrix[8] - matrix[2];
lv[2].x = base_x - matrix[6] + matrix[0];
lv[2].y = base_y - matrix[7] + matrix[1];
lv[2].z = base_z - matrix[8] + matrix[2];
lv[3].x = base_x - matrix[6] - matrix[0];
lv[3].y = base_y - matrix[7] - matrix[1];
lv[3].z = base_z - matrix[8] - matrix[2];
//
// What are the uv's and colour of this quad?
//
rubbish_colour = NIGHT_amb_d3d_colour;
if (i & 32)
{
ubase = 0.0F;
vbase = 0.0F;
}
else
{
ubase = 0.5F;
vbase = 0.0F;
}
if (i == 64)
{
//
// Only one bit of money!
//
ubase = 0.0F;
vbase = 0.5F;
}
else
{
if (!(i & 32))
{
if (i & 64)
{
rubbish_colour &= 0xffffff00;
}
}
}
lv[0].tu = ubase;
lv[0].tv = vbase;
lv[0].color = rubbish_colour;
lv[0].specular = 0xff000000;
lv[1].tu = ubase + 0.5F;
lv[1].tv = vbase;
lv[1].color = rubbish_colour;
lv[1].specular = 0xff000000;
lv[2].tu = ubase;
lv[2].tv = vbase + 0.5F;
lv[2].color = rubbish_colour;
lv[2].specular = 0xff000000;
lv[3].tu = ubase + 0.5F;
lv[3].tv = vbase + 0.5F;
lv[3].color = rubbish_colour;
lv[3].specular = 0xff000000;
#ifdef TEX_EMBED
pp = &POLY_Page[POLY_PAGE_RUBBISH];
lv[0].tu = lv[0].tu * pp->m_UScale + pp->m_UOffset;
lv[0].tv = lv[0].tv * pp->m_VScale + pp->m_VOffset;
lv[1].tu = lv[1].tu * pp->m_UScale + pp->m_UOffset;
lv[1].tv = lv[1].tv * pp->m_VScale + pp->m_VOffset;
lv[2].tu = lv[2].tu * pp->m_UScale + pp->m_UOffset;
lv[2].tv = lv[2].tv * pp->m_VScale + pp->m_VOffset;
lv[3].tu = lv[3].tu * pp->m_UScale + pp->m_UOffset;
lv[3].tv = lv[3].tv * pp->m_VScale + pp->m_VOffset;
#endif
//
// Build the indices.
//
ASSERT(AENG_dirt_index_upto + 6 <= AENG_MAX_DIRT_INDICES);
AENG_dirt_index[AENG_dirt_index_upto + 0] = AENG_dirt_lvert_upto + 0;
AENG_dirt_index[AENG_dirt_index_upto + 1] = AENG_dirt_lvert_upto + 1;
AENG_dirt_index[AENG_dirt_index_upto + 2] = AENG_dirt_lvert_upto + 2;
AENG_dirt_index[AENG_dirt_index_upto + 3] = AENG_dirt_lvert_upto + 3;
AENG_dirt_index[AENG_dirt_index_upto + 4] = AENG_dirt_lvert_upto + 2;
AENG_dirt_index[AENG_dirt_index_upto + 5] = AENG_dirt_lvert_upto + 1;
AENG_dirt_index_upto += 6;
AENG_dirt_lvert_upto += 4;
}
else
{
//
// This is a leaf or snowflake
//
float leaf_size = LEAF_SIZE;
if ((dd->pitch | dd->roll) == 0)
{
//
// This happens often... so we optimise it out.
//
lv[0].x = float(dd->x);
lv[0].y = float(dd->y + LEAF_UP);
lv[0].z = float(dd->z + leaf_size);
lv[1].x = float(dd->x + leaf_size);
lv[1].y = float(dd->y + LEAF_UP);
lv[1].z = float(dd->z - leaf_size);
lv[2].x = float(dd->x - leaf_size);
lv[2].y = float(dd->y + LEAF_UP);
lv[2].z = float(dd->z - leaf_size);
}
else
{
//
// The rotation matrix of this bit of dirt.
//
fpitch = float(dd->pitch) * (PI / 1024.0F);
froll = float(dd->roll) * (PI / 1024.0F);
//
// Copied from MATRIX_calc then fucked with...
//
float cy, cp, cr;
float sy, sp, sr;
#ifdef TARGET_DC
// Use the fast intrinsics.
// Error is 2e-21 at most.
sy = 0.0F; // sin(0)
cy = 1.0F; // cos(0)
_SinCosA ( &sr, &cr, froll );
_SinCosA ( &sp, &cp, fpitch );
#else
sy = 0.0F; // sin(0)
cy = 1.0F; // cos(0)
sp = sin(fpitch);
sr = sin(froll);
cp = cos(fpitch);
cr = cos(froll);
#endif
//
// (matrix[3],matrix[4],matrix[5]) remains undefined...
//
matrix[0] = cy * cr + sy * sp * sr;
matrix[6] = sy * cp;
matrix[1] = -cp * sr;
matrix[7] = sp;
matrix[2] = -sy * cr + cy * sp * sr;
matrix[8] = cy * cp;
matrix[0] *= leaf_size;
matrix[1] *= leaf_size;
matrix[2] *= leaf_size;
matrix[6] *= leaf_size;
matrix[7] *= leaf_size;
matrix[8] *= leaf_size;
//
// Work out the position of the points.
//
lv[0].x = float(dd->x);
lv[0].y = float(dd->y + LEAF_UP);
lv[0].z = float(dd->z);
lv[1].x = lv[0].x - matrix[6] + matrix[0];
lv[1].y = lv[0].y - matrix[7] + matrix[1];
lv[1].z = lv[0].z - matrix[8] + matrix[2];
lv[2].x = lv[0].x - matrix[6] - matrix[0];
lv[2].y = lv[0].y - matrix[7] - matrix[1];
lv[2].z = lv[0].z - matrix[8] - matrix[2];
lv[0].x += matrix[6];
lv[0].y += matrix[7];
lv[0].z += matrix[8];
}
if (world_type == WORLD_TYPE_SNOW)
{
// A snowflake - just subtle shades of grey
DWORD dwColour = ( ( i & 0x0f ) << 2 ) + 0xc0;
dwColour *= 0x010101;
dwColour |= 0xff000000;
lv[0].color = dwColour;
lv[0].specular = 0xff000000;
lv[1].color = dwColour;
lv[1].specular = 0xff000000;
lv[2].color = dwColour;
lv[2].specular = 0xff000000;
}
else
{
//
// The colour of this leaf.
//
leaf_colour = leaf_colour_choice_rgb[i & 0x3];
lv[0].color = (leaf_colour * 3) | 0xff000000;
lv[0].specular = 0xff000000;
lv[1].color = (leaf_colour * 4) | 0xff000000;
lv[1].specular = 0xff000000;
lv[2].color = (leaf_colour * 5) | 0xff000000;
lv[2].specular = 0xff000000;
}
//
// The rotation angle of the leaf.
//
lv[0].tu = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 0 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].u;
lv[0].tv = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 0 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].v;
lv[1].tu = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 1 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].u;
lv[1].tv = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 1 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].v;
lv[2].tu = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 2 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].u;
lv[2].tv = AENG_dirt_uvlookup[(i + (AENG_MAX_DIRT_UVLOOKUP * 2 / 3)) & (AENG_MAX_DIRT_UVLOOKUP - 1)].v;
//
// Build the indices.
//
ASSERT(AENG_dirt_index_upto + 3 <= AENG_MAX_DIRT_INDICES);
AENG_dirt_index[AENG_dirt_index_upto + 0] = AENG_dirt_lvert_upto + 0;
AENG_dirt_index[AENG_dirt_index_upto + 1] = AENG_dirt_lvert_upto + 1;
AENG_dirt_index[AENG_dirt_index_upto + 2] = AENG_dirt_lvert_upto + 2;
AENG_dirt_index_upto += 3;
AENG_dirt_lvert_upto += 3;
}
}
break;
case DIRT_TYPE_HELDCAN:
//
// Don't draw inside the car?!
//
{
Thing *p_person = TO_THING(dd->droll); // droll => owner
if (p_person->Genus.Person->InCar)
{
continue;
}
}
//
// FALLTHROUGH!
//
case DIRT_TYPE_CAN:
case DIRT_TYPE_THROWCAN:
MESH_draw_poly(
PRIM_OBJ_CAN,
dd->x,
dd->y,
dd->z,
dd->yaw,
dd->pitch,
dd->roll,
#ifdef TARGET_DC
NULL,0xff,0);
#else
NULL,0,0);
#endif
break;
case DIRT_TYPE_BRASS:
extern UBYTE kludge_shrink;
kludge_shrink = TRUE;
MESH_draw_poly(
PRIM_OBJ_ITEM_AMMO_SHOTGUN,
dd->x,
dd->y,
dd->z,
dd->yaw,
dd->pitch,
dd->roll,
#ifdef TARGET_DC
NULL,0xff,0);
#else
NULL,0,0);
#endif
kludge_shrink = FALSE;
break;
case DIRT_TYPE_WATER:
SHAPE_droplet(
dd->x,
dd->y,
dd->z,
dd->dx >> 2,
dd->dy >> TICK_SHIFT,
dd->dz >> 2,
#ifdef TARGET
0xff224455,
#else
0x00224455,
#endif
POLY_PAGE_DROPLET);
break;
case DIRT_TYPE_SPARKS:
SHAPE_droplet(
dd->x,
dd->y,
dd->z,
dd->dx >> 2,
dd->dy >> TICK_SHIFT,
dd->dz >> 2,
0x7f997744,
POLY_PAGE_BLOOM1);
break;
case DIRT_TYPE_URINE:
SHAPE_droplet(
dd->x,
dd->y,
dd->z,
dd->dx >> 2,
dd->dy >> TICK_SHIFT,
dd->dz >> 2,
#ifdef TARGET
0xff775533,
#else
0x00775533,
#endif
POLY_PAGE_DROPLET);
break;
case DIRT_TYPE_BLOOD:
SHAPE_droplet(
dd->x,
dd->y,
dd->z,
dd->dx >> 2,
dd->dy >> TICK_SHIFT,
dd->dz >> 2,
0x9fFFFFFF,
POLY_PAGE_BLOODSPLAT);
break;
default:
ASSERT(0);
break;
}
#if 0
/*
switch(di.type)
{
case DIRT_INFO_TYPE_WATER:
SHAPE_droplet(
di.x,
di.y,
di.z,
di.dx * 4,
di.dy * 4,
di.dz * 4,
#ifdef TARGET
0xff224455,
#else
0x00224455,
#endif
POLY_PAGE_DROPLET);
break;
case DIRT_INFO_TYPE_URINE:
SHAPE_droplet(
di.x,
di.y,
di.z,
di.dx * 4,
di.dy * 4,
di.dz * 4,
#ifdef TARGET
0xff775533,
#else
0x00775533,
#endif
POLY_PAGE_DROPLET);
break;
case DIRT_INFO_TYPE_SPARKS:
SHAPE_droplet(
di.x,
di.y,
di.z,
di.dx * 4,
di.dy * 4,
di.dz * 4,
0x7f997744,
POLY_PAGE_BLOOM1);
break;
case DIRT_INFO_TYPE_BLOOD:
SHAPE_droplet(
di.x,
di.y,
di.z,
di.dx * 4,
di.dy * 4,
di.dz * 4,
0x9fFFFFFF,
POLY_PAGE_BLOODSPLAT);
break;
case DIRT_INFO_TYPE_SNOW:
leaf_colour=di.morph1;
leaf_colour<<=23;
leaf_colour|=0xffFFff;
SPRITE_draw_tex(di.x,di.y,di.z,20,leaf_colour,0xFF000000,POLY_PAGE_SNOWFLAKE,0.0,0.0,1.0,1.0,SPRITE_SORT_NORMAL);
break;
case DIRT_INFO_TYPE_LEAF:
//
// Create the rotation matrix for this bit of dirt...
//
if ((di.pitch | di.roll) == 0)
{
}
//
// There is a chance we are going to draw some rubbish instead of a leaf.
//
if ((i & 0xf) == 0 && estate==0)
{
//
// The rotation matrix of this bit of dirt.
//
fpitch = float(di.pitch) * (PI / 1024.0F);
froll = float(di.roll) * (PI / 1024.0F);
fyaw = float(i);
MATRIX_calc(matrix, fyaw, fpitch, froll);
matrix[0] *= 24.0F;
matrix[1] *= 24.0F;
matrix[2] *= 24.0F;
matrix[6] *= 24.0F;
matrix[7] *= 24.0F;
matrix[8] *= 24.0F;
temp[0].X = float(di.x) + matrix[6] + matrix[0];
temp[0].Y = float(di.y) + matrix[7] + matrix[1];
temp[0].Z = float(di.z) + matrix[8] + matrix[2];
temp[1].X = float(di.x) + matrix[6] - matrix[0];
temp[1].Y = float(di.y) + matrix[7] - matrix[1];
temp[1].Z = float(di.z) + matrix[8] - matrix[2];
temp[2].X = float(di.x) - matrix[6] + matrix[0];
temp[2].Y = float(di.y) - matrix[7] + matrix[1];
temp[2].Z = float(di.z) - matrix[8] + matrix[2];
temp[3].X = float(di.x) - matrix[6] - matrix[0];
temp[3].Y = float(di.y) - matrix[7] - matrix[1];
temp[3].Z = float(di.z) - matrix[8] - matrix[2];
//
// Transform the points.
//
for (j = 0; j < 4; j++)
{
POLY_transform(
temp[j].X,
temp[j].Y + 4.0F,
temp[j].Z,
&pp[j]);
if (!pp[j].IsValid())
{
//
// Tell the DIRT module that the leaf is off-screen.
//
DIRT_mark_as_offscreen(i);
//
// Don't bother transforming the other points.
//
goto do_next_dirt;
}
}
if (POLY_valid_quad(quad))
{
float ubase;
float vbase;
SLONG colour_and = 0xffffffff;
if (i & 32)
{
ubase = 0.0F;
vbase = 0.0F;
}
else
{
ubase = 0.5F;
vbase = 0.0F;
}
if (i == 64)
{
//
// Only one bit of money!
//
ubase = 0.0F;
vbase = 0.5F;
}
else
{
if (!(i & 32))
{
if (i & 64)
{
colour_and = 0xffffff00;
}
}
}
//
// Set the uvs.
//
for (j = 0; j < 4; j++)
{
pp[j].u = ubase;
pp[j].v = vbase;
if (j & 1) {pp[j].u += 0.5F;}
if (j & 2) {pp[j].v += 0.5F;}
#ifdef TARGET_DC
pp[j].colour = ( NIGHT_amb_d3d_colour & colour_and ) | 0xff000000;
#else
pp[j].colour = NIGHT_amb_d3d_colour & colour_and;
#endif
pp[j].specular = 0xff000000;
}
//
// Draw the quad.
//
POLY_add_quad(quad, POLY_PAGE_RUBBISH, FALSE);
}
else
{
//
// Tell the DIRT module that the leaf is off-screen.
//
DIRT_mark_as_offscreen(i);
}
}
else
{
if ((di.yaw | di.pitch | di.roll) == 0)
{
//
// This happens often... so we optimise it out.
//
temp[0].X = float(di.x);
temp[0].Y = float(di.y + LEAF_UP);
temp[0].Z = float(di.z + LEAF_SIZE);
temp[1].X = float(di.x + LEAF_SIZE);
temp[1].Y = float(di.y + LEAF_UP);
temp[1].Z = float(di.z - LEAF_SIZE);
temp[2].X = float(di.x - LEAF_SIZE);
temp[2].Y = float(di.y + LEAF_UP);
temp[2].Z = float(di.z - LEAF_SIZE);
}
else
{
//
// The rotation matrix of this bit of dirt.
//
fyaw = float(di.yaw) * (PI / 1024.0F);
fpitch = float(di.pitch) * (PI / 1024.0F);
froll = float(di.roll) * (PI / 1024.0F);
MATRIX_calc(matrix, fyaw, fpitch, froll);
//
// Work out the position of the points.
//
for (j = 0; j < 3; j++)
{
temp[j].X = float(di.x);
temp[j].Y = float(di.y);
temp[j].Z = float(di.z);
temp[j].Y += float(LEAF_UP);
}
temp[0].X += matrix[6] * LEAF_SIZE;
temp[0].Y += matrix[7] * LEAF_SIZE;
temp[0].Z += matrix[8] * LEAF_SIZE;
temp[1].X -= matrix[6] * LEAF_SIZE;
temp[1].Y -= matrix[7] * LEAF_SIZE;
temp[1].Z -= matrix[8] * LEAF_SIZE;
temp[2].X -= matrix[6] * LEAF_SIZE;
temp[2].Y -= matrix[7] * LEAF_SIZE;
temp[2].Z -= matrix[8] * LEAF_SIZE;
temp[1].X += matrix[0] * LEAF_SIZE;
temp[1].Y += matrix[1] * LEAF_SIZE;
temp[1].Z += matrix[2] * LEAF_SIZE;
temp[2].X -= matrix[0] * LEAF_SIZE;
temp[2].Y -= matrix[1] * LEAF_SIZE;
temp[2].Z -= matrix[2] * LEAF_SIZE;
falling = TRUE;
}
//
// Transform the points.
//
for (j = 0; j < 3; j++)
{
POLY_transform(
temp[j].X,
temp[j].Y,
temp[j].Z,
&pp[j]);
if (!pp[j].IsValid())
{
//
// Tell the DIRT module that the leaf is off-screen.
//
DIRT_mark_as_offscreen(i);
//
// Don't bother transforming the other points.
//
goto do_next_dirt;
}
}
if (POLY_valid_triangle(tri))
{
//
// The colour and texture of the leaf.
//
if (POLY_force_additive_alpha)
{
leaf_colour = leaf_colour_choice_grey[i & 0x3];
}
else
{
leaf_colour = leaf_colour_choice_rgb[i & 0x3];
leaf_colour = AENG_colour_mult(leaf_colour, NIGHT_amb_d3d_colour);
}
angle = float(i);
for (j = 0; j < 3; j++)
{
pp[j].colour = leaf_colour * (j + 3);
pp[j].colour &= ~POLY_colour_restrict;
#ifdef TARGET_DC
pp[j].colour |= 0xff000000;
#endif
pp[j].specular = 0xff000000;
pp[j].u = LEAF_U(angle);
pp[j].v = LEAF_V(angle);
angle += 2.0F * PI / 3.0F;
}
POLY_add_triangle(tri, LEAF_PAGE, FALSE);
}
else
{
//
// Tell the DIRT module that the leaf is off-screen.
//
DIRT_mark_as_offscreen(i);
}
}
break;
case DIRT_INFO_TYPE_PRIM:
extern UBYTE kludge_shrink;
if (di.held||(di.prim==253))
{
kludge_shrink = TRUE;
}
MESH_draw_poly(
di.prim,
di.x,
di.y,
di.z,
di.yaw,
di.pitch,
di.roll,
#ifdef TARGET_DC
NULL,0xff,0);
#else
NULL,0,0);
#endif
kludge_shrink = FALSE;
break;
case DIRT_INFO_TYPE_MORPH:
MESH_draw_morph(
di.prim,
di.morph1,
di.morph2,
di.tween,
di.x,
di.y,
di.z,
di.yaw,
di.pitch,
di.roll,
NULL);
break;
default:
ASSERT(0);
break;
}
*/
#endif
do_next_dirt:;
}
//
// Draw left-over leaves.
//
if (AENG_dirt_lvert_upto)
{
// Cope with some wacky internals.
POLY_set_local_rotation_none();
if (world_type == WORLD_TYPE_SNOW)
{
POLY_Page[POLY_PAGE_SNOWFLAKE].RS.SetChanged();
}
else
{
POLY_Page[POLY_PAGE_LEAF].RS.SetChanged();
}
the_display.lp_D3D_Device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,
D3DFVF_LVERTEX,
AENG_dirt_lvert,
AENG_dirt_lvert_upto,
AENG_dirt_index,
AENG_dirt_index_upto,
0);
}
//TRACE ( "Drew %i bits of dirt\n", iDrawnDirtCount );
}
//
// A bucket list for the pows!
//
typedef struct aeng_pow
{
SLONG frame;
float sx;
float sy;
float sz;
float Z;
struct aeng_pow *next;
} AENG_Pow;
#define AENG_MAX_POWS 256
AENG_Pow AENG_pow[AENG_MAX_POWS];
SLONG AENG_pow_upto;
#define AENG_POW_NUM_BUCKETS 1024
AENG_Pow *AENG_pow_bucket[AENG_POW_NUM_BUCKETS];
//
// Draws the POWS
//
void AENG_draw_pows(void)
{
SLONG pow;
SLONG sprite;
SLONG bucket;
AENG_Pow *ap;
POW_Pow *pp;
POW_Sprite *ps;
POLY_Point pt;
//
// Clear the buckets and the AENG_pows.
//
memset(AENG_pow_bucket, 0, sizeof(AENG_pow_bucket));
AENG_pow_upto = 0;
//
// Draw all used pows. Ignore the NGAMUT for now.
//
for (pow = POW_pow_used; pow; pow = pp->next)
{
ASSERT(WITHIN(pow, 1, POW_MAX_POWS - 1));
pp = &POW_pow[pow];
for (sprite = pp->sprite; sprite; sprite = ps->next)
{
ASSERT(WITHIN(sprite, 1, POW_MAX_SPRITES - 1));
ps = &POW_sprite[sprite];
POLY_transform(
float(ps->x) * (1.0F / 256.0F),
float(ps->y) * (1.0F / 256.0F),
float(ps->z) * (1.0F / 256.0F),
&pt);
if (pt.clip & POLY_CLIP_TRANSFORMED)
{
//
// Create an AENG_pow.
//
ASSERT(WITHIN(AENG_pow_upto, 0, AENG_MAX_POWS - 1));
ap = &AENG_pow[AENG_pow_upto++];
ap->frame = ps->frame;
ap->sx = pt.X;
ap->sy = pt.Y;
ap->sz = pt.z;
ap->Z = pt.Z;
ap->next = NULL;
//
// Add to the bucket list.
//
bucket = ftol(pt.z * float(AENG_POW_NUM_BUCKETS));
SATURATE(bucket, 0, AENG_POW_NUM_BUCKETS - 1);
ap->next = AENG_pow_bucket[bucket];
AENG_pow_bucket[bucket] = ap;
}
}
}
//
// Draw the buckets.
//
{
POLY_Point ppt[4];
POLY_Point *quad[4];
float size;
float u;
float v;
ppt[0].colour = 0xffffffff;
ppt[1].colour = 0xffffffff;
ppt[2].colour = 0xffffffff;
ppt[3].colour = 0xffffffff;
ppt[0].specular = 0xff000000;
ppt[1].specular = 0xff000000;
ppt[2].specular = 0xff000000;
ppt[3].specular = 0xff000000;
quad[0] = &ppt[0];
quad[1] = &ppt[1];
quad[2] = &ppt[2];
quad[3] = &ppt[3];
for (bucket = 0; bucket < AENG_POW_NUM_BUCKETS; bucket++)
{
for (ap = AENG_pow_bucket[bucket]; ap; ap = ap->next)
{
//
// Push forward in the z-buffer
//
ap->sz -= 0.025F; // Half a mapsquare!
if (ap->sz < POLY_ZCLIP_PLANE)
{
ap->sz = POLY_ZCLIP_PLANE;
}
ap->Z = POLY_ZCLIP_PLANE / ap->sz;
//
// The frame.
//
u = float(ap->frame & 0x3) * (1.0F / 4.0F);
v = float(ap->frame >> 2) * (1.0F / 4.0F);
//
// Add this sprite to the bucket list.
//
size = 650.0F * ap->Z;
ppt[0].X = ap->sx - size;
ppt[0].Y = ap->sy - size;
ppt[1].X = ap->sx + size;
ppt[1].Y = ap->sy - size;
ppt[2].X = ap->sx - size;
ppt[2].Y = ap->sy + size;
ppt[3].X = ap->sx + size;
ppt[3].Y = ap->sy + size;
ppt[0].u = u + (0.0F / 4.0F);
ppt[0].v = v + (0.0F / 4.0F);
ppt[1].u = u + (1.0F / 4.0F);
ppt[1].v = v + (0.0F / 4.0F);
ppt[2].u = u + (0.0F / 4.0F);
ppt[2].v = v + (1.0F / 4.0F);
ppt[3].u = u + (1.0F / 4.0F);
ppt[3].v = v + (1.0F / 4.0F);
ppt[0].Z = ap->Z;
ppt[1].Z = ap->Z;
ppt[2].Z = ap->Z;
ppt[3].Z = ap->Z;
ppt[0].z = ap->sz;
ppt[1].z = ap->sz;
ppt[2].z = ap->sz;
ppt[3].z = ap->sz;
POLY_add_quad(quad, POLY_PAGE_EXPLODE1, FALSE, TRUE);
}
}
}
}
#ifndef TARGET_DC
void AENG_draw_released_balloons(void)
{
SLONG i;
BALLOON_Balloon *bb;
for (i = 1; i < BALLOON_balloon_upto; i++)
{
bb = &BALLOON_balloon[i];
if (bb->type && !bb->thing)
{
//
// Nobody is holding this balloon so we have to draw it here.
//
SHAPE_draw_balloon(i);
}
}
}
#endif
//
// AA test.
//
#define AENG_AA_LEFT 20
#define AENG_AA_TOP 20
#define AENG_AA_PIX_SIZE 4
#define AENG_AA_BUF_SIZE 32
UBYTE AENG_aa_buffer[AENG_AA_BUF_SIZE][AENG_AA_BUF_SIZE];
#ifdef TARGET_DC
// Try to misalign the map rows to try to stop the cache thrashing.
// DC's cache is 32k and 1-way asssociative!
//#define MAP_SIZE_TWEAK 4
// Actually, it seemed to make very little difference.
#define MAP_SIZE_TWEAK 0
#else
#define MAP_SIZE_TWEAK 0
#endif
#ifdef TARGET_DC
#define NEW_FLOOR defined
#else
#define NEW_FLOOR defined
#endif
#ifndef NEW_FLOOR
POLY_Point AENG_upper[MAP_WIDTH / 2 + MAP_SIZE_TWEAK][MAP_HEIGHT / 2 + MAP_SIZE_TWEAK];
POLY_Point AENG_lower[MAP_WIDTH / 2 + MAP_SIZE_TWEAK*2][MAP_HEIGHT / 2 + MAP_SIZE_TWEAK*2];
#endif
//
// Globals affecting the way the engine works.
//
#define AENG_SKY_TYPE_NIGHT 0
#define AENG_SKY_TYPE_DAY 1
SLONG AENG_torch_on = FALSE;
SLONG AENG_shadows_on = TRUE;
SLONG AENG_sky_type = AENG_SKY_TYPE_DAY;
ULONG AENG_sky_colour_bot = 0x008890ee;
ULONG AENG_sky_colour_top = 0x006670cc;
void AENG_set_sky_nighttime()
{
AENG_sky_type = AENG_SKY_TYPE_NIGHT;
}
void AENG_set_sky_daytime(ULONG bottom_colour, ULONG top_colour)
{
AENG_sky_type = AENG_SKY_TYPE_DAY;
AENG_sky_colour_bot = bottom_colour;
AENG_sky_colour_top = top_colour;
}
struct RRect
{
SLONG x;
SLONG y;
SLONG w;
SLONG h;
SLONG col;
SLONG layer;
SLONG page;
};
struct RRect rrect[2000];
SLONG next_rrect=1;
void AENG_draw_rectr(SLONG x,SLONG y,SLONG w,SLONG h,SLONG col,SLONG layer,SLONG page)
{
ASSERT(next_rrect<2000);
rrect[next_rrect].x=x;
rrect[next_rrect].y=y;
rrect[next_rrect].w=w;
rrect[next_rrect].h=h;
rrect[next_rrect].col=col;
rrect[next_rrect].layer=layer;
rrect[next_rrect].page=page;
next_rrect++;
}
void AENG_draw_rect(SLONG x,SLONG y,SLONG w,SLONG h,SLONG col,SLONG layer,SLONG page);
void draw_all_boxes(void)
{
SLONG x,y,w,h, col,layer,page;
SLONG c0;
for(c0=1;c0<next_rrect;c0++)
{
x=rrect[c0].x;
y=rrect[c0].y;
w=rrect[c0].w;
h=rrect[c0].h;
col=rrect[c0].col;
layer=rrect[c0].layer;
page=rrect[c0].page;
AENG_draw_rect(x,y,w,h,col,layer,page);
}
next_rrect=0;
}
void AENG_draw_rect(SLONG x,SLONG y,SLONG w,SLONG h,SLONG col,SLONG layer,SLONG page)
{
float offset=0.0;
POLY_Point pp [4];
POLY_Point *quad[4];
float top,bottom,left,right;
offset=((float)layer)*0.0001f;
top=(float)y;
bottom=(float)(y+h);
left=(float)x;
right=(float)(x+w);
#define AENG_BACKGROUND_COLOUR 0x55888800
pp[0].X = left;
pp[0].Y = top;
pp[0].z = 0.0F+offset;
pp[0].Z = 1.0F-offset;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = col;
pp[0].specular = 0;
pp[1].X = right;
pp[1].Y = top;
pp[1].z = 0.0F+offset;
pp[1].Z = 1.0F-offset;
pp[1].u = 0.0F;
pp[1].v = 0.0F;
pp[1].colour = col;
pp[1].specular = 0;
pp[2].X = left;
pp[2].Y = bottom;
pp[2].z = 0.0F+offset;
pp[2].Z = 1.0F-offset;
pp[2].u = 0.0F;
pp[2].v = 0.0F;
pp[2].colour = col;
pp[2].specular = 0;
pp[3].X = right;
pp[3].Y = bottom;
pp[3].z = 0.0F+offset;
pp[3].Z = 1.0F-offset;
pp[3].u = 0.0F;
pp[3].v = 0.0F;
pp[3].colour = col;
pp[3].specular = 0;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, page, FALSE, TRUE);
}
void AENG_draw_col_tri(SLONG x0,SLONG y0,SLONG col0,SLONG x1,SLONG y1,SLONG col1,SLONG x2,SLONG y2,SLONG col2,SLONG layer)
{
float offset=0.0;
POLY_Point pp [4];
POLY_Point *tri[4];
POLY_Point *quad[4];
float left,right,top,bottom;
left=100.0;
right=200.0;
top=100.0;
bottom=200.0;
offset=((float)layer)*0.0001f;
/*
#define AENG_BACKGROUND_COLOUR 0x55888800
pp[0].X = left;
pp[0].Y = top;
pp[0].z = 0.0F;
pp[0].Z = 1.0F;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = AENG_BACKGROUND_COLOUR;
pp[0].specular = 0;
pp[1].X = right;
pp[1].Y = top;
pp[1].z = 0.0F;
pp[1].Z = 1.0F;
pp[1].u = 0.0F;
pp[1].v = 0.0F;
pp[1].colour = AENG_BACKGROUND_COLOUR;
pp[1].specular = 0;
pp[2].X = left;
pp[2].Y = bottom;
pp[2].z = 0.0F;
pp[2].Z = 1.0F;
pp[2].u = 0.0F;
pp[2].v = 0.0F;
pp[2].colour = AENG_BACKGROUND_COLOUR;
pp[2].specular = 0;
pp[3].X = right;
pp[3].Y = bottom;
pp[3].z = 0.0F;
pp[3].Z = 1.0F;
pp[3].u = 0.0F;
pp[3].v = 0.0F;
pp[3].colour = AENG_BACKGROUND_COLOUR;
pp[3].specular = 0;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE, TRUE);
*/
#define AENG_BACKGROUND_COLOUR 0x55888800
pp[0].X = (float)x0;
pp[0].Y = (float)y0;
// pp[0].X = left;
// pp[0].Y = top;
pp[0].z = 0.0F+offset;
pp[0].Z = 1.0F-offset;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = col0; //AENG_BACKGROUND_COLOUR;
pp[0].specular = 0;
pp[1].X = (float)x1;
pp[1].Y = (float)y1;
// pp[1].X = right;
// pp[1].Y = top;
pp[1].z = 0.0F+offset;
pp[1].Z = 1.0F-offset;
pp[1].u = 0.0F;
pp[1].v = 0.0F;
pp[1].colour = col1; //AENG_BACKGROUND_COLOUR;
pp[1].specular = 0;
pp[2].X = (float)x2;
pp[2].Y = (float)y2;
pp[2].z = 0.0F+offset;
pp[2].Z = 1.0F-offset;
pp[2].u = 0.0F;
pp[2].v = 0.0F;
pp[2].colour = col2; //AENG_BACKGROUND_COLOUR;
pp[2].specular = 0;
tri[0] = &pp[0];
tri[1] = &pp[1];
tri[2] = &pp[2];
POLY_add_triangle(tri, POLY_PAGE_COLOUR, FALSE, TRUE);
}
void show_gamut_lo(SLONG x,SLONG z)
{
return;
// AENG_draw_rect(x*8,z*8,8,8,0xff0000,2,POLY_PAGE_COLOUR);
}
void show_gamut_hi(SLONG x,SLONG z)
{
return;
// AENG_draw_rect(x*2,z*2,1,1,0xffff00,1,POLY_PAGE_COLOUR);
}
#if 1
// Bin this.
#define show_facet(thing) sizeof(thing)
#else
void show_facet(SLONG facet)
{
return;
struct DFacet *p_facet;
SLONG x1,z1,x2,z2;
SLONG colour=0xffffff;
p_facet=&dfacets[facet];
x1=p_facet->x[0];
x2=p_facet->x[1];
z1=p_facet->z[0];
z2=p_facet->z[1];
x1*=2;
z1*=2;
x2*=2;
z2*=2;
x1+=(p_facet->Y[0]>>8);
z1-=(p_facet->Y[0]>>8);
x2+=(p_facet->Y[0]>>8);
z2-=(p_facet->Y[0]>>8);
switch(p_facet->Height)
{
case 2:
colour=0xff;
break;
case 3:
colour=0xff00;
break;
case 4:
colour=0x7f7f;
break;
case 5:
colour=0xffff;
break;
}
POLY_add_line_2d( (float)x1,(float)z1,(float)x2,(float)z2,colour);
}
#endif
void AENG_draw_people_messages()
{
return;
SLONG x;
SLONG z;
SLONG t_index;
Thing *p_thing;
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Flags & FLAGS_IN_BUILDING)
{
//
// Dont draw things inside buildings when we are outdoors.
//
}
else
{
switch(p_thing->DrawType)
{
case DT_ROT_MULTI:
if (POLY_sphere_visible(
float(p_thing->WorldPos.X >> 8),
float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT,
float(p_thing->WorldPos.Z >> 8),
256.0F / (AENG_DRAW_DIST * 256.0F)))
{
CBYTE str[100];
// FIGURE_draw(p_thing);
sprintf(str,"%d %d",p_thing->State,p_thing->SubState);
AENG_world_text(
(p_thing->WorldPos.X >> 8),
(p_thing->WorldPos.Y >> 8) + 0x60,
(p_thing->WorldPos.Z >> 8),
200,
180,
50,
TRUE,
str);
// PCOM_person_state_debug(p_thing));
}
break;
}
}
t_index = p_thing->Child;
}
}
}
}
//
// Sets the rotation of the bike wheel prim for the given rotation.
//
void AENG_set_bike_wheel_rotation(UWORD rot, UBYTE prim)
{
SLONG i;
PrimObject *po;
PrimFace4 *f4;
po = &prim_objects[prim];
//
// The texture rotation vector.
//
// Oh no they're not.
#if 0
// All the textures are symmetrical, so you can't tell if they rotate.
// Optimised!
const SLONG du1 = 0xf;
const SLONG dv1 = 0;
const SLONG du2 = 0xf;
const SLONG dv2 = 0;
SLONG u;
SLONG v;
static SLONG order[4] = {2, 1, 3, 0};
//
// The faces we rotate the textures on are faces 6 and 7 for PRIM_OBJ_BIKE_BWHEEL.
//
f4 = &prim_faces4[po->StartFace4 + 6];
for (i = 0; i < 4; i++)
{
switch(order[i])
{
case 0: u = 16 + du1; v = 16 + dv1; break;
case 1: u = 16 + dv1; v = 16 - du1; break;
case 2: u = 16 - du1; v = 16 - dv1; break;
case 3: u = 16 - dv1; v = 16 + du1; break;
}
f4[0].UV[i][0] &= ~0x3f;
f4[0].UV[i][1] &= ~0x3f;
f4[0].UV[i][0] |= u;
f4[0].UV[i][1] |= v;
switch(order[i])
{
case 0: u = 16 + du2; v = 16 + dv2; break;
case 1: u = 16 + dv2; v = 16 - du2; break;
case 2: u = 16 - du2; v = 16 - dv2; break;
case 3: u = 16 - dv2; v = 16 + du2; break;
}
f4[1].UV[i][0] &= ~0x3f;
f4[1].UV[i][1] &= ~0x3f;
f4[1].UV[i][0] |= u;
f4[1].UV[i][1] |= v;
}
#else
SLONG du1 = SIN(+rot & 2047) * 15 >> 16;
SLONG dv1 = COS(+rot & 2047) * 15 >> 16;
SLONG du2 = SIN(-rot & 2047) * 15 >> 16;
SLONG dv2 = COS(-rot & 2047) * 15 >> 16;
SLONG u;
SLONG v;
static SLONG order[4] = {2, 1, 3, 0};
//
// The faces we rotate the textures on are faces 6 and 7 for PRIM_OBJ_BIKE_BWHEEL.
//
f4 = &prim_faces4[po->StartFace4 + 6];
for (i = 0; i < 4; i++)
{
switch(order[i])
{
case 0: u = 16 + du1; v = 16 + dv1; break;
case 1: u = 16 + dv1; v = 16 - du1; break;
case 2: u = 16 - du1; v = 16 - dv1; break;
case 3: u = 16 - dv1; v = 16 + du1; break;
}
f4[0].UV[i][0] &= ~0x3f;
f4[0].UV[i][1] &= ~0x3f;
f4[0].UV[i][0] |= u;
f4[0].UV[i][1] |= v;
switch(order[i])
{
case 0: u = 16 + du2; v = 16 + dv2; break;
case 1: u = 16 + dv2; v = 16 - du2; break;
case 2: u = 16 - du2; v = 16 - dv2; break;
case 3: u = 16 - dv2; v = 16 + du2; break;
}
f4[1].UV[i][0] &= ~0x3f;
f4[1].UV[i][1] &= ~0x3f;
f4[1].UV[i][0] |= u;
f4[1].UV[i][1] |= v;
}
#endif
}
/*
//
// Draws warehouse floor surrounding the given facet.
//
void AENG_draw_warehouse_floor_near_door(DFacet *df)
{
SLONG dx;
SLONG dz;
SLONG sx;
SLONG sz;
SLONG lx1;
SLONG lx2;
SLONG x1;
SLONG z1;
SLONG x2;
SLONG z2;
SLONG mx;
SLONG mz;
SLONG page;
POLY_Point *quad[4];
PAP_Hi *ph;
//
// The bounding box of the points.
//
x1 = df->x[0];
z1 = df->z[0];
x2 = df->x[1];
z2 = df->z[1];
if (x1 > x2) {SWAP(x1,x2);}
if (z1 > z2) {SWAP(z1,z2);}
x1 -= 1;
x2 += 1;
z1 -= 1;
z2 += 1;
SATURATE(x1, 1, PAP_SIZE_HI - 2);
SATURATE(z1, 1, PAP_SIZE_HI - 2);
SATURATE(x2, 1, PAP_SIZE_HI - 2);
SATURATE(z2, 1, PAP_SIZE_HI - 2);
//
// Set the colour of the points depending on their distance
// from from the entrance of the warehouse.
//
for (mz = z1; mz <= z2; mz++)
{
if (!WITHIN(mz, NGAMUT_point_zmin, NGAMUT_point_zmax))
{
continue;
}
lx1 = x1;
lx2 = x2;
SATURATE(lx1, NGAMUT_point_gamut[mz].xmin, NGAMUT_point_gamut[mz].xmax);
SATURATE(lx2, NGAMUT_point_gamut[mz].xmin, NGAMUT_point_gamut[mz].xmax);
for (mx = lx1; mx <= lx2; mx++)
{
//
// Remember the upper point colour.
//
AENG_lower[mx][mz].colour = AENG_upper[mx][mz].colour;
//
// Darken this point if it is not adjacent to the exit.
//
for (dx = -1; dx <= 0; dx++);
for (dz = -1; dz <= 0; dz++);
{
sx = mx + dx;
sz = mz + dz;
if (!(PAP_2HI(sx,sz).Flags & PAP_FLAG_HIDDEN))
{
goto dont_darken;
}
}
//
// Completely fogged out...
//
AENG_upper[mx][mz].colour &= 0x00ffffff;
dont_darken:;
}
}
for (mz = z1; mz < z2; mz++)
{
if (!WITHIN(mz, NGAMUT_zmin, NGAMUT_zmax))
{
continue;
}
lx1 = x1;
lx2 = x2;
SATURATE(lx1, NGAMUT_gamut[mz].xmin, NGAMUT_gamut[mz].xmax);
SATURATE(lx2, NGAMUT_gamut[mz].xmin, NGAMUT_gamut[mz].xmax);
for (mx = lx1; mx < lx2; mx++)
{
ph = &PAP_2HI(mx,mz);
if (!(ph->Flags & PAP_FLAG_HIDDEN))
{
continue;
}
quad[0] = &AENG_upper[mx + 0][mz + 0];
quad[1] = &AENG_upper[mx + 1][mz + 0];
quad[2] = &AENG_upper[mx + 0][mz + 1];
quad[3] = &AENG_upper[mx + 1][mz + 1];
if (POLY_valid_quad(quad))
{
TEXTURE_get_minitexturebits_uvs(
ph->Texture,
&page,
&quad[0]->u,
&quad[0]->v,
&quad[1]->u,
&quad[1]->v,
&quad[2]->u,
&quad[2]->v,
&quad[3]->u,
&quad[3]->v);
POLY_add_quad(quad, page, TRUE);
}
}
}
}
*/
// return current detail levels
//#pragma optimize( "a", off )
//#pragma optimize( "y", off )
// store new detail levels
#ifdef TARGET_DC
// Fewer things to set.
void AENG_set_detail_levels(//int stars,
int shadows,
int puddles,
int dirt,
int mist,
int rain,
int skyline,
int crinkles)
#else
void AENG_set_detail_levels(int stars,
int shadows,
int moon_reflection,
int people_reflection,
int puddles,
int dirt,
int mist,
int rain,
int skyline,
int filter,
int perspective,
int crinkles)
#endif
{
//ENV_set_value_number("detail_stars", stars, "Render");
ENV_set_value_number("detail_shadows", shadows, "Render");
//ENV_set_value_number("detail_moon_reflection", moon_reflection, "Render");
//ENV_set_value_number("detail_people_reflection", people_reflection, "Render");
ENV_set_value_number("detail_puddles", puddles, "Render");
ENV_set_value_number("detail_dirt", dirt, "Render");
ENV_set_value_number("detail_mist", mist, "Render");
ENV_set_value_number("detail_rain", rain, "Render");
ENV_set_value_number("detail_skyline", skyline, "Render");
//ENV_set_value_number("detail_filter", filter, "Render");
//ENV_set_value_number("detail_perspective", perspective, "Render");
ENV_set_value_number("detail_crinkles", crinkles, "Render");
// heh heh heh
AENG_read_detail_levels();
}
#ifndef TARGET_DC
// draw some polys
float AENG_draw_some_polys(bool large, bool blend)
{
PolyPoint2D *vert,*vp;
WORD *ind,*ip;
vert = new PolyPoint2D[large ? 300 : 30000];
vp = vert;
ind = new WORD[large ? 300 : 30000];
ip = ind;
float u = 0;
float v = 0;
if (large)
{
for (int ii = 0; ii < 100; ii++)
{
vp->SetSC(0,0);
vp->SetColour(0x80FFFFFF);
vp->SetSpecular(0);
vp->SetUV(u,v);
vp++;
vp->SetSC(640,0);
vp->SetColour(0x80FFFFFF);
vp->SetSpecular(0);
vp->SetUV(u,v);
vp++;
vp->SetSC(0,480);
vp->SetColour(0x80FFFFFF);
vp->SetSpecular(0);
vp->SetUV(u,v);
vp++;
*ip++ = ii*3;
*ip++ = ii*3+1;
*ip++ = ii*3+2;
}
}
else
{
for (int ii = 0; ii < 10000; ii++)
{
int x = ii % 20;
int y = (ii / 20) % 15;
vp->SetSC(x*32,y*32);
vp->SetColour(0x80FFFFFF);
vp->SetSpecular(0);
vp->SetUV(u,v);
vp++;
vp->SetSC(x*32+32,y*32);
vp->SetColour(0x80FFFFFF);
vp->SetSpecular(0);
vp->SetUV(u,v);
vp++;
vp->SetSC(x*32,y*32+32);
vp->SetColour(0x80FFFFFF);
vp->SetSpecular(0);
vp->SetUV(u,v);
vp++;
*ip++ = ii*3;
*ip++ = ii*3+1;
*ip++ = ii*3+2;
}
}
StartStopwatch();
BEGIN_SCENE;
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE, FALSE);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
if (blend)
{
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
}
else
{
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
}
if (large)
{
HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, (D3DTLVERTEX*)vert, 300, ind, 300, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT);
//HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, vert->GetTLVert(), 300, ind, 300, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT);
ASSERT(!FAILED(res));
}
else
{
HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, (D3DTLVERTEX*)vert, 30000, ind, 30000, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT);
//HRESULT res = DRAW_INDEXED_PRIMITIVE(D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, vert->GetTLVert(), 30000, ind, 30000, D3DDP_DONOTUPDATEEXTENTS | D3DDP_DONOTLIGHT);
ASSERT(!FAILED(res));
}
END_SCENE;
the_display.screen_lock();
the_display.screen_unlock();
float time = StopStopwatch();
delete[] vert;
delete[] ind;
return time;
}
// guess detail levels
//
// this is only done if AENG_estimate_detail_levels is true
void AENG_guess_detail_levels()
{
if (!AENG_estimate_detail_levels) return; // don't estimate them
ENV_set_value_number("estimate_detail_levels", 0, "Render");
AENG_estimate_detail_levels = 0;
int generation;
// 0 = software or 1-2 for hardware
D3DDeviceInfo* dev = the_display.GetDeviceInfo();
if (!dev->IsHardware())
{
generation = 0;
}
else
{
// software (P450) 3500/s
// Permedia2 60000/s
float tso = 10000 / AENG_draw_some_polys(false, false);
TRACE("card draws 512-pixel opaque polys at %f per second\n", tso);
if (tso < 10000)
{
generation = 0;
}
else if (tso < 40000)
{
generation = 1;
}
else
{
generation = 2;
if (dev->ModulateAlphaSupported() && dev->DestInvSourceColourSupported())
{
generation = 3;
}
}
}
TRACE("Card generation = %d\n", generation);
// GENVAR(n) = in all generations >= n
#define GENVAR(G) ((generation >= G) ? 1 : 0)
int stars = GENVAR(0);
int shadows = GENVAR(2);
int moon_reflection = GENVAR(2);
int people_reflection = GENVAR(3);
int puddles = GENVAR(2);
int dirt = GENVAR(1);
int mist = GENVAR(2);
int rain = GENVAR(0);
int skyline = GENVAR(2);
int filter = GENVAR(1);
int perspective = GENVAR(1);
int crinkles = GENVAR(3);
AENG_set_detail_levels(stars, shadows, moon_reflection, people_reflection, puddles, dirt, mist, rain, skyline, filter, perspective, crinkles);
}
#endif
#ifdef TARGET_DC
// Fewer things to set.
void AENG_get_detail_levels(//int* stars,
int* shadows,
int* puddles,
int* dirt,
int* mist,
int* rain,
int* skyline,
int* crinkles)
#else
void AENG_get_detail_levels(int* stars,
int* shadows,
int* moon_reflection,
int* people_reflection,
int* puddles,
int* dirt,
int* mist,
int* rain,
int* skyline,
int* filter,
int* perspective,
int* crinkles)
#endif
{
//*stars = AENG_detail_stars;
*shadows = AENG_detail_shadows;
//*moon_reflection = AENG_detail_moon_reflection;
//*people_reflection = AENG_detail_people_reflection;
*puddles = AENG_detail_puddles;
*dirt = AENG_detail_dirt;
*mist = AENG_detail_mist;
*rain = AENG_detail_rain;
*skyline = AENG_detail_skyline;
//*filter = AENG_detail_filter;
//*perspective = AENG_detail_perspective;
*crinkles = AENG_detail_crinkles;
}
//#pragma optimize( "y", on )
//#pragma optimize( "a", on )
#define MAX_WIDTH_DRAWN 100
#define MAX_FLOOR_TILES_FOR_STRIPS (16) // I doubt we will get more than 32 very often (map is 128 wide)
#define MAX_VERTS_FOR_STRIPS (MAX_FLOOR_TILES_FOR_STRIPS*4) // 4 verts per map square
#define MAX_INDICES_FOR_STRIPS (MAX_FLOOR_TILES_FOR_STRIPS*5) // 5 indicies per map square
#ifdef STRIP_STATS
ULONG strip_stats[MAX_FLOOR_TILES_FOR_STRIPS+10];
#endif
#ifdef MIKES_UNUSED_AUTOMATIC_FLOOR_TEXTURE_GROUPER
//
// draws the floor quicker by grouping adjacent squares with the same texture into one index prim
//
UWORD in_group[64*10];
UWORD groups[256][9];
UWORD group_count[256];
SLONG group_stats[256][9]; //how often each member of the group is used
SLONG group_break[256][64*10]; // for each group how often the strip is broken by each texture
SLONG group_hits[256][64*10]; // for each group how often the strip is broken by each texture
UWORD page_next[64*10][64*10];
ULONG group_upto=1;
#define MAX_PREV 8
float how_good(void)
{
SLONG x,z;
SLONG page,my_group=0,prev_group[10];
SLONG bucket_group[10],bucket_length[10],bucket=0;
SLONG length=1;
SLONG total_length=0,strip_count=0;
float average_len,prev_average_len=0.0f;
SLONG count;
SLONG quit=0;
SLONG c0;
UWORD strips[128];
SLONG match;
memset(strips,0,128*2);
PAP_Hi *ph;
group_upto=1;
memset(prev_group,0,4*10);
memset(bucket_group,0,4*10);
memset(bucket_length,0,4*10);
// prev_group[0]=0;
total_length=0;
strip_count=0;
for(z=0;z<128;z++)
{
for(x=0;x<128;x++)
{
ph = &PAP_2HI(x,z);
ASSERT(bucket_group[0]<128*128);
ASSERT(bucket_length[0]<128*128);
// if(x==22 && z==16)
// ASSERT(0);
my_group=0;
page=ph->Texture&0x3ff;
if(in_group[page])
{
my_group=in_group[page];
}
else
{
ASSERT(0);
}
match=0;
for(c0=0;c0<MAX_PREV;c0++)
{
if(my_group==bucket_group[c0])
{
match=c0+1;
}
}
if(match)
{
if(bucket_length[match-1]>32)
{
match=0;
}
}
if(match)//y_group==prev_group)
{
//
// the same group hoorah
//
bucket_length[match-1]++;
ASSERT(bucket_length[bucket]<128);
//length++;
}
else
{
//
// different group
//
// store length stat
bucket++;
bucket%=MAX_PREV;
total_length+=bucket_length[bucket];
ASSERT(bucket_length[bucket]<128);
strip_count++;
strips[bucket_length[bucket]]++;
bucket_length[bucket]=1;
bucket_group[bucket]=my_group;
}
ASSERT(my_group);
for(c0=MAX_PREV;c0>0;c0--)
{
prev_group[c0]=prev_group[c0-1];
}
prev_group[0]=my_group;
}
}
DebugText(" FLOOR STRIP \n");
for(c0=0;c0<128;c0++)
{
DebugText(" %d %d \n",c0,strips[c0]);
}
ASSERT(strip_count>0);
average_len=(float)total_length/(float)strip_count;
DebugText(" FLOOR STRIP average %f\n",average_len);
return(average_len);
}
UWORD frequency[64*10];
float init_groups2(void)
{
SLONG x,z;
SLONG page,p1,p2;
SLONG highest,best;
SLONG g_count=0,g_index=0;
SLONG c1,c2;
SLONG c0;
PAP_Hi *ph;
/*
for(c0=0;c0<64*10;c0++)
{
in_group[c0]=c0+1;
}
how_good();
*/
memset(page_next,0,64*10*64*10*2);
memset(frequency,0,64*10*2);
memset(in_group,0,64*10*2);
memset(groups,0,256*9*2);
// for(page=0;page<8*64;page++)
for(z=0;z<128;z++)
{
for(x=0;x<128;x++)
{
ph = &PAP_2HI(x,z);
p1=ph->Texture&0x3ff;
if(x)
{
ph = &PAP_2HI(x-1,z); //to the left
p2=ph->Texture&0x3ff;
if(p1!=p2)
page_next[p1][p2]++;
}
if(x<127)
{
ph = &PAP_2HI(x+1,z); //to the right
p2=ph->Texture&0x3ff;
if(p1!=p2)
page_next[p1][p2]++;
}
frequency[p1]++;
}
}
//
// for every texture we now know how many times every other texture appears next to it
//
/*
highest=0;
for(c0=0;c0<64*10;c0++)
{
if(frequency[c0]>highest)
{
highest=frequency[c0];
best=c0;
}
}
*/
while(1)
{
g_count=0;
highest=0;
best=-1;
for(c0=0;c0<64*10;c0++)
{
if(!in_group[c0])
for(c1=0;c1<64*10;c1++)
{
if(c0!=c1)
if(page_next[c0][c1]>highest)
{
highest=page_next[c0][c1];
best=c0;
}
}
}
if(best==-1)
break;
//
// for the most frequently used texture, group with it the textures that often appear next to it
//
g_index++;
groups[g_index][g_count]=best;
in_group[best]=g_index;
for(c0=0;c0<64*10;c0++)
{
page_next[c0][best]=0; //remove me from next to other textures
// page_next[best][c0]=0; //remove me from next to other textures
}
// frequency[best]=0;
g_count++;
{
SLONG group_perc[9];
SLONG ndhighest=0;
SLONG perc;
SLONG current_best_perc=0;
SLONG c2;
page=best;
page=-1;
while(g_count<9)
{
SLONG n_of;
//
// for all members of the group find the highest probabilty neihbour
//
ndhighest=0;
best=-1;
for(c1=0;c1<g_count;c1++)
{
n_of=groups[g_index][c1];
for(c0=0;c0<64*10;c0++)
{
if(frequency[c0])
{
perc=0;
for(c2=0;c2<g_count;c2++)
perc+=(page_next[groups[g_index][c2]][c0]);// /frequency[c0];
if(perc>ndhighest)
{
SLONG abort_store=0;
//
//check if better paired up elsewhere
//
for(c2=0;c2<64*10;c2++)
{
if(page_next[c0][c2]>perc)
abort_store=1;
}
if(!abort_store)
{
ndhighest=perc;
best=c0;
}
}
}
}
}
if(best>=0)
{
groups[g_index][g_count]=best;
g_count++;
in_group[best]=g_index;
// frequency[best]=0;
for(c0=0;c0<64*10;c0++)
{
page_next[c0][best]=0; //remove me from next to other textures
// page_next[best][c0]=0; //remove me from next to other textures
}
}
else
{
//
// no more for this group so exit the while loop
//
break;
}
}
group_count[g_index]=g_count;
}
}
for(c0=0;c0<64*10;c0++)
{
if(!in_group[c0] && frequency[c0])
{
//
// not in a group but exists on map
//
groups[g_index][g_count]=c0;
in_group[c0]=g_index;
g_count++;
if(g_count>=9)
{
g_count=0;
g_index++;
}
}
}
//
// compress groups
//
for(c0=1;c0<g_index;c0++)
{
if(group_count[c0]<9)
{
for(c1=c0+1;c1<g_index;c1++)
{
if(group_count[c1])
if(group_count[c0]+group_count[c1]<=9)
{
//
// group c1 can fit into group c0
//
for(c2=0;c2<group_count[c1];c2++)
{
SLONG group,index;
groups[c0][group_count[c0]+c2]=groups[c1][c2];
in_group[groups[c1][c2]]=c0;
}
group_count[c0]=group_count[c0]+group_count[c1];
group_count[c1]=0;
c0--;
break;
}
}
}
}
//
// move g_index back
//
for(;g_index>0;g_index--)
{
if(group_count[g_index-1])
break;
}
float ret;
ret=how_good();
DebugText(" FLOOR STRIP pages %d\n",g_index);
DebugText(" try random \n",g_index);
return(ret);
}
#endif
#define IPRIM_COUNT 5
//
// 16k cache // 512x32byte // 1 way associative
//
//
// data bus 64 bit //100mhz
//
#define MAX_DRAW_WIDTH 128
struct FloorStore
{
ULONG Colour;
// ULONG Specular; // is this needed?
float Alt;
UWORD Flags; //not really needed
UWORD Texture; //not really needed
// SLONG x,z;
};
//40*12 =480 bytes per row, need 2 rows
inline void cache_a_row(SLONG x,SLONG z,struct FloorStore *p2,SLONG endx)
{
SLONG px,pz,dx,dz;
SLONG square;
SLONG mapz;
NIGHT_Square *nq;
PAP_Hi *ph;
ULONG spec;
SLONG y;
//
// pre fetch the data, to avoid reading it 4 times
//
// TRACE(" cache row %d -> %d \n",x,endx);
for (ph = &PAP_2HI(x,z); x <= endx; x++, ph += PAP_SIZE_HI)
{
float dist;
// p2->Alt=ph->Alt; //15 ticks later the cache will have loaded
y = ph->Alt << ALT_SHIFT;
p2->Alt=float(y);
px = x >> 2;
pz = z >> 2;
dx = x & 0x3;
dz = z & 0x3;
square = NIGHT_cache[px][pz];
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
nq = &NIGHT_square[square];
/*
{
SLONG cdx,cdz;
cdx=abs(AENG_cam_x-(x<<8));
cdz=abs(AENG_cam_z-(z<<8));
mapz = QDIST2(cdx,cdz);
dist=((float)mapz)/(float)(AENG_DRAW_DIST<<8);
if(dist>1.0f)
dist=1.0f;
}
NIGHT_get_d3d_colour_and_fade(
nq->colour[dx + dz * PAP_BLOCKS],
&p2->Colour,
&spec,dist);
*/
{
NIGHT_Colour *col = &nq->colour[dx + dz * PAP_BLOCKS];
SLONG r = col->red << 2;
SLONG g = col->green << 2;
SLONG b = col->blue << 2;
if (r > 255) {r = 255;}
if (g > 255) {g = 255;}
if (b > 255) {b = 255;}
p2->Colour = (r << 16) | (g << 8) | b;
}
p2->Flags=ph->Flags;
p2->Texture=ph->Texture;
/*
dx = abs(quick_floor_cam_x - (x << 8));
dy = abs(quick_floor_cam_y - y );
dz = abs(quick_floor_cam_z - (z << 8));
if (dx + dy + dz <= 256)
{
//
// Too close to camera- set the alpha of the colour.
//
p2->Colour |= 0x01000000;
}
*/
// p2->x=x;
// p2->z=z;
//POLY_fadeout_point(pp);
// ph++;
p2++;
}
}
float kerb_scaleu;
float kerb_scalev;
float kerb_du;
float kerb_dv;
inline SLONG add_kerb(float alt1,float alt2,SLONG x,SLONG z,SLONG dx,SLONG dz,D3DLVERTEX *pv, UWORD *p_indicies,SLONG count,ULONG c1,ULONG c2,SLONG flip)
{
// pv=&p_verts[current_set][vert_count[current_set]];
// p_indicies=&indicies[current_set][index_count[current_set]];
// 0 1 0 1 1
//
// 3 2 3 3 2
pv->x = x * 256.0F;
pv->z = z * 256.0F;
pv->y = alt1-KERB_HEIGHT;
pv->tu=0.0f;
pv->tv=1.0f;
#ifdef TEX_EMBED
pv->tu=pv->tu*kerb_scaleu+kerb_du;
pv->tv=pv->tv*kerb_scalev+kerb_dv;
#endif
// set verts colour
pv->color=c1;//0xff808080;//202020;
pv->specular=0xff000000;
SET_MM_INDEX(*pv,0);
pv++;
pv->x = (x+dx) * 256.0F;
pv->z = (z+dz) * 256.0F;
pv->y = alt2-KERB_HEIGHT;
pv->tu=1.0f;
pv->tv=1.0f;
#ifdef TEX_EMBED
pv->tu=pv->tu*kerb_scaleu+kerb_du;
pv->tv=pv->tv*kerb_scalev+kerb_dv;
#endif
// set verts colour
pv->color=c2;//0xff808080;//202020;
pv->specular=0xff000000;
SET_MM_INDEX(*pv,0);
pv++;
pv->x = (x+dx) * 256.0F;
pv->z = (z+dz) * 256.0F;
pv->y = alt2;
pv->tu=1.0f;
pv->tv=0.0f;
#ifdef TEX_EMBED
pv->tu=pv->tu*kerb_scaleu+kerb_du;
pv->tv=pv->tv*kerb_scalev+kerb_dv;
#endif
// set verts colour
pv->color=c2;//0xff808080;//202020;
pv->specular=0xff000000;
SET_MM_INDEX(*pv,0);
pv++;
pv->x = (x) * 256.0F;
pv->z = (z) * 256.0F;
pv->y = alt1;
pv->tu=0.0f;
pv->tv=0.0f;
#ifdef TEX_EMBED
pv->tu=pv->tu*kerb_scaleu+kerb_du;
pv->tv=pv->tv*kerb_scalev+kerb_dv;
#endif
// set verts colour
pv->color=c1;//0xff808080;//202020;
pv->specular=0xff000000;
SET_MM_INDEX(*pv,0);
pv++;
pv-=4;
//
// Shall we z-reject
//
{
SLONG i;
float dx;
float dy;
float dz;
float dprod;
dx = pv[0].x - AENG_cam_x;
dy = pv[0].y - AENG_cam_y;
dz = pv[0].z - AENG_cam_z;
float dist;
float adx;
float ady;
float adz;
adx = fabsf(dx);
ady = fabsf(dy);
adz = fabsf(dz);
dist = adx + ady + adz;
if (dist > 768.0F)
{
//
// No need to zclip!
//
}
else
{
for (i = 0; i < 4; i++)
{
dx = pv[i].x - AENG_cam_x;
dy = pv[i].y - AENG_cam_y;
dz = pv[i].z - AENG_cam_z;
dprod = dx*AENG_cam_matrix[6] + dy*AENG_cam_matrix[7] + dz*AENG_cam_matrix[8];
if (dprod < 8.0F)
{
//
// Too close the camera!
//
return FALSE;
}
}
}
}
//
// make the indicies as we go along
//
if (flip)
{
*p_indicies++=count+0;
*p_indicies++=count+3;
*p_indicies++=count+1;
*p_indicies++=count+2;
*p_indicies++=0xffff;
}
else
{
// SLONG count=vert_count[current_set];
*p_indicies++=count;
*p_indicies++=count+1;
*p_indicies++=count+3;
*p_indicies++=count+2;
*p_indicies++=0xffff;
}
return TRUE;
}
inline void draw_i_prim ( LPDIRECT3DTEXTURE2 page, D3DLVERTEX *verts, UWORD *indicies, SLONG *vert_count, SLONG *index_count, D3DMULTIMATRIX *mm_draw_floor )
{
HRESULT res;
#ifdef STRIP_STATS
strip_stats[(*vert_count>>2)+1]++;
strip_stats[0]++;
strip_stats[1]+=(*vert_count>>2);
#endif
mm_draw_floor->lpvVertices =verts;
indicies[*index_count]=0x1234;
REALLY_SET_TEXTURE(page);
//TRACE ( "S1" );
res=DrawIndPrimMM (the_display.lp_D3D_Device,D3DFVF_LVERTEX ,mm_draw_floor,*vert_count,indicies,*index_count);
//TRACE ( "F1" );
ASSERT(res == DD_OK); //761 //0x887602f9
*index_count = 0;
*vert_count = 0;
}
#define HALF_COL(col) (col)=((col)>>2)&0xff3f3f3f
#define KERB_TILES 16
#define KERB_VERTS (4*KERB_TILES)
#define KERB_INDICIES (5*KERB_TILES)
// Well, it's now become the final code...
#define TOMS_TEST_FIXUP_CODE yes
#ifdef DEBUG
int m_iDrawThingCount = 0;
#endif
// Look Mike, when I say "don't put stuff on the stack", I mean
// DONT PUT STUFF ON THE STACK. And it's "indices" - only two "i"s.
UBYTE m_vert_mem_block32[sizeof(D3DLVERTEX)*KERB_VERTS+sizeof(D3DLVERTEX)*MAX_VERTS_FOR_STRIPS*IPRIM_COUNT+32]; // used to 32 byte align the vertex memory
UWORD m_indicies[IPRIM_COUNT][MAX_INDICES_FOR_STRIPS+1]; //data for verts, on stack or not?
struct GroupInfo
{
LPDIRECT3DTEXTURE2 page; //ptr to actual page to use for drawing
#ifndef TOMS_TEST_FIXUP_CODE
float uscale;
float vscale;
float du,dv;
#endif
#ifdef DEBUG
int iDebugCount;
#endif
};
#define MAX_STEAM 20
inline void general_steam(SLONG x,SLONG z,UWORD texture,SLONG mode)
{
static SLONG stx[MAX_STEAM],sty[MAX_STEAM],stz[MAX_STEAM],lod[MAX_STEAM];
static SLONG count_steam=0;
if(mode==0)
{
count_steam=0;
return;
}
else
if(mode==2)
{
for(SLONG c0=0;c0<count_steam;c0++)
{
extern void draw_steam(SLONG x,SLONG y,SLONG z,SLONG lod);
draw_steam(stx[c0],sty[c0],stz[c0],lod[c0]);//10+(15-dist)*3);
}
count_steam=0;
return;
}
if(count_steam>=MAX_STEAM)
return;
#ifdef TARGET_DC
// Key off the "mist" detail setting instead
if (AENG_detail_mist)
#else
if (AENG_detail_shadows)
#endif
// if(page==4*64+53) function only called if page is correct
{
SLONG dx,dz,dist,sx,sy,sz;
dx=abs( (((SLONG)AENG_cam_x)>>8)-(x) );
dz=abs( (((SLONG)AENG_cam_z)>>8)-(z) );
dist=QDIST2(dx,dz);
if(dist<15)
{
SLONG sx,sy,sz;
switch((texture >> 0xa) & 0x3)
{
case 0:
sx=190;
sz=128;
break;
case 1:
sx=128;
sz=66;
break;
case 2:
sx=66;
sz=128;
break;
case 3:
sx=128;
sz=190;
break;
default:
ASSERT(0);
break;
}
sx+=x<<8;
sz+=z<<8;
sy=PAP_calc_height_at(sx,sz);
stx[count_steam]=sx;
sty[count_steam]=sy;
stz[count_steam]=sz;
lod[count_steam]=10+(15-dist)*3;
count_steam++;
// draw_steam(sx,sy,sz,10+(15-dist)*3);
}
}
}
void draw_quick_floor(SLONG warehouse)
{
PAP_Hi *ph;
// ULONG colour,specular;
SLONG c0;
SLONG x,z;
float dy,y;
UWORD index;
SLONG page,page2,prev_page=-10000,apage=0;
SLONG current_set=0;
struct GroupInfo group[IPRIM_COUNT];
PolyPage *pp;
LPDIRECT3DTEXTURE2 tex_handle;
UWORD kerb_indicies[KERB_INDICIES];
UWORD *p_indicies;
D3DMATRIX *m_view;
D3DLVERTEX *p_verts[IPRIM_COUNT],*pv,*kerb_verts;
UBYTE some_data[sizeof(D3DMATRIX)+32]; // used to 32 byte align the funny fanny thing
UBYTE *ptr32;
SLONG index_count[IPRIM_COUNT],vert_count[IPRIM_COUNT],age[IPRIM_COUNT],kerb_counti=0,kerb_countv=0;
SLONG bin_set;
D3DMULTIMATRIX mm_draw_floor;
static init_stats=1;
static SLONG biggest=0;
struct FloorStore row[MAX_DRAW_WIDTH*2+2];
struct FloorStore *p1,*p2;
SLONG startx,endx,offsetx;
SLONG no_floor=0;
SLONG is_shadow;
#ifdef TEX_EMBED
pp=&POLY_Page[0];
kerb_du =pp->m_UOffset;
kerb_dv =pp->m_VOffset;
kerb_scaleu =pp->m_UScale;
kerb_scalev =pp->m_VScale;
#endif
if (GAME_FLAGS & GF_NO_FLOOR)
no_floor=1;
general_steam(0,0,0,0); //init it
#ifdef STRIP_STATS
memset(strip_stats,0,4*MAX_FLOOR_TILES_FOR_STRIPS+4*10);
#endif
memset(group,0,sizeof(struct GroupInfo)*IPRIM_COUNT);
#ifdef DEBUG
for ( int i = 0; i < IPRIM_COUNT; i++ )
{
group[i].iDebugCount = ( i << 5 ) + 2;
}
#endif
if(init_stats)
{
init_stats=0;
}
ptr32=(UBYTE *)(((ULONG)(some_data+32))&0xffffffe0);
m_view=(D3DMATRIX *)ptr32;
mm_draw_floor.lpd3dMatrices =m_view;
mm_draw_floor.lpvLightDirs =NULL;
mm_draw_floor.lpLightTable =NULL;
ptr32=(UBYTE *)(((ULONG)(m_vert_mem_block32+32))&0xffffffe0);
kerb_verts=(D3DLVERTEX *)ptr32;
ptr32+=sizeof(D3DLVERTEX)*KERB_VERTS;
for(c0=0;c0<IPRIM_COUNT;c0++)
{
p_verts[c0]=(D3DLVERTEX *)ptr32;
ptr32+=sizeof(D3DLVERTEX)*MAX_VERTS_FOR_STRIPS;
index_count[c0]=0;
vert_count[c0]=0;
age[c0]=0x7fff;
}
BEGIN_SCENE;
//
// setup render states for the floor, who knows how many we can assume are ok?
//
/*
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATE);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZENABLE,TRUE);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZWRITEENABLE,TRUE);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ZBIAS,0);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_FOGENABLE,FALSE);
REALLY_SET_RENDER_STATE(D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_CLAMP);
*/
RenderState default_renderstate;
default_renderstate.SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
default_renderstate.SetChanged();
//REALLY_SET_RENDER_STATE(D3DRENDERSTATE_CULLMODE,D3DCULL_CCW);
// GenerateMMMatrixFromStandardD3DOnes (m_view,g_matProjection,g_matWorld,g_viewData);
GenerateMMMatrixFromStandardD3DOnes (m_view,&g_matProjection,NULL,&g_viewData);
// colour = 0x00888888;
// specular = 0xff000000;
z=NGAMUT_zmin;
startx = NGAMUT_point_gamut[z].xmin;
endx = NGAMUT_point_gamut[z].xmax;
extern SLONG NGAMUT_xmin;
offsetx=startx-(NGAMUT_xmin);
ASSERT(offsetx<MAX_DRAW_WIDTH);
ASSERT(offsetx+endx-startx<MAX_DRAW_WIDTH);
if(z&1)
{
p1=&row[0+offsetx];
}
else
{
p1=&row[MAX_DRAW_WIDTH+offsetx];
}
cache_a_row(startx,z,p1,endx);
if(!INDOORS_INDEX)
for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++)
{
startx = NGAMUT_point_gamut[z+1].xmin;
endx = NGAMUT_point_gamut[z+1].xmax;
offsetx=startx-(NGAMUT_xmin);
ASSERT(offsetx<MAX_DRAW_WIDTH);
ASSERT(offsetx+endx-startx<MAX_DRAW_WIDTH);
if(z&1)
{
p2=&row[MAX_DRAW_WIDTH+offsetx];
memset(&row[MAX_DRAW_WIDTH],0,MAX_DRAW_WIDTH*sizeof(struct FloorStore));
}
else
{
p2=&row[0+offsetx];
memset(&row[0],0,MAX_DRAW_WIDTH*sizeof(struct FloorStore));
}
cache_a_row(startx,z+1,p2,endx);
offsetx=NGAMUT_gamut[z].xmin-(NGAMUT_xmin);
ASSERT(offsetx<MAX_DRAW_WIDTH);
ASSERT(offsetx+endx-startx<MAX_DRAW_WIDTH);
if(z&1)
{
p1=&row[0+offsetx];
p2=&row[MAX_DRAW_WIDTH+offsetx];
}
else
{
p1=&row[MAX_DRAW_WIDTH+offsetx];
p2=&row[0+offsetx];
}
//
//
//
// if(NGAMUT_gamut[z].xmax-NGAMUT_gamut[z].xmin>biggest)
// biggest=NGAMUT_gamut[z].xmax-NGAMUT_gamut[z].xmin;
for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++,p1++,p2++)
{
// ASSERT(p1->x==x);
// ASSERT(p1->z==z);
// ASSERT(p2->x==x);
// ASSERT(p2->z==z+1);
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
ASSERT(p1>=&row[0]);
ASSERT(p2>=&row[0]);
ASSERT(p1<&row[MAX_DRAW_WIDTH*2+2]);
ASSERT(p2<&row[MAX_DRAW_WIDTH*2+2]);
ph = &PAP_2HI(x,z);
// ASSERT(ph->Texture==p1->Texture);
if(warehouse)
{
if (!(p1->Flags & PAP_FLAG_HIDDEN))
{
continue;
}
}
else
{
SLONG s1,s2;
s1=p1->Flags & PAP_FLAG_SINK_SQUARE;
s2=(p1+1)->Flags & PAP_FLAG_SINK_SQUARE;
if(s1!=s2)
{
//
// change of sink status along x
//
if(kerb_countv>=KERB_VERTS-4)
{
draw_i_prim(POLY_Page[0].RS.GetTexture(),kerb_verts,kerb_indicies,&kerb_countv,&kerb_counti,&mm_draw_floor);
}
if (add_kerb((p1+1)->Alt,(p2+1)->Alt,x+1,z,0,1,&kerb_verts[kerb_countv],&kerb_indicies[kerb_counti],kerb_countv,(p1+1)->Colour,(p2+1)->Colour,s1))
{
kerb_countv+=4;
kerb_counti+=5;
}
}
s1=p1->Flags & PAP_FLAG_SINK_SQUARE;
s2=(p2)->Flags & PAP_FLAG_SINK_SQUARE;
if(s1!=s2)
{
//
// change of sink status along z
//
if(kerb_countv>=KERB_VERTS-4)
{
draw_i_prim(POLY_Page[0].RS.GetTexture(),kerb_verts,kerb_indicies,&kerb_countv,&kerb_counti,&mm_draw_floor);
}
if (add_kerb((p2)->Alt,(p2+1)->Alt,x,z+1,1,0,&kerb_verts[kerb_countv],&kerb_indicies[kerb_counti],kerb_countv,(p2)->Colour,(p2+1)->Colour,s2))
{
kerb_countv+=4;
kerb_counti+=5;
}
}
//
// Mark this needs to be in the else! MikeD
//
if ((p1->Flags & (PAP_FLAG_HIDDEN|PAP_FLAG_ROOF_EXISTS))== PAP_FLAG_HIDDEN)
{
continue;
}
}
if (warehouse==0 && (p1->Flags & (PAP_FLAG_ROOF_EXISTS)) )
{
y=MAVHEIGHT(x,z)<<6;
if(y>AENG_cam_y)
continue;
}
else
{
if (no_floor)
{
//
// Don't draw the floor if there isn't any! (like the final level)
//
continue;
}
//
// not a roof so might have a kerb
//
}
if(warehouse)
is_shadow=0;
else
is_shadow=p1->Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3);
page=p1->Texture&0x3ff;
if(page==4*64+53)
general_steam(x,z,p1->Texture,1); //store it
pp=&POLY_Page[page];
tex_handle=pp->RS.GetTexture();
current_set=-1;
//
// age the iprims
//
for(c0=0;c0<IPRIM_COUNT;c0++)
age[c0]++;
for(c0=0;c0<IPRIM_COUNT;c0++)
{
if(group[c0].page==tex_handle)//&&0)
{
age[c0]=0;
current_set=c0;
break;
}
}
bin_set=-1;
if(current_set==-1)
{
SLONG oldest=-1;
//
// no group currently supports this new page, so find an empty one, or an old one to bin
//
for(c0=0;c0<IPRIM_COUNT;c0++)
{
if(vert_count[c0]==0)
{
bin_set=-1; //no need to bin an empty one
current_set=c0;
group[current_set].page=tex_handle;
#ifdef TEX_EMBED
#ifndef TOMS_TEST_FIXUP_CODE
group[current_set].du=pp->m_UOffset;
group[current_set].dv=pp->m_VOffset;
group[current_set].uscale=pp->m_UScale;
group[current_set].vscale=pp->m_VScale;
#endif
#endif
break;
}
if(age[c0]>oldest)
{
bin_set=c0;
current_set=c0;
oldest=age[c0];
}
}
}
else
{
SLONG cv=4,ci=5;
if(is_shadow)
{
cv=5; // shadow squares require more verts and indicies as quads are drawn as two seperate tri's
ci=8; //
}
//
// do we have to bin(draw) a prim because it is too full?
//
if(vert_count[current_set]>=MAX_VERTS_FOR_STRIPS-cv || index_count[current_set]>=MAX_INDICES_FOR_STRIPS-ci)
bin_set=current_set;
}
age[current_set]=0;
ASSERT(current_set>=0&& current_set<IPRIM_COUNT);
//
// Draw this prim because its buffer is full, or its buffer is required for new texture page
//
if(bin_set>=0)// || vert_count[current_set]>=MAX_VERTS_FOR_STRIPS-4)
{
if(vert_count[bin_set])
{
draw_i_prim(group[bin_set].page,p_verts[bin_set],&m_indicies[bin_set][0],&vert_count[bin_set],&index_count[bin_set],&mm_draw_floor);
#ifdef DEBUG
group[bin_set].iDebugCount++;
#endif
ASSERT(bin_set==current_set);
group[current_set].page=tex_handle;
#ifdef TEX_EMBED
#ifndef TOMS_TEST_FIXUP_CODE
group[current_set].du=pp->m_UOffset;
group[current_set].dv=pp->m_VOffset;
group[current_set].uscale=pp->m_UScale;
group[current_set].vscale=pp->m_VScale;
#endif
#endif
}
}
// group[current_set]=page;
// current_set=0;
//
// build the floor quad
//
pv=&p_verts[current_set][vert_count[current_set]];
p_indicies=&m_indicies[current_set][index_count[current_set]];
ASSERT(vert_count[current_set]<MAX_VERTS_FOR_STRIPS);
ASSERT(index_count[current_set]<MAX_INDICES_FOR_STRIPS);
if((p1->Flags & PAP_FLAG_SINK_SQUARE) && warehouse==0)
{
dy = -KERB_HEIGHT;
}
else
{
dy = 0.0f;
}
// 0 1 0 1 1
//
// 3 2 3 3 2
pv->x = x * 256.0F;
pv->z = z * 256.0F;
pv->color=p1->Colour;//0xff808080;//202020;
pv->specular=0xff000000;
SET_MM_INDEX(*pv,0);
pv++;
pv->x = (x+1) * 256.0F;
pv->z = z * 256.0F;
pv->color=(p1+1)->Colour;//202020;
pv->specular=0xff000000;
SET_MM_INDEX(*pv,0);
pv++;
pv->x = (x+1) * 256.0F;
pv->z = (z+1) * 256.0F;
pv->color=(p2+1)->Colour;//202020;
pv->specular=0xff000000;
SET_MM_INDEX(*pv,0);
pv++;
pv->x = x * 256.0F;
pv->z = (z+1) * 256.0F;
pv->color=p2->Colour;//202020;
pv->specular=0xff000000;
SET_MM_INDEX(*pv,0);
// pv++;
pv-=3;
TEXTURE_get_minitexturebits_uvs(
p1->Texture,
&page2,
&pv[0].tu,
&pv[0].tv,
&pv[1].tu,
&pv[1].tv,
&pv[3].tu,
&pv[3].tv,
&pv[2].tu,
&pv[2].tv);
#ifdef TEX_EMBED
#ifdef TOMS_TEST_FIXUP_CODE
pv[0].tu=pv[0].tu*pp->m_UScale+pp->m_UOffset;
pv[1].tu=pv[1].tu*pp->m_UScale+pp->m_UOffset;
pv[2].tu=pv[2].tu*pp->m_UScale+pp->m_UOffset;
pv[3].tu=pv[3].tu*pp->m_UScale+pp->m_UOffset;
pv[0].tv=pv[0].tv*pp->m_VScale+pp->m_VOffset;
pv[1].tv=pv[1].tv*pp->m_VScale+pp->m_VOffset;
pv[2].tv=pv[2].tv*pp->m_VScale+pp->m_VOffset;
pv[3].tv=pv[3].tv*pp->m_VScale+pp->m_VOffset;
#else
pv[0].tu=pv[0].tu*group[current_set].uscale+group[current_set].du;
pv[1].tu=pv[1].tu*group[current_set].uscale+group[current_set].du;
pv[2].tu=pv[2].tu*group[current_set].uscale+group[current_set].du;
pv[3].tu=pv[3].tu*group[current_set].uscale+group[current_set].du;
pv[0].tv=pv[0].tv*group[current_set].vscale+group[current_set].dv;
pv[1].tv=pv[1].tv*group[current_set].vscale+group[current_set].dv;
pv[2].tv=pv[2].tv*group[current_set].vscale+group[current_set].dv;
pv[3].tv=pv[3].tv*group[current_set].vscale+group[current_set].dv;
#endif
#endif
#ifdef DEBUG
#ifdef TARGET_DC
// Colour the vertices.
#define BUTTON_IS_PRESSED(value) ((value&0x80)!=0)
extern DIJOYSTATE the_state;
if ( BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_LTRIGGER] ) && BUTTON_IS_PRESSED ( the_state.rgbButtons[DI_DC_BUTTON_RTRIGGER] ) )
{
DWORD dwTemp = group[current_set].iDebugCount;
dwTemp = ( dwTemp ) + ( dwTemp << 8 ) + ( dwTemp << 17 ) + ( dwTemp << 26 );
dwTemp &= 0x7f7f7f7f;
pv[0].dcColor = dwTemp;
pv[1].dcColor = dwTemp;
pv[2].dcColor = dwTemp;
pv[3].dcColor = dwTemp;
pv[0].dcSpecular = dwTemp;
pv[1].dcSpecular = dwTemp;
pv[2].dcSpecular = dwTemp;
pv[3].dcSpecular = dwTemp;
}
#endif
#endif
if ((p1->Flags & (PAP_FLAG_ROOF_EXISTS)) && warehouse==0)
{
y=MAVHEIGHT(x,z)<<6;
pv[0].y = y;
pv[1].y = y;
pv[2].y = y;
pv[3].y = y;
}
else
{
pv[0].y = p1->Alt+dy;// * float(1 << ALT_SHIFT)+dy;
pv[1].y = (p1+1)->Alt+dy;// * float(1 << ALT_SHIFT)+dy;
pv[2].y = (p2+1)->Alt+dy;// * float(1 << ALT_SHIFT)+dy;
pv[3].y = (p2)->Alt+dy;// * float(1 << ALT_SHIFT)+dy;
}
{
SLONG i;
float dx;
float dy;
float dz;
float dprod;
dx = (pv[0].x + pv[2].x) * 0.5F - AENG_cam_x;
dy = (pv[0].y + pv[2].y) * 0.5F - AENG_cam_y;
dz = (pv[0].z + pv[2].z) * 0.5F - AENG_cam_z;
float dist;
float adx;
float ady;
float adz;
adx = fabsf(dx);
ady = fabsf(dy);
adz = fabsf(dz);
dist = 0;
dist += adx;
dist += ady;
dist += adz;
if (dist > 512.0F)
{
//
// No need to zclip!
//
}
else
{
ULONG zclip = 0;
float along[4];
for (i = 0; i < 4; i++)
{
dx = pv[i].x - AENG_cam_x;
dy = pv[i].y - AENG_cam_y;
dz = pv[i].z - AENG_cam_z;
dprod = dx*AENG_cam_matrix[6] + dy*AENG_cam_matrix[7] + dz*AENG_cam_matrix[8];
if (dprod < 8.0F)
{
//
// Too close the camera- zfuck!
//
along[i] = 8.0F - dprod;
zclip |= 1 << i;
}
}
if (zclip)
{
if (zclip == 0xf)
{
//
// Reject whole quad!
//
goto abandon_quad;
}
for (i = 0; i < 4; i++)
{
if (zclip & (1 << i))
{
pv[i].x += along[i] * AENG_cam_matrix[6];
pv[i].y += along[i] * AENG_cam_matrix[7];
pv[i].z += along[i] * AENG_cam_matrix[8];
}
}
}
}
}
pv += 4;
//
// shadows
//
if(is_shadow)
{
//
// for shadows we need to duplicate the diag verts
//
pv-=4;
pv[4]=pv[3];
// to be compatible with shadow.h we have to rotate quad by 180 Degrees
// 3 2 4
//
// 1 0 1
switch(is_shadow)//p1->Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3))
{
case 0:
ASSERT(0); // We shouldn't be doing any of this in this case.
break;
case 1:
HALF_COL(pv[0].color);
HALF_COL(pv[3].color);
break;
case 2:
case 6:
HALF_COL(pv[4].color);
HALF_COL(pv[3].color);
HALF_COL(pv[0].color);
//HALF_COL(pv[2].color);
break;
case 3:
HALF_COL(pv[4].color);
HALF_COL(pv[3].color);
break;
case 4:
HALF_COL(pv[2].color);
HALF_COL(pv[3].color);
HALF_COL(pv[4].color);
break;
case 5:
HALF_COL(pv[2].color);
HALF_COL(pv[0].color);
HALF_COL(pv[4].color);
HALF_COL(pv[3].color);
break;
case 7:
HALF_COL(pv[2].color);
HALF_COL(pv[4].color);
break;
default:
ASSERT(0);
break;
}
pv+=5;
//
// make the indicies as we go along, for 6 vert shadow split quad
//
SLONG count=vert_count[current_set];
*p_indicies++=count+3;
*p_indicies++=count+0;
*p_indicies++=count+1;
*p_indicies++=0xffff;
*p_indicies++=count+2;
*p_indicies++=count+4;
*p_indicies++=count+1;
*p_indicies++=0xffff;
vert_count[current_set]+=5;
index_count[current_set]+=8; //8 per quad because its two separte tri's
}
else
{
//
// make the indicies as we go along, for 4 vert normal quad
//
SLONG count=vert_count[current_set];
*p_indicies++=count+0;
*p_indicies++=count+1;
*p_indicies++=count+3;
*p_indicies++=count+2;
*p_indicies++=0xffff;
vert_count[current_set]+=4;
index_count[current_set]+=5; //5 per quad because terminates with -1
}
abandon_quad:;
}
}
//
// Draw any prims left with data in
//
for(c0=0;c0<IPRIM_COUNT;c0++)
{
if(vert_count[c0])
{
draw_i_prim(group[c0].page,p_verts[c0],&m_indicies[c0][0],&vert_count[c0],&index_count[c0],&mm_draw_floor);
#ifdef DEBUG
group[c0].iDebugCount++;
#endif
}
}
if(kerb_countv)
{
draw_i_prim(POLY_Page[0].RS.GetTexture(),kerb_verts,kerb_indicies,&kerb_countv,&kerb_counti,&mm_draw_floor);
}
general_steam(0,0,0,2); //draw it
// Deal with internals.
POLY_set_local_rotation_none();
general_steam(0,0,0,2); //draw it
END_SCENE;
}
#ifdef TARGET_DC
#ifdef DEBUG
int m_iDCFramerateMin = 15;
int m_iDCFramerateMax = 17;
#else
int m_iDCFramerateMin = 15;
int m_iDCFramerateMax = 18;
#endif
bool m_bTweakFramerates = FALSE;
void fiddle_draw_distance_DC(void)
{
//#ifdef DEBUG
#define BUTTON_IS_PRESSED(value) ((value&0x80)!=0)
extern DIJOYSTATE the_state;
if ( m_bTweakFramerates &&
( BUTTON_IS_PRESSED(the_state.rgbButtons[DI_DC_BUTTON_LTRIGGER] ) ) &&
( BUTTON_IS_PRESSED(the_state.rgbButtons[DI_DC_BUTTON_RTRIGGER] ) ) )
{
static iNotTooFastCounter = 0;
iNotTooFastCounter++;
if ( BUTTON_IS_PRESSED(the_state.rgbButtons[DI_DC_BUTTON_X] ) )
{
// Change DrawDistance
CurDrawDistance += ( the_state.lX - 128 );
TRACE ( "Draw dist: 0x%x\n", CurDrawDistance );
SATURATE(CurDrawDistance,(10<<8)+128,(22<<8)+128);
}
if ( BUTTON_IS_PRESSED(the_state.rgbButtons[DI_DC_BUTTON_A] ) )
{
// Change min frame rate
if ( ( iNotTooFastCounter & 0x3 ) == 0 )
{
if ( the_state.lX < 64 )
{
m_iDCFramerateMin--;
}
else if ( the_state.lX > 192 )
{
m_iDCFramerateMin++;
}
}
TRACE ( "Min framerate: %i\n", m_iDCFramerateMin );
}
if ( BUTTON_IS_PRESSED(the_state.rgbButtons[DI_DC_BUTTON_Y] ) )
{
// Change min frame rate
if ( ( iNotTooFastCounter & 0x3 ) == 0 )
{
if ( the_state.lX < 64 )
{
m_iDCFramerateMax--;
}
else if ( the_state.lX > 192 )
{
m_iDCFramerateMax++;
}
}
TRACE ( "Max framerate: %i\n", m_iDCFramerateMax );
}
if ( BUTTON_IS_PRESSED(the_state.rgbButtons[DI_DC_BUTTON_B] ) )
{
// Kill the auto throttle system.
m_iDCFramerateMin = -1;
m_iDCFramerateMax = 60;
}
}
else
//#endif
{
extern SLONG tick_tock_unclipped;
if(tick_tock_unclipped)
{
int iFramerate = 1000/tick_tock_unclipped;
// If in a cutscene, or in "first-person" mode, move the fog plane to the distance,
// because it looks nicer, and the framerate hit is not nearly as noticeable.
if ( FirstPersonMode || EWAY_stop_player_moving() )
{
CurDrawDistance += 64;
}
else if( iFramerate < m_iDCFramerateMin)
{
CurDrawDistance -= 64;
//remove_dead_people=1;
}
else if ( iFramerate > m_iDCFramerateMax )
{
CurDrawDistance += 64;
}
SATURATE(CurDrawDistance,(10<<8)+128,(22<<8)+128);
}
}
}
#endif
UBYTE index_lookup[]={0,1,3,2};
void AENG_draw_city()
{
//LOG_ENTER ( AENG_Draw_City )
//TRACE ( "AengIn" );
ANNOYINGSCRIBBLECHECK;
DumpTracies();
SLONG i;
SLONG x;
SLONG y;
SLONG z;
SLONG dx;
SLONG dy;
SLONG dz;
SLONG dist;
SLONG nx;
SLONG nz;
SLONG page;
SLONG shadow;
SLONG square;
float world_x;
float world_y;
float world_z;
POLY_Point *pp;
POLY_Point *ppl;
#ifndef TARGET_DC
MapElement *me;
#endif
PAP_Lo *pl;
PAP_Hi *ph;
THING_INDEX t_index;
Thing *p_thing;
POLY_Point *tri [3];
POLY_Point *quad[4];
NIGHT_Square *nq;
SLONG red;
SLONG green;
SLONG blue;
SLONG px;
SLONG pz;
SLONG sx;
SLONG sz;
SLONG px1;
SLONG pz1;
SLONG px2;
SLONG pz2;
SLONG mx;
SLONG mz;
SLONG worked_out_colour;
ULONG colour;
ULONG specular;
OB_Info *oi;
LIGHT_Colour pcol;
static outside=1;
static sea_offset=0;
AENG_total_polys_drawn = 0;
void draw_all_boxes(void);
draw_all_boxes();
extern SLONG tick_tock_unclipped;
sea_offset+=(tick_tock_unclipped);
#if 0
#ifdef TARGET_DC
// For some reason the PC version decides not to call this.
// I think they have some mad scheme of calling it in the previous
// frame, but it really screws things up. STOP IT!
POLY_frame_init(TRUE,TRUE);
#endif
#endif
LOG_ENTER ( AENG_Check_Visible );
//
// Work out which things are in view.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Flags & FLAGS_IN_BUILDING)
{
//
// Dont draw things inside buildings when we are outdoors.
//
}
else
{
switch(p_thing->Class)
{
case CLASS_PERSON:
//
// We only have a rejection test for people now.
//
if(p_thing->Genus.Person->PlayerID && !p_thing->Genus.Person->Ware)
p_thing->Flags |= FLAGS_IN_VIEW;
else
if (!p_thing->Genus.Person->Ware && FC_can_see_person(AENG_cur_fc_cam, p_thing))
{
if (POLY_sphere_visible(
float(p_thing->WorldPos.X >> 8),
float(p_thing->WorldPos.Y >> 8) + 0x80,
float(p_thing->WorldPos.Z >> 8),
256.0F / (AENG_DRAW_DIST * 256.0F)))
{
p_thing->Flags |= FLAGS_IN_VIEW;
}
}
break;
default:
p_thing->Flags |= FLAGS_IN_VIEW;
break;
}
}
t_index = p_thing->Child;
}
NIGHT_square[NIGHT_cache[x][z]].flag &= ~NIGHT_SQUARE_FLAG_DELETEME;
}
}
BreakTime("Worked out things in view");
LOG_EXIT ( AENG_Check_Visible );
LOG_ENTER ( AENG_Draw_Indoors_Floors );
ANNOYINGSCRIBBLECHECK;
//
// Points out of the ambient light.
//
shadow =
((NIGHT_amb_red >> 1) << 16) |
((NIGHT_amb_green >> 1) << 8) |
((NIGHT_amb_blue >> 1) << 0);
if(Keys[KB_L]&&ControlFlag)
{
outside^=1;
}
if(INDOORS_INDEX)
{
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
POLY_frame_init(TRUE,TRUE);
#endif
if(INDOORS_INDEX_NEXT)
AENG_draw_inside_floor(INDOORS_INDEX_NEXT,INDOORS_ROOM_NEXT,0);
// POLY_frame_draw(TRUE,TRUE);
if(INDOORS_INDEX)
AENG_draw_inside_floor(INDOORS_INDEX,INDOORS_ROOM,INDOORS_INDEX_FADE);
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
POLY_frame_init(TRUE,TRUE);
#endif
// return;
}
LOG_EXIT ( AENG_Draw_Indoors_Floors );
#ifdef NEW_FLOOR
draw_quick_floor(0);
#endif
//
// Rotate all the points. //draw_floor
//
LOG_ENTER ( AENG_Rotate_Points );
#ifndef NEW_FLOOR
colour = 0x00888888;
specular = 0xff000000;
#ifdef TARGET_DC
// DC internals fixup.
POLY_flush_local_rot();
#endif
if(!INDOORS_INDEX||outside)
for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++)
{
for (x = NGAMUT_point_gamut[z].xmin; x <= NGAMUT_point_gamut[z].xmax; x++)
{
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
extern UBYTE player_visited[16][128];
// player_visited[x>>3][z]|=1<<(x&7);
ph = &PAP_2HI(x,z);
//show_gamut_hi(x,z);
//
// The upper point.
//
world_x = x * 256.0F;
world_y = ph->Alt * float(1 << ALT_SHIFT);
world_z = z * 256.0F;
worked_out_colour = FALSE;
if (!(ph->Flags & PAP_FLAG_NOUPPER))
{
pp = &AENG_upper[x & 63][z & 63];
POLY_transform(world_x, world_y, world_z, pp);
if (pp->MaybeValid())
{
//
// Work out the colour of this point... what a palaver!
//
if(INDOORS_INDEX)
{
/*
NIGHT_get_d3d_colour_dim(
nq->colour[dx + dz * PAP_BLOCKS],
&pp->colour,
&pp->specular);
*/
#ifdef TARGET_DC
pp->colour=0xff808080;//202020;
pp->specular=0xff000000;
#else
pp->colour=0x80808080;//202020;
pp->specular=0x80000000;
#endif
}
else
{
px = x >> 2;
pz = z >> 2;
dx = x & 0x3;
dz = z & 0x3;
ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1));
square = NIGHT_cache[px][pz];
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
nq = &NIGHT_square[square];
NIGHT_get_d3d_colour(
nq->colour[dx + dz * PAP_BLOCKS],
&pp->colour,
&pp->specular);
}
#ifndef TARGET_DC
apply_cloud((SLONG)world_x,(SLONG)world_y,(SLONG)world_z,&pp->colour);
#endif
POLY_fadeout_point(pp);
colour = pp->colour;
specular = pp->specular;
worked_out_colour = TRUE;
}
}
//
// The lower point.
//
if (ph->Flags & PAP_FLAG_SINK_POINT|| (MAV_SPARE(x,z) & MAV_SPARE_FLAG_WATER))
{
if(ph->Flags & PAP_FLAG_SINK_POINT)
{
world_y -= KERB_HEIGHT;
}
else
{
world_y+=(COS(((x<<8)+(sea_offset>>1))&2047)+SIN(((z<<8)+(sea_offset>>1)+700)&2047))>>13;
}
ppl = &AENG_lower[x & 63][z & 63];
POLY_transform(world_x, world_y, world_z, ppl);
if (ppl->MaybeValid())
{
if (worked_out_colour)
{
//
// Use the colour of the upper point...
//
ppl->colour = colour;
ppl->specular = specular;
#ifdef TARGET_DC
ppl->colour |= 0xff000000;
ppl->specular |= 0xff000000;
#endif
}
else
{
//
// Work out the colour of this point... what a palaver!
//
if(INDOORS_INDEX)
{
/*
NIGHT_get_d3d_colour_dim(
nq->colour[dx + dz * PAP_BLOCKS],
&ppl->colour,
&ppl->specular);
*/
ppl->colour=0x202020;
ppl->specular=0xff000000;
#ifdef TARGET_DC
ppl->colour |= 0xff000000;
ppl->specular |= 0xff000000;
#endif
}
else
{
px = x >> 2;
pz = z >> 2;
dx = x & 0x3;
dz = z & 0x3;
ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1));
square = NIGHT_cache[px][pz];
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
nq = &NIGHT_square[square];
NIGHT_get_d3d_colour(
nq->colour[dx + dz * PAP_BLOCKS],
&ppl->colour,
&ppl->specular);
}
POLY_fadeout_point(ppl);
}
#ifndef TARGET_DC
apply_cloud((SLONG)world_x,(SLONG)world_y,(SLONG)world_z,&ppl->colour);
#endif
}
}
}
}
#endif
BreakTime("Rotated points");
ANNOYINGSCRIBBLECHECK;
LOG_EXIT ( AENG_Rotate_Points );
//
// No reflection and shadow stuff second time round during 3d mode.
//
#ifndef TARGET_DC
LOG_ENTER ( AENG_Draw_Stars );
if (AENG_detail_stars && !(NIGHT_flag & NIGHT_FLAG_DAYTIME))
{
//
// Draw the stars...
//
if (the_display.screen_lock())
{
BreakTime("Locked for stars");
SKY_draw_stars(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_DRAW_DIST * 256.0F);
BreakTime("Drawn stars");
the_display.screen_unlock();
}
}
BreakTime("Done stars");
LOG_EXIT ( AENG_Draw_Stars );
#endif
ANNOYINGSCRIBBLECHECK;
//
// Shadows.
//
#ifdef TARGET_DC
// Tweak my number of shadows PLEASE BOB
#define AENG_NUM_SHADOWS 4
#else
#define AENG_NUM_SHADOWS 4
#endif
LOG_ENTER ( AENG_Draw_Shadows )
struct
{
Thing *p_person;
SLONG dist;
} shadow_person[AENG_NUM_SHADOWS];
SLONG shadow_person_upto = 0;
if (AENG_detail_shadows)
{
Thing *darci = FC_cam[AENG_cur_fc_cam].focus;
//
// How many people do we generate shadows for?
//
SLONG shadow_person_worst_dist = -INFINITY;
SLONG shadow_person_worst_person;
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Class == CLASS_PERSON && (p_thing->Flags & FLAGS_IN_VIEW))
{
//
// Distance from darci.
//
dx = p_thing->WorldPos.X - darci->WorldPos.X;
dz = p_thing->WorldPos.Z - darci->WorldPos.Z;
dist = abs(dx) + abs(dz);
if (dist < 0x60000)
{
if (shadow_person_upto < AENG_NUM_SHADOWS)
{
//
// Put this person in the shadow array.
//
shadow_person[shadow_person_upto].p_person = p_thing;
shadow_person[shadow_person_upto].dist = dist;
//
// Keep track of the furthest person away.
//
if (dist > shadow_person_worst_dist)
{
shadow_person_worst_dist = dist;
shadow_person_worst_person = shadow_person_upto;
}
shadow_person_upto += 1;
}
else
{
if (dist < shadow_person_worst_dist)
{
//
// Replace the worst person.
//
ASSERT(WITHIN(shadow_person_worst_person, 0, AENG_NUM_SHADOWS - 1));
shadow_person[shadow_person_worst_person].p_person = p_thing;
shadow_person[shadow_person_worst_person].dist = dist;
//
// Find the worst person
//
shadow_person_worst_dist = -INFINITY;
for (i = 0; i < AENG_NUM_SHADOWS; i++)
{
if (shadow_person[i].dist > shadow_person_worst_dist)
{
shadow_person_worst_dist = shadow_person[i].dist;
shadow_person_worst_person = i;
}
}
}
}
}
}
t_index = p_thing->Child;
}
}
}
//
// Draw the people's shadow maps.
//
SLONG offset_x;
SLONG offset_y;
POLY_flush_local_rot();
for (i = 0; i < shadow_person_upto; i++)
{
darci = shadow_person[i].p_person;
memset(AENG_aa_buffer, 0, sizeof(AENG_aa_buffer));
SMAP_person(
darci,
(UBYTE *) AENG_aa_buffer,
AENG_AA_BUF_SIZE,
AENG_AA_BUF_SIZE,
147,
-148,
-147);
//
// Where do we put it in the shadow texture page? Hard code everything!
//
ASSERT(AENG_AA_BUF_SIZE == 32);
ASSERT(TEXTURE_SHADOW_SIZE == 64);
offset_x = (i & 1) << 5;
offset_y = (i & 2) << 4;
//
// Plonk it into the shadow texture page.
//
if (TEXTURE_shadow_lock())
{
SLONG x;
SLONG y;
UWORD *line;
UBYTE *buf = (UBYTE *) AENG_aa_buffer;
UWORD* mapping = GetShadowPixelMapping();
for (y = 0; y < AENG_AA_BUF_SIZE; y++)
{
line = &TEXTURE_shadow_bitmap[((y + offset_y) * TEXTURE_shadow_pitch >> 1) + offset_x];
for (x = AENG_AA_BUF_SIZE - 1; x >= 0; x--)
{
*line++ = mapping[*buf++];
}
}
TEXTURE_shadow_unlock();
}
//
// How we map floating points coordinates from 0 to 1 onto
// where we plonked the shadow map in the texture page.
//
AENG_project_offset_u = float(offset_x) / float(TEXTURE_SHADOW_SIZE);
AENG_project_offset_v = float(offset_y) / float(TEXTURE_SHADOW_SIZE);
AENG_project_mul_u = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE);
AENG_project_mul_v = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE);
//
// The position from which the shadow fades out.
//
AENG_project_fadeout_x = float(darci->WorldPos.X >> 8);
AENG_project_fadeout_z = float(darci->WorldPos.Z >> 8);
{
//
// Map this poly onto the mapsquares surrounding darci.
//
SLONG i;
SLONG mx;
SLONG mz;
SLONG dx;
SLONG dz;
SLONG mx1;
SLONG mz1;
SLONG mx2;
SLONG mz2;
SLONG exit = FALSE;
SLONG mx_lo;
SLONG mz_lo;
#ifndef TARGET_DC
MapElement *me[4];
#endif
PAP_Hi *ph[4];
SVector_F poly[4];
SMAP_Link *projected;
SLONG v_list;
SLONG i_vect;
DFacet *df;
SLONG w_list;
SLONG w_face;
PrimFace4 *p_f4;
PrimPoint *pp;
SLONG wall;
SLONG storey;
SLONG building;
SLONG thing;
SLONG face_height;
UBYTE face_order[4] = {0,1,3,2};
Thing *p_fthing;
//
// Colvects we have already done.
//
#define AENG_MAX_DONE 8
SLONG done[AENG_MAX_DONE];
SLONG done_upto = 0;
for (dx = -1; dx <= 1; dx++)
for (dz = -1; dz <= 1; dz++)
{
mx = (darci->WorldPos.X >> 16) + dx;
mz = (darci->WorldPos.Z >> 16) + dz;
if (WITHIN(mx, 0, MAP_WIDTH - 2) &&
WITHIN(mz, 0, MAP_HEIGHT - 2))
{
#ifndef TARGET_DC
me[0] = &MAP[MAP_INDEX(mx + 0, mz + 0)];
me[1] = &MAP[MAP_INDEX(mx + 1, mz + 0)];
me[2] = &MAP[MAP_INDEX(mx + 1, mz + 1)];
me[3] = &MAP[MAP_INDEX(mx + 0, mz + 1)];
#endif
ph[0] = &PAP_2HI(mx + 0, mz + 0);
ph[1] = &PAP_2HI(mx + 1, mz + 0);
ph[2] = &PAP_2HI(mx + 1, mz + 1);
ph[3] = &PAP_2HI(mx + 0, mz + 1);
if ( (!(PAP_2HI(mx,mz).Flags & (PAP_FLAG_HIDDEN|PAP_FLAG_WATER))) || (PAP_2HI(mx,mz).Flags & (PAP_FLAG_ROOF_EXISTS)))
{
poly[3].X = float(mx << 8);
poly[3].Z = float(mz << 8);
poly[0].X = poly[3].X + 256.0F;
poly[0].Z = poly[3].Z;
poly[1].X = poly[3].X + 256.0F;
poly[1].Z = poly[3].Z + 256.0F;
poly[2].X = poly[3].X;
poly[2].Z = poly[3].Z + 256.0F;
if (PAP_2HI(mx,mz).Flags & (PAP_FLAG_ROOF_EXISTS))
{
poly[0].Y =poly[1].Y =poly[2].Y =poly[3].Y = MAVHEIGHT(mx,mz)<<6;
}
else
{
poly[3].Y = float(ph[0]->Alt << ALT_SHIFT);
poly[2].Y = float(ph[3]->Alt << ALT_SHIFT);
poly[0].Y = float(ph[1]->Alt << ALT_SHIFT);
poly[1].Y = float(ph[2]->Alt << ALT_SHIFT);
}
if (PAP_2HI(mx,mz).Flags & PAP_FLAG_SINK_SQUARE)
{
poly[0].Y -= KERB_HEIGHT;
poly[1].Y -= KERB_HEIGHT;
poly[2].Y -= KERB_HEIGHT;
poly[3].Y -= KERB_HEIGHT;
}
if (ph[0]->Alt == ph[1]->Alt &&
ph[0]->Alt == ph[2]->Alt &&
ph[0]->Alt == ph[3]->Alt)
{
//
// This quad is coplanar.
//
projected = SMAP_project_onto_poly(poly, 4);
if (projected)
{
AENG_add_projected_fadeout_shadow_poly(projected);
}
}
else
{
//
// Do each triangle separatly.
//
projected = SMAP_project_onto_poly(poly, 3);
if (projected)
{
AENG_add_projected_fadeout_shadow_poly(projected);
}
//
// The triangles are 0,1,2 and 0,2,3.
//
poly[1] = poly[0];
projected = SMAP_project_onto_poly(poly + 1, 3);
if (projected)
{
AENG_add_projected_fadeout_shadow_poly(projected);
}
}
}
}
}
mx1 = (darci->WorldPos.X >> 8) - 0x100 >> PAP_SHIFT_LO;
mz1 = (darci->WorldPos.Z >> 8) - 0x100 >> PAP_SHIFT_LO;
mx2 = (darci->WorldPos.X >> 8) + 0x100 >> PAP_SHIFT_LO;
mz2 = (darci->WorldPos.Z >> 8) + 0x100 >> PAP_SHIFT_LO;
SATURATE(mx1, 0, PAP_SIZE_LO - 1);
SATURATE(mz1, 0, PAP_SIZE_LO - 1);
SATURATE(mx2, 0, PAP_SIZE_LO - 1);
SATURATE(mz2, 0, PAP_SIZE_LO - 1);
for (mx_lo = mx1; mx_lo <= mx2; mx_lo++)
for (mz_lo = mz1; mz_lo <= mz2; mz_lo++)
{
SLONG count = 0;
//
// Project onto nearby colvects...
//
v_list = PAP_2LO(mx_lo,mz_lo).ColVectHead;
if (v_list)
{
exit = FALSE;
while(!exit)
{
i_vect = facet_links[v_list];
if(i_vect<0)
{
i_vect = -i_vect;
exit = TRUE;
}
df = &dfacets[i_vect];
if (df->FacetType == STOREY_TYPE_NORMAL)
{
for (i = 0; i < done_upto; i++)
{
if (done[i] == i_vect)
{
//
// Dont do this facet again
//
goto ignore_this_facet;
}
}
if (1 /* Fast facet shadows */)
{
float facet_height = float((df->BlockHeight << 4) * (df->Height >> 2));
poly[0].X = float(df->x[1] << 8);
poly[0].Y = float(df->Y[1] );
poly[0].Z = float(df->z[1] << 8);
poly[1].X = float(df->x[1] << 8);
poly[1].Y = float(df->Y[1] ) + facet_height;
poly[1].Z = float(df->z[1] << 8);
poly[2].X = float(df->x[0] << 8);
poly[2].Y = float(df->Y[0] ) + facet_height;
poly[2].Z = float(df->z[0] << 8);
poly[3].X = float(df->x[0] << 8);
poly[3].Y = float(df->Y[0] );
poly[3].Z = float(df->z[0] << 8);
if (df->FHeight)
{
//
// Foundations go down deep into the ground...
//
poly[0].Y -= 512.0F;
poly[3].Y -= 512.0F;
}
projected = SMAP_project_onto_poly(poly, 4);
if (projected)
{
AENG_add_projected_fadeout_shadow_poly(projected);
}
}
else
{
//
// Slow crinkled-shadows!
//
FACET_project_crinkled_shadow(i_vect);
}
//
// Remember We've already done this facet.
//
if (done_upto < AENG_MAX_DONE)
{
done[done_upto++] = i_vect;
}
}
ignore_this_facet:;
v_list++;
}
}
//if (darci->OnFace) Always do this.
{
//
// Cast shadow on walkable faces.
//
w_face = PAP_2LO(mx_lo,mz_lo).Walkable;
while(w_face)
{
if (w_face > 0)
{
p_f4 = &prim_faces4[w_face];
face_height = prim_points[p_f4->Points[0]].Y;
if (face_height > ((darci->WorldPos.Y + 0x11000) >> 8))
{
//
// This face is above Darci, so don't put her shadow
// on it.
//
}
else
{
for (i = 0; i < 4; i++)
{
pp = &prim_points[p_f4->Points[face_order[i]]];
poly[i].X = float(pp->X);
poly[i].Y = float(pp->Y);
poly[i].Z = float(pp->Z);
}
projected = SMAP_project_onto_poly(poly, 4);
if (projected)
{
AENG_add_projected_fadeout_shadow_poly(projected);
}
}
w_face = p_f4->Col2;
}
else
{
struct RoofFace4 *rf;
rf = &roof_faces4[-w_face];
face_height = rf->Y;
if (face_height > ((darci->WorldPos.Y + 0x11000) >> 8))
{
//
// This face is above Darci, so don't put her shadow
// on it.
//
}
else
{
SLONG mx,mz;
mx=(rf->RX&127)<<8;
mz=(rf->RZ&127)<<8;
poly[0].X=(float)(mx);
poly[0].Y=(float)(rf->Y);
poly[0].Z=(float)(mz);
poly[1].X=(float)(mx+256);
poly[1].Y=(float)(rf->Y+(rf->DY[0]<<ROOF_SHIFT));
poly[1].Z=(float)(mz);
poly[2].X=(float)(mx+256);
poly[2].Y=(float)(rf->Y+(rf->DY[1]<<ROOF_SHIFT));
poly[2].Z=(float)(mz+256);
poly[3].X=(float)(mx);
poly[3].Y=(float)(rf->Y+(rf->DY[2]<<ROOF_SHIFT));
poly[3].Z=(float)(mz+256);
projected = SMAP_project_onto_poly(poly, 4);
if (projected)
{
AENG_add_projected_fadeout_shadow_poly(projected);
}
}
w_face = rf->Next;
}
}
}
}
}
TEXTURE_shadow_update();
}
}
BreakTime("Done shadows");
LOG_EXIT ( AENG_Draw_Shadows )
#ifndef TARGET_DC
// No reflections on DC.
ANNOYINGSCRIBBLECHECK;
//
// Where we remember the bounding boxes of reflections.
//
LOG_ENTER ( AENG_Moon )
struct
{
SLONG x1;
SLONG y1;
SLONG x2;
SLONG y2;
SLONG water_box;
} bbox[AENG_MAX_BBOXES];
SLONG bbox_upto = 0;
if (AENG_detail_moon_reflection && !(NIGHT_flag & NIGHT_FLAG_DAYTIME) && !(GAME_FLAGS & GF_NO_FLOOR))
{
//
// The moon upside down...
//
float moon_x1;
float moon_y1;
float moon_x2;
float moon_y2;
if (SKY_draw_moon_reflection(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_DRAW_DIST * 256.0F,
&moon_x1,
&moon_y1,
&moon_x2,
&moon_y2))
{
/*
//
// The moon is wibbled with polys now.
//
bbox[0].x1 = MAX((SLONG)moon_x1 - AENG_BBOX_PUSH_OUT, AENG_BBOX_PUSH_IN);
bbox[0].y1 = MAX((SLONG)moon_y1, 0);
bbox[0].x2 = MIN((SLONG)moon_x2 + AENG_BBOX_PUSH_OUT, DisplayWidth - AENG_BBOX_PUSH_IN);
bbox[0].y2 = MIN((SLONG)moon_y2, DisplayHeight);
bbox[0].water_box = FALSE;
bbox_upto = 1;
*/
}
}
LOG_EXIT ( AENG_Moon )
ANNOYINGSCRIBBLECHECK;
//
// Draw the reflections of people.
//
LOG_ENTER ( AENG_People_Reflection )
if (AENG_detail_people_reflection)
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Class == CLASS_PERSON && (p_thing->Flags & FLAGS_IN_VIEW))
{
//
// This is a person... Is she standing near a puddle or some water?
//
mx = p_thing->WorldPos.X >> 16;
mz = p_thing->WorldPos.Z >> 16;
if (!PAP_on_map_hi(mx,mz))
{
//
// Off the map.
//
}
else
{
ph = &PAP_2HI(mx,mz);
if (ph->Flags & (PAP_FLAG_REFLECTIVE|PAP_FLAG_WATER))
{
//
// Not too far away?
//
dx = abs(p_thing->WorldPos.X - FC_cam[AENG_cur_fc_cam].x >> 8);
dz = abs(p_thing->WorldPos.Z - FC_cam[AENG_cur_fc_cam].z >> 8);
if (dx + dz < 0x600)
{
SLONG reflect_height;
//
// Puddles are always on the floor nowadays...
//
if (ph->Flags & PAP_FLAG_REFLECTIVE)
{
reflect_height = PAP_calc_height_at(p_thing->WorldPos.X >> 8, p_thing->WorldPos.Z >> 8);
}
else
{
//
// The height of the water is given by the lo-res mapsquare corresponding
// to the hi-res mapsquare that Darci is standing on.
//
pl = &PAP_2LO(
p_thing->WorldPos.X >> (8 + PAP_SHIFT_LO),
p_thing->WorldPos.Z >> (8 + PAP_SHIFT_LO));
reflect_height = pl->water << ALT_SHIFT;
}
//
// Draw the reflection!
//
FIGURE_draw_reflection(p_thing, reflect_height);
if (WITHIN(bbox_upto, 0, AENG_MAX_BBOXES - 1))
{
//
// Create a new bounding box
//
bbox[bbox_upto].x1 = MAX(FIGURE_reflect_x1 - AENG_BBOX_PUSH_OUT, AENG_BBOX_PUSH_IN);
bbox[bbox_upto].y1 = MAX(FIGURE_reflect_y1, 0);
bbox[bbox_upto].x2 = MIN(FIGURE_reflect_x2 + AENG_BBOX_PUSH_OUT, DisplayWidth - AENG_BBOX_PUSH_IN);
bbox[bbox_upto].y2 = MIN(FIGURE_reflect_y2, DisplayHeight);
bbox[bbox_upto].water_box = ph->Flags & PAP_FLAG_WATER;
bbox_upto += 1;
}
}
}
}
}
t_index = p_thing->Child;
}
}
}
/*
//
// Draw the reflections of the OBs.
//
if(DETAIL_LEVEL&DETAIL_REFLECTIONS)
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
for (oi = OB_find(x,z); oi->prim; oi += 1)
{
//
// On map?
//
mx = oi->x >> 8;
mz = oi->z >> 8;
if (WITHIN(mx, 0, PAP_SIZE_HI - 1) &&
WITHIN(mz, 0, PAP_SIZE_HI - 1))
{
//
// On a reflective square?
//
if (PAP_2HI(mx,mz).Flags & (PAP_FLAG_WATER|PAP_FLAG_REFLECTIVE))
{
//
// Not too far away?
//
dx = abs(oi->x - (FC_cam[AENG_cur_fc_cam].x >> 8));
dz = abs(oi->z - (FC_cam[AENG_cur_fc_cam].z >> 8));
if (dx + dz < 0x00)
{
MESH_draw_reflection(
oi->prim,
oi->x,
oi->y,
oi->z,
oi->yaw,
NULL);
}
}
}
}
}
}
*/
BreakTime("Drawn reflections");
LOG_EXIT ( AENG_People_Reflection )
ANNOYINGSCRIBBLECHECK;
#ifdef TARGET_DC
if ( AENG_detail_moon_reflection || AENG_detail_people_reflection )
#endif
{
//
// Drips inside puddles only...
//
AENG_draw_drips(1);
//
// Draw the reflections and drips. Clear the poly lists.
//
#ifndef TARGET_DC
POLY_frame_draw(FALSE,FALSE);
POLY_frame_init(TRUE,TRUE);
#endif
BreakTime("Done first poly flush");
}
//
// Draw the puddles.
//
LOG_ENTER ( AENG_Puddles )
if (AENG_detail_puddles && !(GAME_FLAGS & GF_NO_FLOOR))
{
SLONG i;
PUDDLE_Info *pi;
float px1;
float pz1;
float px2;
float pz2;
float world_x;
float world_y;
float world_z;
static struct
{
float u;
float v;
} texture_coords[4] =
{
{0.0F,0.0F},
{1.0F,0.0F},
{1.0F,1.0F},
{0.0F,1.0F}
};
POLY_Point pp [4];
POLY_Point *quad[4];
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++)
{
PUDDLE_get_start(z, NGAMUT_gamut[z].xmin, NGAMUT_gamut[z].xmax);
while(pi = PUDDLE_get_next())
{
px1 = float(pi->x1);
pz1 = float(pi->z1);
px2 = float(pi->x2);
pz2 = float(pi->z2);
world_y = float(pi->y);
for (i = 0; i < 4; i++)
{
world_x = (i & 0x1) ? px1 : px2;
world_z = (i & 0x2) ? pz1 : pz2;
POLY_transform(
world_x,
world_y,
world_z,
&pp[i]);
if (pp[i].MaybeValid())
{
pp[i].u = ((i & 0x1) ? float(pi->u1) : float(pi->u2)) * (1.0F / 256.0F);
pp[i].v = ((i & 0x2) ? float(pi->v1) : float(pi->v2)) * (1.0F / 256.0F);
pp[i].colour = 0xffffffff;
if (ControlFlag) {pp[i].colour = 0x44ffffff;}
if (ShiftFlag) {pp[i].colour = 0x88ffffff;}
pp[i].specular = 0xff000000;
}
else
{
goto ignore_this_puddle;
}
}
if (POLY_valid_quad(quad))
{
if ((GAME_FLAGS & GF_RAINING) && (rand() & 0x100))
{
float drip_along_x;
float drip_along_z;
//
// Choose somewhere in the puddle to put a drip.
//
drip_along_x = float(rand() & 0xff) * (1.0F / 256.0F);
drip_along_z = float(rand() & 0xff) * (1.0F / 256.0F);
world_x = px1 + (px2 - px1) * drip_along_x;
world_z = pz1 + (pz2 - pz1) * drip_along_z;
DRIP_create(
UWORD(world_x),
SWORD(world_y),
UWORD(world_z),
1);
if (rand() & 0x11)
{
//
// Don't splash.
//
}
else
{
//
// Splash the puddle.
//
PUDDLE_splash(
SLONG(world_x),
SLONG(world_y),
SLONG(world_z));
}
}
if (pi->rotate_uvs)
{
SWAP_FL(pp[0].u, pp[1].u);
SWAP_FL(pp[1].u, pp[3].u);
SWAP_FL(pp[3].u, pp[2].u);
SWAP_FL(pp[0].v, pp[1].v);
SWAP_FL(pp[1].v, pp[3].v);
SWAP_FL(pp[3].v, pp[2].v);
}
POLY_add_quad(quad, POLY_PAGE_PUDDLE, FALSE);
if (pi->puddle_s1 | pi->puddle_s2)
{
//
// Find the bounding box of this puddle quad on screen.
//
SLONG px;
SLONG py;
SLONG px1 = +INFINITY;
SLONG py1 = +INFINITY;
SLONG px2 = -INFINITY;
SLONG py2 = -INFINITY;
for (i = 0; i < 4; i++)
{
px = SLONG(pp[i].X);
py = SLONG(pp[i].Y);
if (px < px1) {px1 = px;}
if (py < py1) {py1 = py;}
if (px > px2) {px2 = px;}
if (py > py2) {py2 = py;}
}
//
// Wibble the intersection of this bounding box with the bounding
// box of each reflection we have drawn.
//
SLONG ix1;
SLONG iy1;
SLONG ix2;
SLONG iy2;
for (i = 0; i < bbox_upto; i++)
{
if (bbox[i].water_box)
{
//
// This box always gets wibbled anyway.
//
continue;
}
ix1 = MAX(px1, bbox[i].x1);
iy1 = MAX(py1, bbox[i].y1);
ix2 = MIN(px2, bbox[i].x2);
iy2 = MIN(py2, bbox[i].y2);
if (ix1 < ix2 && iy1 < iy2)
{
if (the_display.screen_lock())
{
//
// Wibble away!
//
WIBBLE_simple(
ix1, iy1,
ix2, iy2,
pi->puddle_y1,
pi->puddle_y2,
pi->puddle_g1,
pi->puddle_g2,
pi->puddle_s1,
pi->puddle_s2);
the_display.screen_unlock();
}
}
}
}
}
ignore_this_puddle:;
}
}
}
BreakTime("Drawn puddles");
LOG_EXIT ( AENG_Puddles )
ANNOYINGSCRIBBLECHECK;
#ifndef NEW_FLOOR
if (AENG_detail_people_reflection)
#ifndef TARGET_DC
if(!SOFTWARE)
#endif
{
SLONG oldcolour [4];
SLONG oldspecular[4];
//
// Draw all the floor-reflective squares
//
for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++)
{
for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++)
{
#ifndef TARGET_DC
me = &MAP[MAP_INDEX(x,z)];
#endif
ph = &PAP_2HI(x,z);
if (ph->Flags & PAP_FLAG_HIDDEN)
{
continue;
}
if (!(ph->Flags & PAP_FLAG_REFLECTIVE))
{
continue;
}
//
// The four points of the quad.
//
if (ph->Flags & PAP_FLAG_SINK_SQUARE)
{
quad[0] = &AENG_lower[(x + 0) & 63][(z + 0) & 63];
quad[1] = &AENG_lower[(x + 1) & 63][(z + 0) & 63];
quad[2] = &AENG_lower[(x + 0) & 63][(z + 1) & 63];
quad[3] = &AENG_lower[(x + 1) & 63][(z + 1) & 63];
}
else
{
quad[0] = &AENG_upper[(x + 0) & 63][(z + 0) & 63];
quad[1] = &AENG_upper[(x + 1) & 63][(z + 0) & 63];
quad[2] = &AENG_upper[(x + 0) & 63][(z + 1) & 63];
quad[3] = &AENG_upper[(x + 1) & 63][(z + 1) & 63];
}
if (POLY_valid_quad(quad))
{
//
// Darken the quad.
//
for (i = 0; i < 4; i++)
{
oldcolour [i] = quad[i]->colour;
oldspecular[i] = quad[i]->specular;
quad[i]->colour >>= 1;
quad[i]->colour &= 0x007f7f7f;
#ifdef TARGET_DC
quad[i]->colour |= 0xff000000;
#endif
quad[i]->specular = 0xff000000;
}
//
// Texture the quad.
//
if (ph->Flags & PAP_FLAG_ANIM_TMAP)
{
struct AnimTmap *p_a;
SLONG cur;
p_a=&anim_tmaps[ph->Texture];
cur=p_a->Current;
quad[0]->u = float(p_a->UV[cur][0][0] & 0x3f) * (1.0F / 32.0F);
quad[0]->v = float(p_a->UV[cur][0][1] ) * (1.0F / 32.0F);
quad[1]->u = float(p_a->UV[cur][1][0] ) * (1.0F / 32.0F);
quad[1]->v = float(p_a->UV[cur][1][1] ) * (1.0F / 32.0F);
quad[2]->u = float(p_a->UV[cur][2][0] ) * (1.0F / 32.0F);
quad[2]->v = float(p_a->UV[cur][2][1] ) * (1.0F / 32.0F);
quad[3]->u = float(p_a->UV[cur][3][0] ) * (1.0F / 32.0F);
quad[3]->v = float(p_a->UV[cur][3][1] ) * (1.0F / 32.0F);
page = p_a->UV[cur][0][0] & 0xc0;
page <<= 2;
page |= p_a->Page[cur];
}
else
{
TEXTURE_get_minitexturebits_uvs(
ph->Texture,
&page,
&quad[0]->u,
&quad[0]->v,
&quad[1]->u,
&quad[1]->v,
&quad[2]->u,
&quad[2]->v,
&quad[3]->u,
&quad[3]->v);
}
POLY_add_quad(quad, page, FALSE);
//
// Restore old colour info.
//
for (i = 0; i < 4; i++)
{
quad[i]->colour = oldcolour [i];
quad[i]->specular = oldspecular[i];
}
}
}
}
}
#endif
BreakTime("Drawn reflective squares");
/*
//
// Draw the water in the city.
//
{
SLONG dmx;
SLONG dmz;
SLONG dx;
SLONG dz;
SLONG px;
SLONG py;
SLONG pz;
SLONG ix;
SLONG iz;
POLY_Point water_pp[5][5];
POLY_Point *quad[4];
POLY_Point *pp;
SLONG user_upto = 1;
for (i = 0, pp = &water_pp[0][0]; i < 25; i++, pp++)
{
pp->user = 0;
}
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
pl = &PAP_2LO(x,z);
if (pl->water == PAP_LO_NO_WATER)
{
//
// No water in this square.
//
}
else
{
//
// The height of water in this lo-res mapsquare.
//
py = pl->water << ALT_SHIFT;
//
// Look for water in the hi-res mapsquare enclosed by this
// lo-res mapsqure.
//
for (dmx = 0; dmx < 4; dmx++)
for (dmz = 0; dmz < 4; dmz++)
{
mx = (x << 2) + dmx;
mz = (z << 2) + dmz;
ph = &PAP_2HI(mx,mz);
if (ph->Flags & PAP_FLAG_WATER)
{
//
// Transform all the points.
//
i = 0;
for (i = 0; i < 4; i++)
{
dx = i & 1;
dz = i >> 1;
ix = dmx + dx;
iz = dmz + dz;
if (water_pp[ix][iz].user == user_upto)
{
//
// Already transformed.
//
}
else
{
//
// Transform this point.
//
water_pp[ix][iz].user = user_upto;
px = mx + dx << 8;
pz = mz + dz << 8;
POLY_transform(
float(px),
float(py),
float(pz),
&water_pp[ix][iz]);
water_pp[ix][iz].colour = 0x44608564;
water_pp[ix][iz].specular = 0xff000000;
POLY_fadeout_point(&water_pp[ix][iz]);
//
// This point's (u,v) coordinates are a function of its
// position and the time.
//
{
float angle_u = float(((((mx + dx) * 5 + (mz + dz) * 6) & 0x1f) + 0x1f) * GAME_TURN) * (1.0F / 1754.0F);
float angle_v = float(((((mx + dx) * 4 + (mz + dz) * 7) & 0x1f) + 0x1f) * GAME_TURN) * (1.0F / 1816.0F);
water_pp[ix][iz].u = px * (1.0F / 256.0F) + sin(angle_u) * 0.15F;
water_pp[ix][iz].v = pz * (1.0F / 256.0F) + cos(angle_v) * 0.15F;
}
}
if (!water_pp[ix][iz].MaybeValid())
{
goto abandon_poly;
}
quad[i] = &water_pp[ix][iz];
}
if (POLY_valid_quad(quad))
{
POLY_add_quad(quad, POLY_PAGE_SEWATER, FALSE);
}
}
abandon_poly:;
}
user_upto += 1;
}
}
}
}
*/
// End of reflection stuff.
#endif //#ifndef TARGET_DC
//
// The sky.
//
LOG_ENTER ( AENG_Draw_Sky )
extern void SKY_draw_poly_sky_old(float world_camera_x,float world_camera_y,float world_camera_z,float world_camera_yaw,float max_dist,ULONG bot_colour,ULONG top_colour);
#ifdef TARGET_DC
// Fade sky textures out a bit.
if (AENG_detail_skyline)
SKY_draw_poly_sky_old(AENG_cam_x,AENG_cam_y,AENG_cam_z,AENG_cam_yaw,AENG_DRAW_DIST * 256.0F,0x80808080,0x80808080);
#else
if (AENG_detail_skyline)
SKY_draw_poly_sky_old(AENG_cam_x,AENG_cam_y,AENG_cam_z,AENG_cam_yaw,AENG_DRAW_DIST * 256.0F,0xffffff,0xffffff);
#endif
/*
SKY_draw_poly_clouds(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_DRAW_DIST * 256.0F);
*/
if(!INDOORS_INDEX||outside)
if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME))
{
SKY_draw_poly_moon(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
/*AENG_DRAW_DIST * 256.0F*/
256.0f * 22.0f);
}
LOG_EXIT ( AENG_Draw_Sky )
ANNOYINGSCRIBBLECHECK;
//
// Draw the puddles and clear the poly lists.
//
#ifdef TARGET_DC
if ( AENG_detail_people_reflection && AENG_detail_puddles )
#endif
{
#ifndef TARGET_DC
POLY_frame_draw_odd();
POLY_frame_draw_puddles();
#endif
#ifdef DEBUG
POLY_frame_draw_sewater();
#endif
#ifndef TARGET_DC
POLY_frame_init(TRUE,TRUE);
#endif
}
BreakTime("Done second polygon flush");
//
// FAR FACETS!!!!!!!!!!!!!
//
LOG_ENTER ( AENG_Draw_Skyline )
FARFACET_draw(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
// Draw dist changes dynamically, so do it to a fixed distance.
//AENG_DRAW_DIST * 4,
90.0F*256.0F,
AENG_LENS);
//#if defined(NDEBUG) || defined(TARGET_DC)
// if (AENG_detail_skyline)
// AENG_draw_far_facets();
//#endif
LOG_EXIT ( AENG_Draw_Skyline )
ANNOYINGSCRIBBLECHECK;
//
// Create all the squares.
//
//
// draw floor draw_floor //things to search for
//
#ifndef NEW_FLOOR
LOG_ENTER ( AENG_Draw_Floors )
SLONG num_squares_drawn = 0;
{
if(!INDOORS_INDEX||outside)
for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++)
{
for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++)
{
ASSERT(WITHIN(x, 0, PAP_SIZE_HI - 2));
ASSERT(WITHIN(z, 0, PAP_SIZE_HI - 2));
ph = &PAP_2HI(x,z);
if ((ph->Flags & (PAP_FLAG_HIDDEN|PAP_FLAG_ROOF_EXISTS))== PAP_FLAG_HIDDEN)
{
continue;
}
#ifdef FAST_EDDIE
if (Keys[KB_1] && ((x ^ z) & 1)) continue;
#endif
/*
if (ph->Flags & PAP_FLAG_WATER)
{
//
// We don't draw the ground because it is covered by water.
//
}
else
*/
{
POLY_Point fake_roof[4];
//
// The four points of the quad.
//
if ((ph->Flags & (PAP_FLAG_ROOF_EXISTS)) )
{
SLONG c0,light_lookup;
float y;
y=MAVHEIGHT(x,z)<<6;//(PAP_hi[x][z].Height<<6);
// 0 1
//
// 2 3
POLY_transform((x)<<8,y, (z)<<8, &fake_roof[0]);
POLY_transform((x+1)<<8,y, (z)<<8, &fake_roof[1]);
POLY_transform((x)<<8,y, (z+1)<<8, &fake_roof[3]);
POLY_transform((x+1)<<8,y, (z+1)<<8, &fake_roof[2]);
extern UWORD hidden_roof_index[128][128];
light_lookup=hidden_roof_index[x][z];
ASSERT(light_lookup);
for(c0=0;c0<4;c0++)
{
SLONG c0_bodge;
c0_bodge=index_lookup[c0];
pp=&fake_roof[c0];
// pp->colour=0x808080;
if (pp->MaybeValid())
{
NIGHT_get_d3d_colour(NIGHT_ROOF_WALKABLE_POINT(light_lookup,c0),&pp->colour,&pp->specular);
apply_cloud((x+(c0_bodge&1))<<8,y,(z+((c0_bodge&2)>>1))<<8,&pp->colour);
POLY_fadeout_point(pp);
}
// pp->specular=0xff000000;
// pp->colour=0xff000000;
}
quad[0] = &fake_roof[0];
quad[1] = &fake_roof[1];
quad[2] = &fake_roof[3];
quad[3] = &fake_roof[2];
}
else
{
if (GAME_FLAGS & GF_NO_FLOOR)
{
//
// Don't draw the floor if there isn't any!
//
continue;
}
if (ph->Flags & PAP_FLAG_SINK_SQUARE)
{
quad[0] = &AENG_lower[(x + 0) & 63][(z + 0) & 63];
quad[1] = &AENG_lower[(x + 1) & 63][(z + 0) & 63];
quad[2] = &AENG_lower[(x + 0) & 63][(z + 1) & 63];
quad[3] = &AENG_lower[(x + 1) & 63][(z + 1) & 63];
}
else
{
if((MAV_SPARE(x,z) & MAV_SPARE_FLAG_WATER))
quad[0] = &AENG_lower[(x + 0) & 63][(z + 0) & 63];
else
quad[0] = &AENG_upper[(x + 0) & 63][(z + 0) & 63];
if((MAV_SPARE(x+1,z) & MAV_SPARE_FLAG_WATER))
quad[1] = &AENG_lower[(x + 1) & 63][(z + 0) & 63];
else
quad[1] = &AENG_upper[(x + 1) & 63][(z + 0) & 63];
if((MAV_SPARE(x,z+1) & MAV_SPARE_FLAG_WATER))
quad[2] = &AENG_lower[(x + 0) & 63][(z + 1) & 63];
else
quad[2] = &AENG_upper[(x + 0) & 63][(z + 1) & 63];
if((MAV_SPARE(x+1,z+1) & MAV_SPARE_FLAG_WATER))
quad[3] = &AENG_lower[(x + 1) & 63][(z + 1) & 63];
else
quad[3] = &AENG_upper[(x + 1) & 63][(z + 1) & 63];
}
}
if (POLY_valid_quad(quad))
{
num_squares_drawn += 1;
{
//
// Texture the quad.
//
/*
if (ph->Flags & PAP_FLAG_ANIM_TMAP)
{
struct AnimTmap *p_a;
SLONG cur;
p_a=&anim_tmaps[ph->Texture];
cur=p_a->Current;
quad[0]->u = float(p_a->UV[cur][0][0] & 0x3f) * (1.0F / 32.0F);
quad[0]->v = float(p_a->UV[cur][0][1] ) * (1.0F / 32.0F);
quad[1]->u = float(p_a->UV[cur][1][0] ) * (1.0F / 32.0F);
quad[1]->v = float(p_a->UV[cur][1][1] ) * (1.0F / 32.0F);
quad[2]->u = float(p_a->UV[cur][2][0] ) * (1.0F / 32.0F);
quad[2]->v = float(p_a->UV[cur][2][1] ) * (1.0F / 32.0F);
quad[3]->u = float(p_a->UV[cur][3][0] ) * (1.0F / 32.0F);
quad[3]->v = float(p_a->UV[cur][3][1] ) * (1.0F / 32.0F);
page = p_a->UV[cur][0][0] & 0xc0;
page <<= 2;
page |= p_a->Page[cur];
}
else
*/
{
TEXTURE_get_minitexturebits_uvs(
ph->Texture,
&page,
&quad[0]->u,
&quad[0]->v,
&quad[1]->u,
&quad[1]->v,
&quad[2]->u,
&quad[2]->v,
&quad[3]->u,
&quad[3]->v);
// page = 86;
}
#ifdef TARGET_DC
// Key off the "mist" detail setting instead
if (AENG_detail_mist)
#else
if (AENG_detail_shadows)
#endif
if(page==4*64+53)
{
SLONG dx,dz,dist;
dx=abs( (((SLONG)AENG_cam_x)>>8)-(x) );
dz=abs( (((SLONG)AENG_cam_z)>>8)-(z) );
dist=QDIST2(dx,dz);
if(dist<15)
{
SLONG sx,sy,sz;
void draw_steam(SLONG x,SLONG y,SLONG z,SLONG lod);
switch((ph->Texture >> 0xa) & 0x3)
{
case 0:
sx=190;
sz=128;
break;
case 1:
sx=128;
sz=66;
break;
case 2:
sx=66;
sz=128;
break;
case 3:
sx=128;
sz=190;
break;
default:
ASSERT(0);
break;
}
sx+=x<<8;
sz+=z<<8;
sy=PAP_calc_height_at(sx,sz);
draw_steam(sx,sy,sz,10+(15-dist)*3);
}
}
if (ph->Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3))
{
POLY_Point ps[4];
//
// Create four darkened points.
//
ps[0] = *(quad[0]);
ps[1] = *(quad[1]);
ps[2] = *(quad[2]);
ps[3] = *(quad[3]);
//
// Darken the points.
//
for (i = 0; i < 4; i++)
{
red = (ps[i].colour >> 16) & 0xff;
green = (ps[i].colour >> 8) & 0xff;
blue = (ps[i].colour >> 0) & 0xff;
red -= 120;
green -= 120;
blue -= 120;
if (red < 0) {red = 0;}
if (green < 0) {green = 0;}
if (blue < 0) {blue = 0;}
ps[i].colour = (red << 16) | (green << 8) | (blue << 0)|(0xff000000);
}
ASSERT(PAP_FLAG_SHADOW_1 == 1);
switch(ph->Flags & (PAP_FLAG_SHADOW_1|PAP_FLAG_SHADOW_2|PAP_FLAG_SHADOW_3))
{
case 0:
ASSERT(0); // We shouldn't be doing any of this in this case.
break;
case 1:
tri[0] = &ps [0];
tri[1] = quad[1];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
tri[0] = quad[1];
tri[1] = quad[3];
tri[2] = quad[2];
POLY_add_triangle(tri, page, TRUE);
break;
case 2:
tri[0] = &ps [0];
tri[1] = quad[1];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
tri[0] = quad[1];
tri[1] = quad[3];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
break;
case 3:
//ps[2].colour += 0x00101010;
tri[0] = quad[0];
tri[1] = quad[1];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
tri[0] = quad[1];
tri[1] = quad[3];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
break;
case 4:
tri[0] = quad[0];
tri[1] = quad[1];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
tri[0] = quad[1];
tri[1] = &ps [3];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
break;
case 5:
tri[0] = &ps [0];
tri[1] = quad[1];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
tri[0] = quad[1];
tri[1] = &ps [3];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
break;
case 6:
tri[0] = &ps [0];
tri[1] = quad[1];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
tri[0] = quad[1];
tri[1] = quad[3];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
break;
case 7:
tri[0] = quad[0];
tri[1] = quad[1];
tri[2] = quad[2];
POLY_add_triangle(tri, page, TRUE);
tri[0] = quad[1];
tri[1] = &ps [3];
tri[2] = &ps [2];
POLY_add_triangle(tri, page, TRUE);
break;
default:
ASSERT(0);
break;
}
}
else
{
#if 0
//
// Crinkle? Not on the ground yet... I'll have to code rotation first.
//
if (/*crinkles enabled*/ 0 && page < 64 * 8 && TEXTURE_crinkle[page])
{
//
// This quad could be crinkled!
//
if (quad[0]->z > 0.5F)
{
//
// Too far away to be crinkled.
//
POLY_add_quad(quad, page, FALSE);
}
else
if (quad[0]->z < 0.2F)
{
//
// Maximum crinkleyness!
//
CRINKLE_do(
TEXTURE_crinkle[page],
page,
1.0F,
quad,
FALSE);
}
else
{
float extrude;
float av_z;
//
// Intermediate crinkle extrusion.
//
av_z = quad[0]->z + quad[1]->z + quad[2]->z + quad[3]->z;
av_z *= 0.25F;
extrude = av_z - 0.4F;
extrude *= 1.0F / (0.3F - 0.4F);
if (extrude > 0.0F)
{
if (extrude > 1.0F)
{
extrude = 1.0F;
}
CRINKLE_do(
TEXTURE_crinkle[page],
page,
extrude,
quad,
FALSE);
}
else
{
POLY_add_quad(quad, page, FALSE);
}
}
}
else
#endif
{
POLY_add_quad(quad, page, FALSE);
}
}
}
}
}
if (ph->Flags & (PAP_FLAG_SINK_SQUARE|PAP_FLAG_WATER))
{
//
// Do the curbs now.
//
static struct
{
SLONG dpx1;
SLONG dpz1;
SLONG dpx2;
SLONG dpz2;
SLONG dsx;
SLONG dsz;
} curb[4] =
{
{0,0,0,1,-1,0},
{0,1,1,1,0,+1},
{1,1,1,0,+1,0},
{1,0,0,0,0,-1}
};
for (i = 0; i < 4; i++)
{
nx = x + curb[i].dsx;
nz = z + curb[i].dsz;
if (PAP_on_map_hi(nx,nz))
{
if (PAP_2HI(nx,nz).Flags & (PAP_FLAG_SINK_SQUARE|PAP_FLAG_WATER))
{
//
// No need for a curb here.
//
}
else
{
quad[0] = &AENG_lower[(x + curb[i].dpx1) & 63][(z + curb[i].dpz1) & 63];
quad[1] = &AENG_lower[(x + curb[i].dpx2) & 63][(z + curb[i].dpz2) & 63];
quad[2] = &AENG_upper[(x + curb[i].dpx1) & 63][(z + curb[i].dpz1) & 63];
quad[3] = &AENG_upper[(x + curb[i].dpx2) & 63][(z + curb[i].dpz2) & 63];
if (POLY_valid_quad(quad))
{
TEXTURE_get_minitexturebits_uvs(
0,
&page,
&quad[0]->u,
&quad[0]->v,
&quad[1]->u,
&quad[1]->v,
&quad[2]->u,
&quad[2]->v,
&quad[3]->u,
&quad[3]->v);
//
// Add the poly.
//
POLY_add_quad(quad, page, TRUE);
}
}
}
}
}
}
}
}
#endif
BreakTime("Drawn floors");
LOG_EXIT ( AENG_Draw_Floors )
ANNOYINGSCRIBBLECHECK;
// POLY_frame_draw(FALSE,FALSE);
// POLY_frame_init(TRUE,TRUE);
// BreakTime("Done another flush");
//
// Draw the objects and the things.
//
LOG_ENTER ( AENG_Draw_Things )
dfacets_drawn_this_gameturn = 0;
{
LOG_ENTER ( AENG_Draw_Prims )
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
OB_Info *oi;
NIGHT_Colour *col;
//
// The cached lighting for this low-res mapsquare.
//
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
//ASSERT(WITHIN(NIGHT_cache[x][z], 1, NIGHT_MAX_SQUARES - 1));
col = NIGHT_square[NIGHT_cache[x][z]].colour;
//
// Skip over the mapsquares.
//
col += PAP_BLOCKS * PAP_BLOCKS;
//
// The objects on this mapsquare.
//
oi = OB_find(x,z);
while(oi->prim)
{
if (!(oi->flags & OB_FLAG_WAREHOUSE))
{
if (oi->prim == 133 || oi->prim == 235)
{
//
// This prim slowly rotates...
//
oi->yaw = (GAME_TURN << 1) & 2047;
}
#ifdef EDITOR
UBYTE fade;
extern HWND GEDIT_edit_wnd;
if (GEDIT_edit_wnd)
fade=(oi->flags & OB_FLAG_NOT_ON_PSX)?0x7f:0xff;
else
fade=0xff;
#else
UBYTE fade=0xff;
#endif
col = MESH_draw_poly(
oi->prim,
oi->x,
oi->y,
oi->z,
oi->yaw,
oi->pitch,
oi->roll,
col,
fade,
oi->crumple);
if(!SOFTWARE)
SHAPE_prim_shadow(oi);
if ((prim_objects[oi->prim].flag & PRIM_FLAG_GLARE)&& !SOFTWARE)
{
if (oi->prim == 230)
{
BLOOM_draw(oi->x,oi->y+48,oi->z, 0,0,0,0x808080,BLOOM_RAISE_LOS);
}
else
{
BLOOM_draw(oi->x,oi->y,oi->z, 0,0,0,0x808080,0);
}
}
else
if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME) && !SOFTWARE)
{
switch (oi->prim)
{
case 2:
/*
BLOOM_draw(oi->x+270,oi->y+350,oi->z, 0,-255,0,0x7f6500,BLOOM_BEAM);
BLOOM_draw(oi->x-270,oi->y+350,oi->z, 0,-255,0,0x7f6500,BLOOM_BEAM);
BLOOM_draw(oi->x,oi->y+350,oi->z+270, 0,-255,0,0x7f6500,BLOOM_BEAM);
BLOOM_draw(oi->x,oi->y+350,oi->z-270, 0,-255,0,0x7f6500,BLOOM_BEAM);
*/
break;
case 190:
BLOOM_draw(oi->x,oi->y,oi->z, 0,0,0,0x808080,0);
break;
}
}
//
// As good a place as any to put this!
//
if (prim_objects[oi->prim].flag & PRIM_FLAG_ITEM)
{
OB_ob[oi->index].yaw += 1;
}
}
oi += 1;
}
}
}
LOG_EXIT ( AENG_Draw_Prims )
ANNOYINGSCRIBBLECHECK;
BreakTime("Drawn prims");
// POLY_frame_draw(FALSE,FALSE);
// POLY_frame_init(TRUE,TRUE);
// BreakTime("Flushed prims");
LOG_ENTER ( AENG_Draw_Facets )
POLY_set_local_rotation_none();
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
//
// The cached lighting for this low-res mapsquare.
//
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
//
// Look at the colvects on this square.
//
{
SLONG f_list;
SLONG facet;
SLONG build;
SLONG exit = FALSE;
f_list = PAP_2LO(x,z).ColVectHead;
show_gamut_lo(x,z);
if (f_list)
{
SLONG count=0;
while(!exit)
{
struct DFacet *p_vect;
facet=facet_links[f_list];
p_vect=&dfacets[facet];
/*
AENG_world_text(x<<10,(PAP_2HI(x<<2,z<<2).Alt<<3)+count*50,z<<10,128,128,128,1,"x %d z %d %d type %d",x,z,facet,p_vect->FacetType);
if(x==13 && z==5)
AENG_world_line_infinite(p_vect->X[0],p_vect->Y[0]+10+count*50,p_vect->Z[0],2,0xffffff,
p_vect->X[1],p_vect->Y[1]+10+count*50,p_vect->Z[1],2,0xffffff,0);
*/
count++;
ASSERT(facet);
if (facet < 0)
{
//
// The last facet in the list for each square
// is negative.
//
facet = -facet;
exit = TRUE;
}
if(dfacets[facet].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam])
{
// ASSERT(facet!=676);
//
// Mark this facet as drawn this gameturn already.
//
dfacets[facet].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam];
if(dfacets[facet].FacetType==STOREY_TYPE_NORMAL)
build = dfacets[facet].Building;
else
build = 0;
//
// Don't draw inside facets
//
if (build && dbuildings[build].Type == BUILDING_TYPE_CRATE_IN || (dfacets[facet].FacetFlags&FACET_FLAG_INSIDE))
{
//
// Don't draw inside buildings outside.
//
}
else
if (dfacets[facet].FacetType == STOREY_TYPE_DOOR)
{
//
// Draw the warehouse ground around this facet but don't draw
// the facet.
//
AENG_draw_box_around_recessed_door(&dfacets[facet], FALSE);
}
else
{
//
// Draw the facet.
//
show_facet(facet);
FACET_draw(facet,0);
//
// Has this facet's building been processed this
// gameturn yet?
//
switch(dfacets[facet].FacetType)
{
case STOREY_TYPE_NORMAL:
if (build)
{
if (dbuildings[build].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam])
{
//
// Draw all the walkable faces for this building.
//
FACET_draw_walkable(build);
//
// Mark the buiding as procesed this gameturn.
//
dbuildings[build].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam];
}
}
break;
}
}
}
f_list++;
}
}
}
}
}
BreakFacets(dfacets_drawn_this_gameturn);
BreakTime("Drawn facets");
// POLY_frame_draw(FALSE,FALSE);
// POLY_frame_init(TRUE,TRUE);
// BreakTime("Flushed facets");
LOG_EXIT ( AENG_Draw_Facets )
ANNOYINGSCRIBBLECHECK;
LOG_ENTER ( AENG_Draw_Other_Things )
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
//
// The cached lighting for this low-res mapsquare.
//
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Flags & FLAGS_IN_VIEW)
{
// p_thing->Flags &=~FLAGS_IN_VIEW;
switch(p_thing->DrawType)
{
case DT_NONE:
break;
case DT_BUILDING:
break;
case DT_PRIM:
break;
case DT_ANIM_PRIM:
extern void ANIM_obj_draw(Thing *p_thing,DrawTween *dt);
ANIM_obj_draw(p_thing,p_thing->Draw.Tweened);
if (p_thing->Class == CLASS_BAT &&
p_thing->Genus.Bat->type == BAT_TYPE_BANE)
{
DRAWXTRA_final_glow(
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y + 0x8000 >> 8,
p_thing->WorldPos.Z >> 8,
p_thing->Genus.Bat->glow >> 8);
}
break;
case DT_ROT_MULTI:
LOG_ENTER ( AENG_Draw_DT_ROT_MULTI )
/*
if (ControlFlag)
if (p_thing->Genus.Person->PlayerID)
{
//
// Draw some wheels above Darci's head!
//
AENG_set_bike_wheel_rotation((GAME_TURN << 3) & 2047, PRIM_OBJ_BIKE_BWHEEL);
MESH_draw_poly(
PRIM_OBJ_BIKE_BWHEEL,
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y + 0xa000 >> 8,
p_thing->WorldPos.Z >> 8,
p_thing->Draw.Tweened->Angle,
0,0,
NULL,0);
AENG_set_bike_wheel_rotation((GAME_TURN << 3) & 2047, PRIM_OBJ_VAN_WHEEL);
MESH_draw_poly(
PRIM_OBJ_VAN_WHEEL,
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y + 0x10000 >> 8,
p_thing->WorldPos.Z >> 8,
p_thing->Draw.Tweened->Angle,
0,0,
NULL,0);
AENG_set_bike_wheel_rotation((GAME_TURN << 3) & 2047, PRIM_OBJ_CAR_WHEEL);
MESH_draw_poly(
PRIM_OBJ_CAR_WHEEL,
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y + 0x16000 >> 8,
p_thing->WorldPos.Z >> 8,
p_thing->Draw.Tweened->Angle,
0,0,
NULL,0);
}
*/
{
ASSERT(p_thing->Class == CLASS_PERSON);
#ifdef BIKE
#error Better not be doing this.
//
// If this person is riding the bike...
//
if (p_thing->SubState == SUB_STATE_RIDING_BIKE)
{
Thing *p_bike = TO_THING(p_thing->Genus.Person->InCar);
ASSERT(p_thing->Genus.Person->Flags & FLAG_PERSON_BIKING);
ASSERT(p_thing->Genus.Person->InCar);
BIKE_Drawinfo bdi = BIKE_get_drawinfo(p_bike);
//
// Move to the same position above the bike.
//
GameCoord newpos = p_bike->WorldPos;
p_thing->Draw.Tweened->Angle = bdi.yaw;
p_thing->Draw.Tweened->Tilt = bdi.pitch;
p_thing->Draw.Tweened->Roll = bdi.roll;
/*
{
SLONG roll = bdi.roll;
if (roll > 1024)
{
roll -= 2048;
}
roll /= 2;
roll &= 2047;
p_thing->Draw.Tweened->Roll = roll;
}
*/
{
BIKE_Control bc;
DrawTween *dt = p_thing->Draw.Tweened;
SLONG steer;
bc = BIKE_control_get(p_bike);
steer=bc.steer>>1;
if(steer>32)
steer=32;
else
if(steer<-32)
steer=-32;
if(abs(steer)>21)
{
SLONG tween;
if(steer<0)
{
dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_RIGHT];
dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_RIGHT_FOOT];
tween = ((-steer)-21) << 5;
}
else
{
dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_LEFT];
dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_LEFT_FOOT];
tween = ((steer)-21) << 5;
}
if(tween<0)
tween=0;
if(tween>255)
tween=255;
dt->AnimTween=tween;
}
else
if (bc.steer == 0)
{
//dt->CurrentFrame = dt->TheChunk->AnimList[248];
//dt->NextFrame = dt->TheChunk->AnimList[248];
dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN];
dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN];
}
else
if (bc.steer < 0)
{
//dt->CurrentFrame = dt->TheChunk->AnimList[248];
//dt->NextFrame = dt->TheChunk->AnimList[250];
dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN];
dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_RIGHT];
dt->AnimTween = -steer << 3;
}
else
{
//dt->CurrentFrame = dt->TheChunk->AnimList[248];
//dt->NextFrame = dt->TheChunk->AnimList[252];
dt->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN];
dt->NextFrame = global_anim_array[p_thing->Genus.Person->AnimType][ANIM_BIKE_LEAN_LEFT];
dt->AnimTween = steer << 3;
}
}
{
GameCoord oldpos = p_thing->WorldPos;
p_thing->WorldPos = newpos;
FIGURE_draw(p_thing);
p_thing->WorldPos = oldpos;
}
/*
// p_person->Draw.Tweened->Roll = bdi.roll;//BIKE_get_roll(TO_THING(p_person->Genus.Person->InCar));
// p_person->Draw.Tweened->Tilt = bdi.pitch;
// if (p_person->Draw.Tweened.Roll > 1024)
*/
}
else
#endif
{
if (p_thing->Genus.Person->PlayerID)
{
if (FirstPersonMode)
{
FirstPersonAlpha -= (TICK_RATIO * 16) >> TICK_SHIFT;
if (FirstPersonAlpha < MAX_FPM_ALPHA) FirstPersonAlpha = MAX_FPM_ALPHA;
}
else
{
FirstPersonAlpha += (TICK_RATIO * 16) >> TICK_SHIFT;
if (FirstPersonAlpha > 255) FirstPersonAlpha = 255;
}
//FIGURE_alpha = FirstPersonAlpha;
FIGURE_draw(p_thing);
//FIGURE_alpha = 255;
}
else
{
SLONG dx,dy,dz,dist;
dx=abs((p_thing->WorldPos.X >> 8)-AENG_cam_x);
dy=abs((p_thing->WorldPos.Y >> 8)-AENG_cam_y);
dz=abs((p_thing->WorldPos.Z >> 8)-AENG_cam_z);
dist=QDIST3(dx,dy,dz);
if(dist<AENG_DRAW_PEOPLE_DIST)
{
FIGURE_draw(p_thing);
}
}
}
p_thing->Draw.Tweened->Drawn=(UBYTE)SUPERMAP_counter;
if (ControlFlag&&allow_debug_keys)
{
AENG_world_text(
(p_thing->WorldPos.X >> 8),
(p_thing->WorldPos.Y >> 8) + 0x60,
(p_thing->WorldPos.Z >> 8),
200,
180,
50,
TRUE,
PCOM_person_state_debug(p_thing));
}
#if DRAW_THIS_DEBUG_STUFF
AENG_world_line(
(p_thing->WorldPos.X >> 8),
(p_thing->WorldPos.Y >> 8) + 0x60,
(p_thing->WorldPos.Z >> 8),
32,
0x00ffffff,
(x << PAP_SHIFT_LO) + (1 << (PAP_SHIFT_LO - 1)),
(p_thing->WorldPos.Y >> 8),
(z << PAP_SHIFT_LO) + (1 << (PAP_SHIFT_LO - 1)),
0,
0x0000ff00,
FALSE);
#endif
}
#ifndef TARGET_DC
#if NO_MORE_BALLOONS
if (p_thing->Genus.Person->Balloon)
{
SLONG balloon;
BALLOON_Balloon *bb;
//
// Draw this person's balloon.
//
for (balloon = p_thing->Genus.Person->Balloon; balloon; balloon = BALLOON_balloon[balloon].next)
{
SHAPE_draw_balloon(balloon);
}
}
#endif
#endif
if (p_thing->State == STATE_DEAD)
{
if (p_thing->Genus.Person->Timer1 > 10)
{
if (p_thing->Genus.Person->PersonType == PERSON_MIB1 ||
p_thing->Genus.Person->PersonType == PERSON_MIB2 ||
p_thing->Genus.Person->PersonType == PERSON_MIB3)
{
//
// Dead MIB self destruct!
//
DRAWXTRA_MIB_destruct(p_thing);
/*
SLONG px;
SLONG py;
SLONG pz;
calc_sub_objects_position(
p_thing,
p_thing->Draw.Tweened->AnimTween,
SUB_OBJECT_PELVIS,
&px,
&py,
&pz);
px += p_thing->WorldPos.X >> 8;
py += p_thing->WorldPos.Y >> 8;
pz += p_thing->WorldPos.Z >> 8;
//
// Ripped from the DRAWXTRA_special!
//
// (So why didn't you put it there?!)
{
SLONG c0;
SLONG dx;
SLONG dz;
c0=3+(THING_NUMBER(p_thing)&7);
c0=(((GAME_TURN*c0)+(THING_NUMBER(p_thing)*9))<<4)&2047;
dx=SIN(c0)>>8;
dz=COS(c0)>>8;
BLOOM_draw(
px, py+15, pz,
dx,0,dz,0x9F2040,0);
}*/
}
}
}
if (p_thing->Genus.Person->pcom_ai == PCOM_AI_BANE)
{
DRAWXTRA_final_glow(
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y + 0x8000 >> 8,
p_thing->WorldPos.Z >> 8,
-p_thing->Draw.Tweened->Tilt);
}
LOG_EXIT ( AENG_Draw_DT_ROT_MULTI )
break;
case DT_EFFECT:
break;
case DT_MESH:
{
// Weapons & other powerups.
if (p_thing->Class == CLASS_SPECIAL) DRAWXTRA_Special(p_thing);
MESH_draw_poly(
p_thing->Draw.Mesh->ObjectId,
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y >> 8,
p_thing->WorldPos.Z >> 8,
p_thing->Draw.Mesh->Angle,
p_thing->Draw.Mesh->Tilt,
p_thing->Draw.Mesh->Roll,
NULL,0xff,0);
}
break;
#ifdef BIKE
#error A bike! Are you mad?
case DT_BIKE:
ASSERT(p_thing->Class == CLASS_BIKE);
{
//
// Nasty eh! But I can't be arsed to create a new drawtype.
//
BIKE_Drawinfo bdi = BIKE_get_drawinfo(p_thing);
//
// Draw the frame of the bike.
//
ANIM_obj_draw(p_thing, p_thing->Draw.Tweened);
//
// If the bike is parked or being mounted then the wheels are
// included in the animating object.
//
if (p_thing->Genus.Bike->mode == BIKE_MODE_DRIVING)
{
AENG_set_bike_wheel_rotation(bdi.front_rot, PRIM_OBJ_BIKE_BWHEEL);
MESH_draw_poly(
PRIM_OBJ_BIKE_BWHEEL,
bdi.front_x,
bdi.front_y,
bdi.front_z,
bdi.steer,
bdi.pitch,
bdi.roll,
NULL,0xff,0);
AENG_set_bike_wheel_rotation(bdi.back_rot, PRIM_OBJ_BIKE_BWHEEL);
MESH_draw_poly(
PRIM_OBJ_BIKE_BWHEEL,
bdi.back_x,
bdi.back_y,
bdi.back_z,
bdi.yaw,
0,
bdi.roll,
NULL,0xff,0);
}
// Now some bike fx... first the exhaust
PARTICLE_Exhaust2(p_thing, 5, 16);
if (!(NIGHT_flag & NIGHT_FLAG_DAYTIME))
{
SLONG matrix[9], vector[3], dx,dy,dz;
// FMATRIX_calc(matrix, 1024-bdi.steer, bdi.pitch, bdi.roll);
FMATRIX_calc(matrix, bdi.steer, bdi.pitch, bdi.roll);
FMATRIX_TRANSPOSE(matrix);
vector[2]=-255; vector[1]=0; vector[0]=0;
FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]);
dx=vector[0]; dy=vector[1]; dz=vector[2];
vector[2]=25; vector[1]=80; vector[0]=0;
FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]);
BLOOM_draw(bdi.front_x+vector[0],bdi.front_y+vector[1],bdi.front_z+vector[2],dx,dy,dz,0x606040,BLOOM_LENSFLARE|BLOOM_BEAM);
FMATRIX_calc(matrix, bdi.yaw, bdi.pitch, bdi.roll);
FMATRIX_TRANSPOSE(matrix);
vector[2]=255; vector[1]=0; vector[0]=0;
FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]);
dx=vector[0]; dy=vector[1]; dz=vector[2];
vector[2]=70; vector[1]=75; vector[0]=0;
FMATRIX_MUL(matrix,vector[0],vector[1],vector[2]);
BLOOM_draw(
(p_thing->WorldPos.X >> 8)+vector[0],
(p_thing->WorldPos.Y >> 8)+vector[1],
(p_thing->WorldPos.Z >> 8)+vector[2],
dx,dy,dz,0x800000,0);
}
}
break;
#endif
case DT_VEHICLE:
if(p_thing->Class==CLASS_VEHICLE)
{
if(p_thing->Genus.Vehicle->Driver)
{
TO_THING(p_thing->Genus.Vehicle->Driver)->Flags|=FLAGS_IN_VIEW;
}
}
//
// Set the tinted colour of this van.
//
{
#if 1
ULONG car_colours[6] =
{
0xffffff00,
0xffff00ff,
0xff00ffff,
0xffff0000,
0xff00ff00,
0xf00000ff
};
MESH_colour_and = car_colours[THING_NUMBER(p_thing) % 6];
#else
#define DEFCOL(R,G,B) (0xFF000000 | R | (G << 8) | (B << 16))
static DWORD colours[7] =
{
DEFCOL(18,192,120),
DEFCOL(255,14,90),
DEFCOL(112,122,216),
DEFCOL(176,158,54),
DEFCOL(0,149,186),
DEFCOL(194,162,34),
DEFCOL(255,255,255),
};
int col = THING_NUMBER(p_thing) % 7;
MESH_colour_and = colours[col];
#endif
}
extern void draw_car(Thing *p_car);
draw_car(p_thing);
#ifndef TARGET_DC
if (ControlFlag && allow_debug_keys)
{
//
// Draw a line towards where you have to be
// to get into the van.
//
SLONG dx = -SIN(p_thing->Genus.Vehicle->Draw.Angle);
SLONG dz = -COS(p_thing->Genus.Vehicle->Draw.Angle);
SLONG ix = p_thing->WorldPos.X >> 8;
SLONG iz = p_thing->WorldPos.Z >> 8;
ix += dx >> 9;
iz += dz >> 9;
ix -= dz >> 9;
iz += dx >> 9;
AENG_world_line(
p_thing->WorldPos.X >> 8, p_thing->WorldPos.Y >> 8, p_thing->WorldPos.Z >> 8, 64, 0x00ffffff,
ix, p_thing->WorldPos.Y >> 8, iz, 0, 0x0000ff00, TRUE);
}
#endif
break;
case DT_CHOPPER:
CHOPPER_draw_chopper(p_thing);
break;
case DT_PYRO:
PYRO_draw_pyro(p_thing);
break;
case DT_ANIMAL_PRIM:
#if 0
extern void ANIMAL_draw(Thing *p_thing);
ANIMAL_draw(p_thing);
#endif
break;
case DT_TRACK:
if(!INDOORS_INDEX)
TRACKS_DrawTrack(p_thing);
break;
default:
ASSERT(0);
break;
}
}
t_index = p_thing->Child;
}
}
}
LOG_EXIT ( AENG_Draw_Other_Things )
}
BreakTime("Drawn things");
LOG_EXIT ( AENG_Draw_Things )
ANNOYINGSCRIBBLECHECK;
// POLY_frame_draw(FALSE,FALSE);
// POLY_frame_init(TRUE,TRUE);
// BreakTime("Flushed things");
//
// debug info for the car movement
//
//void draw_car_tracks(void);
// if(!INDOORS_INDEX||outside)
// draw_car_tracks();
LOG_ENTER ( AENG_Draw_Oval_Shadows )
if(!SOFTWARE)
{
//
// Do oval shadows.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Flags & FLAGS_IN_VIEW)
{
bool draw = true;
for (int ii = 0; ii < shadow_person_upto; ii++)
{
if (shadow_person[ii].p_person == p_thing)
{
draw = false;
break;
}
}
if (draw)
{
switch(p_thing->Class)
{
case CLASS_PERSON:
{
SLONG px;
SLONG py;
SLONG pz;
calc_sub_objects_position(
p_thing,
p_thing->Draw.Tweened->AnimTween,
SUB_OBJECT_PELVIS,
&px,
&py,
&pz);
px += p_thing->WorldPos.X >> 8;
py += p_thing->WorldPos.Y >> 8;
pz += p_thing->WorldPos.Z >> 8;
OVAL_add(
px,
py,
pz,
130);
}
break;
case CLASS_SPECIAL:
OVAL_add(
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y >> 8,
p_thing->WorldPos.Z >> 8,
100);
break;
case CLASS_BARREL:
OVAL_add(
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y >> 8,
p_thing->WorldPos.Z >> 8,
128);
break;
default:
break;
}
}
}
t_index = p_thing->Child;
}
}
}
}
LOG_EXIT ( AENG_Draw_Oval_Shadows )
ANNOYINGSCRIBBLECHECK;
//
// The dirt.
//
LOG_ENTER ( AENG_Draw_Dirt )
if(!INDOORS_INDEX||outside)
if(AENG_detail_dirt)
AENG_draw_dirt();
LOG_EXIT ( AENG_Draw_Dirt )
// Cope with some wacky internals.
POLY_set_local_rotation_none();
POLY_flush_local_rot();
ANNOYINGSCRIBBLECHECK;
// Grenades should be drawn here.
DrawGrenades();
ANNOYINGSCRIBBLECHECK;
LOG_ENTER ( AENG_Draw_Ballons )
//
// The balloons that nobody is holding.
//
#ifndef TARGET_DC
if(!INDOORS_INDEX||outside)
AENG_draw_released_balloons();
#endif
LOG_EXIT ( AENG_Draw_Ballons )
ANNOYINGSCRIBBLECHECK;
//
// The POWs!
//
LOG_ENTER ( AENG_Draw_POWs )
AENG_draw_pows();
LOG_EXIT ( AENG_Draw_POWs )
ANNOYINGSCRIBBLECHECK;
//
// Draw the mist.
//
LOG_ENTER ( AENG_Draw_Mist )
if(!INDOORS_INDEX||outside)
if (AENG_detail_mist)
{
SLONG i;
SLONG sx;
SLONG sz;
SLONG px;
SLONG pz;
SLONG detail;
SLONG wx;
SLONG wy;
SLONG wz;
// Internal gubbins.
POLY_flush_local_rot();
POLY_Point *pp;
POLY_Point *quad[4];
#define MAX_MIST_DETAIL 32
POLY_Point mist_pp[MAX_MIST_DETAIL][MAX_MIST_DETAIL];
MIST_get_start();
while(detail = MIST_get_detail())
{
//
// Only draw as much as we can!
//
if (detail > MAX_MIST_DETAIL)
{
detail = MAX_MIST_DETAIL;
}
for (px = 0; px < detail; px++)
for (pz = 0; pz < detail; pz++)
{
pp = &mist_pp[px][pz];
MIST_get_point(px, pz,
&wx,
&wy,
&wz);
POLY_transform(
float(wx),
float(wy),
float(wz),
pp);
if (pp->MaybeValid())
{
pp->colour = 0x88666666;
pp->specular = 0xff000000;
MIST_get_texture(
px,
pz,
&pp->u,
&pp->v);
POLY_fadeout_point(pp);
}
}
for (sx = 0; sx < detail - 1; sx++)
for (sz = 0; sz < detail - 1; sz++)
{
quad[0] = &mist_pp[sx + 0][sz + 0];
quad[1] = &mist_pp[sx + 1][sz + 0];
quad[2] = &mist_pp[sx + 0][sz + 1];
quad[3] = &mist_pp[sx + 1][sz + 1];
if (POLY_valid_quad(quad))
{
POLY_add_quad(quad, POLY_PAGE_FOG, FALSE);
}
}
}
}
LOG_EXIT ( AENG_Draw_Mist )
ANNOYINGSCRIBBLECHECK;
//
// Rain.
//
LOG_ENTER ( AENG_Draw_Rain )
/*
#ifdef _DEBUG // about time we removed this kind of crap
if (Keys[KB_R] && !ShiftFlag)
{
Keys[KB_R] = 0;
GAME_FLAGS ^= GF_RAINING;
}
#endif
*/
if(!INDOORS_INDEX||outside)
{
if (GAME_FLAGS & GF_RAINING)
{
if(AENG_detail_rain)
AENG_draw_rain();
}
}
#ifdef _DEBUG
if(Keys[KB_N])
{
Keys[KB_N]=0;
if ((NIGHT_flag & NIGHT_FLAG_DAYTIME))
{
NIGHT_flag &=~NIGHT_FLAG_DAYTIME;
DETAIL_LEVEL|=DETAIL_RAIN;
}
else
{
NIGHT_flag |=NIGHT_FLAG_DAYTIME;
DETAIL_LEVEL&=~DETAIL_RAIN;
}
}
#endif
#if defined(_DEBUG) && defined(FAST_EDDIE) && 0
POLY_Point tpt[4];
POLY_Point *tptp[4];
tpt[0].X = 0; tpt[0].Y = 0; tpt[0].Z = 1; tpt[0].u = 0; tpt[0].v = 0;
tpt[1].X = 64; tpt[1].Y = 0; tpt[1].Z = 1; tpt[1].u = 1; tpt[1].v = 0;
tpt[2].X = 0; tpt[2].Y = 64; tpt[2].Z = 1; tpt[2].u = 0; tpt[2].v = 1;
tpt[3].X = 64; tpt[3].Y = 64; tpt[3].Z = 1; tpt[3].u = 1; tpt[3].v = 1;
tpt[0].colour = 0xFFFFFFFF; tpt[0].specular = 0xFF000000;
tpt[1].colour = 0xFFFFFFFF; tpt[1].specular = 0xFF000000;
tpt[2].colour = 0xFFFFFFFF; tpt[2].specular = 0xFF000000;
tpt[3].colour = 0xFFFFFFFF; tpt[3].specular = 0xFF000000;
tptp[0] = &tpt[0];
tptp[1] = &tpt[1];
tptp[2] = &tpt[2];
tptp[3] = &tpt[3];
POLY_add_quad(tptp, POLY_PAGE_TEST_SHADOWMAP, FALSE, TRUE);
#endif
LOG_EXIT ( AENG_Draw_Rain )
ANNOYINGSCRIBBLECHECK;
//
// Drawing the steam.
//
// void draw_steam(SLONG x,SLONG y,SLONG z,SLONG lod);
// void draw_flames(SLONG x,SLONG y,SLONG z,SLONG lod);
//
// Pyrotechincs.
//
LOG_ENTER ( AENG_Draw_Pyros )
if(!INDOORS_INDEX||outside)
AENG_draw_bangs();
if(!INDOORS_INDEX||outside)
AENG_draw_fire();
if(!INDOORS_INDEX||outside)
AENG_draw_sparks();
// ANEG_draw_messages();
LOG_EXIT ( AENG_Draw_Pyros )
ANNOYINGSCRIBBLECHECK;
/*
for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++)
{
PUDDLE_Info *pi;
SLONG sx,sy,sz;
SLONG dx,dy,dz,dist,lod;
PUDDLE_get_start(z, NGAMUT_gamut[z].xmin, NGAMUT_gamut[z].xmax);
while(pi = PUDDLE_get_next())
{
sx = (pi->x1+pi->x2)>>1;
sz = (pi->z1+pi->z2)>>1;
sy = pi->y;
dx=abs( ((SLONG)AENG_cam_x>>0)-sx);
// dy=abs( ((SLONG)AENG_cam_y>>0)-SLONG(world_y))*4;
dy=abs( ((SLONG)AENG_cam_y>>0)-sy);
dz=abs( ((SLONG)AENG_cam_z>>0)-sz);
dist=QDIST3(dx,dy,dz);
lod = 90-(dist/(32*2));
if(lod>0)
draw_steam(sx,sy,sz,lod);
// draw_flames(sx,sy,sz,lod);
}
}
*/
// if (Keys[KB_RBRACE] && !ShiftFlag) {Keys[KB_RBRACE] = 0; AENG_torch_on ^= TRUE;}
//
// Draw a torch out of darci...
//
#ifdef TARGET_DC
// No more torches.
ASSERT ( !AENG_torch_on );
#else
if (AENG_torch_on)
{
Thing *darci = NET_PERSON(0);
float angle;
float dx;
float dy;
float dz;
SLONG x;
SLONG y;
SLONG z;
calc_sub_objects_position(
darci,
darci->Draw.Tweened->AnimTween,
0, // Torso?
&x,
&y,
&z);
x += darci->WorldPos.X >> 8;
y += darci->WorldPos.Y >> 8;
z += darci->WorldPos.Z >> 8;
angle = float(darci->Draw.Tweened->Angle);
angle *= 2.0F * PI / 2048.0F;
float dyaw = ((float)sin(float(GAME_TURN) * 0.025F)) * 0.25F;
float dpitch = ((float)cos(float(GAME_TURN) * 0.020F) - 0.5F) * 0.25F;
float matrix[3];
dyaw += angle;
dyaw += PI;
MATRIX_vector(
matrix,
dyaw,
dpitch);
dx = matrix[0];
dy = matrix[1];
dz = matrix[2];
// experimental light bloom
// BLOOM_draw(x,y,z,dx*256,dy*256,dz*256,0x00666600);
BLOOM_draw(x,y,z,dx*256,dy*256,dz*256,0x00ffffa0);
CONE_create(
float(x),
float(y),
float(z),
dx,
dy,
dz,
256.0F * 4.0F,
256.0F,
0x00666600,
0x00000000,
50);
CONE_intersect_with_map();
// CONE_draw();
}
#endif
//
// Draw the tripwires.
//
LOG_ENTER ( AENG_Draw_Tripwires )
{
SLONG map_x1;
SLONG map_z1;
SLONG map_x2;
SLONG map_z2;
TRIP_Info *ti;
// Deal with internal bollocks.
POLY_flush_local_rot();
TRIP_get_start();
while(ti = TRIP_get_next())
{
//
// Check whether this tripwire is on the map.
//
map_x1 = ti->x1 >> 8;
map_z1 = ti->z1 >> 8;
map_x2 = ti->x2 >> 8;
map_z2 = ti->z2 >> 8;
if ((WITHIN(map_z1, NGAMUT_zmin, NGAMUT_zmax) && WITHIN(map_x1, NGAMUT_gamut[map_z1].xmin, NGAMUT_gamut[map_z1].xmax)) ||
(WITHIN(map_z2, NGAMUT_zmin, NGAMUT_zmax) && WITHIN(map_x2, NGAMUT_gamut[map_z2].xmin, NGAMUT_gamut[map_z2].xmax)))
{
//
// Draw the bugger.
//
#define AENG_TRIPWIRE_WIDTH 0x3
SHAPE_tripwire(
ti->x1,
ti->y,
ti->z1,
ti->x2,
ti->y,
ti->z2,
AENG_TRIPWIRE_WIDTH,
0x00661122,
ti->counter,
ti->along);
}
}
}
LOG_EXIT ( AENG_Draw_Tripwires )
ANNOYINGSCRIBBLECHECK;
//
// Draw the hook.
//
#ifndef TARGET_DC
if(!INDOORS_INDEX||outside)
AENG_draw_hook();
#endif
//
// Draw the sphere-matter.
//
LOG_ENTER ( AENG_Draw_Spherematter )
if(!INDOORS_INDEX||outside)
{
SM_Info *si;
SM_get_start();
while(si = SM_get_next())
{
SHAPE_sphere(
si->x,
si->y,
si->z,
si->radius,
si->colour);
}
}
LOG_EXIT ( AENG_Draw_Spherematter )
ANNOYINGSCRIBBLECHECK;
//
// Draw the drips... again!
//
LOG_ENTER ( AENG_Draw_Drips2 )
if(!INDOORS_INDEX||outside)
AENG_draw_drips(0);
LOG_EXIT ( AENG_Draw_Drips2 )
ANNOYINGSCRIBBLECHECK;
//
// Draw the particle system
//
LOG_ENTER ( AENG_Draw_Particles )
if(!INDOORS_INDEX||outside)
PARTICLE_Draw();
LOG_EXIT ( AENG_Draw_Particles )
ANNOYINGSCRIBBLECHECK;
//
// Draw the ribbon system
//
LOG_ENTER ( AENG_Draw_Ribbons )
if(!INDOORS_INDEX||outside)
RIBBON_draw();
LOG_EXIT ( AENG_Draw_Ribbons )
ANNOYINGSCRIBBLECHECK;
//
// Draw the tyre tracks (changed -- now turned into things)
//
/*
if (ControlFlag) {
TRACKS_Draw();
}*/
//
// Draw the cloth.
//
// if(!INDOORS_INDEX||outside)
// AENG_draw_cloth();
//
// Draw.
//
//
// Draw the people messages.
//
AENG_draw_people_messages();
// MSG_add(" draw insides %d and %d \n",INDOORS_INDEX,INDOORS_INDEX_NEXT);
/*
POLY_frame_draw(TRUE,TRUE);
if(INDOORS_INDEX_NEXT)
AENG_draw_inside_floor(INDOORS_INDEX_NEXT,INDOORS_ROOM_NEXT,255); //downtairs non transparent
POLY_frame_draw(TRUE,TRUE);
if(INDOORS_INDEX)
{
AENG_draw_inside_floor(INDOORS_INDEX,INDOORS_ROOM,INDOORS_INDEX_FADE);
}
*/
BreakTime("Drawn other crap");
LOG_ENTER ( AENG_Poly_Flush )
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
#endif
LOG_EXIT ( AENG_Poly_Flush )
BreakTime("Done final polygon flush");
ANNOYINGSCRIBBLECHECK;
// Tell the pyros we've done a frame.
Pyros_EndOfFrameMarker();
// ANEG_draw_messages();
/*
//
// This really _is_ shite!
//
if (ShiftFlag)
{
static float focus = 0.95F;
if (Keys[KB_P7]) {focus += 0.001F;}
if (Keys[KB_P4]) {focus -= 0.001F;}
POLY_frame_draw_focused(focus);
}
*/
// TRACE("Total polys = %d\n", AENG_total_polys_drawn);
//LOG_EXIT ( AENG_Draw_City )
LOG_EVENT ( AENG_Draw_End )
//TRACE ( "AengOut" );
}
void AENG_draw_far_facets(void)
{
SLONG x,z;
POLY_camera_set(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
129.0F*256.0F,//float(AENG_DRAW_DIST) * 256.0F*3.0F,
AENG_LENS,
POLY_SPLITSCREEN_NONE);
AENG_calc_gamut_lo_only(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
64.0F*256.0F,//AENG_DRAW_DIST*3,
AENG_LENS);
#ifdef DEBUG
SLONG count = 0;
#endif
LOG_ENTER ( Skyline_Scan_Map_Square )
for (z = AENG_gamut_lo_zmin; z <= AENG_gamut_lo_zmax; z++)
{
for (x = AENG_gamut_lo_xmin; x <= AENG_gamut_lo_xmax; x++)
{
//
// The cached lighting for this low-res mapsquare.
//
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
//
// Look at the colvects on this square.
//
{
SLONG f_list;
SLONG facet;
SLONG build;
SLONG exit = FALSE;
f_list = PAP_2LO(x,z).ColVectHead;
if (f_list)
{
LOG_ENTER ( Skyline_Draw_Facet )
while(!exit)
{
struct DFacet *p_vect;
facet=facet_links[f_list];
p_vect=&dfacets[facet];
ASSERT(facet);
if (facet < 0)
{
//
// The last facet in the list for each square
// is negative.
//
facet = -facet;
exit = TRUE;
}
if(dfacets[facet].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam])
{
dfacets[facet].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam];
if(dfacets[facet].FacetType==STOREY_TYPE_NORMAL)
build = dfacets[facet].Building;
else
build = 0;
//
// Don't draw inside facets
//
if (build && dbuildings[build].Type == BUILDING_TYPE_CRATE_IN || (dfacets[facet].FacetFlags&FACET_FLAG_INSIDE))
{
//
// Don't draw inside buildings outside.
//
}
else
if (dfacets[facet].FacetType == STOREY_TYPE_DOOR)
{
}
else
{
//
// Draw the facet.
//
show_facet(facet);
extern void FACET_draw_quick(SLONG facet,UBYTE alpha);
FACET_draw_quick(facet,0);
#ifdef DEBUG
count++;
#endif
}
}
f_list++;
}
LOG_EXIT ( Skyline_Draw_Facet )
}
}
}
}
//TRACE("Far facets = %d\n", count);
LOG_EXIT ( Skyline_Scan_Map_Square )
POLY_camera_set(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
float(AENG_DRAW_DIST) * 256.0F,
AENG_LENS,
POLY_SPLITSCREEN_NONE);
}
//
// Draws the warehouse that they player is in.
//
void AENG_draw_warehouse()
{
SLONG i;
SLONG x;
SLONG z;
SLONG dx;
SLONG dz;
SLONG px;
SLONG pz;
SLONG dist;
SLONG t_index;
SLONG square;
SLONG build;
SLONG page;
SLONG facet;
SLONG f_list;
SLONG exit;
SLONG balloon;
SLONG dfcache;
SLONG next;
ULONG colour;
ULONG specular;
float world_x;
float world_y;
float world_z;
//
// No cloud inside warehouses!
//
SLONG old_aeng_draw_cloud_flag = aeng_draw_cloud_flag; FALSE;
aeng_draw_cloud_flag = FALSE;
Thing *p_thing;
OB_Info *oi;
PAP_Hi *ph;
NIGHT_Square *nq;
NIGHT_Colour *col;
NIGHT_Dfcache *ndf;
POLY_Point *pp;
DFacet *df;
#ifndef TARGET_DC
//BALLOON_Balloon *bb;
#endif
POLY_Point *quad[4];
//POLY_frame_init(FALSE,FALSE);
#ifndef TARGET_DC
POLY_frame_init(FALSE,FALSE);
#endif
//
// Work out which things are in view.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
switch(p_thing->Class)
{
case CLASS_PERSON:
//
// Only draw people who are in warehouses.
//
if(p_thing->Genus.Person->PlayerID && (p_thing->Genus.Person->Flags & FLAG_PERSON_WAREHOUSE))
p_thing->Flags |= FLAGS_IN_VIEW;
else
if (p_thing->Genus.Person->Flags & FLAG_PERSON_WAREHOUSE)
{
if (POLY_sphere_visible(
float(p_thing->WorldPos.X >> 8),
float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT,
float(p_thing->WorldPos.Z >> 8),
256.0F / (AENG_DRAW_DIST * 256.0F)))
{
p_thing->Flags |= FLAGS_IN_VIEW;
}
}
break;
default:
//
// Draw everything else that is on a HIDDEN square (i.e. is inside the
// floorplan of the warehouse)
//
if (PAP_2HI(p_thing->WorldPos.X >> 16, p_thing->WorldPos.Z >> 16).Flags & PAP_FLAG_HIDDEN)
{
p_thing->Flags |= FLAGS_IN_VIEW;
}
break;
}
t_index = p_thing->Child;
}
NIGHT_square[NIGHT_cache[x][z]].flag &= ~NIGHT_SQUARE_FLAG_DELETEME;
}
}
//
// Rotate all the points.
//
#ifndef NEW_FLOOR
for (z = NGAMUT_point_zmin; z <= NGAMUT_point_zmax; z++)
{
for (x = NGAMUT_point_gamut[z].xmin; x <= NGAMUT_point_gamut[z].xmax; x++)
{
ASSERT(WITHIN(x, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_HI - 1));
ph = &PAP_2HI(x,z);
//
// We only have upper points inside a warehouse.
//
world_x = x * 256.0F;
world_y = ph->Alt * float(1 << ALT_SHIFT);
world_z = z * 256.0F;
pp = &AENG_upper[x & 63][z & 63];
POLY_transform(
world_x,
world_y,
world_z,
pp);
if (pp->MaybeValid())
{
//
// Work out the colour of this point... what a palaver!
//
px = x >> 2;
pz = z >> 2;
dx = x & 0x3;
dz = z & 0x3;
ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1));
square = NIGHT_cache[px][pz];
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
nq = &NIGHT_square[square];
NIGHT_get_d3d_colour(
nq->colour[dx + dz * PAP_BLOCKS],
&pp->colour,
&pp->specular);
apply_cloud((SLONG)world_x,(SLONG)world_y,(SLONG)world_z,&pp->colour);
POLY_fadeout_point(pp);
colour = pp->colour;
specular = pp->specular;
}
}
}
#endif
//
// Who shall we generate shadows for?
//
if (AENG_shadows_on)
{
Thing *darci = NET_PERSON(0);
//
// How many people do we generate shadows for?
//
#define AENG_NUM_SHADOWS 4
struct
{
Thing *p_person;
SLONG dist;
} shadow_person[AENG_NUM_SHADOWS];
SLONG shadow_person_upto = 0;
SLONG shadow_person_worst_dist = -INFINITY;
SLONG shadow_person_worst_person;
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Class == CLASS_PERSON && (p_thing->Flags & FLAGS_IN_VIEW))
{
//
// Distance from darci.
//
dx = p_thing->WorldPos.X - darci->WorldPos.X;
dz = p_thing->WorldPos.Z - darci->WorldPos.Z;
dist = abs(dx) + abs(dz);
if (dist < 0x60000)
{
if (shadow_person_upto < AENG_NUM_SHADOWS)
{
//
// Put this person in the shadow array.
//
shadow_person[shadow_person_upto].p_person = p_thing;
shadow_person[shadow_person_upto].dist = dist;
//
// Keep track of the furthest person away.
//
if (dist > shadow_person_worst_dist)
{
shadow_person_worst_dist = dist;
shadow_person_worst_person = shadow_person_upto;
}
shadow_person_upto += 1;
}
else
{
if (dist < shadow_person_worst_dist)
{
//
// Replace the worst person.
//
ASSERT(WITHIN(shadow_person_worst_person, 0, AENG_NUM_SHADOWS - 1));
shadow_person[shadow_person_worst_person].p_person = p_thing;
shadow_person[shadow_person_worst_person].dist = dist;
//
// Find the worst person
//
shadow_person_worst_dist = -INFINITY;
for (i = 0; i < AENG_NUM_SHADOWS; i++)
{
if (shadow_person[i].dist > shadow_person_worst_dist)
{
shadow_person_worst_dist = shadow_person[i].dist;
shadow_person_worst_person = i;
}
}
}
}
}
}
t_index = p_thing->Child;
}
}
}
//
// Draw the people's shadow maps.
//
SLONG offset_x;
SLONG offset_y;
for (i = 0; i < shadow_person_upto; i++)
{
darci = shadow_person[i].p_person;
memset(AENG_aa_buffer, 0, sizeof(AENG_aa_buffer));
SMAP_person(
darci,
(UBYTE *) AENG_aa_buffer,
AENG_AA_BUF_SIZE,
AENG_AA_BUF_SIZE,
0,
-255,
-0);
//
// Where do we put it in the shadow texture page? Hard code everything!
//
ASSERT(AENG_AA_BUF_SIZE == 32);
ASSERT(TEXTURE_SHADOW_SIZE == 64);
offset_x = (i & 1) << 5;
offset_y = (i & 2) << 4;
//
// Plonk it into the shadow texture page.
//
if (TEXTURE_shadow_lock())
{
SLONG x;
SLONG y;
UWORD *line;
UBYTE *buf = (UBYTE *) AENG_aa_buffer;
UWORD* mapping = GetShadowPixelMapping();
for (y = 0; y < AENG_AA_BUF_SIZE; y++)
{
line = &TEXTURE_shadow_bitmap[((y + offset_y) * TEXTURE_shadow_pitch >> 1) + offset_x];
for (x = AENG_AA_BUF_SIZE - 1; x >= 0; x--)
{
*line++ = mapping[*buf++];
}
}
TEXTURE_shadow_unlock();
}
//
// How we map floating points coordinates from 0 to 1 onto
// where we plonked the shadow map in the texture page.
//
AENG_project_offset_u = float(offset_x) / float(TEXTURE_SHADOW_SIZE);
AENG_project_offset_v = float(offset_y) / float(TEXTURE_SHADOW_SIZE);
AENG_project_mul_u = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE);
AENG_project_mul_v = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE);
{
//
// Map this poly onto the mapsquares surrounding darci.
//
SLONG i;
SLONG mx;
SLONG mz;
SLONG dx;
SLONG dz;
SLONG mx1;
SLONG mz1;
SLONG mx2;
SLONG mz2;
SLONG exit = FALSE;
SLONG mx_lo;
SLONG mz_lo;
#ifndef TARGET_DC
MapElement *me[4];
#endif
PAP_Hi *ph[4];
SVector_F poly[4];
SMAP_Link *projected;
SLONG v_list;
SLONG i_vect;
DFacet *df;
SLONG w_list;
SLONG w_face;
PrimFace4 *p_f4;
PrimPoint *pp;
SLONG wall;
SLONG storey;
SLONG building;
SLONG thing;
SLONG face_height;
UBYTE face_order[4] = {0,1,3,2};
Thing *p_fthing;
//
// Colvects we have already done.
//
#define AENG_MAX_DONE 8
SLONG done[AENG_MAX_DONE];
SLONG done_upto = 0;
for (dx = -1; dx <= 1; dx++)
for (dz = -1; dz <= 1; dz++)
{
mx = (darci->WorldPos.X >> 16) + dx;
mz = (darci->WorldPos.Z >> 16) + dz;
if (WITHIN(mx, 0, MAP_WIDTH - 2) &&
WITHIN(mz, 0, MAP_HEIGHT - 2))
{
#ifndef TARGET_DC
me[0] = &MAP[MAP_INDEX(mx + 0, mz + 0)];
me[1] = &MAP[MAP_INDEX(mx + 1, mz + 0)];
me[2] = &MAP[MAP_INDEX(mx + 1, mz + 1)];
me[3] = &MAP[MAP_INDEX(mx + 0, mz + 1)];
#endif
ph[0] = &PAP_2HI(mx + 0, mz + 0);
ph[1] = &PAP_2HI(mx + 1, mz + 0);
ph[2] = &PAP_2HI(mx + 1, mz + 1);
ph[3] = &PAP_2HI(mx + 0, mz + 1);
if (PAP_2HI(mx,mz).Flags & PAP_FLAG_HIDDEN)
{
poly[3].X = float(mx << 8);
poly[3].Y = float(ph[0]->Alt << ALT_SHIFT);
poly[3].Z = float(mz << 8);
poly[0].X = poly[3].X + 256.0F;
poly[0].Y = float(ph[1]->Alt << ALT_SHIFT);
poly[0].Z = poly[3].Z;
poly[1].X = poly[3].X + 256.0F;
poly[1].Y = float(ph[2]->Alt << ALT_SHIFT);
poly[1].Z = poly[3].Z + 256.0F;
poly[2].X = poly[3].X;
poly[2].Y = float(ph[3]->Alt << ALT_SHIFT);
poly[2].Z = poly[3].Z + 256.0F;
if (ph[0]->Alt == ph[1]->Alt &&
ph[0]->Alt == ph[2]->Alt &&
ph[0]->Alt == ph[3]->Alt)
{
//
// This quad is coplanar.
//
projected = SMAP_project_onto_poly(poly, 4);
if (projected)
{
AENG_add_projected_shadow_poly(projected);
}
}
else
{
//
// Do each triangle separatly.
//
projected = SMAP_project_onto_poly(poly, 3);
if (projected)
{
AENG_add_projected_fadeout_shadow_poly(projected);
}
//
// The triangles are 0,1,2 and 0,2,3.
//
poly[1] = poly[0];
projected = SMAP_project_onto_poly(poly + 1, 3);
if (projected)
{
AENG_add_projected_fadeout_shadow_poly(projected);
}
}
}
}
}
mx1 = (darci->WorldPos.X >> 8) - 0x100 >> PAP_SHIFT_LO;
mz1 = (darci->WorldPos.Z >> 8) - 0x100 >> PAP_SHIFT_LO;
mx2 = (darci->WorldPos.X >> 8) + 0x100 >> PAP_SHIFT_LO;
mz2 = (darci->WorldPos.Z >> 8) + 0x100 >> PAP_SHIFT_LO;
SATURATE(mx1, 0, PAP_SIZE_LO - 1);
SATURATE(mz1, 0, PAP_SIZE_LO - 1);
SATURATE(mx2, 0, PAP_SIZE_LO - 1);
SATURATE(mz2, 0, PAP_SIZE_LO - 1);
for (mx_lo = mx1; mx_lo <= mx2; mx_lo++)
for (mz_lo = mz1; mz_lo <= mz2; mz_lo++)
{
//
// Cast shadow on walkable faces.
//
w_face = PAP_2LO(mx_lo,mz_lo).Walkable;
while(w_face)
{
if (w_face > 0)
{
p_f4 = &prim_faces4[w_face];
face_height = prim_points[p_f4->Points[0]].Y;
if (face_height > ((darci->WorldPos.Y + 0x11000) >> 8))
{
//
// This face is above Darci, so don't put her shadow
// on it.
//
}
else
{
for (i = 0; i < 4; i++)
{
pp = &prim_points[p_f4->Points[face_order[i]]];
poly[i].X = float(pp->X);
poly[i].Y = float(pp->Y);
poly[i].Z = float(pp->Z);
}
projected = SMAP_project_onto_poly(poly, 4);
if (projected)
{
AENG_add_projected_shadow_poly(projected);
}
}
w_face = p_f4->Col2;
}
else
{
struct RoofFace4 *rf;
rf = &roof_faces4[-w_face];
face_height = rf->Y;
if (face_height > ((darci->WorldPos.Y + 0x11000) >> 8))
{
//
// This face is above Darci, so don't put her shadow
// on it.
//
}
else
{
SLONG mx,mz;
mx=(rf->RX&127)<<8;
mz=(rf->RZ&127)<<8;
poly[0].X=(float)(mx);
poly[0].Y=(float)(rf->Y);
poly[0].Z=(float)(mz);
poly[1].X=(float)((mx)+256);
poly[1].Y=(float)(rf->Y+(rf->DY[0]<<ROOF_SHIFT));
poly[1].Z=(float)((mz));
poly[2].X=(float)((mx)+256);
poly[2].Y=(float)(rf->Y+(rf->DY[1]<<ROOF_SHIFT));
poly[2].Z=(float)((mz)+256);
poly[3].X=(float)((mx));
poly[3].Y=(float)(rf->Y+(rf->DY[2]<<ROOF_SHIFT));
poly[3].Z=(float)((mz)+256);
//
// Assuming its coplanar!
//
projected = SMAP_project_onto_poly(poly, 4);
if (projected)
{
AENG_add_projected_shadow_poly(projected);
}
}
w_face = rf->Next;
}
}
}
}
TEXTURE_shadow_update();
}
}
else
{
//
// Do oval shadows instead!
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Flags & FLAGS_IN_VIEW)
{
switch(p_thing->Class)
{
case CLASS_PERSON:
OVAL_add(
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y >> 8,
p_thing->WorldPos.Z >> 8,
32);
break;
case CLASS_SPECIAL:
OVAL_add(
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y >> 8,
p_thing->WorldPos.Z >> 8,
16);
break;
case CLASS_BARREL:
OVAL_add(
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y >> 8,
p_thing->WorldPos.Z >> 8,
32);
break;
default:
break;
}
}
t_index = p_thing->Child;
}
}
}
}
#ifdef NEW_FLOOR
draw_quick_floor(1);
#endif
//
// Create all the squares.
//
#ifndef NEW_FLOOR
for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++)
{
for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++)
{
ASSERT(WITHIN(x, 0, PAP_SIZE_HI - 2));
ASSERT(WITHIN(z, 0, PAP_SIZE_HI - 2));
ph = &PAP_2HI(x,z);
if (!(ph->Flags & PAP_FLAG_HIDDEN))
{
//
// We only draw hidden squares!
//
continue;
}
//
// The four points of the quad.
//
quad[0] = &AENG_upper[(x + 0) & 63][(z + 0) & 63];
quad[1] = &AENG_upper[(x + 1) & 63][(z + 0) & 63];
quad[2] = &AENG_upper[(x + 0) & 63][(z + 1) & 63];
quad[3] = &AENG_upper[(x + 1) & 63][(z + 1) & 63];
if (POLY_valid_quad(quad))
{
TEXTURE_get_minitexturebits_uvs(
ph->Texture,
&page,
&quad[0]->u,
&quad[0]->v,
&quad[1]->u,
&quad[1]->v,
&quad[2]->u,
&quad[2]->v,
&quad[3]->u,
&quad[3]->v);
POLY_add_quad(quad, page, TRUE);
}
}
}
#endif
//
// Draw the objects and the things.
//
SLONG pos = 0;
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
/*
{
CBYTE str[20];
sprintf(str, "%d,%d", x, z);
FONT2D_DrawString(str, (pos & 7) * 60 + 20, (pos >> 3) * 20 + 200, 0xff00ff);
}
pos += 1;
*/
//
// The cached lighting for this low-res mapsquare.
//
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(NIGHT_cache[x][z], 1, NIGHT_MAX_SQUARES - 1));
col = NIGHT_square[NIGHT_cache[x][z]].colour;
//
// Skip over the mapsquares.
//
col += PAP_BLOCKS * PAP_BLOCKS;
//
// The objects on this mapsquare.
//
oi = OB_find(x,z);
while(oi->prim)
{
//
// Only draw objects that are in buildings. (Assume that means our warehouse!)
//
if (oi->flags & OB_FLAG_WAREHOUSE)
{
if (oi->prim == 235)
{
oi->yaw = GAME_TURN;
}
col = MESH_draw_poly(
oi->prim,
oi->x,
oi->y,
oi->z,
oi->yaw,
oi->pitch,
oi->roll,
col,0xff,0);
//
// As good a place as any to put this!
//
if (prim_objects[oi->prim].flag & PRIM_FLAG_ITEM)
{
OB_ob[oi->index].yaw += 1;
}
}
oi += 1;
}
//
// Draw the facets on this square.
//
f_list = PAP_2LO(x,z).ColVectHead;
if (f_list)
{
exit = FALSE;
while(!exit)
{
facet = facet_links[f_list];
ASSERT(facet);
if (facet < 0)
{
//
// The last facet in the list for each square is negative.
//
facet = -facet;
exit = TRUE;
}
df = &dfacets[facet];
if ( ( df->FacetType == STOREY_TYPE_NORMAL ) || ( df->FacetType == STOREY_TYPE_DOOR ) ||( df->FacetType == STOREY_TYPE_FENCE )||( df->FacetType == STOREY_TYPE_FENCE_FLAT ))
{
build = df->Building;
//
// Has this facet's building been processed this gameturn yet?
//
if (df->Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam])
{
//
// warehouse walls only drawn if they are inside walls
//
if ( (dbuildings[build].Type == BUILDING_TYPE_WAREHOUSE && (df->FacetFlags&FACET_FLAG_INSIDE))||
dbuildings[build].Type == BUILDING_TYPE_CRATE_IN||df->FacetType == STOREY_TYPE_DOOR)
{
//
// Draw the facet.
//
if (df->FacetType == STOREY_TYPE_DOOR)
{
//
// Draw the outside around this facet but don't draw
//
AENG_draw_box_around_recessed_door(&dfacets[facet], TRUE);
}
else
//if (df->FacetType == STOREY_TYPE_NORMAL) Why only draw normal facets?
{
FACET_draw(facet,0);
build = df->Building;
if (df->FacetType == STOREY_TYPE_NORMAL) //Why only draw normal facets?
if (build)
{
if (dbuildings[build].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam])
{
//
// Draw all the walkable faces for this building.
//
FACET_draw_walkable(build);
//
// Mark the buiding as procesed this gameturn.
//
dbuildings[build].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam];
}
}
}
}
//
// Mark this facet as drawn this gameturn already.
//
dfacets[facet].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam];
}
}
f_list++;
}
}
//
// Draw the things.
//
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Flags & FLAGS_IN_VIEW)
{
switch(p_thing->DrawType)
{
case DT_NONE:
break;
case DT_BUILDING:
break;
case DT_PRIM:
break;
case DT_ANIM_PRIM:
ANIM_obj_draw(p_thing,p_thing->Draw.Tweened);
break;
case DT_ROT_MULTI:
ASSERT(p_thing->Class == CLASS_PERSON);
if (p_thing->Genus.Person->PlayerID)
{
if (FirstPersonMode)
{
FirstPersonAlpha -= (TICK_RATIO * 16) >> TICK_SHIFT;
if (FirstPersonAlpha < MAX_FPM_ALPHA) FirstPersonAlpha = MAX_FPM_ALPHA;
}
else
{
FirstPersonAlpha += (TICK_RATIO * 16) >> TICK_SHIFT;
if (FirstPersonAlpha > 255) FirstPersonAlpha = 255;
}
//FIGURE_alpha = FirstPersonAlpha;
FIGURE_draw(p_thing);
//FIGURE_alpha = 255;
}
else
{
SLONG dx,dy,dz,dist;
dx=abs((p_thing->WorldPos.X >> 8)-AENG_cam_x);
dy=abs((p_thing->WorldPos.Y >> 8)-AENG_cam_y);
dz=abs((p_thing->WorldPos.Z >> 8)-AENG_cam_z);
dist=QDIST3(dx,dy,dz);
if(dist<AENG_DRAW_PEOPLE_DIST)
{
FIGURE_draw(p_thing);
}
}
#if NO_MORE_BALLOONS_NOW
if (p_thing->Genus.Person->Balloon)
{
//
// Draw this person's balloon.
//
for (balloon = p_thing->Genus.Person->Balloon; balloon; balloon = BALLOON_balloon[balloon].next)
{
SHAPE_draw_balloon(balloon);
}
}
#endif
if (ControlFlag&&allow_debug_keys)
{
AENG_world_text(
(p_thing->WorldPos.X >> 8),
(p_thing->WorldPos.Y >> 8) + 0x60,
(p_thing->WorldPos.Z >> 8),
200,
180,
50,
TRUE,
PCOM_person_state_debug(p_thing));
}
if ((p_thing->State == STATE_DEAD)&&(p_thing->Genus.Person->Timer1 > 10))
{
if (p_thing->Genus.Person->PersonType == PERSON_MIB1 ||
p_thing->Genus.Person->PersonType == PERSON_MIB2 ||
p_thing->Genus.Person->PersonType == PERSON_MIB3)
{
//
// Dead MIB self destruct!
//
DRAWXTRA_MIB_destruct(p_thing);
}
}
break;
case DT_EFFECT:
break;
case DT_MESH:
if (p_thing->Class == CLASS_SPECIAL)
{
DRAWXTRA_Special(p_thing);
}
if (p_thing->Class == CLASS_BIKE)
{
//
// There shouldn't be any bikes indoors.
//
ASSERT(0);
}
else
{
MESH_draw_poly(
p_thing->Draw.Mesh->ObjectId,
p_thing->WorldPos.X >> 8,
p_thing->WorldPos.Y >> 8,
p_thing->WorldPos.Z >> 8,
p_thing->Draw.Mesh->Angle,
p_thing->Draw.Mesh->Tilt,
p_thing->Draw.Mesh->Roll,
NULL,0xff,0);
}
break;
case DT_VEHICLE:
case DT_CHOPPER:
//
// There shouldn't be any vehicles or helicopters indoors.
//
break;
case DT_PYRO:
PYRO_draw_pyro(p_thing);
break;
case DT_ANIMAL_PRIM:
#if 0
ANIMAL_draw(p_thing);
#endif
break;
case DT_TRACK:
TRACKS_DrawTrack(p_thing);
break;
default:
break;
}
}
t_index = p_thing->Child;
}
}
}
//
// Now draw the special fx that somebody left out before
//
POLY_set_local_rotation_none();
PARTICLE_Draw();
RIBBON_draw();
AENG_draw_sparks();
//
// Now actually draw everything!
//
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
#endif
//
// Restore cloud to default value.
//
aeng_draw_cloud_flag = old_aeng_draw_cloud_flag;
}
//
// For drawing water.
//
#ifdef EDITOR
typedef struct
{
UBYTE height[4];
POLY_Point pp[4];
} AENG_Nswater;
AENG_Nswater AENG_nswater[5][5];
void AENG_draw_ns()
{
SLONG i;
SLONG j;
SLONG k;
SLONG x;
SLONG z;
float base_x;
float base_z;
float px;
float py;
float pz;
SLONG x1;
SLONG z1;
SLONG x2;
SLONG z2;
SLONG dropx;
SLONG dropy;
SLONG dropz;
SLONG dropdx;
SLONG dropdy;
SLONG dropdz;
SLONG along;
SLONG bx;
SLONG bz;
SLONG dx;
SLONG dz;
SLONG dist;
SLONG dsx;
SLONG dsz;
SLONG sx;
SLONG sz;
SLONG ix;
SLONG iz;
SLONG page;
NS_Cache *nc;
NS_Point *np;
NS_Face *nf;
NS_Texture *nt;
NS_Lo *nl;
NS_St *nst;
POLY_Point *pp;
POLY_Point *quad[4];
THING_INDEX t_index;
Thing *p_thing;
static bright = FALSE;
if (Keys[KB_COLON])
{
Keys[KB_COLON] = 0;
bright ^= TRUE;
}
//
// Where we remember the bounding boxes of reflections.
//
struct
{
SLONG x1;
SLONG y1;
SLONG x2;
SLONG y2;
} bbox[AENG_MAX_BBOXES];
SLONG bbox_upto = 0;
//
// Create the gamut
//
AENG_calc_gamut(
AENG_cam_x,
AENG_cam_y,
AENG_cam_z,
AENG_cam_yaw,
AENG_cam_pitch,
AENG_cam_roll,
AENG_DRAW_DIST,
AENG_LENS);
//
// Start the frame.
//
#ifndef TARGET_DC
POLY_frame_init(TRUE, TRUE);
#endif
//
// Go through the cache squares and free any we don't need.
//
for (i = 1; i < NS_MAX_CACHES; i++)
{
nc = &NS_cache[i];
if (nc->used)
{
ASSERT(WITHIN(nc->map_x, 1, PAP_SIZE_LO - 2));
ASSERT(WITHIN(nc->map_z, 1, PAP_SIZE_LO - 2));
if (!WITHIN(nc->map_z, NGAMUT_lo_zmin, NGAMUT_lo_zmax) ||
!WITHIN(nc->map_x, NGAMUT_lo_gamut[nc->map_z].xmin, NGAMUT_lo_gamut[nc->map_z].xmax))
{
//
// We don't need this any more.
//
NS_cache_destroy(i);
}
}
}
//
// Shadows.
//
if (Keys[KB_3]) {Keys[KB_3] = 0; AENG_shadows_on ^= TRUE;}
if (AENG_shadows_on)
{
Thing *darci = NET_PERSON(0);
//
// Find the 'AENG_NUM_SHADOWS' nearest people to generate shadows for.
//
struct
{
Thing *p_person;
SLONG dist;
} shadow_person[AENG_NUM_SHADOWS];
SLONG shadow_person_upto = 0;
SLONG shadow_person_worst_dist = -INFINITY;
SLONG shadow_person_worst_person;
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (p_thing->Class == CLASS_PERSON && (p_thing->Flags & FLAGS_IN_SEWERS))
{
if (POLY_sphere_visible(
float(p_thing->WorldPos.X >> 8),
float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT,
float(p_thing->WorldPos.Z >> 8),
256.0F / (AENG_DRAW_DIST * 256.0F)))
{
//
// Distance from darci.
//
dx = p_thing->WorldPos.X - darci->WorldPos.X;
dz = p_thing->WorldPos.Z - darci->WorldPos.Z;
dist = abs(dx) + abs(dz);
if (shadow_person_upto < AENG_NUM_SHADOWS)
{
//
// Put this person in the shadow array.
//
shadow_person[shadow_person_upto].p_person = p_thing;
shadow_person[shadow_person_upto].dist = dist;
//
// Keep track of the furthest person away.
//
if (dist > shadow_person_worst_dist)
{
shadow_person_worst_dist = dist;
shadow_person_worst_person = shadow_person_upto;
}
shadow_person_upto += 1;
}
else
{
if (dist < shadow_person_worst_dist)
{
//
// Replace the worst person.
//
ASSERT(WITHIN(shadow_person_worst_person, 0, AENG_NUM_SHADOWS - 1));
shadow_person[shadow_person_worst_person].p_person = p_thing;
shadow_person[shadow_person_worst_person].dist = dist;
//
// Find the worst person
//
shadow_person_worst_dist = -INFINITY;
for (i = 0; i < AENG_NUM_SHADOWS; i++)
{
if (shadow_person[i].dist > shadow_person_worst_dist)
{
shadow_person_worst_dist = shadow_person[i].dist;
shadow_person_worst_person = i;
}
}
}
}
}
}
t_index = p_thing->Child;
}
}
}
//
// Draw the people's shadow maps.
//
SLONG mx;
SLONG mz;
SLONG light_x;
SLONG light_y;
SLONG light_z;
SLONG light_dx;
SLONG light_dy;
SLONG light_dz;
SLONG offset_x;
SLONG offset_y;
NS_Lo *nl;
for (i = 0; i < shadow_person_upto; i++)
{
darci = shadow_person[i].p_person;
mx = darci->WorldPos.X >> (8 + PAP_SHIFT_LO);
mz = darci->WorldPos.Z >> (8 + PAP_SHIFT_LO);
if (!WITHIN(mx, 0, PAP_SIZE_LO - 1) ||
!WITHIN(mz, 0, PAP_SIZE_LO - 1))
{
continue;
}
nl = &NS_lo[mx][mz];
//
// If this lo-res sewer square doesn't have a light, then
// we don't have to do any shadow stuff.
//
if (nl->light_y == 0)
{
continue;
}
//
// Where is the light in this lo-res mapsquare?
//
light_x = (mx << PAP_SHIFT_LO) + (nl->light_x << 3);
light_z = (mz << PAP_SHIFT_LO) + (nl->light_z << 3);
light_y = (nl->light_y << 5) + -32 * 0x100;
//
// The direction vector of the light creating the shadow-
// we dont have to bother normalising it.
//
light_dx = (darci->WorldPos.X >> 8) - light_x;
light_dy = (darci->WorldPos.Y >> 8) - light_y;
light_dz = (darci->WorldPos.Z >> 8) - light_z;
//
// Draw the shadow of the person from the light.
//
memset(AENG_aa_buffer, 0, sizeof(AENG_aa_buffer));
SMAP_person(
darci,
(UBYTE *) AENG_aa_buffer,
AENG_AA_BUF_SIZE,
AENG_AA_BUF_SIZE,
light_dx,
light_dy,
light_dz);
//
// Where do we put it in the shadow texture page? Hard code everything!
//
ASSERT(AENG_AA_BUF_SIZE == 32);
ASSERT(TEXTURE_SHADOW_SIZE == 64);
offset_x = (i & 1) << 5;
offset_y = (i & 2) << 4;
//
// Plonk it into the shadow texture page.
//
if (TEXTURE_shadow_lock())
{
SLONG x;
SLONG y;
UWORD *line;
UBYTE *buf = (UBYTE *) AENG_aa_buffer;
UWORD* mapping = GetShadowPixelMapping();
for (y = 0; y < AENG_AA_BUF_SIZE; y++)
{
line = &TEXTURE_shadow_bitmap[((y + offset_y) * TEXTURE_shadow_pitch >> 1) + offset_x];
for (x = AENG_AA_BUF_SIZE - 1; x >= 0; x--)
{
*line++ = mapping[*buf++];
}
}
TEXTURE_shadow_unlock();
}
//
// How we map floating points coordinates from 0 to 1 onto
// where we plonked the shadow map in the texture page.
//
AENG_project_offset_u = float(offset_x) / float(TEXTURE_SHADOW_SIZE);
AENG_project_offset_v = float(offset_y) / float(TEXTURE_SHADOW_SIZE);
AENG_project_mul_u = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE);
AENG_project_mul_v = float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE);
AENG_project_lit_light_x = float(light_x);
AENG_project_lit_light_y = float(light_y);
AENG_project_lit_light_z = float(light_z);
AENG_project_lit_light_range = 600.0F;
//
// Map the shadow polygon onto the sewers around each Darci.
//
{
SLONG mx1;
SLONG mz1;
SLONG mx2;
SLONG mz2;
SLONG px;
SLONG py;
SLONG pz;
SLONG base_x;
SLONG base_z;
NS_Hi *nh;
NS_Lo *nl;
NS_Cache *nc;
NS_Point *np_base;
NS_Face *nf_base;
NS_Point *np;
NS_Face *nf;
SLONG face_point;
UBYTE face_order[4] = {0,1,3,2};
SVector_F poly[4];
SMAP_Link *projected;
mx1 = (darci->WorldPos.X - 0x10000) >> (8 + PAP_SHIFT_LO);
mz1 = (darci->WorldPos.Z - 0x10000) >> (8 + PAP_SHIFT_LO);
mx2 = (darci->WorldPos.X + 0x10000) >> (8 + PAP_SHIFT_LO);
mz2 = (darci->WorldPos.Z + 0x10000) >> (8 + PAP_SHIFT_LO);
SATURATE(mx1, 0, PAP_SIZE_LO - 1);
SATURATE(mz1, 0, PAP_SIZE_LO - 1);
SATURATE(mx2, 0, PAP_SIZE_LO - 1);
SATURATE(mz2, 0, PAP_SIZE_LO - 1);
for (mx = mx1; mx <= mx2; mx++)
for (mz = mz1; mz <= mz2; mz++)
{
nl = &NS_lo[mx][mz];
if (nl->cache == NULL)
{
//
// We can't see this lo-res mapsquare, so there is no point projecting
// a shadow onto it!
//
continue;
}
ASSERT(WITHIN(nl->cache, 1, NS_MAX_CACHES - 1));
nc = &NS_cache[nl->cache];
//
// The origin of this lo-res mapsquare.
//
base_x = mx << PAP_SHIFT_LO;
base_z = mz << PAP_SHIFT_LO;
//
// Point and face memory.
//
np_base = (NS_Point *) nc->memory;
nf_base = (NS_Face *) &np_base[nc->num_points];
for (j = 0, nf = nf_base; j < nc->num_faces; j++, nf++)
{
for (k = 0; k < 4; k++)
{
face_point = face_order[k];
ASSERT(WITHIN(nf->p[face_point], 0, nc->num_points - 1));
np = &np_base[nf->p[face_point]];
px = base_x + (np->x << 3);
pz = base_z + (np->z << 3);
py = (np->y << 5) + -32 * 0x100;
poly[k].X = float(px);
poly[k].Y = float(py);
poly[k].Z = float(pz);
}
projected = SMAP_project_onto_poly(poly, 4);
if (projected)
{
//
// We have generated a shadow poly!
//
AENG_add_projected_lit_shadow_poly(projected);
}
}
}
}
}
}
TEXTURE_shadow_update();
//
// Draw the reflections of people in the sewers.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (!(p_thing->Flags & FLAGS_IN_SEWERS))
{
//
// Only draw things in the sewers.
//
}
else
{
if (p_thing->DrawType == DT_ROT_MULTI)
{
if (POLY_sphere_visible(
float(p_thing->WorldPos.X >> 8),
float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT,
float(p_thing->WorldPos.Z >> 8),
256.0F / (AENG_DRAW_DIST * 256.0F)))
{
SLONG mx = p_thing->WorldPos.X >> 16;
SLONG mz = p_thing->WorldPos.Z >> 16;
ASSERT(WITHIN(mx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(mz, 0, PAP_SIZE_HI - 1));
NS_Hi *nh = &NS_hi[mx][mz];
if (NS_HI_TYPE(nh) != NS_HI_TYPE_ROCK &&
NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE &&
nh->water)
{
//
// The height of the reflection.
//
SLONG reflect_height = (nh->water << 5) + (-32 * 0x100);
FIGURE_draw_reflection(p_thing, reflect_height);
if (WITHIN(bbox_upto, 0, AENG_MAX_BBOXES - 1))
{
//
// Create a new bounding box
//
bbox[bbox_upto].x1 = MAX(FIGURE_reflect_x1 - AENG_BBOX_PUSH_OUT, AENG_BBOX_PUSH_IN);
bbox[bbox_upto].y1 = MAX(FIGURE_reflect_y1, 0);
bbox[bbox_upto].x2 = MIN(FIGURE_reflect_x2 + AENG_BBOX_PUSH_OUT, DisplayWidth - AENG_BBOX_PUSH_IN);
bbox[bbox_upto].y2 = MIN(FIGURE_reflect_y2, DisplayHeight);
bbox_upto += 1;
}
}
}
}
}
t_index = p_thing->Child;
}
}
}
//
// Draw the reflections.
// Clear the poly lists.
//
#ifndef TARGET_DC
POLY_frame_draw(FALSE,FALSE);
POLY_frame_init(TRUE,TRUE);
#endif
//
// Draw the water in all the lo-res mapsquares. Create the ones
// that aren't already cached.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
if (z == 0 || z == PAP_SIZE_LO - 1)
{
continue;
}
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
if (x == 0 || x == PAP_SIZE_LO - 1)
{
continue;
}
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
nl = &NS_lo[x][z];
if (nl->cache == NULL)
{
//
// Create the points and faces for this mapsquare.
//
if (!NS_cache_create(x,z))
{
//
// Houston, we have a problem [grrrrrrrgh]
//
continue;
}
}
ASSERT(WITHIN(nl->cache, 1, NS_MAX_CACHES - 1));
nc = &NS_cache[nl->cache];
base_x = float(x << PAP_SHIFT_LO);
base_z = float(z << PAP_SHIFT_LO);
//
// Draw the water.
//
{
float water_height;
AENG_Nswater *answ;
NS_Hi *nh;
//
// Mark all the water points as untransformed.
//
answ = &AENG_nswater[0][0];
for (i = 0; i < 25; i++)
{
answ->height[0] = 0;
answ->height[1] = 0;
answ->height[2] = 0;
answ->height[3] = 0;
answ += 1;
}
//
// Draw the water squares.
//
bx = x << 2;
bz = z << 2;
for (dx = 0; dx < 4; dx++)
for (dz = 0; dz < 4; dz++)
{
sx = bx + dx;
sz = bz + dz;
ASSERT(WITHIN(sx, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(sz, 0, PAP_SIZE_HI - 1));
nh = &NS_hi[sx][sz];
//
// Curve squares use the water field as the type of curve...
//
if (nh->water && NS_HI_TYPE(nh) != NS_HI_TYPE_CURVE)
{
//
// The height of this square.
//
water_height = float((nh->water << 5) + (-32 * 0x100));
for (i = 0; i < 4; i++)
{
ix = dx + (i & 1);
iz = dz + (i >> 1);
answ = &AENG_nswater[ix][iz];
for (j = 0; j < 4; j++)
{
if (answ->height[j] == nh->water)
{
quad[i] = &answ->pp[j];
goto found_point;
}
if (answ->height[j] == 0)
{
//
// We must create a new point.
//
POLY_transform(
float(bx + ix << 8),
water_height,
float(bz + iz << 8),
&answ->pp[j]);
if (answ->pp[j].MaybeValid())
{
answ->pp[j].colour = 0xaa4488aa;
answ->pp[j].specular = 0xff000000;
POLY_fadeout_point(&answ->pp[j]);
}
quad[i] = &answ->pp[j];
goto found_point;
}
}
found_point:;
}
if (POLY_valid_quad(quad))
{
//
// No textures?
//
quad[0]->u = 0.0F;
quad[0]->v = 0.0F;
quad[1]->u = 1.0F;
quad[1]->v = 0.0F;
quad[2]->u = 0.0F;
quad[2]->v = 1.0F;
quad[3]->u = 1.0F;
quad[3]->v = 1.0F;
POLY_add_quad(quad, POLY_PAGE_SEWATER, TRUE);
}
}
}
}
}
}
if (bbox_upto)
{
if (the_display.screen_lock())
{
//
// Wibble the bounding boxes of the reflections.
//
for (i = 0; i < bbox_upto; i++)
{
WIBBLE_simple(
bbox[i].x1,
bbox[i].y1,
bbox[i].x2,
bbox[i].y2,
62, 137, 17, 178, 40, 45);
}
the_display.screen_unlock();
}
}
//
// Draw the sewer water.
//
/*
#if 0
POLY_sort_sewater_page();
POLY_frame_draw_sewater();
#else
// Shouldn't need to render sewer stuff.
ASSERT ( !(POLY_Page[POLY_PAGE_SEWATER].NeedsRendering()) );
#endif
*/
#ifndef TARGET_DC
POLY_frame_init(TRUE,TRUE);
#endif
//
// Draw all the low res mapsquares. None of the mapsquare
// should be uncached.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
if (z == 0 || z == PAP_SIZE_LO - 1)
{
continue;
}
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
if (x == 0 || x == PAP_SIZE_LO - 1)
{
continue;
}
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
nl = &NS_lo[x][z];
ASSERT(WITHIN(nl->cache, 1, NS_MAX_CACHES - 1));
nc = &NS_cache[nl->cache];
//
// Draw the waterfalls...
//
{
SLONG top;
SLONG bot;
SLONG fall;
NS_Fall *nf;
for (fall = nc->fall; fall; fall = nf->next)
{
ASSERT(WITHIN(fall, 1, NS_MAX_FALLS - 1));
nf = &NS_fall[fall];
top = (nf->top << 5) + (-32 * 0x100);
bot = (nf->bot << 5) + (-32 * 0x100);
SHAPE_waterfall(
nf->x,
nf->z,
nf->dx,
nf->dz,
top,
bot);
//
// Create dirt-drops...
//
sx = (nf->x << 8) + 0x80;
sz = (nf->z << 8) + 0x80;
dsx = nf->dx;
dsz = nf->dz;
dsx <<= 7;
dsz <<= 7;
x1 = sx + dsx;
z1 = sz + dsz;
x2 = sx + dsx;
z2 = sz + dsz;
x1 += -dsz;
z1 += +dsx;
x2 -= -dsz;
z2 -= +dsx;
dropdx = -nf->dx << 3;
dropdz = -nf->dz << 3;
dropdy = 0;
for (i = 0; i < 4; i++)
{
along = rand() & 0xff;
dropx = x1 + ((x2 - x1) * along >> 8);
dropz = z1 + ((z2 - z1) * along >> 8);
dropy = top;
DIRT_new_water(
dropx,
dropy,
dropz,
dropdx,
dropdy,
dropdz);
}
}
}
base_x = float(x << PAP_SHIFT_LO);
base_z = float(z << PAP_SHIFT_LO);
//
// Rotate all the points into the POLY_buffer.
//
POLY_buffer_upto = 0;
np = (NS_Point *) nc->memory;
pp = &POLY_buffer[0];
for (i = 0; i < nc->num_points; i++)
{
px = float(np->x << 3) + base_x;
pz = float(np->z << 3) + base_z;
py = float(np->y << 5) + (32.0F * -256.0F);
POLY_transform(
px,
py,
pz,
pp);
if (pp->MaybeValid())
{
pp->colour = (np->bright) | (np->bright << 8) | (np->bright << 16);
#ifdef TARGET_DC
pp->colour |= 0xff000000;
#endif
pp->specular = 0xff000000;
if (bright)
{
#ifdef TARGET_DC
pp->colour = 0xffffffff;
#else
pp->colour = 0x00ffffff;
#endif
}
POLY_fadeout_point(pp);
}
np++;
pp++;
}
//
// Create all the faces.
//
nf = (NS_Face *) np;
for (i = 0; i < nc->num_faces; i++)
{
ASSERT(WITHIN(nf->p[0], 0, nc->num_points - 1));
ASSERT(WITHIN(nf->p[1], 0, nc->num_points - 1));
ASSERT(WITHIN(nf->p[2], 0, nc->num_points - 1));
ASSERT(WITHIN(nf->p[3], 0, nc->num_points - 1));
quad[0] = &POLY_buffer[nf->p[0]];
quad[1] = &POLY_buffer[nf->p[1]];
quad[2] = &POLY_buffer[nf->p[2]];
quad[3] = &POLY_buffer[nf->p[3]];
if (POLY_valid_quad(quad))
{
//
// Texture the quad.
//
ASSERT(WITHIN(nf->texture, 0, NS_texture_upto - 1));
nt = &NS_texture[nf->texture];
for (j = 0; j < 4; j++)
{
quad[j]->u = float(nt->u[j]) * (1.0F / 32.0F);
quad[j]->v = float(nt->v[j]) * (1.0F / 32.0F);
}
//
// Find the texture page.
//
ASSERT(WITHIN(nf->page, 0, NS_PAGE_NUMBER - 1));
//
// And add it.
//
page = NS_page[nf->page].page;
POLY_add_quad(quad, page, TRUE);
}
nf += 1;
}
//
// The sewer mapwho.
//
for (i = nl->st; i; i = nst->next)
{
ASSERT(WITHIN(i, 1, NS_MAX_STS - 1));
nst = &NS_st[i];
switch(nst->type)
{
case NS_ST_TYPE_PRIM:
MESH_draw_poly(
nst->prim.prim,
(x << PAP_SHIFT_LO) + (nst->prim.x << 3),
(nst->prim.y << 5) + 0x100 * -32,
(z << PAP_SHIFT_LO) + (nst->prim.z << 3),
nst->prim.yaw << 3,
0, 0,
NULL,0xff,0);
break;
case NS_ST_TYPE_LADDER:
FACET_draw_ns_ladder(
nst->ladder.x1,
nst->ladder.z1,
nst->ladder.x2,
nst->ladder.z2,
nst->ladder.height);
break;
default:
ASSERT(0);
break;
}
}
//
// Look at the colvects on this square.
//
{
SLONG f_list;
SLONG facet;
SLONG build;
SLONG exit = FALSE;
f_list = PAP_2LO(x,z).ColVectHead;
show_gamut_lo(x,z);
if (f_list)
{
while(!exit)
{
facet=facet_links[f_list];
ASSERT(facet);
if (facet < 0)
{
//
// The last facet in the list for each square
// is negative.
//
facet = -facet;
exit = TRUE;
}
if (dfacets[facet].Counter[AENG_cur_fc_cam] != SUPERMAP_counter[AENG_cur_fc_cam])
{
if (dfacets[facet].FacetType == STOREY_TYPE_LADDER)
{
//
// Draw the facet.
//
FACET_draw(facet,0);
}
//
// Mark this facet as drawn this gameturn already.
//
dfacets[facet].Counter[AENG_cur_fc_cam] = SUPERMAP_counter[AENG_cur_fc_cam];
}
f_list++;
}
}
}
}
}
//
// Draw the objects and the things.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
//
// The game mapwho.
//
t_index = PAP_2LO(x,z).MapWho;
while(t_index)
{
p_thing = TO_THING(t_index);
if (!(p_thing->Flags & FLAGS_IN_SEWERS))
{
//
// Only draw things in the sewers.
//
}
else
{
switch(p_thing->DrawType)
{
case DT_NONE:
break;
case DT_BUILDING:
break;
case DT_PRIM:
break;
case DT_ROT_MULTI:
if (POLY_sphere_visible(
float(p_thing->WorldPos.X >> 8),
float(p_thing->WorldPos.Y >> 8) + KERB_HEIGHT,
float(p_thing->WorldPos.Z >> 8),
256.0F / (AENG_DRAW_DIST * 256.0F)))
{
FIGURE_draw(p_thing);
}
break;
case DT_EFFECT:
break;
case DT_MESH:
break;
default:
ASSERT(0);
break;
}
}
t_index = p_thing->Child;
}
}
}
//
// The dirt.
//
AENG_draw_dirt();
//
// Draw the drips.
//
// AENG_draw_drips(0);
//
// Draw the polys.
//
POLY_frame_draw(TRUE,TRUE);
}
#endif
void AENG_draw_scanner(
SLONG screen_x1,
SLONG screen_y1,
SLONG screen_x2,
SLONG screen_y2,
SLONG map_x,
SLONG map_z,
SLONG map_zoom,
SLONG map_angle)
{
#ifdef DOG_POO
SLONG i;
AZ_Line *al;
float tx1;
float tx2;
float tz1;
float tz2;
float rx1;
float rx2;
float rz1;
float rz2;
float sx1;
float sx2;
float sy1;
float sy2;
float left = float(screen_x1);
float right = float(screen_x2);
float top = float(screen_y1);
float bottom = float(screen_y2);
float screen_mid_x = float(screen_x1 + screen_x2 >> 1);
float screen_mid_y = float(screen_y1 + screen_y2 >> 1);
float angle = float(map_angle) * (-2.0F * PI / 2048.0F);
float zoom = float(map_zoom) * (1.0F / 65536.0F);
float sin_yaw = sin(angle);
float cos_yaw = cos(angle);
float matrix[4];
UBYTE clip1;
UBYTE clip2;
UBYTE clip_and;
UBYTE clip_xor;
matrix[0] = cos_yaw;
matrix[1] = sin_yaw;
matrix[2] = -sin_yaw;
matrix[3] = cos_yaw;
//
// Set the clipping rectangle.
//
POLY_clip_line_box(
left,
top,
right,
bottom);
//
// Initialise the frame.
//
POLY_frame_init(FALSE,FALSE);
//
// Add each line in turn.
//
ULONG type_colour[AZ_LINE_TYPE_NUMBER] =
{
0x00d83377,
0x00eed811,
0x0033ccff
};
for (i = 0; i < AZ_line_upto; i++)
{
al = &AZ_line[i];
tx1 = float((al->x1 << ELE_SHIFT) - map_x);
tz1 = float((al->z1 << ELE_SHIFT) - map_z);
tx2 = float((al->x2 << ELE_SHIFT) - map_x);
tz2 = float((al->z2 << ELE_SHIFT) - map_z);
//
// Rotate the points.
//
rx1 = tx1 * matrix[0] + tz1 * matrix[1];
rz1 = tx1 * matrix[2] + tz1 * matrix[3];
rx2 = tx2 * matrix[0] + tz2 * matrix[1];
rz2 = tx2 * matrix[2] + tz2 * matrix[3];
//
// Their screen positions.
//
sx1 = screen_mid_x + zoom * rx1;
sy1 = screen_mid_y + zoom * rz1;
sx2 = screen_mid_x + zoom * rx2;
sy2 = screen_mid_y + zoom * rz2;
//
// Add the line.
//
ASSERT(WITHIN(al->type, 0, AZ_LINE_TYPE_NUMBER - 1));
POLY_clip_line_add(sx1, sy1, sx2, sy2, type_colour[al->type]);
}
//
// Draw all the people.
//
{
THING_INDEX t_index;
Thing *p_thing;
SLONG dx;
SLONG dz;
for (t_index = the_game.UsedPrimaryThings; t_index; t_index = p_thing->LinkChild)
{
p_thing = TO_THING(t_index);
if (p_thing->Class == CLASS_PERSON)
{
dx = -SIN(p_thing->Draw.Tweened->Angle) >> 9;
dz = -COS(p_thing->Draw.Tweened->Angle) >> 9;
tx1 = float((p_thing->WorldPos.X >> 8) - map_x);
tz1 = float((p_thing->WorldPos.Z >> 8) - map_z);
tx2 = float((p_thing->WorldPos.X >> 8) + dx - map_x);
tz2 = float((p_thing->WorldPos.Z >> 8) + dz - map_z);
//
// Rotate the points.
//
rx1 = tx1 * matrix[0] + tz1 * matrix[1];
rz1 = tx1 * matrix[2] + tz1 * matrix[3];
rx2 = tx2 * matrix[0] + tz2 * matrix[1];
rz2 = tx2 * matrix[2] + tz2 * matrix[3];
//
// Their screen positions.
//
sx1 = screen_mid_x + zoom * rx1;
sy1 = screen_mid_y + zoom * rz1;
sx2 = screen_mid_x + zoom * rx2;
sy2 = screen_mid_y + zoom * rz2;
//
// Add the line.
//
POLY_clip_line_add(sx1, sy1, sx2, sy2, 0x00ffffff);
}
}
}
//
// Draw a cross in the middle of the map.
//
#define AENG_CROSS_SIZE 5
#define AENG_CROSS_COLOUR 0x0033aa33
POLY_clip_line_add(
screen_mid_x - AENG_CROSS_SIZE,
screen_mid_y - AENG_CROSS_SIZE,
screen_mid_x + AENG_CROSS_SIZE,
screen_mid_y + AENG_CROSS_SIZE,
AENG_CROSS_COLOUR);
POLY_clip_line_add(
screen_mid_x - AENG_CROSS_SIZE,
screen_mid_y + AENG_CROSS_SIZE,
screen_mid_x + AENG_CROSS_SIZE,
screen_mid_y - AENG_CROSS_SIZE,
AENG_CROSS_COLOUR);
//
// Draw an outline.
//
#define AENG_BORDER_COLOUR 0x003355cc
POLY_add_line_2d(left, top, right, top, AENG_BORDER_COLOUR);
POLY_add_line_2d(right, top, right, bottom, AENG_BORDER_COLOUR);
POLY_add_line_2d(right, bottom, left, bottom, AENG_BORDER_COLOUR);
POLY_add_line_2d(left, bottom, left, top, AENG_BORDER_COLOUR);
//
// The transparent background background.
//
POLY_Point pp [4];
POLY_Point *quad[4];
#define AENG_BACKGROUND_COLOUR 0x55888800
pp[0].X = left;
pp[0].Y = top;
pp[0].z = 0.0F;
pp[0].Z = 1.0F;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = AENG_BACKGROUND_COLOUR;
pp[0].specular = 0;
pp[1].X = right;
pp[1].Y = top;
pp[1].z = 0.0F;
pp[1].Z = 1.0F;
pp[1].u = 0.0F;
pp[1].v = 0.0F;
pp[1].colour = AENG_BACKGROUND_COLOUR;
pp[1].specular = 0;
pp[2].X = left;
pp[2].Y = bottom;
pp[2].z = 0.0F;
pp[2].Z = 1.0F;
pp[2].u = 0.0F;
pp[2].v = 0.0F;
pp[2].colour = AENG_BACKGROUND_COLOUR;
pp[2].specular = 0;
pp[3].X = right;
pp[3].Y = bottom;
pp[3].z = 0.0F;
pp[3].Z = 1.0F;
pp[3].u = 0.0F;
pp[3].v = 0.0F;
pp[3].colour = AENG_BACKGROUND_COLOUR;
pp[3].specular = 0;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, TRUE);
#if WE_WANT_TO_DRAW_THE_TEXTURE_SHADOW_PAGE
{
left = 80;
top = 80;
right = 144;
bottom = 144;
#define USIZE (float(AENG_AA_BUF_SIZE) / float(TEXTURE_SHADOW_SIZE))
pp[0].X = left;
pp[0].Y = top;
pp[0].z = 0.0F;
pp[0].Z = 1.0F;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = 0xffffffff;
pp[0].specular = 0xff000000;
pp[1].X = right;
pp[1].Y = top;
pp[1].z = 0.0F;
pp[1].Z = 1.0F;
pp[1].u = USIZE;
pp[1].v = 0.0F;
pp[1].colour = 0xffffffff;
pp[1].specular = 0xff000000;
pp[2].X = left;
pp[2].Y = bottom;
pp[2].z = 0.0F;
pp[2].Z = 1.0F;
pp[2].u = 0.0F;
pp[2].v = USIZE;
pp[2].colour = 0xffffffff;
pp[2].specular = 0xff000000;
pp[3].X = right;
pp[3].Y = bottom;
pp[3].z = 0.0F;
pp[3].Z = 1.0F;
pp[3].u = USIZE;
pp[3].v = USIZE;
pp[3].colour = 0xffffffff;
pp[3].specular = 0xff000000;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, POLY_PAGE_SHADOW, FALSE, TRUE);
}
#endif
//
// Draw the polys.
//
POLY_frame_draw(TRUE,TRUE);
#endif
}
void AENG_draw_power(SLONG x,SLONG y,SLONG w,SLONG h,SLONG val,SLONG max)
{
/*
SLONG left,right,top,bottom;
POLY_Point pp [4];
POLY_Point *quad[4];
left=x;
right=left+w;
top=y;
bottom=y+h;
//
// Set the clipping rectangle.
//
POLY_clip_line_box(
x,
y,
x+w,
y+h);
POLY_frame_init(FALSE,FALSE);
//
// Draw an outline.
//
#define AENG_PBORDER_COLOUR 0x003355cc
#define AENG_PFOREGROUND_COLOUR 0x55888800
POLY_add_line_2d(left, top, right, top, AENG_PBORDER_COLOUR);
POLY_add_line_2d(right, top, right, bottom, AENG_PBORDER_COLOUR);
POLY_add_line_2d(right, bottom, left, bottom, AENG_PBORDER_COLOUR);
POLY_add_line_2d(left, bottom, left, top, AENG_PBORDER_COLOUR);
right=left+(val*w)/max;
pp[0].X = left;
pp[0].Y = top;
pp[0].z = 0.0F;
pp[0].Z = 1.0F;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[1].colour = AENG_PFOREGROUND_COLOUR;
pp[0].specular = 0;
pp[1].X = right;
pp[1].Y = top;
pp[1].z = 0.0F;
pp[1].Z = 1.0F;
pp[1].u = 0.0F;
pp[1].v = 0.0F;
pp[1].colour = AENG_PFOREGROUND_COLOUR;
pp[1].specular = 0;
pp[2].X = left;
pp[2].Y = bottom;
pp[2].z = 0.0F;
pp[2].Z = 1.0F;
pp[2].u = 0.0F;
pp[2].v = 0.0F;
pp[1].colour = AENG_PFOREGROUND_COLOUR;
pp[2].specular = 0;
pp[3].X = right;
pp[3].Y = bottom;
pp[3].z = 0.0F;
pp[3].Z = 1.0F;
pp[3].u = 0.0F;
pp[3].v = 0.0F;
pp[1].colour = AENG_PFOREGROUND_COLOUR;
pp[3].specular = 0;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
POLY_add_quad(quad, POLY_PAGE_COLOUR, FALSE, TRUE);
POLY_frame_draw(TRUE,TRUE);
*/
}
UBYTE record_video=0;
#if defined(TARGET_DC)
// Chews memory - sod it.
void AENG_screen_shot(void)
{
}
// time.h doesn't seem to exist in the DC stuff - wierd.
// Bin this function on the DC for now.
void AENG_draw_FPS()
{
}
#else //#if defined(TARGET_DC)
void AENG_screen_shot(void)
{
if(allow_debug_keys)
if (Keys[KB_S] || record_video)
{
Keys[KB_S] = 0;
if(ShiftFlag)
{
record_video^=1;
}
if (the_display.screen_lock())
{
extern void tga_dump(void);
tga_dump();
//DumpBackToRaw();
the_display.screen_unlock();
}
}
}
void AENG_draw_FPS()
{
static SLONG fps = 0; // current FPS
static SLONG avfps = 0; // average FPS
static SLONG last_game_turn = 0; // game turn when FPS was sampled
static clock_t last_time = 0; // time when FPS was sampled
static SLONG total_frames = 0;
static float total_time = 0;
static SLONG ups = 0; // us per frame
static SLONG avups = 0;
clock_t this_time = clock();
int frames_passed = GAME_TURN - last_game_turn;
if ((frames_passed < 0) || (frames_passed > 200))
{
// reset
fps = 0;
last_game_turn = GAME_TURN;
last_time = this_time;
}
else
{
if (frames_passed >= 20)
{
float seconds = float(this_time - last_time) / float(CLOCKS_PER_SEC);
float _fps = float(frames_passed) / seconds;
fps = floor(_fps + 0.5);
float _ups = 1000000 / _fps;
ups = floor(_ups + 0.5);
if (fps > 10) // don't include really slow frames in the average
{
total_frames += frames_passed;
total_time += seconds;
float _avfps = float(total_frames) / total_time;
avfps = floor(_avfps + 0.5);
float _avups = 1000000 / _avfps;
avups = floor(_avups + 0.5);
}
last_time = this_time;
last_game_turn = GAME_TURN;
}
}
/*
if (the_display.screen_lock())
{
FONT_draw(DisplayWidth >> 1, 10, "FPS: %d = %d us", fps, ups);
FONT_draw(DisplayWidth >> 1, 30, "Avg: %d = %d us", avfps, avups);
the_display.screen_unlock();
}
*/
if (allow_debug_keys)
{
CBYTE str[100];
sprintf(str,"FPS: %d = %d us",fps,ups);
FONT2D_DrawString(str,DisplayWidth >> 1, 10,0xffffff,128);
sprintf(str,"Avg: %d = %d us",avfps,avups);
FONT2D_DrawString(str,DisplayWidth >> 1, 30,0xffffff,128);
}
}
#endif //#else //#if defined(TARGET_DC)
void AENG_draw_messages()
{
//
// fps stuff.
//
static SLONG fps = 0;
#if !defined(TARGET_DC)
static SLONG last_game_turn = 0;
static clock_t last_time = 0;
clock_t this_time = 0;
this_time = clock() / CLOCKS_PER_SEC;
if (this_time != last_time)
{
if (this_time - last_time > 1)
{
//
// Only work out the new frames per second if there hasn't been a major
// delay.
//
}
else
{
fps = GAME_TURN - last_game_turn;
}
last_time = this_time;
last_game_turn = GAME_TURN;
}
#else
fps = 0;
#endif
#if ARGH
static SLONG px[3] = {4 << 16, 8 << 16, 8 << 16};
static SLONG py[3] = {4 << 16, 4 << 16, 8 << 16};
if (LeftButton)
{
SLONG mx;
SLONG my;
SLONG dx;
SLONG dy;
mx = MouseX - AENG_AA_LEFT;
my = MouseY - AENG_AA_TOP;
mx <<= 16;
my <<= 16;
mx /= AENG_AA_PIX_SIZE;
my /= AENG_AA_PIX_SIZE;
SLONG i;
SLONG dist;
SLONG best_dist = INFINITY;
SLONG *best_x;
SLONG *best_y;
for (i = 0; i < 3; i++)
{
dx = abs(px[i] - mx);
dy = abs(py[i] - my);
dist = dx + dy;
if (dist < best_dist)
{
best_dist = dist;
best_x = &px[i];
best_y = &py[i];
}
}
*best_x = mx;
*best_y = my;
}
{
//
// Draw a mad quad!
//
memset(AENG_aa_buffer, 0, sizeof(AENG_aa_buffer));
AA_draw(
(UBYTE *) AENG_aa_buffer,
AENG_AA_BUF_SIZE,
AENG_AA_BUF_SIZE,
AENG_AA_BUF_SIZE,
px[0], py[0],
px[1], py[1],
px[2], py[2]);
}
#endif
//
// Draw stuff straight to the screen.
//
if (the_display.screen_lock())
{
/*
if (Keys[KB_S])
{
Keys[KB_S] = 0;
//
// Take a screen shot.
//
DumpBackToRaw();
}
*/
//
// Draw the fps.
//
FONT_draw(DisplayWidth >> 1, 10, "FPS: %d", fps);
/*
//
// Number of facets drawn.
//
FONT_draw(DisplayWidth >> 1, 20, "Facets: %d", dfacets_drawn_this_gameturn);
extern SLONG damp;
FONT_draw(20,30, "DAMP: %d", damp);
*/
//
// Draw the messages.
//
//MSG_draw();
#if werrr
SLONG x;
SLONG y;
SLONG dx;
SLONG dy;
for (x = 0; x < AENG_AA_BUF_SIZE; x++)
for (y = 0; y < AENG_AA_BUF_SIZE; y++)
{
for (dx = 0; dx < AENG_AA_PIX_SIZE; dx++)
for (dy = 0; dy < AENG_AA_PIX_SIZE; dy++)
{
the_display.PlotPixel(
AENG_AA_LEFT + x * AENG_AA_PIX_SIZE + dx,
AENG_AA_TOP + y * AENG_AA_PIX_SIZE + dy,
AENG_aa_buffer[y][x],
AENG_aa_buffer[y][x],
AENG_aa_buffer[y][x]);
}
}
for (SLONG i = 0; i < 3; i++)
{
x = AENG_AA_LEFT + (px[i] * AENG_AA_PIX_SIZE >> 16);
y = AENG_AA_TOP + (py[i] * AENG_AA_PIX_SIZE >> 16);
the_display.PlotPixel(x + 0, y + 0, 255, 255, 0);
the_display.PlotPixel(x + 1, y + 0, 255, 100, 0);
the_display.PlotPixel(x + 0, y + 1, 255, 100, 0);
the_display.PlotPixel(x - 1, y + 0, 255, 100, 0);
the_display.PlotPixel(x + 0, y - 1, 255, 100, 0);
}
#endif
the_display.screen_unlock();
}
}
void AENG_fade_out(UBYTE amount)
{
SLONG logo_fade_top = amount;
SLONG back_fade_top = amount;
ULONG logo_colour_top = (logo_fade_top << 24) | 0x00ffffff;
ULONG back_colour_top = (back_fade_top << 24) | 0x00ffffff;
SLONG logo_fade_bot = amount;
SLONG back_fade_bot = amount;
ULONG logo_colour_bot = (logo_fade_bot << 24) | 0x00ffffff;
ULONG back_colour_bot = (back_fade_bot << 24) | 0x00ffffff;
//
// Draw the logo.
//
POLY_Point pp[4];
POLY_Point *quad[4];
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
#define AENG_LOGO_MID_X (320.0F)
#define AENG_LOGO_MID_Y (240.0F)
#define AENG_LOGO_SIZE (128.0F)
#ifndef TARGET_DC
POLY_frame_init(FALSE,FALSE);
#endif
pp[0].X = AENG_LOGO_MID_X - AENG_LOGO_SIZE;
pp[0].Y = AENG_LOGO_MID_Y - AENG_LOGO_SIZE;
pp[0].z = 1.0F / 65536.0F;
pp[0].Z = 1.0F;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = logo_colour_top;
pp[0].specular = 0x00000000;
pp[1].X = AENG_LOGO_MID_X + AENG_LOGO_SIZE;
pp[1].Y = AENG_LOGO_MID_Y - AENG_LOGO_SIZE;
pp[1].z = 1.0F / 65536.0F;
pp[1].Z = 1.0F;
pp[1].u = 1.0F;
pp[1].v = 0.0F;
pp[1].colour = logo_colour_top;
pp[1].specular = 0x00000000;
pp[2].X = AENG_LOGO_MID_X - AENG_LOGO_SIZE;
pp[2].Y = AENG_LOGO_MID_Y + AENG_LOGO_SIZE;
pp[2].z = 1.0F / 65536.0F;
pp[2].Z = 1.0F;
pp[2].u = 0.0F;
pp[2].v = 1.0F;
pp[2].colour = logo_colour_bot;
pp[2].specular = 0x00000000;
pp[3].X = AENG_LOGO_MID_X + AENG_LOGO_SIZE;
pp[3].Y = AENG_LOGO_MID_Y + AENG_LOGO_SIZE;
pp[3].z = 1.0F / 65536.0F;
pp[3].Z = 1.0F;
pp[3].u = 1.0F;
pp[3].v = 1.0F;
pp[3].colour = logo_colour_bot;
pp[3].specular = 0x00000000;
POLY_add_quad(quad, POLY_PAGE_LOGO, FALSE, TRUE);
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
POLY_frame_init(FALSE,FALSE);
#endif
pp[0].X = 0.0F;
pp[0].Y = 0.0F;
pp[0].z = 2.0F / 65536.0F;
pp[0].Z = 65535.0F / 65536.0F;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = back_colour_top;
pp[0].specular = 0x00000000;
pp[1].X = 640.0F;
pp[1].Y = 0.0F;
pp[1].z = 2.0F / 65536.0F;
pp[1].Z = 65535.0F / 65536.0F;
pp[1].u = 1.0F;
pp[1].v = 0.0F;
pp[1].colour = back_colour_top;
pp[1].specular = 0x00000000;
pp[2].X = 0.0F;
pp[2].Y = 480.0F;
pp[2].z = 2.0F / 65536.0F;
pp[2].Z = 65535.0F / 65536.0F;
pp[2].u = 0.0F;
pp[2].v = 1.0F;
pp[2].colour = back_colour_bot;
pp[2].specular = 0x00000000;
pp[3].X = 640.0F;
pp[3].Y = 480.0F;
pp[3].z = 2.0F / 65536.0F;
pp[3].Z = 65535.0F / 65536.0F;
pp[3].u = 1.0F;
pp[3].v = 1.0F;
pp[3].colour = back_colour_bot;
pp[3].specular = 0x00000000;
POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, TRUE);
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
#endif
}
void AENG_fade_in(UBYTE amount)
{
SLONG logo_fade_top = 255 - amount;
SLONG back_fade_top = 255 - (amount * amount >> 8);
ULONG logo_colour_top = (logo_fade_top << 24);
ULONG back_colour_top = (back_fade_top << 24);
SLONG logo_fade_bot = 255 - amount;
SLONG back_fade_bot = 255 - (amount * amount >> 8);
ULONG logo_colour_bot = (logo_fade_bot << 24);
ULONG back_colour_bot = (back_fade_bot << 24);
//
// Draw the logo.
//
POLY_Point pp[4];
POLY_Point *quad[4];
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
#ifndef TARGET_DC
POLY_frame_init(TRUE,TRUE);
#endif
pp[0].X = AENG_LOGO_MID_X - AENG_LOGO_SIZE;
pp[0].Y = AENG_LOGO_MID_Y - AENG_LOGO_SIZE;
pp[0].z = 1.0F / 65536.0F;
pp[0].Z = 1.0F;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = logo_colour_top;
pp[0].specular = 0xff000000;
pp[1].X = AENG_LOGO_MID_X + AENG_LOGO_SIZE;
pp[1].Y = AENG_LOGO_MID_Y - AENG_LOGO_SIZE;
pp[1].z = 1.0F / 65536.0F;
pp[1].Z = 1.0F;
pp[1].u = 1.0F;
pp[1].v = 0.0F;
pp[1].colour = logo_colour_top;
pp[1].specular = 0xff000000;
pp[2].X = AENG_LOGO_MID_X - AENG_LOGO_SIZE;
pp[2].Y = AENG_LOGO_MID_Y + AENG_LOGO_SIZE;
pp[2].z = 1.0F / 65536.0F;
pp[2].Z = 1.0F;
pp[2].u = 0.0F;
pp[2].v = 1.0F;
pp[2].colour = logo_colour_bot;
pp[2].specular = 0xff000000;
pp[3].X = AENG_LOGO_MID_X + AENG_LOGO_SIZE;
pp[3].Y = AENG_LOGO_MID_Y + AENG_LOGO_SIZE;
pp[3].z = 1.0F / 65536.0F;
pp[3].Z = 1.0F;
pp[3].u = 1.0F;
pp[3].v = 1.0F;
pp[3].colour = logo_colour_bot;
pp[3].specular = 0xff000000;
POLY_add_quad(quad, POLY_PAGE_LOGO, FALSE, TRUE);
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
#endif
pp[0].X = 0.0F;
pp[0].Y = 0.0F;
pp[0].z = 2.0F / 65536.0F;
pp[0].Z = 65535.0F / 65536.0F;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[0].colour = back_colour_top;
pp[0].specular = 0xff000000;
pp[1].X = 640.0F;
pp[1].Y = 0.0F;
pp[1].z = 2.0F / 65536.0F;
pp[1].Z = 65535.0F / 65536.0F;
pp[1].u = 1.0F;
pp[1].v = 0.0F;
pp[1].colour = back_colour_top;
pp[1].specular = 0xff000000;
pp[2].X = 0.0F;
pp[2].Y = 480.0F;
pp[2].z = 2.0F / 65536.0F;
pp[2].Z = 65535.0F / 65536.0F;
pp[2].u = 0.0F;
pp[2].v = 1.0F;
pp[2].colour = back_colour_bot;
pp[2].specular = 0xff000000;
pp[3].X = 640.0F;
pp[3].Y = 480.0F;
pp[3].z = 2.0F / 65536.0F;
pp[3].Z = 65535.0F / 65536.0F;
pp[3].u = 1.0F;
pp[3].v = 1.0F;
pp[3].colour = back_colour_bot;
pp[3].specular = 0xff000000;
POLY_add_quad(quad, POLY_PAGE_ALPHA, FALSE, TRUE);
#ifndef TARGET_DC
POLY_frame_draw(TRUE,TRUE);
POLY_frame_init(FALSE,FALSE);
#endif
}
void AENG_clear_screen()
{
#ifdef TARGET_DC
static int iBlah = 0;
iBlah++;
iBlah = 0;
if ( ( iBlah & 0x3 ) == 0 )
{
SET_BLACK_BACKGROUND;
}
else if ( ( iBlah & 0x3 ) == 1 )
{
SET_WHITE_BACKGROUND;
}
else if ( ( iBlah & 0x3 ) == 2 )
{
SET_BLACK_BACKGROUND;
}
else if ( ( iBlah & 0x3 ) == 3 )
{
SET_WHITE_BACKGROUND;
}
#else
SET_BLACK_BACKGROUND;
#endif
CLEAR_VIEWPORT;
TheVPool->ReclaimBuffers();
}
SLONG AENG_lock()
{
return SLONG(the_display.screen_lock());
}
void AENG_unlock()
{
the_display.screen_unlock();
}
void AENG_flip()
{
#ifndef TARGET_DC
if (sw_hack)
{
SW_copy_to_bb();
}
#endif
FLIP(NULL, DDFLIP_WAIT); // PerMedia2 needs this, or else!
}
void AENG_blit()
{
#ifndef TARGET_DC
if (sw_hack)
{
SW_copy_to_bb();
}
#endif
the_display.blit_back_buffer();
}
#ifndef TARGET_DC
void AENG_e_draw_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2)
{
AENG_world_line(
x1,y1,z1,8,0x00ffffff,
x2,y2,z2,8,0x00ffffff,
TRUE);
}
void AENG_e_draw_3d_line_dir(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2)
{
AENG_world_line(
x1,y1,z1,32,0x00ffffff,
x2,y2,z2, 0,0x00553311,
TRUE);
}
void AENG_e_draw_3d_line_col(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b)
{
ULONG colour;
colour = r << 16;
colour |= g << 8;
colour |= b << 0;
AENG_world_line(
x1,y1,z1,8,colour,
x2,y2,z2,8,colour,
TRUE);
}
void AENG_e_draw_3d_line_col_sorted(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b)
{
ULONG colour;
colour = r << 16;
colour |= g << 8;
colour |= b << 0;
AENG_world_line(
x1,y1,z1,8,colour,
x2,y2,z2,8,colour,
FALSE);
}
void AENG_e_draw_3d_mapwho(SLONG x1, SLONG z1)
{
x1 <<= ELE_SHIFT;
z1 <<= ELE_SHIFT;
e_draw_3d_line(x1,0,z1,x1+256,0,z1);
e_draw_3d_line(x1+256,0,z1,x1+256,0,z1+256);
e_draw_3d_line(x1+256,0,z1+256,x1,0,z1+256);
e_draw_3d_line(x1,0,z1+256,x1,0,z1);
}
void AENG_e_draw_3d_mapwho_y(SLONG x1, SLONG y1, SLONG z1)
{
x1 <<= ELE_SHIFT;
z1 <<= ELE_SHIFT;
e_draw_3d_line(x1,y1,z1,x1+256,y1,z1);
e_draw_3d_line(x1+256,y1,z1,x1+256,y1,z1+256);
e_draw_3d_line(x1+256,y1,z1+256,x1,y1,z1+256);
e_draw_3d_line(x1,y1,z1+256,x1,y1,z1);
}
#endif //#ifndef TARGET_DC
//---------------------------------------------------------------
void AENG_demo_attract(SLONG x,SLONG y,CBYTE *text)
{
/*
static flash = 0;
POLY_frame_init(FALSE,FALSE);
text_fudge = TRUE;
draw_centre_text_at(x,y,text,1,1);
//if (flash++ & 0x10) Do it all the time!
{
text_fudge = FALSE;
text_colour = 0x00eeeeff;
draw_centre_text_at(
320, 30,
"Press any button to play demo\n",
0,0);
}
POLY_frame_draw(FALSE,TRUE);
*/
}
//---------------------------------------------------------------
#ifndef TARGET_DC
// ========================================================
//
// EDITOR SUPPORT FUNCTIONS.
//
// ========================================================
SLONG AENG_raytraced_position(
SLONG sx,
SLONG sy,
SLONG *world_x,
SLONG *world_y,
SLONG *world_z,
SLONG indoors)
{
SLONG i;
float ax;
float ay;
float ex;
float ey;
float ez;
float dx;
float dy;
float dz;
float len;
SLONG wx;
SLONG wy;
SLONG wz;
float rx = AENG_cam_x;
float ry = AENG_cam_y;
float rz = AENG_cam_z;
//
// Use to cone to find out the direction of the vector through (sx,sy).
//
ax = float(sx) * (1.0F / 640.0F);
ay = float(sy) * (1.0F / 480.0F);
ex = AENG_cone[1].x;
ey = AENG_cone[1].y;
ez = AENG_cone[1].z;
ex += ax * (AENG_cone[0].x - AENG_cone[1].x);
ey += ax * (AENG_cone[0].y - AENG_cone[1].y);
ez += ax * (AENG_cone[0].z - AENG_cone[1].z);
ex += ay * (AENG_cone[2].x - AENG_cone[1].x);
ey += ay * (AENG_cone[2].y - AENG_cone[1].y);
ez += ay * (AENG_cone[2].z - AENG_cone[1].z);
//
// This is all in mapsquare coordinates, not world coordinates.
//
ex *= 256.0F;
ey *= 256.0F;
ez *= 256.0F;
//
// The direction of our ray.
//
dx = ex - rx;
dy = ey - ry;
dz = ez - rz;
len = sqrt(dx*dx + dy*dy + dz*dz);
#define AENG_RAYTRACE_ACCURACY 16
dx *= (256.0F / AENG_RAYTRACE_ACCURACY) / len;
dy *= (256.0F / AENG_RAYTRACE_ACCURACY) / len;
dz *= (256.0F / AENG_RAYTRACE_ACCURACY) / len;
if (GAME_FLAGS & GF_SEWERS)
{
//
// Use the sewer LOS function.
//
SLONG x1 = SLONG(rx);
SLONG y1 = SLONG(ry);
SLONG z1 = SLONG(rz);
SLONG x2 = SLONG(rx + dx * (AENG_RAYTRACE_ACCURACY * 16));
SLONG y2 = SLONG(ry + dy * (AENG_RAYTRACE_ACCURACY * 16));
SLONG z2 = SLONG(rz + dz * (AENG_RAYTRACE_ACCURACY * 16));
if (NS_there_is_a_los(
x1, y1, z1,
x2, y2, z2))
{
return FALSE;
}
*world_x = NS_los_fail_x;
*world_y = NS_los_fail_y;
*world_z = NS_los_fail_z;
if (!WITHIN(*world_x, 0, (PAP_SIZE_HI << 8) - 1) ||
!WITHIN(*world_z, 0, (PAP_SIZE_HI << 8) - 1))
{
return FALSE;
}
else
{
return TRUE;
}
}
//
// Intersect the ray with the world.
//
rx += dx * AENG_RAYTRACE_ACCURACY;
ry += dy * AENG_RAYTRACE_ACCURACY;
rz += dz * AENG_RAYTRACE_ACCURACY;
for (i = 0; i < AENG_RAYTRACE_ACCURACY * (AENG_DRAW_DIST - 1); i++)
{
wx = (SLONG) rx;
wy = (SLONG) ry;
wz = (SLONG) rz;
if (
(indoors&&(wy<get_inside_alt(indoors))) ||
((!indoors)&&(wy < PAP_calc_map_height_at(wx, wz)))
)
{
if (indoors)
wy = get_inside_alt(indoors);
else
wy = PAP_calc_map_height_at(wx, wz);
*world_x = wx;
*world_y = wy;
*world_z = wz;
if (!WITHIN(*world_x, 0, (PAP_SIZE_HI << 8) - 1) ||
!WITHIN(*world_z, 0, (PAP_SIZE_HI << 8) - 1))
{
return FALSE;
}
else
{
return TRUE;
}
}
rx += dx;
ry += dy;
rz += dz;
}
return FALSE;
}
ULONG AENG_light_draw(
SLONG mx,
SLONG my,
SLONG lx,
SLONG ly,
SLONG lz,
ULONG colour,
UBYTE highlight)
{
ULONG ans = 0;
SLONG h1 = PAP_calc_map_height_at(lx, lz);
SLONG h2 = ly;
#ifndef TARGET_DC
POLY_frame_init(FALSE, FALSE);
#endif
//
// Draw a couple of sphere connected by a line.
//
SHAPE_alpha_sphere(
lx,
h1,
lz,
30,
0x00ffffff,
0xff000000);
SHAPE_alpha_sphere(
lx,
h2,
lz,
30 + (highlight >> 4),
colour,0xFF000000);
AENG_world_line(
lx, h1, lz, 32, 0xffffff,
lx, h2, lz, 0, colour,
FALSE);
#ifndef TARGET_DC
POLY_frame_draw(FALSE, FALSE);
#endif
//
// Was either over the mouse?
//
SLONG dx;
SLONG dy;
SLONG dist;
SLONG sx;
SLONG sy;
SLONG swidth;
if (POLY_get_sphere_circle(
float(lx),
float(h1),
float(lz),
30.0F,
&sx,
&sy,
&swidth))
{
dx = abs(sx - mx);
dy = abs(sy - my);
dist = QDIST2(dx,dy);
if (dist < swidth * 3)
{
ans |= AENG_MOUSE_OVER_LIGHT_BOT;
}
}
if (POLY_get_sphere_circle(
float(lx),
float(h2),
float(lz),
30.0F,
&sx,
&sy,
&swidth))
{
dx = abs(sx - mx);
dy = abs(sy - my);
dist = QDIST2(dx,dy);
if (dist < swidth * 3)
{
ans |= AENG_MOUSE_OVER_LIGHT_TOP;
}
}
return ans;
}
#ifdef SEWERS
void AENG_draw_sewer_editor(
SLONG cam_x,
SLONG cam_y,
SLONG cam_z,
SLONG cam_yaw,
SLONG cam_pitch,
SLONG cam_roll,
SLONG mouse_x,
SLONG mouse_y,
SLONG *mouse_over_valid,
SLONG *mouse_over_x,
SLONG *mouse_over_y,
SLONG *mouse_over_z,
SLONG draw_prim_at_mouse,
SLONG prim_object,
SLONG prim_yaw)
{
SLONG i;
SLONG x;
SLONG z;
float px;
float py;
float pz;
float wy;
SLONG height;
SLONG page;
float along_01;
float along_02;
POLY_Point pp[4];
POLY_Point *quad[4];
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
pp[0].colour = 0x00ffffff;
pp[1].colour = 0x00ffffff;
pp[2].colour = 0x00ffffff;
pp[3].colour = 0x00ffffff;
pp[0].specular = 0xff000000;
pp[1].specular = 0xff000000;
pp[2].specular = 0xff000000;
pp[3].specular = 0xff000000;
pp[0].u = 0.0F;
pp[0].v = 0.0F;
pp[1].u = 1.0F;
pp[1].v = 0.0F;
pp[2].u = 0.0F;
pp[2].v = 1.0F;
pp[3].u = 1.0F;
pp[3].v = 1.0F;
ES_Hi *eh;
ES_Lo *el;
ES_Thing *et;
//
// Clear screen.
//
AENG_clear_screen();
//
// Clear out stuff.
//
POLY_frame_init(FALSE,FALSE);
//
// Set the camera.
//
POLY_camera_set(
float(cam_x),
float(cam_y),
float(cam_z),
float(cam_yaw) * 2.0F * PI / 2048.0F,
float(cam_pitch) * 2.0F * PI / 2048.0F,
float(cam_roll) * 2.0F * PI / 2048.0F,
float(AENG_DRAW_DIST) * 256.0F,
AENG_LENS);
//
// Calculate the gamut.
//
AENG_calc_gamut(
float(cam_x),
float(cam_y),
float(cam_z),
float(cam_yaw) * 2.0F * PI / 2048.0F,
float(cam_pitch) * 2.0F * PI / 2048.0F,
float(cam_roll) * 2.0F * PI / 2048.0F,
float(AENG_DRAW_DIST),
AENG_LENS);
*mouse_over_valid = FALSE;
for (z = NGAMUT_zmin; z <= NGAMUT_zmax; z++)
{
for (x = NGAMUT_gamut[z].xmin; x <= NGAMUT_gamut[z].xmax; x++)
{
ASSERT(WITHIN(x, 0, PAP_SIZE_HI - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_HI - 1));
eh = &ES_hi[x][z];
switch(eh->type)
{
case ES_TYPE_ROCK: page = NS_page[NS_PAGE_ROCK ].page; break;
case ES_TYPE_SEWER: page = NS_page[NS_PAGE_SWALL].page; break;
case ES_TYPE_GROUND: page = NS_page[NS_PAGE_STONE].page; break;
case ES_TYPE_HOLE: page = 0; break;
default:
ASSERT(0);
break;
}
if (eh->flag & ES_FLAG_GRATING)
{
page = NS_page[NS_PAGE_GRATE].page;
}
//
// The height.
//
py = float((eh->height << 5) + -32 * 0x100);
//
// Create the four points.
//
for (i = 0; i < 4; i++)
{
px = float(x + ((i & 1) ? 1 : 0)) * 256.0F;
pz = float(z + ((i & 2) ? 1 : 0)) * 256.0F;
POLY_transform(
px,
py,
pz,
&pp[i]);
if (!pp[i].MaybeValid())
{
goto abandon_this_square;
}
}
if (POLY_valid_quad(quad))
{
POLY_add_quad(quad, page, FALSE);
//
// Is the mouse in this quad?
//
if (POLY_inside_quad(
float(mouse_x),
float(mouse_y),
quad,
&along_01,
&along_02))
{
*mouse_over_valid = TRUE;
*mouse_over_x = x * 256 + 0x80;
*mouse_over_y = SLONG(py);
*mouse_over_z = z * 256 + 0x80;
}
}
abandon_this_square:;
//
// Draw water above this square?
//
if (eh->water)
{
//
// The height.
//
wy = float((eh->water << 5) + -32 * 0x100);
//
// Create the four points.
//
for (i = 0; i < 4; i++)
{
px = float(x + ((i & 1) ? 1 : 0)) * 256.0F;
pz = float(z + ((i & 2) ? 1 : 0)) * 256.0F;
POLY_transform(
px,
wy,
pz,
&pp[i]);
if (!pp[i].MaybeValid())
{
goto abandon_this_water;
}
}
pp[0].colour = 0x00222266;
pp[1].colour = 0x00222266;
pp[2].colour = 0x00222266;
pp[3].colour = 0x00222266;
if (POLY_valid_quad(quad))
{
POLY_add_quad(quad, POLY_PAGE_ADDITIVE, FALSE);
}
pp[0].colour = 0x00ffffff;
pp[1].colour = 0x00ffffff;
pp[2].colour = 0x00ffffff;
pp[3].colour = 0x00ffffff;
abandon_this_water:;
}
if (eh->flag & ES_FLAG_ENTRANCE)
{
SLONG mx = (x << 8) + 0x80;
SLONG mz = (z << 8) + 0x80;
SLONG colourbot;
SLONG colourtop;
if (eh->flag & ES_FLAG_NOCURBS)
{
colourbot = 0x0000ff00;
colourtop = 0x000000ff;
}
else
{
colourbot = 0x00ff0000;
colourtop = 0x00ffff88;
}
AENG_world_line(
mx, SLONG(py) + 0x010, mz, 32, colourbot,
mx, SLONG(py) + 0x280, mz, 0, colourtop,
FALSE);
}
}
}
//
// Draw the lights.
//
for (z = NGAMUT_lo_zmin; z <= NGAMUT_lo_zmax; z++)
{
for (x = NGAMUT_lo_gamut[z].xmin; x <= NGAMUT_lo_gamut[z].xmax; x++)
{
ASSERT(WITHIN(x, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(z, 0, PAP_SIZE_LO - 1));
el = &ES_lo[x][z];
if (el->light_y)
{
SLONG lx = (x << PAP_SHIFT_LO) + (el->light_x << 3);
SLONG ly = (el->light_y << 5) + -32 * 0x100;
SLONG lz = (z << PAP_SHIFT_LO) + (el->light_z << 3);
SHAPE_sphere(
lx, ly, lz,
32,
0x00ddddff);
}
}
}
//
// Draw the things.
//
for (i = 0; i < ES_MAX_THINGS; i++)
{
et = &ES_thing[i];
switch(et->type)
{
case ES_THING_TYPE_UNUSED:
break;
case ES_THING_TYPE_LADDER:
FACET_draw_ns_ladder(
et->x1,
et->z1,
et->x2,
et->z2,
et->height);
break;
case ES_THING_TYPE_PRIM:
MESH_draw_poly(
et->prim,
et->x,
et->y,
et->z,
et->yaw, 0, 0,
NULL,0xff,0);
break;
default:
ASSERT(0);
break;
}
}
if (*mouse_over_valid)
{
//
// Highlight the square the mouse is over.
//
AENG_e_draw_3d_mapwho_y(
*mouse_over_x >> 8,
*mouse_over_y,
*mouse_over_z >> 8);
if (draw_prim_at_mouse)
{
MESH_draw_poly(
prim_object,
*mouse_over_x & ~0xff,
*mouse_over_y,
*mouse_over_z & ~0xff,
prim_yaw, 0, 0,
NULL,0xff,0);
}
}
POLY_frame_draw(TRUE,TRUE);
return;
}
#endif
#endif //#ifndef TARGET_DC
//
// Draws text at the given point.
//
void AENG_world_text(
SLONG x,
SLONG y,
SLONG z,
UBYTE red,
UBYTE blue,
UBYTE green,
UBYTE shadowed_or_not,
CBYTE *fmt, ...)
{
POLY_Point pp;
// return;
POLY_transform(
float(x),
float(y),
float(z),
&pp);
if (pp.IsValid())
{
//
// Work out the real message.
//
CBYTE message[FONT_MAX_LENGTH];
va_list ap;
va_start(ap, fmt);
vsprintf(message, fmt, ap);
va_end (ap);
//
// Add the message.
//
FONT_buffer_add(
pp.X,
pp.Y,
red,
green,
blue,
shadowed_or_not,
message);
}
}
#ifndef TARGET_DC
//---------------------------------------------------------------
// GUY.
//---------------------------------------------------------------
ULONG AENG_waypoint_draw(
SLONG mx,
SLONG my,
SLONG lx,
SLONG ly,
SLONG lz,
ULONG colour,
UBYTE highlight)
{
ULONG ans = 0;
// SLONG h1 = PAP_calc_map_height_at(lx, lz);
SLONG h2 = ly;
POLY_frame_init(FALSE, FALSE);
//
// Draw a single sphere.
//
if (INDOORS_INDEX)
SHAPE_alpha_sphere(
lx,
h2,
lz,
30 + (highlight >> 4),
colour,
0xff000000);
else
SHAPE_sphere(
lx,
h2,
lz,
30 + (highlight >> 4),
colour);
POLY_frame_draw(FALSE, FALSE);
//
// Was it over the mouse?
//
SLONG dx;
SLONG dy;
SLONG dist;
SLONG sx;
SLONG sy;
SLONG swidth;
if (POLY_get_sphere_circle(
float(lx),
float(h2),
float(lz),
(float)(30 + (highlight >> 4)),
&sx,
&sy,
&swidth))
{
dx = abs(sx - mx);
dy = abs(sy - my);
dist = QDIST2(dx,dy);
if (dist < swidth * 2)
{
ans |= AENG_MOUSE_OVER_WAYPOINT;
}
}
return ans;
}
//---------------------------------------------------------------
ULONG AENG_rad_trigger_draw(
SLONG mx,
SLONG my,
SLONG lx,
SLONG ly,
SLONG lz,
ULONG rad,
ULONG colour,
UBYTE highlight)
{
ULONG ans = 0;
SLONG h1 = PAP_calc_map_height_at(lx, lz);
SLONG h2 = ly;
POLY_frame_init(FALSE, FALSE);
//
// Draw a single sphere.
//
/*
SHAPE_sphere(
lx,
h1,
lz,
30 + (highlight >> 4),
colour);
*/
SHAPE_alpha_sphere(
lx,
h2,
lz,
rad,
colour,
0x88000000);
POLY_frame_draw(FALSE, FALSE);
//
// Was it over the mouse?
//
SLONG dx;
SLONG dy;
SLONG dist;
SLONG sx;
SLONG sy;
SLONG swidth;
if (POLY_get_sphere_circle(
float(lx),
float(h1),
float(lz),
(float)(30 + (highlight >> 4)),
&sx,
&sy,
&swidth))
{
dx = abs(sx - mx);
dy = abs(sy - my);
dist = QDIST2(dx,dy);
if (dist < swidth * 2)
{
ans |= AENG_MOUSE_OVER_WAYPOINT;
}
}
return ans;
}
//---------------------------------------------------------------
// CANIS.
//---------------------------------------------------------------
void AENG_groundsquare_draw(
SLONG lx,
SLONG ly,
SLONG lz,
ULONG colour,
UBYTE polyinit)
{
POLY_Point pp[4];
POLY_Point *quad[4];
SLONG x,y,z,id,diff;
quad[0] = &pp[0];
quad[1] = &pp[1];
quad[2] = &pp[2];
quad[3] = &pp[3];
// y = PAP_calc_map_height_at(lx>>8,lz>>8)+ly;
POLY_transform(lx ,ly,lz ,&pp[0]);
// y = PAP_calc_map_height_at((lx>>8)+1,lz>>8)+ly;
POLY_transform(lx+256,ly,lz ,&pp[1]);
// y = PAP_calc_map_height_at(lx>>8,(lz>>8)+1)+ly;
POLY_transform(lx ,ly,lz+256 ,&pp[2]);
// y = PAP_calc_map_height_at((lx>>8)+1,(lz>>8)+1)+ly;
POLY_transform(lx+256,ly,lz+256 ,&pp[3]);
pp[0].specular=pp[1].specular=pp[2].specular=pp[3].specular=0xFF000000;
pp[0].colour=pp[1].colour=pp[2].colour=pp[3].colour=colour;
if (polyinit & 1) POLY_frame_init(FALSE, FALSE);
if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid() && pp[3].MaybeValid())
{
POLY_add_quad(quad,POLY_PAGE_ALPHA,FALSE);
}
if (polyinit & 2) POLY_frame_draw(FALSE, FALSE);
}
#endif //#ifndef TARGET_DC
//---------------------------------------------------------------
UBYTE AENG_transparent_warehouses;
void AENG_clear_viewport()
{
//
// Clear screen...
//
if (INDOORS_INDEX||(GAME_FLAGS & GF_SEWERS) || (GAME_FLAGS & GF_INDOORS))
{
SET_BLACK_BACKGROUND;
CLEAR_VIEWPORT;
}
else
{
if (draw_3d)
{
SLONG white = NIGHT_sky_colour.red + NIGHT_sky_colour.green + NIGHT_sky_colour.blue;
white /= 3;
the_display.SetUserColour(
white,
white,
white);
}
else
{
if(fade_black)
{
the_display.SetUserColour(0,0,0);
}
else
{
the_display.SetUserColour(
NIGHT_sky_colour.red,
NIGHT_sky_colour.green,
NIGHT_sky_colour.blue);
}
}
the_display.SetUserBackground();
the_display.ClearViewport();
#if 0 && USE_TOMS_ENGINE_PLEASE_BOB
// Haha! Nasty kludge!
the_display.lp_D3D_Viewport->Clear2(
1,
&(the_display.ViewportRect),
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
0xff806040,
1.0f,
0);
#endif
}
BreakTime("Cleared Viewport");
}
SLONG AENG_drawing_a_warehouse;
ULONG AENG_draw_time;
ULONG AENG_poly_add_quad_time;
void AENG_draw(SLONG draw_3d)
{
ULONG start_rdtsc = AENG_rdtsc();
AENG_poly_add_quad_time = 0;
#ifndef TARGET_DC
if (SOFTWARE)
{
//
// Leave dirt as it is. Turn everything else off.
//
AENG_detail_crinkles = FALSE;
AENG_detail_stars = FALSE;
AENG_detail_shadows = FALSE;
AENG_detail_moon_reflection = FALSE;
AENG_detail_people_reflection = FALSE;
AENG_detail_puddles = FALSE;
AENG_detail_mist = FALSE;
AENG_detail_rain = FALSE;
AENG_detail_skyline = FALSE;
AENG_detail_filter = FALSE;
}
#endif //#ifndef TARGET_DC
/*
if (Keys[KB_PPOINT])
{
Keys[KB_PPOINT] = 0;
sw_hack ^= TRUE;
if (sw_hack)
{
SW_reload_textures();
NIGHT_amb_red >>= 1;
NIGHT_amb_green >>= 1;
NIGHT_amb_blue >>= 1;
}
else
{
NIGHT_amb_red <<= 1;
NIGHT_amb_green <<= 1;
NIGHT_amb_blue <<= 1;
}
NIGHT_Colour amb_colour;
amb_colour.red = NIGHT_amb_red;
amb_colour.green = NIGHT_amb_green;
amb_colour.blue = NIGHT_amb_blue;
NIGHT_get_d3d_colour(
amb_colour,
&NIGHT_amb_d3d_colour,
&NIGHT_amb_d3d_specular);
NIGHT_cache_recalc();
NIGHT_dfcache_recalc();
NIGHT_generate_walkable_lighting();
}
*/
SLONG i;
SLONG warehouse;
FC_Cam *fc;
#if 0
// set CurDrawDistance
CurDrawDistance = FC_cam[1].focus ? 16 : NormalDrawDistance;
#endif
#ifndef TARGET_DC
if (SOFTWARE)
{
CurDrawDistance = 16;
}
#endif
#ifdef TARGET_DC
fiddle_draw_distance_DC();
#endif
/*
if (Keys[KB_RBRACE])
{
Keys[KB_RBRACE] = 0;
AENG_transparent_warehouses ^= 1;
}
*/
AENG_drawing_a_warehouse = FALSE;
//
// Update stuff.
//
//d AENG_movie_update();
#ifndef TARGET_DC
move_clouds();
#endif
POLY_set_wibble(62, 137, 17, 178, 20, 25);
#ifndef TARGET_DC
if (sw_hack)
{
SLONG width = MIN(RealDisplayWidth, SW_MAX_WIDTH);
SLONG height = MIN(RealDisplayHeight, SW_MAX_HEIGHT);
SW_init(width, height);
}
#endif
AENG_clear_viewport();
//
// reclaim vertex buffers
//
TheVPool->ReclaimBuffers();
//
// Put in the dynamic lighting.
//
NIGHT_dlight_squares_up();
POLY_colour_restrict = 0;
POLY_force_additive_alpha = FALSE;
//
// Mark all NIGHT cache squares for deletion.
//
AENG_mark_night_squares_as_deleteme();
if (FC_cam[1].focus)
{
//
// Splitscreen mode!
//
SUPERMAP_counter_increase(0);
SUPERMAP_counter_increase(1);
for (i = 0; i < FC_MAX_CAMS; i++)
{
fc = &FC_cam[i];
AENG_lens = fc->lens * 1.5F * (1.0F / float(65536.0F));
AENG_set_camera_radians(
fc->x >> 8,
fc->y >> 8,
fc->z >> 8,
float(fc->yaw) * (2.0F * PI / (2048.0F * 256.0F)),
float(fc->pitch) * (2.0F * PI / (2048.0F * 256.0F)),
float(fc->roll) * (2.0F * PI / (2048.0F * 256.0F)),
(i == 0) ? POLY_SPLITSCREEN_TOP : POLY_SPLITSCREEN_BOTTOM);
AENG_cur_fc_cam = i;
if (fc->focus->Class == CLASS_PERSON &&
fc->focus->Genus.Person->Ware)
{
AENG_ensure_appropriate_caching(TRUE);
AENG_draw_warehouse();
}
else
{
AENG_ensure_appropriate_caching(FALSE);
AENG_draw_city();
}
}
AENG_get_rid_of_deleteme_squares();
AENG_get_rid_of_unused_dfcache_lighting(TRUE);
}
else
{
fc = &FC_cam[0];
SUPERMAP_counter_increase(0);
//
// Not splitscreen. We might have to use the cutscene camera.
//
SLONG old_cam_x = fc->x;
SLONG old_cam_y = fc->y;
SLONG old_cam_z = fc->z;
SLONG old_cam_yaw = fc->yaw;
SLONG old_cam_pitch = fc->pitch;
SLONG old_cam_roll = fc->roll;
SLONG old_cam_lens = fc->lens;
//
// If there is a cut-scene camera...
//
if (EWAY_grab_camera(
&fc->x,
&fc->y,
&fc->z,
&fc->yaw,
&fc->pitch,
&fc->roll,
&fc->lens))
{
warehouse = EWAY_camera_warehouse();
}
else
{
warehouse = (fc->focus->Class == CLASS_PERSON && fc->focus->Genus.Person->Ware);
}
extern MFFileHandle playback_file;
extern MFFileHandle verifier_file;
if (GAME_STATE & GS_PLAYBACK)
{
FileRead(playback_file, &fc->x, sizeof(fc->x));
FileRead(playback_file, &fc->y, sizeof(fc->y));
FileRead(playback_file, &fc->z, sizeof(fc->z));
FileRead(playback_file, &fc->yaw, sizeof(fc->yaw));
FileRead(playback_file, &fc->pitch, sizeof(fc->pitch));
FileRead(playback_file, &fc->roll, sizeof(fc->roll));
FileRead(playback_file, &fc->lens, sizeof(fc->lens));
if (verifier_file)
{
extern void check_thing_data();
check_thing_data();
}
}
else if (GAME_STATE & GS_RECORD)
{
FileWrite(playback_file, &fc->x, sizeof(fc->x));
FileWrite(playback_file, &fc->y, sizeof(fc->y));
FileWrite(playback_file, &fc->z, sizeof(fc->z));
FileWrite(playback_file, &fc->yaw, sizeof(fc->yaw));
FileWrite(playback_file, &fc->pitch, sizeof(fc->pitch));
FileWrite(playback_file, &fc->roll, sizeof(fc->roll));
FileWrite(playback_file, &fc->lens, sizeof(fc->lens));
if (verifier_file)
{
extern void store_thing_data();
store_thing_data();
}
}
AENG_lens = fc->lens * (1.0F / float(65536.0F));
AENG_set_camera_radians(
fc->x >> 8,
fc->y >> 8,
fc->z >> 8,
float(fc->yaw ) * (2.0F * PI / (2048.0F * 256.0F)),
float(fc->pitch) * (2.0F * PI / (2048.0F * 256.0F)),
float(fc->roll ) * (2.0F * PI / (2048.0F * 256.0F)),
POLY_SPLITSCREEN_NONE);
AENG_cur_fc_cam = 0;
if (warehouse)
{
AENG_drawing_a_warehouse = TRUE;
AENG_ensure_appropriate_caching(TRUE);
AENG_draw_warehouse();
}
else
{
AENG_ensure_appropriate_caching(FALSE);
// if(ShiftFlag)
AENG_draw_city();
if (AENG_transparent_warehouses)
{
SUPERMAP_counter_increase(0);
AENG_ensure_appropriate_caching(TRUE);
AENG_draw_warehouse();
}
}
AENG_get_rid_of_deleteme_squares();
AENG_get_rid_of_unused_dfcache_lighting(FALSE);
//
// Restore the old camera.
//
fc->x = old_cam_x;
fc->y = old_cam_y;
fc->z = old_cam_z;
fc->yaw = old_cam_yaw;
fc->pitch = old_cam_pitch;
fc->roll = old_cam_roll;
fc->lens = old_cam_lens;
}
/*
if (draw_3d)
{
//
// How far apart are our eyes!?
//
static float eyes_apart = 10.0F;
if (Keys[KB_6])
{
if (ShiftFlag)
{
eyes_apart -= 1.0F;
}
else
{
eyes_apart += 1.0F;
}
}
float cam_x = AENG_cam_x;
float cam_y = AENG_cam_y;
float cam_z = AENG_cam_z;
float cam_yaw = AENG_cam_yaw;
float cam_pitch = AENG_cam_pitch;
float cam_roll = AENG_cam_roll;
float cam_matrix[9];
MATRIX_calc(
cam_matrix,
cam_yaw,
cam_pitch,
cam_roll);
//
// Left eye.
//
if (!ControlFlag)
{
AENG_set_camera_radians(
SLONG(cam_x + cam_matrix[0] * eyes_apart),
SLONG(cam_y + cam_matrix[1] * eyes_apart),
SLONG(cam_z + cam_matrix[2] * eyes_apart),
cam_yaw,
cam_pitch,
cam_roll);
POLY_colour_restrict = 0x0000ffff; // No green or blue
POLY_force_additive_alpha = FALSE;
AENG_draw_city();
//
// Clear just the z-buffer.
//
HRESULT res = the_display.lp_D3D_Viewport->Clear(1, &the_display.ViewportRect, D3DCLEAR_ZBUFFER);
ASSERT(res == DD_OK);
}
if (!ShiftFlag)
{
//
// Right eye.
//
AENG_set_camera_radians(
SLONG(cam_x - cam_matrix[0] * eyes_apart),
SLONG(cam_y - cam_matrix[1] * eyes_apart),
SLONG(cam_z - cam_matrix[2] * eyes_apart),
cam_yaw,
cam_pitch,
cam_roll);
POLY_colour_restrict = 0x00ff0000; // No red
POLY_force_additive_alpha = TRUE;
GAME_TURN += 1; // So the buildings are drawn again...
AENG_draw_city();
}
}
else
{
if (GAME_FLAGS & GF_INDOORS)
{
// AENG_draw_inside();
}
else
if (GAME_FLAGS & GF_SEWERS)
{
AENG_draw_ns();
}
else
if (WARE_in)
{
AENG_draw_warehouse();
}
else
{
AENG_draw_city();
}
}
*/
//
// Take out the dynamic lighting.
//
NIGHT_dlight_squares_down();
POLY_colour_restrict = 0;
POLY_force_additive_alpha = FALSE;
//SPONG
//#if !USE_TOMS_ENGINE_PLEASE_BOB
//
// Do it here so that AENG_world_line works during the game.
//
#ifndef TARGET_DC
POLY_frame_init(FALSE, FALSE);
#endif
//#endif
ULONG end_rdtsc = AENG_rdtsc();
if (end_rdtsc > start_rdtsc)
{
//
// The counter hasn't wrapped...
//
AENG_draw_time = end_rdtsc - start_rdtsc;
}
}
// read detail levels from file
void AENG_read_detail_levels()
{
#ifdef TARGET_DC
// Most things turned on, apart from the things that won't work.
//AENG_estimate_detail_levels = ENV_get_value_number("estimate_detail_levels", 0, "Render");
AENG_detail_stars = ENV_get_value_number("detail_stars", 1, "Render");
AENG_detail_shadows = ENV_get_value_number("detail_shadows", 0, "Render");
AENG_detail_moon_reflection = ENV_get_value_number("detail_moon_reflection", 0, "Render");
AENG_detail_people_reflection = ENV_get_value_number("detail_people_reflection", 0, "Render");
AENG_detail_puddles = ENV_get_value_number("detail_puddles", 0, "Render");
AENG_detail_dirt = ENV_get_value_number("detail_dirt", 1, "Render");
AENG_detail_mist = ENV_get_value_number("detail_mist", 1, "Render");
AENG_detail_rain = ENV_get_value_number("detail_rain", 1, "Render");
AENG_detail_skyline = ENV_get_value_number("detail_skyline", 1, "Render");
AENG_detail_filter = ENV_get_value_number("detail_filter", 1, "Render");
AENG_detail_perspective = ENV_get_value_number("detail_perspective", 1, "Render");
AENG_detail_crinkles = ENV_get_value_number("detail_crinkles", 0, "Render");
#ifndef DEBUG
// Release build - doesn't include the things that don't work yet!
AENG_detail_stars = ENV_get_value_number("detail_stars", 1, "Render");
AENG_detail_shadows = ENV_get_value_number("detail_shadows", 0, "Render");
AENG_detail_moon_reflection = ENV_get_value_number("detail_moon_reflection", 0, "Render");
AENG_detail_people_reflection = ENV_get_value_number("detail_people_reflection", 0, "Render");
AENG_detail_puddles = ENV_get_value_number("detail_puddles", 1, "Render");
AENG_detail_dirt = ENV_get_value_number("detail_dirt", 1, "Render");
AENG_detail_mist = ENV_get_value_number("detail_mist", 1, "Render");
AENG_detail_rain = ENV_get_value_number("detail_rain", 1, "Render");
AENG_detail_skyline = ENV_get_value_number("detail_skyline", 1, "Render");
AENG_detail_filter = ENV_get_value_number("detail_filter", 1, "Render");
AENG_detail_perspective = ENV_get_value_number("detail_perspective", 1, "Render");
AENG_detail_crinkles = ENV_get_value_number("detail_crinkles", 0, "Render");
#endif
#else
AENG_estimate_detail_levels = ENV_get_value_number("estimate_detail_levels", 1, "Render");
AENG_detail_stars = ENV_get_value_number("detail_stars", 1, "Render");
AENG_detail_shadows = ENV_get_value_number("detail_shadows", 1, "Render");
AENG_detail_moon_reflection = ENV_get_value_number("detail_moon_reflection", 1, "Render");
AENG_detail_people_reflection = ENV_get_value_number("detail_people_reflection", 1, "Render");
AENG_detail_puddles = ENV_get_value_number("detail_puddles", 1, "Render");
AENG_detail_dirt = ENV_get_value_number("detail_dirt", 1, "Render");
AENG_detail_mist = ENV_get_value_number("detail_mist", 1, "Render");
AENG_detail_rain = ENV_get_value_number("detail_rain", 1, "Render");
AENG_detail_skyline = ENV_get_value_number("detail_skyline", 1, "Render");
AENG_detail_filter = ENV_get_value_number("detail_filter", 1, "Render");
AENG_detail_perspective = ENV_get_value_number("detail_perspective", 1, "Render");
AENG_detail_crinkles = ENV_get_value_number("detail_crinkles", 1, "Render");
#endif
}
//
// Draws a small inside of the warehouse.
//
void AENG_draw_box_around_recessed_door(DFacet *df, SLONG inside_out)
{
SLONG i;
SLONG x;
SLONG z;
SLONG dx;
SLONG dz;
SLONG mx;
SLONG mz;
SLONG page;
SLONG upto;
ULONG sky_colour;
ULONG sky_specular;
SLONG col_page;
SLONG specular;
#ifdef TARGET_DC
POLY_flush_local_rot();
#endif
NIGHT_get_d3d_colour(
NIGHT_sky_colour,
&sky_colour,
&sky_specular);
sky_specular |= 0xff000000;
PAP_Hi *ph;
float wx;
float wy;
float wz;
#define MAX_DOOR_LENGTH 8
POLY_Point lower[MAX_DOOR_LENGTH][2];
POLY_Point upper[MAX_DOOR_LENGTH][2];
POLY_Point *pp;
POLY_Point *quad[4];
if (inside_out)
{
SWAP(df->x[0], df->x[1]);
SWAP(df->z[0], df->z[1]);
}
if (sw_hack)
{
col_page = POLY_PAGE_COLOUR;
specular = 0xee000000;
}
else
{
col_page = POLY_PAGE_COLOUR_WITH_FOG;
specular = 0xff000000;
}
//
// Create the points.
//
x = df->x[0];
z = df->z[0];
dx = df->x[1] - df->x[0];
dz = df->z[1] - df->z[0];
dx = SIGN(dx);
dz = SIGN(dz);
upto = 0;
while(1)
{
ASSERT(WITHIN(upto, 0, MAX_DOOR_LENGTH - 1));
for (i = 0; i < 4; i++)
{
wx = float(x << 8);
wz = float(z << 8);
wy = float(df->Y[0]);
if (i & 1)
{
//
// One block inside the warehouse.
//
wx += float(-dz << 8);
wz += float(+dx << 8);
}
if (i & 2)
{
//
// The upper level.
//
pp = &upper[upto][i & 1];
wy += 256.0F;
}
else
{
//
// The lower level.
//
pp = &lower[upto][i & 1];
}
POLY_transform(
wx,
wy,
wz,
pp);
if (i == 0)
{
if (inside_out)
{
pp->colour = 0xffaaaaaa;
pp->specular = 0xff000000;
}
else
{
pp->colour = 0xffaaaaaa;
pp->specular = 0xff000000;
}
}
else
{
if (inside_out)
{
pp->colour = 0xffffffff;
pp->specular = 0x01000000; // Completely fogged out...
}
else
{
pp->colour = 0xff000000;
pp->specular = 0xff000000;
}
}
pp->u = 0.0F;
pp->v = 0.0F;
}
upto += 1;
if (x == df->x[1] && z == df->z[1])
{
break;
}
x += dx;
z += dz;
}
ASSERT(upto >= 2);
//
// The faces on the floor and the ceiling.
//
x = df->x[0];
z = df->z[0];
for (i = 0; i < upto - 1; i++)
{
mx = (x << 8) + dx - dz >> 8;
mz = (z << 8) + dz + dx >> 8;
//
// The floor.
//
ph = &PAP_2HI(mx,mz);
quad[0] = &lower[i + 0][0];
quad[1] = &lower[i + 0][1];
quad[2] = &lower[i + 1][0];
quad[3] = &lower[i + 1][1];
if (POLY_valid_quad(quad))
{
TEXTURE_get_minitexturebits_uvs(
ph->Texture,
&page,
&quad[0]->u,
&quad[0]->v,
&quad[1]->u,
&quad[1]->v,
&quad[2]->u,
&quad[2]->v,
&quad[3]->u,
&quad[3]->v);
POLY_add_quad(quad, page, FALSE);
}
//
// The ceiling.
//
quad[0] = &upper[i + 0][0];
quad[1] = &upper[i + 0][1];
quad[2] = &upper[i + 1][0];
quad[3] = &upper[i + 1][1];
if (POLY_valid_quad(quad))
{
POLY_add_quad(quad, col_page, FALSE);
}
//
// The back wall.
//
quad[0] = &lower[i + 0][1];
quad[1] = &lower[i + 1][1];
quad[2] = &upper[i + 0][1];
quad[3] = &upper[i + 1][1];
if (POLY_valid_quad(quad))
{
POLY_add_quad(quad, col_page, FALSE);
}
x += dx;
z += dz;
}
//
// Create the two faces at each end.
//
quad[0] = &upper[0][0];
quad[2] = &upper[0][1];
quad[1] = &lower[0][0];
quad[3] = &lower[0][1];
if (POLY_valid_quad(quad))
{
if (!inside_out)
{
quad[0]->colour = 0xff000000;
quad[0]->specular = 0xff000000;
quad[1]->colour = 0xff000000;
quad[1]->specular = 0xff000000;
}
POLY_add_quad(quad, col_page, TRUE);
}
quad[0] = &upper[upto - 1][0];
quad[1] = &upper[upto - 1][1];
quad[2] = &lower[upto - 1][0];
quad[3] = &lower[upto - 1][1];
if (POLY_valid_quad(quad))
{
if (!inside_out)
{
quad[0]->colour = 0xff000000;
quad[0]->specular = 0xff000000;
quad[2]->colour = 0xff000000;
quad[2]->specular = 0xff000000;
}
POLY_add_quad(quad, col_page, TRUE);
}
if (inside_out)
{
SWAP(df->x[0], df->x[1]);
SWAP(df->z[0], df->z[1]);
}
}
//
// Get rid of any unused dfcache lighting.
//
void AENG_get_rid_of_unused_dfcache_lighting(SLONG splitscreen) // Splitscreen = TRUE or FALSE
{
SLONG dfcache;
SLONG next;
NIGHT_Dfcache *ndf;
for (dfcache = NIGHT_dfcache_used; dfcache; dfcache = next)
{
ASSERT(WITHIN(dfcache, 1, NIGHT_MAX_DFCACHES - 1));
ndf = &NIGHT_dfcache[dfcache];
next = ndf->next;
//
// Was this facet drawn this gameturn? If it wasn't then
// free up the cached lighting info for it.
//
ASSERT(WITHIN(ndf->dfacet, 1, next_dfacet - 1));
ASSERT(dfacets[ndf->dfacet].Dfcache == dfcache);
if (dfacets[ndf->dfacet].Counter[0] != SUPERMAP_counter[0])
{
if (splitscreen)
{
//
// Might have been drawn from the second camera.
//
if (dfacets[ndf->dfacet].Counter[1] == SUPERMAP_counter[1])
{
//
// It was drawn from the second camera! Don't get rid of it.
//
continue;
}
}
//
// Free up the lighting info.
//
dfacets[ndf->dfacet].Dfcache = 0;
NIGHT_dfcache_destroy(dfcache);
}
}
}
void AENG_draw_inside_floor(UWORD inside_index,UWORD inside_room,UBYTE fade)
{
SLONG x,z;
SLONG page;
float world_x;
float world_y,floor_y,roof_y;
float world_z;
POLY_Point pp[4];
#ifndef TARGET_DC
MapElement *me;
#endif
PAP_Lo *pl;
PAP_Hi *ph;
POLY_Point *quad[4];
struct InsideStorey *p_inside;
SLONG in_width;
UBYTE *in_block;
SLONG min_z,max_z;
SLONG c0;
SLONG floor_type;
SLONG do_light;
if(inside_index==light_inside)
do_light=1;
else
do_light=0;
//
// draw the internal walls
//
extern void draw_insides(SLONG indoor_index,SLONG room,UBYTE fade);
draw_insides(inside_index,inside_room,fade);
p_inside=&inside_storeys[inside_index];
floor_type=p_inside->TexType;
// MSG_add("in room %d\n",INDOORS_ROOM);
floor_y=(float)p_inside->StoreyY;
roof_y=floor_y+256.0f;
min_z=MAX(NGAMUT_point_zmin,p_inside->MinZ);
max_z=MIN(NGAMUT_point_zmax,p_inside->MaxZ);
in_width=p_inside->MaxX-p_inside->MinX;
in_block=&inside_block[p_inside->InsideBlock];
for(c0=0;c0<4;c0++)
{
pp[c0].colour=0xffffff;
pp[c0].specular=0xff000000;
}
quad[0]=&pp[0];
quad[1]=&pp[1];
quad[2]=&pp[2];
quad[3]=&pp[3];
quad[0]->u=0.0;
quad[0]->v=0.0;
quad[1]->u=1.0;
quad[1]->v=0.0;
quad[2]->u=0.0;
quad[2]->v=1.0;
quad[3]->u=1.0;
quad[3]->v=1.0;
for (z = min_z; z < max_z; z++)
{
SLONG min_x,max_x;
float face_y;
SLONG col;
min_x=MAX(NGAMUT_point_gamut[z].xmin,p_inside->MinX);
max_x=MIN(NGAMUT_point_gamut[z].xmax,p_inside->MaxX);
for (x = min_x;x<max_x;x++)
{
ASSERT(WITHIN(x, 0, MAP_WIDTH - 1));
ASSERT(WITHIN(z, 0, MAP_HEIGHT - 1));
#ifndef TARGET_DC
me = &MAP[MAP_INDEX(x, z)];
#endif
ph = &PAP_2HI(x,z);
if ((PAP_2HI(x,z).Flags & (PAP_FLAG_HIDDEN)))
{
SLONG room_id;
SLONG px,pz,dx,dz,square;
NIGHT_Square *nq;
room_id=in_block[(x-p_inside->MinX)+(z-p_inside->MinZ)*in_width]&(0xf|0x80|0x40);
if(!(room_id&0xc0))
{
if(1||(room_id&0xf)==inside_room)
{
face_y=floor_y;
col=0xffffff;
}
else
{
face_y=roof_y;
col=0;
}
col=col|( (fade&255)<<24);
if(room_id)
{
world_x = x * 256.0F;
world_z = z * 256.0F;
POLY_transform(world_x, face_y, world_z, &pp[0]);
if(do_light)
{
px = x >> 2;
pz = z >> 2;
ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1));
square = NIGHT_cache[px][pz];
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
if(!square)
return;
nq = &NIGHT_square[square];
NIGHT_get_d3d_colour(
nq->colour[(x&3) + (z&3) * PAP_BLOCKS],
&pp->colour,
&pp->specular);
pp->colour|=fade<<24;
}
else
{
pp->colour=0x7f7f7f|(fade<<24);
pp->specular=0xff000000;
}
world_x = (x+1) * 256.0F;
world_z = z * 256.0F;
POLY_transform(world_x, face_y, world_z, &pp[1]);
if(do_light)
{
if( (x+1)>>2!=px)
{
px = (x+1) >> 2;
// pz = z >> 2;
ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1));
square = NIGHT_cache[px][pz];
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
if(!square)
return;
nq = &NIGHT_square[square];
}
NIGHT_get_d3d_colour(
nq->colour[((x+1)&3) + (z&3) * PAP_BLOCKS],
&(pp[1].colour),
&(pp[1].specular));
pp[1].colour|=fade<<24;
}
else
{
pp[1].colour=0x7f7f7f|(fade<<24);
pp[1].specular=0xff000000;
}
world_x = x * 256.0F;
world_z = (z+1) * 256.0F;
POLY_transform(world_x, face_y, world_z, &pp[2]);
if(do_light)
{
if( (z+1)>>2!=pz || (x>>2)!=px)
{
px = x >> 2;
pz = (z+1) >> 2;
ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1));
square = NIGHT_cache[px][pz];
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
if(!square)
return;
nq = &NIGHT_square[square];
}
NIGHT_get_d3d_colour(
nq->colour[(x&3) + ((z+1)&3) * PAP_BLOCKS],
&(pp[2].colour),
&(pp[2].specular));
pp[2].colour|=fade<<24;
}
else
{
pp[2].colour=0x7f7f7f|(fade<<24);
pp[2].specular=0xff000000;
}
world_x = (x+1) * 256.0F;
world_z = (z+1) * 256.0F;
POLY_transform(world_x, face_y, world_z, &pp[3]);
if(do_light)
{
if( (x+1)>>2!=px || (z+1)>>2!=pz)
{
px = (x+1) >> 2;
pz = (z+1) >> 2;
ASSERT(WITHIN(px, 0, PAP_SIZE_LO - 1));
ASSERT(WITHIN(pz, 0, PAP_SIZE_LO - 1));
square = NIGHT_cache[px][pz];
if(!square)
return;
ASSERT(WITHIN(square, 1, NIGHT_MAX_SQUARES - 1));
ASSERT(NIGHT_square[square].flag & NIGHT_SQUARE_FLAG_USED);
nq = &NIGHT_square[square];
}
NIGHT_get_d3d_colour(
nq->colour[((x+1)&3) + ((z+1)&3) * PAP_BLOCKS],
&(pp[3].colour),
&(pp[3].specular));
pp[3].colour|=fade<<24;
}
else
{
pp[3].colour=0x7f7f7f|(fade<<24);
pp[3].specular=0xff000000;
}
if (pp[0].MaybeValid() && pp[1].MaybeValid() && pp[2].MaybeValid() && pp[3].MaybeValid())
{
pp[0].colour=col;
pp[1].colour=col;
pp[2].colour=col;
pp[3].colour=col;
page=inside_tex[floor_type][room_id-1]+START_PAGE_FOR_FLOOR*64; // temp
POLY_add_quad(quad, page, FALSE);
}
}
}
}
}
}
}