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

1154 lines
20 KiB
C++

#include "game.h"
#include "supermap.h"
#include "pap.h"
#include "ob.h"
#include "memory.h"
#ifdef _DEBUG
#define FACET_REMOVAL_TEST // if defined, still put removed facets into the map
#endif
#ifndef PSX
void calc_ladder_ends(SLONG *x1,SLONG *z1,SLONG *x2,SLONG *z2)
{
SLONG dx,dz;
dx=*x2-*x1;
dz=*z2-*z1;
*x1+=dx/3;
*z1+=dz/3;
*x2-=dx/3;
*z2-=dz/3;
*x1+=dz>>3;
*x2+=dz>>3;
*z1-=dx>>3;
*z2-=dx>>3;
}
//
// find an available block of links
//
SLONG find_empty_facet_block(SLONG count)
{
SLONG c0,c1;
//
// Is there space at the end?
//
if((MAX_FACET_LINK)-next_facet_link>count)
{
next_facet_link+=count;
return(next_facet_link-count);
}
else
{
//
// search for gap
//
// return(0);
for(c0=1;c0<next_facet_link;c0++)
{
if(facet_links[c0]==0)
{
SLONG empty=1;
for(c1=c0+1;(c1<next_facet_link) && (empty<count) ;c1++)
{
if(facet_links[c1])
break;
empty++;
}
if(empty==count)
return(c0);
}
}
}
return(0);
}
//
// facet index is the block to insert a gap before
//
SLONG garbage_collection(void)
{
SLONG index,next=1;
SWORD *mem;
SLONG x,z;
SLONG ret=0;
UWORD per_map[150],c0,saved=0;
memset(per_map,0,300);
mem=(SWORD*)MemAlloc(MAX_FACET_LINK*sizeof(SWORD));
ASSERT(mem);
// DebugText(" garbage collect nfl %d\n",next_facet_link);
for(x=0;x<PAP_SIZE_LO;x++)
for(z=0;z<PAP_SIZE_LO;z++)
{
SLONG count;
if(index=PAP_2LO(x,z).ColVectHead)
{
PAP_2LO(x,z).ColVectHead=next;
#ifdef SAVE_A_FEW_MORE_BYTES
for(c0=1;c0<next;c0++)
{
SLONG match=0;
count=0;
while(mem[c0+match]==facet_links[index+match] && (c0+match)<next)
{
count++;
if(facet_links[index+match]<0)
{
saved+=count;
// DebugText(" found match saved %d (total %d)\n",count,saved);
PAP_2LO(x,z).ColVectHead=c0;
goto repeated_duplicate;
}
match++;
}
}
#endif
count=0;
while(1)
{
// DebugText(" copy from %d to %d (data %d) count %d \n",index,next,facet_links[index],count);
count++;
mem[next++]=facet_links[index++];
if(facet_links[index-1]<0)
{
ASSERT(count<150);
per_map[count]++;
break;
}
}
#ifdef SAVE_A_FEW_MORE_BYTES
repeated_duplicate:;
#endif
}
}
for(c0=0;c0<150;c0++)
{
DebugText(" FACET_PER MAP (%d) ==%d \n",c0,per_map[c0]);
}
memcpy((UBYTE*)&facet_links[0],(UBYTE*) mem,next*sizeof(UWORD));
next_facet_link=next;
DebugText(" after nfl=%d +saved=%d\n",next_facet_link,next_facet_link+saved);
for(x=0;x<PAP_SIZE_LO;x++)
for(z=0;z<PAP_SIZE_LO;z++)
{
if(PAP_2LO(x,z).ColVectHead)
ASSERT(facet_links[PAP_2LO(x,z).ColVectHead]!=0);
}
MemFree((UBYTE*)mem);
return(0);
}
//
// create an extra facet for a block.
//
SLONG create_extra_facet(SLONG facet,SLONG findex)
{
SLONG pos,count=1;
SLONG garbage=0;
//
// count number of facets on this facetlink (-ve is end flag)
//
pos=findex;
while(facet_links[pos++]>0)
{
ASSERT(facet_links[pos-1]!=facet);
count++;
}
ASSERT(abs(facet_links[pos-1])!=abs(facet));
//
// find place with count+1 available slots (if room just stick them on the end)
//
try_again:;
pos=find_empty_facet_block(count+1);
if(pos)
{
SLONG pos_copy;
pos_copy=pos+1;
//
// copy to new place, and erase old place
//
while(count)
{
facet_links[pos_copy++]=facet_links[findex++];
facet_links[findex-1]=0;
count--;
}
}
else
{
//
// failed to find a gap so garbage collect
//
ASSERT(garbage==0);
garbage++;
garbage_collection();
goto try_again;
}
//
// return place found for count+1 facets
//
return(pos);
}
#endif
#ifndef PSX
void link_facet_to_mapwho(SLONG mx,SLONG mz,SLONG facet)
{
SLONG index;
SLONG pos;
// ASSERT(facet!=17);
// if(facet==2456)
// {
// ASSERT(0);
// }
if(mx==13 && mz==5)
LogText(" add FACET %d to %d,%d\n",facet,mx,mz);
if(mx<0||mx>PAP_SIZE_LO||mz<0||mz>PAP_SIZE_LO)
{
LogText("ERROR add facet %d to mx %d %d nfl %d\n",facet,mx,mz,next_facet_link);
return;
}
// DebugText(" add facet %d to mx %d %d nfl %d link count %d\n",facet,mx,mz,next_facet_link,facet_link_count);
facet_link_count++;
if(facet_link_count>=MAX_FACET_LINK)
return;
if(index=PAP_2LO(mx,mz).ColVectHead)
{
//
// mapwho allready contains some data
//
pos=create_extra_facet(facet,index);
if(pos)
{
// ASSERT(pos!=129);
// MAP2(mx,mz).ColVectHead=pos;
PAP_2LO(mx,mz).ColVectHead=pos;
// ASSERT(pos!=23);
facet_links[pos]=facet;
}
else
ASSERT(0);
}
else
{
//
// no data there so start list
//
pos=find_empty_facet_block(1);
// ASSERT(pos!=129);
if(pos)
{
// MAP2(mx,mz).ColVectHead=pos;
PAP_2LO(mx,mz).ColVectHead=pos;
// ASSERT(pos!=23);
facet_links[pos]=-facet;
}
else
{
ASSERT(0);
// out of facet links
}
}
}
void add_facet_to_map(SLONG facet)
{
SLONG x1,z1,x2,z2,dx,dz;
SLONG count;
struct DFacet *p_f;
p_f=&dfacets[facet];
// if(facet==2456)
// {
// ASSERT(0);
// }
if(facet==288||facet==289)
LogText("break");
x1=p_f->x[0] << 8;
x2=p_f->x[1] << 8;
z1=p_f->z[0] << 8;
z2=p_f->z[1] << 8;
dx=x2-x1;
dz=z2-z1;
if(dx==0&&dz==0)
return;
switch(p_f->FacetType)
{
case STOREY_TYPE_LADDER:
{
SLONG y,extra_height;
calc_ladder_ends(&x1,&z1,&x2,&z2);
}
break;
}
{
SLONG x;
SLONG z;
SLONG mx;
SLONG mz;
SLONG end_mx;
SLONG end_mz;
SLONG frac;
SLONG xfrac;
SLONG zfrac;
#ifndef NDEBUG
SLONG count = 0;
#endif
dx = x2 - x1;
dz = z2 - z1;
SLONG adx = abs(dx);
SLONG adz = abs(dz);
mx = x1 >> PAP_SHIFT_LO;
mz = z1 >> PAP_SHIFT_LO;
end_mx = x2 >> PAP_SHIFT_LO;
end_mz = z2 >> PAP_SHIFT_LO;
xfrac = x1 & ((1 << PAP_SHIFT_LO) - 1);
zfrac = z1 & ((1 << PAP_SHIFT_LO) - 1);
if (adx > adz)
{
frac = (dz << PAP_SHIFT_LO) / dx;
if (dx > 0)
{
z = z1;
z -= frac * xfrac >> PAP_SHIFT_LO;
}
else
{
z = z1;
z += frac * ((1 << PAP_SHIFT_LO) - xfrac) >> PAP_SHIFT_LO;
}
while(1)
{
#ifndef NDEBUG
ASSERT(count++ < 64);
#endif
if (WITHIN(mx, 0, PAP_SIZE_LO - 1) &&
WITHIN(mz, 0, PAP_SIZE_LO - 1))
{
link_facet_to_mapwho(mx,mz,facet);
}
if (mx == end_mx &&
mz == end_mz)
{
return;
}
//
// Step in z.
//
if (dx > 0)
{
z += frac;
}
else
{
z -= frac;
}
if ((z >> PAP_SHIFT_LO) != mz)
{
//
// Step up/down in z through another mapsquare.
//
mz = z >> PAP_SHIFT_LO;
if (WITHIN(mx, 0, PAP_SIZE_LO - 1) &&
WITHIN(mz, 0, PAP_SIZE_LO - 1))
{
link_facet_to_mapwho(mx,mz,facet);
}
}
//
// Step in x.
//
if (dx > 0)
{
mx += 1;
if (mx > end_mx)
{
return;
}
}
else
{
mx -= 1;
if (mx < end_mx)
{
return;
}
}
}
}
else
{
frac = (dx << PAP_SHIFT_LO) / dz;
if (dz > 0)
{
x = x1;
x -= frac * zfrac >> PAP_SHIFT_LO;
}
else
{
x = x1;
x += frac * ((1 << PAP_SHIFT_LO) - zfrac) >> PAP_SHIFT_LO;
}
while(1)
{
#ifndef NDEBUG
ASSERT(count++ < 64);
#endif
if (WITHIN(mx, 0, PAP_SIZE_LO - 1) &&
WITHIN(mz, 0, PAP_SIZE_LO - 1))
{
link_facet_to_mapwho(mx,mz,facet);
}
if (mx == end_mx &&
mz == end_mz)
{
return;
}
//
// Step in x.
//
if (dz > 0)
{
x += frac;
}
else
{
x -= frac;
}
if ((x >> PAP_SHIFT_LO) != mx)
{
//
// Step up/down in z through another mapsquare.
//
mx = x >> PAP_SHIFT_LO;
if (WITHIN(mx, 0, PAP_SIZE_LO - 1) &&
WITHIN(mz, 0, PAP_SIZE_LO - 1))
{
link_facet_to_mapwho(mx,mz,facet);
}
}
//
// Step in z.
//
if (dz > 0)
{
mz += 1;
if (mz > end_mz)
{
return;
}
}
else
{
mz -= 1;
if (mz < end_mz)
{
return;
}
}
}
}
}
/*
dx=x2-x1;
dz=z2-z1;
if(abs(dz)>abs(dx))
{
//
// step along dz
//
count=(abs(dz)+((1<<PAP_SHIFT_LO)-1))>>PAP_SHIFT_LO;
if(dz<0)
dz=-(1<<PAP_SHIFT_LO);
else
dz=(1<<PAP_SHIFT_LO);
while(count--)
{
link_facet_to_mapwho(x1>>PAP_SHIFT_LO,z1>>PAP_SHIFT_LO,facet);
z1+=dz;
}
}
else
{
//
// step along dx
//
count=(abs(dx)+((1<<PAP_SHIFT_LO)-1))>>PAP_SHIFT_LO;
if(dx<0)
dx=-(1<<PAP_SHIFT_LO);
else
dx=(1<<PAP_SHIFT_LO);
while(count--)
{
link_facet_to_mapwho(x1>>PAP_SHIFT_LO,z1>>PAP_SHIFT_LO,facet);
x1+=dx;
}
}
*/
}
void process_facet(SLONG facet)
{
if(dfacets[facet].FacetType!=STOREY_TYPE_INSIDE)
if(dfacets[facet].FacetType!=STOREY_TYPE_OINSIDE)
if(dfacets[facet].FacetType!=STOREY_TYPE_INSIDE_DOOR)
add_facet_to_map(facet);
}
void process_building(SLONG build)
{
SLONG c0;
struct DBuilding *p_build;
p_build=&dbuildings[build];
for(c0=p_build->StartFacet;c0<p_build->EndFacet;c0++)
{
// only process if not marked as invisible
#ifndef FACET_REMOVAL_TEST
if (dfacets[c0].FacetFlags & FACET_FLAG_INVISIBLE)
{
if (dbuildings[dfacets[c0].Building].Type == BUILDING_TYPE_CRATE_IN)
{
//
// We must add the facet to the map for CRATE_INSIDEs because it make the
// floor of Poshetas dissapear.
//
}
else
{
continue;
}
}
#endif
process_facet(c0);
}
}
void clear_colvects(void)
{
SLONG x,z;
for(x=0;x<PAP_SIZE_LO;x++)
for(z=0;z<PAP_SIZE_LO;z++)
{
PAP_2LO(x,z).ColVectHead=0;
PAP_2LO(x,z).Walkable=0;
}
}
void clear_facet_links(void)
{
SLONG c0;
for(c0=0;c0<MAX_FACET_LINK;c0++)
{
facet_links[c0]=0;
}
}
#endif
void attach_walkable_to_map(SLONG face)
{
SLONG x=0,z=0;
SLONG c0;
if(face>0)
{
for(c0=0;c0<4;c0++)
{
x+=prim_points[prim_faces4[face].Points[c0]].X;
z+=prim_points[prim_faces4[face].Points[c0]].Z;
}
x >>= 2;
z >>= 2;
x >>= PAP_SHIFT_LO;
z >>= PAP_SHIFT_LO;
SATURATE(x, 0, PAP_SIZE_LO - 1);
SATURATE(z, 0, PAP_SIZE_LO - 1);
prim_faces4[face].WALKABLE=PAP_2LO(x,z).Walkable;
PAP_2LO(x,z).Walkable=face;
}
else
{
roof_faces4[-face].Next=PAP_2LO((roof_faces4[-face].RX&127)>>2,(roof_faces4[-face].RZ&127)>>2).Walkable;
PAP_2LO((roof_faces4[-face].RX&127)>>2,(roof_faces4[-face].RZ&127)>>2).Walkable=face;
}
}
void remove_walkable_from_map(SLONG face)
{
SLONG x=0,z=0;
SLONG c0;
SWORD *prev;
SWORD next;
SWORD count=50;
for(c0=0;c0<4;c0++)
{
x+=prim_points[prim_faces4[face].Points[c0]].X;
z+=prim_points[prim_faces4[face].Points[c0]].Z;
}
x >>= 2;
z >>= 2;
x >>= PAP_SHIFT_LO;
z >>= PAP_SHIFT_LO;
SATURATE(x, 0, PAP_SIZE_LO - 1);
SATURATE(z, 0, PAP_SIZE_LO - 1);
prev = &PAP_2LO(x,z).Walkable;
next = PAP_2LO(x,z).Walkable;
while(count--)
{
// ASSERT(WITHIN(next, 1, next_prim_face4 - 1));
if (next == face)
{
if(face<0)
{
*prev = roof_faces4[-next].Next;
}
else
{
*prev = prim_faces4[next].WALKABLE;
}
return;
}
if(next<0)
{
prev = &roof_faces4[-next].Next;
next = roof_faces4[-next].Next;
}
else
{
prev = &prim_faces4[next].WALKABLE;
next = prim_faces4[next].WALKABLE;
}
}
//printf("Couldn't find face %d to remove.\n",face);
ASSERT(0);
}
/*
NOGO flag is not used anymore
void set_nogo_pap_flags(void)
{
SLONG x,z;
for(x=0;x<PAP_SIZE_HI;x++)
for(z=0;z<PAP_SIZE_HI;z++)
{
SLONG min,max,h;
h=PAP_hi[(x)&(PAP_SIZE_HI-1)][(z)&(PAP_SIZE_HI-1)].Alt;
min=h;
max=h;
h=PAP_hi[(x+1)&(PAP_SIZE_HI-1)][(z)&(PAP_SIZE_HI-1)].Alt;
min=MIN(h,min);
max=MAX(h,max);
h=PAP_hi[(x+1)&(PAP_SIZE_HI-1)][(z+1)&(PAP_SIZE_HI-1)].Alt;
min=MIN(h,min);
max=MAX(h,max);
h=PAP_hi[(x)&(PAP_SIZE_HI-1)][(z+1)&(PAP_SIZE_HI-1)].Alt;
min=MIN(h,min);
max=MAX(h,max);
if((abs(min-max))>30)
PAP_hi[x][z].Flags|=PAP_FLAG_NOGO;
}
}
*/
#ifndef PSX
static void mark_naughty_facets();
void build_quick_city(void)
{
SLONG c0;
clear_colvects();
clear_facet_links();
facet_link_count=0;
next_facet_link=1;
// mark those facets which can't be seen
mark_naughty_facets();
for(c0=1;c0<next_dbuilding;c0++)
{
process_building(c0);
}
garbage_collection();
/*
{
SLONG x,z;
for(x=0;x<PAP_SIZE_LO;x++)
for(z=0;z<PAP_SIZE_LO;z++)
{
SLONG index,count=0;
SLONG exit=0;
index=PAP_2LO(x,z).ColVectHead;
while(!exit)
{
if(facet_links[index]<0)
exit=1;
index++;
count++;
}
LogText(" map x %d z %d count %d \n",x,z,count);
}
}
*/
for(c0=1;c0<next_dwalkable;c0++)
{
SLONG face;
ASSERT(dwalkables[c0].StartFace4<=next_roof_face4);
ASSERT(dwalkables[c0].EndFace4<=next_roof_face4);
for(face=dwalkables[c0].StartFace4;face<dwalkables[c0].EndFace4;face++)
{
/*
prim_faces4[face].ThingIndex=dwalkables[c0].Building;
attach_walkable_to_map(face);
prim_faces4[face].FaceFlags|=FACE_FLAG_WALKABLE;
prim_faces4[face].FaceFlags&=~FACE_FLAG_SMOOTH; // This is used by moving walkables.
*/
attach_walkable_to_map(-face);
}
}
//
// NOGO flags dont exist any more.
//
// set_nogo_pap_flags();
//
}
#endif
// mark_naughty_facets
//
// remove any facets which can never be seen and clear the style value
// for subfacets which can never be seen
static bool facet_is_solid(const DFacet* pf);
static int compare_facets(const DFacet* pf1, const DFacet* pf2);
#ifndef PSX
static void mark_naughty_facets()
{
SLONG ii;
SLONG jj;
SLONG cnt;
// mark all the facets as live
for (ii = 0; ii < next_dfacet; ii++)
{
dfacets[ii].FacetFlags &= ~FACET_FLAG_INVISIBLE;
}
// mark dead facets
cnt = 0;
for (ii = 0; ii < next_dfacet; ii++)
{
DFacet* pf1 = &dfacets[ii];
if(pf1->x[0]==pf1->x[1] && pf1->z[0]==pf1->z[1])
{
pf1->FacetFlags |= FACET_FLAG_INVISIBLE;
continue;
}
// ASSERT(ii!=155 && ii!=157);
if (pf1->FacetFlags & FACET_FLAG_INVISIBLE) continue;
if (!facet_is_solid(pf1)) continue;
// compare against all others
for (jj = ii + 1; jj < next_dfacet; jj++)
{
DFacet* pf2 = &dfacets[jj];
if(pf2->x[0]==pf2->x[1] && pf2->z[0]==pf2->z[1])
{
pf2->FacetFlags |= FACET_FLAG_INVISIBLE;
continue;
}
if (pf2->FacetFlags & FACET_FLAG_INVISIBLE) continue;
if (!facet_is_solid(pf2)) continue;
switch (compare_facets(pf1, pf2))
{
case 1:
pf1->FacetFlags |= FACET_FLAG_INVISIBLE;
cnt++;
break;
case 2:
pf2->FacetFlags |= FACET_FLAG_INVISIBLE;
cnt++;
break;
case 3:
pf1->FacetFlags |= FACET_FLAG_INVISIBLE;
pf2->FacetFlags |= FACET_FLAG_INVISIBLE;
cnt += 2;
break;
}
}
}
TRACE("Removed %d invisible facets\n", cnt);
}
extern void MAV_remove_facet_car(SLONG x1, SLONG z1, SLONG x2, SLONG z2);
void BUILD_car_facets()
{
for (int ii = 0; ii < next_dfacet; ii++)
{
DFacet* pf = &dfacets[ii];
if (pf->FacetFlags & FACET_FLAG_INVISIBLE) continue;
if (pf->FacetType == STOREY_TYPE_CABLE) continue;
MAV_remove_facet_car(pf->x[0], pf->z[0], pf->x[1], pf->z[1]);
}
}
static bool facet_is_solid(const DFacet* pf)
{
if (pf->FacetFlags & FACET_FLAG_2SIDED) return false;
if (pf->FacetFlags & FACET_FLAG_2TEXTURED) return false;
if ((pf->FacetType == STOREY_TYPE_JUST_COLLISION) ||
(pf->FacetType == STOREY_TYPE_FENCE) ||
(pf->FacetType == STOREY_TYPE_FENCE_FLAT) ||
(pf->FacetType == STOREY_TYPE_FENCE_BRICK) ||
(pf->FacetType == STOREY_TYPE_INSIDE) ||
(pf->FacetType == STOREY_TYPE_INSIDE_DOOR) ||
(pf->FacetType == STOREY_TYPE_OUTSIDE_DOOR) ||
(pf->FacetType == STOREY_TYPE_LADDER) ||
(pf->FacetType == STOREY_TYPE_CABLE))
{
return false; // not solid
}
return true;
}
#endif
// compare_facets
//
// see if we can delete one or both of the facets because they hide each other
//
// note: takes no notice of the facet types; you should first check they are
// solid one-sided facets
//
// we test for multiple cases:
//
// two facets facing each other of same size (remove both)
// two facets facing each other one surrounding the other (remove smaller)
// two facets facing same way, one surrounding the other (remove smaller)
// two facets facing same way of same size (remove one at random)
//
// returns +1 to remove pf1, +2 to remove pf2
#ifndef PSX
static int compare_facets(const DFacet* pf1, const DFacet* pf2)
{
// are the facets parallel?
SLONG dx1 = pf1->x[1] - pf1->x[0];
SLONG dz1 = pf1->z[1] - pf1->z[0];
SLONG dx2 = pf2->x[1] - pf2->x[0];
SLONG dz2 = pf2->z[1] - pf2->z[0];
if (dx1 * dz2 != dx2 * dz1) return 0;
// are the facets collinear?
// check three cases - dz == 0, dx == 0 and neither == 0
if (!dz1)
{
if (pf1->z[0] != pf2->z[0]) return 0;
}
else if (!dx1)
{
if (pf1->x[0] != pf2->x[0]) return 0;
}
else
{
// intercept point (with x axis) is at zi = z1 - x1 * dz / dx
// giving zi * dx = z1 * dx - x1 * dz (nice and symettrical)
// so we need (pf1->z[0] * dx1 - pf1->x[0] * dz1) / dx1 = (pf2->z[0] * dx2 - pf2->x[0] * dz2) / dx2
// but we can multiply through by dx1 and dx2 so we can work in integers
SLONG lhs = (pf1->z[0] * dx1 - pf1->x[0] * dz1) * dx2;
SLONG rhs = (pf2->z[0] * dx2 - pf2->x[0] * dz2) * dx1;
if (lhs != rhs) return 0;
}
// extract start and end points which can be compared
SLONG s1,e1;
SLONG s2,e2;
if (abs(dx1) > abs(dz1))
{
s1 = pf1->x[0]; e1 = pf1->x[1];
s2 = pf2->x[0]; e2 = pf2->x[1];
}
else
{
s1 = pf1->z[0]; e1 = pf1->z[1];
s2 = pf2->z[0]; e2 = pf2->z[1];
}
// remove either facet if it's null
int rc = 0;
if (s1 == e1) rc += 1; // remove facet 1, it's null
if (s2 == e2) rc += 2; // remove facet 2, it's null
if (rc) return rc;
// are the facets facing the same way?
SLONG sgn1 = s1 - e1;
SLONG sgn2 = s2 - e2;
bool sameway = ((sgn1 ^ sgn2) >= 0); // true iff (s1 - e1) and (s2 - e2) have same sign
// get y at bottom of start and end, and heights
SLONG ys1 = pf1->Y[0];
SLONG ye1 = pf1->Y[1];
SLONG ys2 = pf2->Y[0];
SLONG ye2 = pf2->Y[1];
SLONG h1 = (pf1->Height / 4) * pf1->BlockHeight * 16;
SLONG h2 = (pf2->Height / 4) * pf2->BlockHeight * 16;
// put start and end in order
if (s1 > e1)
{
SWAP(s1,e1);
SWAP(ys1,ye1);
}
if (s2 > e2)
{
SWAP(s2,e2);
SWAP(ys2,ye2);
}
// quick special case of exactly the same size
if ((s1 == s2) && (e1 == e2) && (ys1 == ys2) && (ye1 == ye2) && (h1 == h2))
{
if (sameway)
{
// remove one at random
// TRACE("Facets %d and %d are identical but face the same way - removing one at random\n", pf1 - dfacets, pf2 - dfacets);
return (rand() & 128) ? 1 : 2;
}
else
{
// remove both
// TRACE("Facets %d and %d are identical and cancel out - removing both\n", pf1 - dfacets, pf2 - dfacets);
return 3;
}
}
// equal extents along the ground?
if ((s1 == s2) && (e1 == e2))
{
// TRACE("Facets %d and %d are identical on the ground\n", pf1 - dfacets, pf2 - dfacets);
// TRACE("y1 - %d -> %d + %d\n", ys1, ye1, h1);
// TRACE("y2 - %d -> %d + %d\n", ys2, ye2, h2);
// yes - check for containment either way
if ((ys1 <= ys2) && (ys1 + h1 >= ys2 + h2) && (ye1 <= ye2) && (ye1 + h1 >= ye2 + h2))
{
// TRACE("Removing 2\n");
return 2; // 1 contains 2
}
if ((ys2 <= ys1) && (ys2 + h2 >= ys1 + h1) && (ye2 <= ye1) && (ye2 + h2 >= ye1 + h1))
{
// TRACE("Removing 1\n");
return 1; // 2 contains 1
}
return 0;
}
// 1 contains 2 along ground?
if ((s1 <= s2) && (e1 >= e2))
{
// TRACE("Facet %d contains %d on the ground\n", pf1 - dfacets, pf2 - dfacets);
// TRACE("(%d - %d) contains (%d - %d)\n", s1,e1, s2,e2);
// TRACE("y1 - %d -> %d + %d\n", ys1, ye1, h1);
// TRACE("y2 - %d -> %d + %d\n", ys2, ye2, h2);
// get ys1 and ye1 when s1 -> s2 and e1 -> e2
ys1 += (s2 - s1) * (ye1 - ys1) / (e1 - s1);
s1 = s2;
ye1 += (e2 - e1) * (ye1 - ys1) / (e1 - s1);
e1 = e2;
// TRACE("NEW y1 - %d -> %d + %d\n", ys1, ye1, h1);
// check for 1 contains 2
if ((ys1 <= ys2) && (ys1 + h1 >= ys2 + h2) && (ye1 <= ye2) && (ye1 + h1 >= ye2 + h2))
{
// TRACE("Removing 2\n");
return 2;
}
return 0;
}
// 2 contains 1 along ground?
if ((s2 <= s1) && (e2 >= e1))
{
// TRACE("Facet %d is contained by %d on the ground\n", pf1 - dfacets, pf2 - dfacets);
// TRACE("(%d - %d) is contained by (%d - %d)\n", s1,e1, s2,e2);
// TRACE("y1 - %d -> %d + %d\n", ys1, ye1, h1);
// TRACE("y2 - %d -> %d + %d\n", ys2, ye2, h2);
// get ys2 and ye2 when s2 -> s1 and e2 -> e1
ys2 += (s1 - s2) * (ye2 - ys2) / (e2 - s2);
s2 = s1;
ye2 += (e1 - e2) * (ye2 - ys2) / (e2 - s2);
e2 = e1;
// TRACE("NEW y2 - %d -> %d + %d\n", ys2, ye2, h2);
// check for 2 contains 1
if ((ys2 <= ys1) && (ys2 + h2 >= ys1 + h1) && (ye2 <= ye1) && (ye2 + h2 >= ye1 + h1))
{
// TRACE("Removing 1\n");
return 1;
}
return 0;
}
// neither contains the other
return 0;
}
#endif