mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-14 08:31:23 +00:00
14a42bbada
SVN r1801 (trunk)
1596 lines
48 KiB
C++
1596 lines
48 KiB
C++
/**************************************************************************************************
|
||
"POLYMOST" code written by Ken Silverman
|
||
Ken Silverman's official web site: http://www.advsys.net/ken
|
||
This file has been modified (severely) from Ken Silverman's original release
|
||
|
||
Motivation:
|
||
When 3D Realms released the Duke Nukem 3D source code, I thought somebody would do a OpenGL or
|
||
Direct3D port. Well, after a few months passed, I saw no sign of somebody working on a true
|
||
hardware-accelerated port of Build, just people saying it wasn't possible. Eventually, I realized
|
||
the only way this was going to happen was for me to do it myself. First, I needed to port Build to
|
||
Windows. I could have done it myself, but instead I thought I'd ask my Australian buddy, Jonathon
|
||
Fowler, if he would upgrade his Windows port to my favorite compiler (MSVC) - which he did. Once
|
||
that was done, I was ready to start the "POLYMOST" project.
|
||
|
||
About:
|
||
This source file is basically a complete rewrite of the entire rendering part of the Build engine.
|
||
There are small pieces in ENGINE.C to activate this code, and other minor hacks in other source
|
||
files, but most of it is in here. If you're looking for polymost-related code in the other source
|
||
files, you should find most of them by searching for either "polymost" or "rendmode". Speaking of
|
||
rendmode, there are now 4 rendering modes in Build:
|
||
|
||
rendmode 0: The original code I wrote from 1993-1997
|
||
rendmode 1: Solid-color rendering: my debug code before I did texture mapping
|
||
rendmode 2: Software rendering before I started the OpenGL code (Note: this is just a quick
|
||
hack to make testing easier - it's not optimized to my usual standards!)
|
||
rendmode 3: The OpenGL code
|
||
|
||
The original Build engine did hidden surface removal by using a vertical span buffer on the tops
|
||
and bottoms of walls. This worked nice back in the day, but it it's not suitable for a polygon
|
||
engine. So I decided to write a brand new hidden surface removal algorithm - using the same idea
|
||
as the original Build - but one that worked with vectors instead of already rasterized data.
|
||
|
||
Brief history:
|
||
06/20/2000: I release Build Source code
|
||
04/01/2003: 3D Realms releases Duke Nukem 3D source code
|
||
10/04/2003: Jonathon Fowler gets his Windows port working in Visual C
|
||
10/04/2003: I start writing POLYMOST.BAS, a new hidden surface removal algorithm for Build that
|
||
works on a polygon level instead of spans.
|
||
10/16/2003: Ported POLYMOST.BAS to C inside JonoF KenBuild's ENGINE.C; later this code was split
|
||
out of ENGINE.C and put in this file, POLYMOST.C.
|
||
12/10/2003: Started OpenGL code for POLYMOST (rendmode 3)
|
||
12/23/2003: 1st public release
|
||
01/01/2004: 2nd public release: fixed stray lines, status bar, mirrors, sky, and lots of other bugs.
|
||
|
||
----------------------------------------------------------------------------------------------------
|
||
|
||
Todo list (in approximate chronological order):
|
||
|
||
High priority:
|
||
* BOTH: Do accurate software sorting/chopping for sprites: drawing in wrong order is bad :/
|
||
* BOTH: Fix hall of mirrors near "zenith". Call polymost_drawrooms twice?
|
||
* OPENGL: drawmapview()
|
||
|
||
Low priority:
|
||
* SOFT6D: Do back-face culling of sprites during up/down/tilt transformation (top of drawpoly)
|
||
* SOFT6D: Fix depth shading: use saturation&LUT
|
||
* SOFT6D: Optimize using hyperbolic mapping (similar to KUBE algo)
|
||
* SOFT6D: Slab6-style voxel sprites. How to accelerate? :/
|
||
* OPENGL: KENBUILD: Write flipping code for floor mirrors
|
||
* BOTH: KENBUILD: Parallaxing sky modes 1&2
|
||
* BOTH: Masked/1-way walls don't clip correctly to sectors of intersecting ceiling/floor slopes
|
||
* BOTH: Editart x-center is not working correctly with Duke's camera/turret sprites
|
||
* BOTH: Get rid of horizontal line above Duke full-screen status bar
|
||
* BOTH: Combine ceilings/floors into a single triangle strip (should lower poly count by 2x)
|
||
* BOTH: Optimize/clean up texture-map setup equations
|
||
|
||
**************************************************************************************************/
|
||
|
||
#include <stdlib.h>
|
||
#include <assert.h>
|
||
#include <math.h>
|
||
#include "doomtype.h"
|
||
#include "r_polymost.h"
|
||
#include "c_cvars.h"
|
||
#include "c_dispatch.h"
|
||
#include "r_main.h"
|
||
#include "r_draw.h"
|
||
#include "templates.h"
|
||
#include "r_sky.h"
|
||
#include "g_level.h"
|
||
#include "r_bsp.h"
|
||
#include "v_palette.h"
|
||
#include "v_font.h"
|
||
|
||
EXTERN_CVAR (Int, r_polymost)
|
||
|
||
#define SCISDIST 1.0 //1.0: Close plane clipping distance
|
||
|
||
static double gyxscale, gxyaspect, gviewxrange, ghalfx, grhalfxdown10, grhalfxdown10x, ghoriz;
|
||
static double gcosang, gsinang, gcosang2, gsinang2;
|
||
static double gchang, gshang, gctang, gstang;
|
||
//static float gtang = 0.0;
|
||
CVAR (Float, gtang, 0, 0);
|
||
double guo, gux, guy; //Screen-based texture mapping parameters
|
||
double gvo, gvx, gvy;
|
||
double gdo, gdx, gdy;
|
||
|
||
#ifdef _MSC_VER
|
||
#pragma warning (disable:4244)
|
||
#endif
|
||
|
||
PolyClipper::PolyClipper ()
|
||
: vsps (&EmptyList)
|
||
{
|
||
UsedList.Next = UsedList.Prev = &UsedList;
|
||
}
|
||
|
||
PolyClipper::~PolyClipper ()
|
||
{
|
||
vspgroup *probe = vsps.NextGroup;
|
||
while (probe != NULL)
|
||
{
|
||
vspgroup *next = probe->NextGroup;
|
||
delete probe;
|
||
probe = next;
|
||
}
|
||
}
|
||
|
||
PolyClipper::vspgroup::vspgroup (vsptype *sentinel)
|
||
{
|
||
int i;
|
||
|
||
NextGroup = NULL;
|
||
vsp[0].Prev = sentinel;
|
||
vsp[0].Next = &vsp[1];
|
||
for (i = 1; i < GROUP_SIZE-1; ++i)
|
||
{
|
||
vsp[i].Next = &vsp[i+1];
|
||
vsp[i].Prev = &vsp[i-1];
|
||
}
|
||
vsp[i].Next = sentinel;
|
||
vsp[i].Prev = &vsp[i-1];
|
||
sentinel->Next = &vsp[0];
|
||
sentinel->Prev = &vsp[i];
|
||
}
|
||
|
||
/*Init viewport boundary (must be 4 point convex loop):
|
||
// (px[0],py[0]).----.(px[1],py[1])
|
||
// / \
|
||
// / \
|
||
// (px[3],py[3]).--------------.(px[2],py[2])
|
||
*/
|
||
void PolyClipper::InitMosts (double *px, double *py, int n)
|
||
{
|
||
int i, j, k, imin;
|
||
int vcnt;
|
||
vsptype *vsp[8];
|
||
|
||
EmptyAll ();
|
||
vcnt = 1; // 0 is dummy solid node
|
||
|
||
if (n < 3) return;
|
||
imin = (px[1] < px[0]);
|
||
for(i=n-1;i>=2;i--) if (px[i] < px[imin]) imin = i;
|
||
|
||
vsp[0] = &UsedList;
|
||
vsp[vcnt] = GetVsp ();
|
||
vsp[vcnt]->X = px[imin];
|
||
vsp[vcnt]->Cy[0] = vsp[vcnt]->Fy[0] = py[imin];
|
||
vsp[vcnt]->CTag = vsp[vcnt]->FTag = 1;
|
||
vcnt++;
|
||
i = imin+1; if (i >= n) i = 0;
|
||
j = imin-1; if (j < 0) j = n-1;
|
||
do
|
||
{
|
||
if (px[i] < px[j])
|
||
{
|
||
if ((vcnt > 1) && (px[i] - vsp[vcnt-1]->X < 0.00001)) vcnt--;
|
||
else vsp[vcnt] = GetVsp ();
|
||
vsp[vcnt]->X = px[i];
|
||
vsp[vcnt]->Cy[0] = py[i];
|
||
k = j+1; if (k >= n) k = 0;
|
||
//(px[k],py[k])
|
||
//(px[i],?)
|
||
//(px[j],py[j])
|
||
vsp[vcnt]->Fy[0] = (px[i]-px[k])*(py[j]-py[k])/(px[j]-px[k]) + py[k];
|
||
if (vcnt > 1)
|
||
{
|
||
vsp[vcnt]->CTag = vsp[vcnt-1]->CTag + 1;
|
||
vsp[vcnt]->FTag = vsp[vcnt-1]->FTag;
|
||
}
|
||
vcnt++;
|
||
i++; if (i >= n) i = 0;
|
||
}
|
||
else if (px[j] < px[i])
|
||
{
|
||
if ((vcnt > 1) && (px[j] - vsp[vcnt-1]->X < 0.00001)) vcnt--;
|
||
else vsp[vcnt] = GetVsp ();
|
||
vsp[vcnt]->X = px[j];
|
||
vsp[vcnt]->Fy[0] = py[j];
|
||
k = i-1; if (k < 0) k = n-1;
|
||
//(px[k],py[k])
|
||
//(px[j],?)
|
||
//(px[i],py[i])
|
||
vsp[vcnt]->Cy[0] = (px[j]-px[k])*(py[i]-py[k])/(px[i]-px[k]) + py[k];
|
||
if (vcnt > 1)
|
||
{
|
||
vsp[vcnt]->FTag = vsp[vcnt-1]->FTag + 1;
|
||
vsp[vcnt]->CTag = vsp[vcnt-1]->CTag;
|
||
}
|
||
vcnt++;
|
||
j--; if (j < 0) j = n-1;
|
||
}
|
||
else
|
||
{
|
||
if ((vcnt > 1) && (px[i] - vsp[vcnt-1]->X < 0.00001)) vcnt--;
|
||
else vsp[vcnt] = GetVsp ();
|
||
vsp[vcnt]->X = px[i];
|
||
vsp[vcnt]->Cy[0] = py[i];
|
||
vsp[vcnt]->Fy[0] = py[j];
|
||
if (vcnt > 1)
|
||
{
|
||
vsp[vcnt]->CTag = vsp[vcnt-1]->CTag + 1;
|
||
vsp[vcnt]->FTag = vsp[vcnt-1]->FTag + 1;
|
||
}
|
||
vcnt++;
|
||
i++; if (i >= n) i = 0; if (i == j) break;
|
||
j--; if (j < 0) j = n-1;
|
||
}
|
||
} while (i != j);
|
||
if (px[i] > vsp[vcnt-1]->X)
|
||
{
|
||
vsp[vcnt] = GetVsp ();
|
||
vsp[vcnt]->X = px[i];
|
||
vsp[vcnt]->Cy[0] = vsp[vcnt]->Fy[0] = py[i];
|
||
vsp[vcnt]->CTag = vsp[vcnt-1]->CTag + 1;
|
||
vsp[vcnt]->FTag = vsp[vcnt-1]->FTag + 1;
|
||
vcnt++;
|
||
}
|
||
|
||
assert (vcnt < 8);
|
||
|
||
vsp[vcnt-1]->CTag = vsp[vcnt-1]->FTag = vcnt-1;
|
||
for(i=0;i<vcnt-1;i++)
|
||
{
|
||
vsp[i]->Cy[1] = vsp[i+1]->Cy[0]; //vsp[i]->CTag = i;
|
||
vsp[i]->Fy[1] = vsp[i+1]->Fy[0]; //vsp[i]->FTag = i;
|
||
vsp[i]->Next = vsp[i+1]; vsp[i]->Prev = vsp[i-1];
|
||
}
|
||
vsp[vcnt-1]->Next = &UsedList; UsedList.Prev = vsp[vcnt-1];
|
||
GTag = vcnt;
|
||
}
|
||
|
||
void PolyClipper::EmptyAll ()
|
||
{
|
||
if (UsedList.Next != &UsedList)
|
||
{
|
||
if (EmptyList.Next != &EmptyList)
|
||
{
|
||
// Move the used list to the start of the empty list
|
||
UsedList.Prev->Next = EmptyList.Next;
|
||
EmptyList.Next = UsedList.Next;
|
||
UsedList.Next->Prev = &EmptyList;
|
||
}
|
||
else
|
||
{
|
||
// The empty list is empty, so we can just move the
|
||
// used list to the empty list.
|
||
EmptyList.Next = UsedList.Next;
|
||
EmptyList.Prev = UsedList.Prev;
|
||
}
|
||
UsedList.Next = UsedList.Prev = &UsedList;
|
||
}
|
||
}
|
||
|
||
void PolyClipper::AddGroup ()
|
||
{
|
||
vspgroup *group = new vspgroup (&EmptyList);
|
||
group->NextGroup = vsps.NextGroup;
|
||
vsps.NextGroup = group;
|
||
}
|
||
|
||
PolyClipper::vsptype *PolyClipper::GetVsp ()
|
||
{
|
||
vsptype *vsp;
|
||
|
||
if (EmptyList.Next == &EmptyList)
|
||
{
|
||
AddGroup ();
|
||
}
|
||
vsp = EmptyList.Next;
|
||
EmptyList.Next = vsp->Next;
|
||
vsp->Next->Prev = &EmptyList;
|
||
return vsp;
|
||
}
|
||
|
||
void PolyClipper::FreeVsp (vsptype *vsp)
|
||
{
|
||
vsp->Next->Prev = vsp->Prev;
|
||
vsp->Prev->Next = vsp->Next;
|
||
|
||
vsp->Next = EmptyList.Next;
|
||
vsp->Next->Prev = vsp;
|
||
vsp->Prev = &EmptyList;
|
||
EmptyList.Next = vsp;
|
||
}
|
||
|
||
PolyClipper::vsptype *PolyClipper::vsinsaft (vsptype *i)
|
||
{
|
||
vsptype *r;
|
||
|
||
// Get an element from the empty list
|
||
r = GetVsp ();
|
||
|
||
*r = *i; // Copy i to r
|
||
|
||
// Insert r after i
|
||
r->Prev = i;
|
||
r->Next = i->Next;
|
||
i->Next->Prev = r;
|
||
i->Next = r;
|
||
|
||
return r;
|
||
}
|
||
|
||
bool PolyClipper::TestVisibleMost (float x0, float x1)
|
||
{
|
||
vsptype *i, *newi;
|
||
|
||
for (i = UsedList.Next; i != &UsedList; i = newi)
|
||
{
|
||
newi = i->Next;
|
||
if ((x0 < newi->X) && (i->X < x1) && (i->CTag >= 0)) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
int PolyClipper::DoMost (float x0, float y0, float x1, float y1, pmostcallbacktype callback, void *callbackdata)
|
||
{
|
||
double dpx[4], dpy[4];
|
||
float f, slop, dx0, dx1, nx, nx0, ny0, nx1, ny1;
|
||
double dx, d, n, t;
|
||
float spx[4], spy[4], cy[2], cv[2];
|
||
int j, k, z, scnt, dir, spt[4];
|
||
vsptype *vsp, *nvsp, *vcnt = NULL, *ni;
|
||
int did = 1;
|
||
|
||
if (x0 < x1)
|
||
{
|
||
dir = 1; //clip dmost (floor)
|
||
y0 -= .01f; y1 -= .01f;
|
||
}
|
||
else
|
||
{
|
||
if (x0 == x1) return 0;
|
||
f = x0; x0 = x1; x1 = f;
|
||
f = y0; y0 = y1; y1 = f;
|
||
dir = 0; //clip umost (ceiling)
|
||
//y0 += .01f; y1 += .01f; //necessary?
|
||
}
|
||
|
||
slop = (y1-y0)/(x1-x0);
|
||
for (vsp = UsedList.Next; vsp != &UsedList; vsp = nvsp)
|
||
{
|
||
nvsp = vsp->Next; nx0 = vsp->X; nx1 = nvsp->X;
|
||
if ((x0 >= nx1) || (nx0 >= x1) || (vsp->CTag <= 0)) continue;
|
||
dx = nx1-nx0;
|
||
cy[0] = vsp->Cy[0]; cv[0] = vsp->Cy[1]-cy[0];
|
||
cy[1] = vsp->Fy[0]; cv[1] = vsp->Fy[1]-cy[1];
|
||
|
||
scnt = 0;
|
||
|
||
//Test if left edge requires split (x0,y0) (nx0,cy(0)),<dx,cv(0)>
|
||
if ((x0 > nx0) && (x0 < nx1))
|
||
{
|
||
t = (x0-nx0)*cv[dir] - (y0-cy[dir])*dx;
|
||
if (((!dir) && (t < 0)) || ((dir) && (t > 0)))
|
||
{ spx[scnt] = x0; spy[scnt] = y0; spt[scnt] = -1; scnt++; }
|
||
}
|
||
|
||
//Test for intersection on umost (j == 0) and dmost (j == 1)
|
||
for(j=0;j<2;j++)
|
||
{
|
||
d = (y0-y1)*dx - (x0-x1)*cv[j];
|
||
n = (y0-cy[j])*dx - (x0-nx0)*cv[j];
|
||
if ((fabsf(n) <= fabsf(d)) && (d*n >= 0) && (d != 0))
|
||
{
|
||
t = n/d; nx = (x1-x0)*t + x0;
|
||
if ((nx > nx0) && (nx < nx1))
|
||
{
|
||
spx[scnt] = nx; spy[scnt] = (y1-y0)*t + y0;
|
||
spt[scnt] = j; scnt++;
|
||
}
|
||
}
|
||
}
|
||
|
||
//Nice hack to avoid full sort later :)
|
||
if ((scnt >= 2) && (spx[scnt-1] < spx[scnt-2]))
|
||
{
|
||
f = spx[scnt-1]; spx[scnt-1] = spx[scnt-2]; spx[scnt-2] = f;
|
||
f = spy[scnt-1]; spy[scnt-1] = spy[scnt-2]; spy[scnt-2] = f;
|
||
j = spt[scnt-1]; spt[scnt-1] = spt[scnt-2]; spt[scnt-2] = j;
|
||
}
|
||
|
||
//Test if right edge requires split
|
||
if ((x1 > nx0) && (x1 < nx1))
|
||
{
|
||
t = (x1-nx0)*cv[dir] - (y1-cy[dir])*dx;
|
||
if (((!dir) && (t < 0)) || ((dir) && (t > 0)))
|
||
{ spx[scnt] = x1; spy[scnt] = y1; spt[scnt] = -1; scnt++; }
|
||
}
|
||
|
||
vsp->Tag = nvsp->Tag = -1;
|
||
for(z = 0; z <= scnt; z++, vsp = vcnt)
|
||
{
|
||
if (z < scnt)
|
||
{
|
||
vcnt = vsinsaft(vsp);
|
||
t = (spx[z]-nx0)/dx;
|
||
vsp->Cy[1] = t*cv[0] + cy[0];
|
||
vsp->Fy[1] = t*cv[1] + cy[1];
|
||
vcnt->X = spx[z];
|
||
vcnt->Cy[0] = vsp->Cy[1];
|
||
vcnt->Fy[0] = vsp->Fy[1];
|
||
vcnt->Tag = spt[z];
|
||
}
|
||
|
||
ni = vsp->Next; if (ni == &UsedList) continue; //this 'if' fixes many bugs!
|
||
dx0 = vsp->X; if (x0 > dx0) continue;
|
||
dx1 = ni->X; if (x1 < dx1) continue;
|
||
ny0 = (dx0-x0)*slop + y0;
|
||
ny1 = (dx1-x0)*slop + y0;
|
||
|
||
// dx0 dx1
|
||
// <20> <20>
|
||
//----------------------------
|
||
// t0+=0 t1+=0
|
||
// vsp[i].cy[0] vsp[i].cy[1]
|
||
//============================
|
||
// t0+=1 t1+=3
|
||
//============================
|
||
// vsp[i].fy[0] vsp[i].fy[1]
|
||
// t0+=2 t1+=6
|
||
//
|
||
// ny0 ? ny1 ?
|
||
|
||
k = 1+3;
|
||
if ((vsp->Tag == 0) || (ny0 <= vsp->Cy[0]+.01)) k--;
|
||
if ((vsp->Tag == 1) || (ny0 >= vsp->Fy[0]-.01)) k++;
|
||
if ((ni->Tag == 0) || (ny1 <= vsp->Cy[1]+.01)) k -= 3;
|
||
if ((ni->Tag == 1) || (ny1 >= vsp->Fy[1]-.01)) k += 3;
|
||
|
||
if (!dir)
|
||
{
|
||
switch(k)
|
||
{
|
||
case 1: case 2:
|
||
dpx[0] = dx0; dpy[0] = vsp->Cy[0];
|
||
dpx[1] = dx1; dpy[1] = vsp->Cy[1];
|
||
dpx[2] = dx0; dpy[2] = ny0;
|
||
if(callback) callback(dpx,dpy,3,callbackdata);
|
||
vsp->Cy[0] = ny0; vsp->CTag = GTag; break;
|
||
case 3: case 6:
|
||
dpx[0] = dx0; dpy[0] = vsp->Cy[0];
|
||
dpx[1] = dx1; dpy[1] = vsp->Cy[1];
|
||
dpx[2] = dx1; dpy[2] = ny1;
|
||
if(callback) callback(dpx,dpy,3,callbackdata);
|
||
vsp->Cy[1] = ny1; vsp->CTag = GTag; break;
|
||
case 4: case 5: case 7:
|
||
dpx[0] = dx0; dpy[0] = vsp->Cy[0];
|
||
dpx[1] = dx1; dpy[1] = vsp->Cy[1];
|
||
dpx[2] = dx1; dpy[2] = ny1;
|
||
dpx[3] = dx0; dpy[3] = ny0;
|
||
if(callback) callback(dpx,dpy,4,callbackdata);
|
||
vsp->Cy[0] = ny0; vsp->Cy[1] = ny1; vsp->CTag = GTag; break;
|
||
case 8:
|
||
dpx[0] = dx0; dpy[0] = vsp->Cy[0];
|
||
dpx[1] = dx1; dpy[1] = vsp->Cy[1];
|
||
dpx[2] = dx1; dpy[2] = vsp->Fy[1];
|
||
dpx[3] = dx0; dpy[3] = vsp->Fy[0];
|
||
if(callback) callback(dpx,dpy,4,callbackdata);
|
||
vsp->CTag = vsp->FTag = -1; break;
|
||
default: did = 0; break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
switch(k)
|
||
{
|
||
case 7: case 6:
|
||
dpx[0] = dx0; dpy[0] = ny0;
|
||
dpx[1] = dx1; dpy[1] = vsp->Fy[1];
|
||
dpx[2] = dx0; dpy[2] = vsp->Fy[0];
|
||
if(callback) callback(dpx,dpy,3,callbackdata);
|
||
vsp->Fy[0] = ny0; vsp->FTag = GTag; break;
|
||
case 5: case 2:
|
||
dpx[0] = dx0; dpy[0] = vsp->Fy[0];
|
||
dpx[1] = dx1; dpy[1] = ny1;
|
||
dpx[2] = dx1; dpy[2] = vsp->Fy[1];
|
||
if(callback) callback(dpx,dpy,3,callbackdata);
|
||
vsp->Fy[1] = ny1; vsp->FTag = GTag; break;
|
||
case 4: case 3: case 1:
|
||
dpx[0] = dx0; dpy[0] = ny0;
|
||
dpx[1] = dx1; dpy[1] = ny1;
|
||
dpx[2] = dx1; dpy[2] = vsp->Fy[1];
|
||
dpx[3] = dx0; dpy[3] = vsp->Fy[0];
|
||
if(callback) callback(dpx,dpy,4,callbackdata);
|
||
vsp->Fy[0] = ny0; vsp->Fy[1] = ny1; vsp->FTag = GTag; break;
|
||
case 0:
|
||
dpx[0] = dx0; dpy[0] = vsp->Cy[0];
|
||
dpx[1] = dx1; dpy[1] = vsp->Cy[1];
|
||
dpx[2] = dx1; dpy[2] = vsp->Fy[1];
|
||
dpx[3] = dx0; dpy[3] = vsp->Fy[0];
|
||
if(callback) callback(dpx,dpy,4,callbackdata);
|
||
vsp->CTag = vsp->FTag = -1; break;
|
||
default: did = 0; break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
GTag++;
|
||
|
||
//Combine neighboring vertical strips with matching collinear top&bottom edges
|
||
//This prevents x-splits from propagating through the entire scan
|
||
vsp = UsedList.Next;
|
||
while (vsp->Next != &UsedList)
|
||
{
|
||
ni = vsp->Next;
|
||
if ((vsp->Cy[0] >= vsp->Fy[0]) && (vsp->Cy[1] >= vsp->Fy[1]))
|
||
{ vsp->CTag = vsp->FTag = -1; }
|
||
if ((vsp->CTag == ni->CTag) && (vsp->FTag == ni->FTag))
|
||
{ vsp->Cy[1] = ni->Cy[1]; vsp->Fy[1] = ni->Fy[1]; FreeVsp (ni); }
|
||
else vsp = ni;
|
||
}
|
||
return did;
|
||
}
|
||
|
||
#include "d_event.h"
|
||
CVAR(Bool, testpolymost, false, 0)
|
||
static int pmx, pmy;
|
||
static int pt, px0, py0, px1, py1;
|
||
static struct polypt { float x, y; } polypts[80];
|
||
static BYTE polysize[32];
|
||
static int numpoly, polypt;
|
||
PolyClipper TestPoly;
|
||
|
||
void drawline2d (float x1, float y1, float x2, float y2, BYTE col)
|
||
{
|
||
float dx, dy, fxresm1, fyresm1, f;
|
||
long i, x, y, xi, yi, xup16, yup16;
|
||
|
||
//Always draw lines in same direction
|
||
if ((y2 > y1) || ((y2 == y1) && (x2 > x1))) { f = x1; x1 = x2; x2 = f; f = y1; y1 = y2; y2 = f; }
|
||
|
||
dx = x2-x1; dy = y2-y1; if ((dx == 0) && (dy == 0)) return;
|
||
fxresm1 = (float)RenderTarget->GetWidth()-.5; fyresm1 = (float)RenderTarget->GetHeight()-.5;
|
||
if (x1 >= fxresm1) { if (x2 >= fxresm1) return; y1 += (fxresm1-x1)*dy/dx; x1 = fxresm1; }
|
||
else if (x1 < 0) { if (x2 < 0) return; y1 += ( 0-x1)*dy/dx; x1 = 0; }
|
||
if (x2 >= fxresm1) { y2 += (fxresm1-x2)*dy/dx; x2 = fxresm1; }
|
||
else if (x2 < 0) { y2 += ( 0-x2)*dy/dx; x2 = 0; }
|
||
if (y1 >= fyresm1) { if (y2 >= fyresm1) return; x1 += (fyresm1-y1)*dx/dy; y1 = fyresm1; }
|
||
else if (y1 < 0) { if (y2 < 0) return; x1 += ( 0-y1)*dx/dy; y1 = 0; }
|
||
if (y2 >= fyresm1) { x2 += (fyresm1-y2)*dx/dy; y2 = fyresm1; }
|
||
else if (y2 < 0) { x2 += ( 0-y2)*dx/dy; y2 = 0; }
|
||
|
||
dx = x2-x1; dy = y2-y1;
|
||
i = (long)(MAX(fabsf(dx)+1,fabsf(dy)+1)); f = 65536.f/((float)i);
|
||
x = (long)(x1*65536.f)+32768; xi = (long)(dx*f); xup16 = (RenderTarget->GetWidth()<<16);
|
||
y = (long)(y1*65536.f)+32768; yi = (long)(dy*f); yup16 = (RenderTarget->GetHeight()<<16);
|
||
do
|
||
{
|
||
if (((unsigned long)x < (unsigned long)xup16) && ((unsigned long)y < (unsigned long)yup16))
|
||
*(ylookup[y>>16]+(x>>16)+dc_destorg) = col;
|
||
x += xi; y += yi; i--;
|
||
} while (i >= 0);
|
||
}
|
||
|
||
static int maskhack;
|
||
|
||
void fillconvpoly (float x[], float y[], int n, int col, int bcol)
|
||
{
|
||
int mini = y[0] >= y[1], maxi = 1 - mini;
|
||
int i, j, y2, oz, z, yy, zz, ncol;
|
||
float area, xi, xx;
|
||
static int lastx[MAXHEIGHT+2];
|
||
|
||
for (z = 2; z < n; ++z)
|
||
{
|
||
if (y[z] < y[mini]) mini = z;
|
||
if (y[z] > y[maxi]) maxi = z;
|
||
}
|
||
|
||
area = 0; zz = n - 1;
|
||
for (z = 0; z < n; ++z)
|
||
{
|
||
area += (x[zz] - x[z]) * (y[z] + y[zz]); zz = z;
|
||
}
|
||
if (area <= 0) return;
|
||
|
||
i = maxi; y2 = int(y[i]);
|
||
do
|
||
{
|
||
j = i + 1; if (j == n) j = 0;
|
||
yy = int(ceilf(y[j]));
|
||
if (yy < 0) yy = 0;
|
||
if (yy < y2)
|
||
{
|
||
xi = (x[j] - x[i]) / (y[j] - y[i]);
|
||
xx = (y2 - y[j]) * xi + x[j];
|
||
if (y2 >= RenderTarget->GetHeight()) { xx = xx - (y2 - RenderTarget->GetHeight() + 1)*xi; y2 = RenderTarget->GetHeight()-1; }
|
||
for (; y2 >= yy; --y2)
|
||
{
|
||
lastx[y2] = MAX (0, int(ceilf(xx))); xx = xx - xi;
|
||
}
|
||
}
|
||
i = j;
|
||
} while (i != mini);
|
||
if (y2 == yy) lastx[yy] = lastx[yy+1];
|
||
do
|
||
{
|
||
j = i + 1; if (j == n) j = 0;
|
||
y2 = int(y[j]);
|
||
if (y2 >= RenderTarget->GetHeight()) y2 = RenderTarget->GetHeight()-1;
|
||
if (y2 > yy)
|
||
{
|
||
xi = (x[j] - x[i]) / (y[j] - y[i]);
|
||
xx = (yy - y[i]) * xi + x[i];
|
||
if (yy < 0) { xx = xx - xi*yy; yy = 0; }
|
||
ncol = col; if (yy & 1) ncol = ncol ^ maskhack;
|
||
for (; yy <= y2; ++yy)
|
||
{
|
||
//drawline2d(lastx[yy], yy, int(ceilf(xx)), yy, ncol); xx = xx + xi;
|
||
int xxx = MIN(RenderTarget->GetWidth(), int(ceilf(xx)));
|
||
if (yy < RenderTarget->GetHeight() && lastx[yy] < xxx) memset(RenderTarget->GetBuffer()+yy*RenderTarget->GetPitch()+lastx[yy], ncol, xxx-lastx[yy]);
|
||
xx = xx + xi;
|
||
ncol = ncol ^ maskhack;
|
||
}
|
||
}
|
||
i = j;
|
||
} while (i != maxi);
|
||
|
||
if (col != bcol)
|
||
{
|
||
oz = n - 1;
|
||
for (z = 0; z < n; ++z)
|
||
{
|
||
drawline2d(x[oz], y[oz], x[z], y[z], bcol);
|
||
oz = z;
|
||
}
|
||
}
|
||
}
|
||
|
||
void drawtri(float x0, float y0, float x1, float y1, float x2, float y2, int col, int bcol)
|
||
{
|
||
float x[3], y[3];
|
||
x[0] = x0; y[0] = y0;
|
||
x[1] = x1; y[1] = y1;
|
||
x[2] = x2; y[2] = y2;
|
||
fillconvpoly(x, y, 3, col, bcol);
|
||
}
|
||
|
||
void drawquad(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, int col, int bcol)
|
||
{
|
||
float x[4], y[4];
|
||
x[0] = x0; y[0] = y0;
|
||
x[1] = x1; y[1] = y1;
|
||
x[2] = x2; y[2] = y2;
|
||
x[3] = x3; y[3] = y3;
|
||
fillconvpoly(x, y, 4, col, bcol); // 2 triangles
|
||
if (col != bcol)
|
||
{
|
||
if (fabsf(y0-y2) < fabsf(y1-y3))
|
||
drawline2d(x0,y0,x2,y2,bcol);
|
||
else
|
||
drawline2d(x1,y1,x3,y3,bcol);
|
||
}
|
||
}
|
||
|
||
void printnum(int x, int y, int num)
|
||
{
|
||
char foo[16]; mysnprintf (foo, countof(foo), "%d", num);
|
||
RenderTarget->DrawText (SmallFont, CR_WHITE, x, y, foo);
|
||
}
|
||
|
||
void drawpolymosttest()
|
||
{
|
||
float cx0 = 0, cy0 = 0, fx0 = 0, fy0 = 0;
|
||
int ccol, fcol;
|
||
PolyClipper::vsptype *vsp, *ovsp = &TestPoly.UsedList, *nvsp;
|
||
|
||
fcol = 0; ccol = 0;
|
||
|
||
RenderTarget->Clear(0, 0, RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0, 0);
|
||
for (vsp = ovsp->Next; vsp->Next != &TestPoly.UsedList; ovsp = vsp, vsp = nvsp)
|
||
{
|
||
nvsp = vsp->Next;
|
||
if (vsp->CTag == -1 && vsp->FTag == -1)
|
||
{ // Hide spans that have been clipped away
|
||
vsp->Cy[0] = vsp->Cy[1] = vsp->Fy[0] = vsp->Fy[1] = RenderTarget->GetHeight()/2;
|
||
}
|
||
|
||
if (vsp->CTag != ovsp->CTag) cx0 = vsp->X, cy0 = vsp->Cy[0];
|
||
if (vsp->CTag != nvsp->CTag)
|
||
{ // fill the ceiling region
|
||
maskhack = 0x18;
|
||
drawquad(cx0, 0, nvsp->X, 0, nvsp->X, vsp->Cy[1], cx0, cy0, ccol, ccol);
|
||
maskhack = 0; ccol ^= 0x18;
|
||
printnum(int(cx0 + nvsp->X) / 2, 2, vsp->CTag);
|
||
}
|
||
|
||
if(vsp->FTag != ovsp->FTag) fx0 = vsp->X, fy0 = vsp->Fy[0];
|
||
if(vsp->FTag != nvsp->FTag)
|
||
{ // fill the floor region
|
||
maskhack = 0x78;
|
||
drawquad(fx0, fy0+1, nvsp->X, vsp->Fy[1]+1, nvsp->X, RenderTarget->GetHeight(), fx0, RenderTarget->GetHeight(), fcol, fcol);
|
||
maskhack = 0; fcol ^= 0x78;
|
||
printnum(int(fx0 + nvsp->X) / 2, RenderTarget->GetHeight()-10, vsp->FTag);
|
||
}
|
||
|
||
// fill the unclipped middle region
|
||
drawquad(vsp->X, vsp->Cy[0], nvsp->X, vsp->Cy[1], nvsp->X, vsp->Fy[1], vsp->X, vsp->Fy[0], 0xC4, 0xE6);
|
||
}
|
||
|
||
int x = (pmx + 3) & ~7, y = (pmy + 3) & ~7;
|
||
|
||
drawline2d (x - 3, y, x + 3, y, 30);
|
||
drawline2d (x, y - 3, x, y + 3, 30);
|
||
printnum ( 0, 20, x);
|
||
printnum (50, 20, y);
|
||
|
||
if (pt > 0 && px0 != px1)
|
||
{
|
||
if (px0 < px1)
|
||
{
|
||
drawline2d (px0, py0, px0, RenderTarget->GetHeight()-1, 47);
|
||
drawline2d (px1, py1, px1, RenderTarget->GetHeight()-1, 47);
|
||
}
|
||
else
|
||
{
|
||
drawline2d (px0, py0, px0, 0, 47);
|
||
drawline2d (px1, py1, px1, 0, 47);
|
||
}
|
||
drawline2d (px0, py0, px1, py1, 47);
|
||
}
|
||
if (pt == 2)
|
||
{
|
||
int i = 0;
|
||
for (x = 0; x < numpoly; ++x)
|
||
{
|
||
if (polysize[x] == 3)
|
||
{
|
||
drawtri (polypts[i ].x, polypts[i ].y,
|
||
polypts[i+1].x, polypts[i+1].y,
|
||
polypts[i+2].x, polypts[i+2].y, 0x7f, 0x9f);
|
||
i += 3;
|
||
}
|
||
else
|
||
{
|
||
drawquad (polypts[i ].x, polypts[i ].y,
|
||
polypts[i+1].x, polypts[i+1].y,
|
||
polypts[i+2].x, polypts[i+2].y,
|
||
polypts[i+3].x, polypts[i+3].y, 0x7f, 0x9f);
|
||
i += 4;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
CCMD(initpolymosttest)
|
||
{
|
||
double px[4], py[4];
|
||
int test = 0;
|
||
|
||
if (argv.argc() > 1)
|
||
test = atoi(argv[1]);
|
||
|
||
// Box
|
||
px[0] = px[3] = 0;
|
||
px[1] = px[2] = screen->GetWidth();
|
||
py[0] = py[1] = screen->GetHeight()/4;
|
||
py[2] = py[3] = screen->GetHeight()*3/4;
|
||
|
||
switch (test)
|
||
{
|
||
case 1: // Shorter top edge
|
||
px[0] = px[1]/6;
|
||
px[1] = px[1]*5/6;
|
||
break;
|
||
|
||
case 2: // Shorter bottom edge
|
||
px[3] = px[2]/6;
|
||
px[2] = px[2]*5/6;
|
||
break;
|
||
|
||
case 3: // Shorter left edge
|
||
py[0] = screen->GetHeight()*3/8;
|
||
py[3] = screen->GetHeight()*5/8;
|
||
break;
|
||
|
||
case 4: // Shorter right edge
|
||
py[1] = screen->GetHeight()*3/8;
|
||
py[2] = screen->GetHeight()*5/8;
|
||
break;
|
||
|
||
case 5:
|
||
px[0] = -1.0048981460288360/2+50; py[0] = -1.0/2+50;
|
||
px[1] = 643.00492866407262/2+50; py[1] = -1.0/2+50;
|
||
px[2] = 643.00492866407262/2+50; py[2] = 483/2+50;
|
||
px[3] = -1.0048981460288360/2+50; py[3] = 483/2+50;
|
||
break;
|
||
}
|
||
TestPoly.InitMosts (px, py, 4);
|
||
pmx = screen->GetWidth()/2;
|
||
pmy = screen->GetHeight()/2;
|
||
pt = 0;
|
||
}
|
||
|
||
static void testpolycallback (double *dpx, double *dpy, int n, void *foo)
|
||
{
|
||
if (numpoly == sizeof(polysize)) return;
|
||
if (size_t(polypt + n) > countof(polypts)) return;
|
||
polysize[numpoly++] = n;
|
||
for (int i = 0; i < n; ++i)
|
||
{
|
||
polypts[polypt + i].x = dpx[i];
|
||
polypts[polypt + i].y = dpy[i];
|
||
}
|
||
polypt += n;
|
||
}
|
||
|
||
void Polymost_Responder (event_t *ev)
|
||
{
|
||
if (ev->type == EV_Mouse && pt < 2)
|
||
{
|
||
pmx = clamp (pmx + ev->x, 0, screen->GetWidth()-1);
|
||
pmy = clamp (pmy - ev->y, 0, screen->GetHeight()-1);
|
||
int x = (pmx + 3) & ~7, y = (pmy + 3) & ~7;
|
||
if (pt == 0) px0 = x, py0 = y;
|
||
if (pt <= 1) px1 = x, py1 = y;
|
||
}
|
||
else if (ev->type == EV_KeyDown && ev->data1 == KEY_MOUSE1)
|
||
{
|
||
if (pt == 0) pt = 1; else pt = 0;
|
||
}
|
||
else if (ev->type == EV_KeyUp && ev->data1 == KEY_MOUSE1)
|
||
{
|
||
if (pt == 1) { if (px0 != px1) pt++; else pt--; }
|
||
if (pt == 2)
|
||
{
|
||
numpoly = polypt = 0;
|
||
TestPoly.DoMost (px0, py0, px1, py1, testpolycallback, NULL);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
extern fixed_t WallSZ1, WallSZ2, WallTX1, WallTX2, WallTY1, WallTY2, WallCX1, WallCX2, WallCY1, WallCY2;
|
||
extern int WallSX1, WallSX2;
|
||
extern float WallUoverZorg, WallUoverZstep, WallInvZorg, WallInvZstep, WallDepthScale, WallDepthOrg;
|
||
extern fixed_t rw_backcz1, rw_backcz2;
|
||
extern fixed_t rw_backfz1, rw_backfz2;
|
||
extern fixed_t rw_frontcz1, rw_frontcz2;
|
||
extern fixed_t rw_frontfz1, rw_frontfz2;
|
||
extern fixed_t rw_offset;
|
||
extern bool rw_markmirror;
|
||
extern bool rw_havehigh;
|
||
extern bool rw_havelow;
|
||
extern bool markfloor;
|
||
extern bool markceiling;
|
||
extern FTexture *toptexture;
|
||
extern FTexture *bottomtexture;
|
||
extern FTexture *midtexture;
|
||
extern bool rw_mustmarkfloor, rw_mustmarkceiling;
|
||
extern void R_NewWall(bool);
|
||
extern void R_GetExtraLight (int *light, const secplane_t &plane, FExtraLight *el);
|
||
extern int doorclosed;
|
||
extern int viewpitch;
|
||
#include "p_lnspec.h"
|
||
|
||
PolyClipper Mosts;
|
||
static bool drawback;
|
||
|
||
bool RP_SetupFrame (bool backside)
|
||
{
|
||
double ox, oy, oz, ox2, oy2, oz2, r, px[6], py[6], pz[6], px2[6], py2[6], pz2[6], sx[6], sy[6];
|
||
int i, j, n, n2;
|
||
|
||
drawback = backside;
|
||
if (backside)
|
||
{
|
||
viewangle += ANGLE_180;
|
||
viewsin = finesine[viewangle>>ANGLETOFINESHIFT];
|
||
viewcos = finecosine[viewangle>>ANGLETOFINESHIFT];
|
||
viewtansin = FixedMul (FocalTangent, viewsin);
|
||
viewtancos = FixedMul (FocalTangent, viewcos);
|
||
}
|
||
//Polymost supports true look up/down :) Here, we convert horizon to angle.
|
||
//gchang&gshang are cos&sin of this angle (respectively)
|
||
// gyxscale = ((double)xdimenscale)/131072.0;
|
||
gyxscale = double(InvZtoScale)/65536.0;///131072.0/320.0;
|
||
// gxyaspect = ((double)xyaspect*(double)viewingrange)*(5.0/(65536.0*262144.0));
|
||
// gviewxrange = ((double)viewingrange)*((double)xdimen)/(32768.0*128.0);
|
||
gcosang = double(viewcos)/65536.0;
|
||
gsinang = double(viewsin)/65536.0;
|
||
gcosang2 = gcosang*double(FocalTangent)/65536.0;
|
||
gsinang2 = gsinang*double(FocalTangent)/65536.0;
|
||
ghalfx = (double)viewwidth*0.5; grhalfxdown10 = 1.0/(((double)ghalfx)*1024);
|
||
|
||
//global cos/sin height angle
|
||
angle_t pitch = (angle_t)viewpitch;
|
||
if (backside) pitch = ANGLE_180 - pitch;
|
||
|
||
gshang = double(finesine[pitch>>ANGLETOFINESHIFT])/65536.0;
|
||
gchang = double(finecosine[pitch>>ANGLETOFINESHIFT])/65536.0;
|
||
ghoriz = double(viewheight)*0.5;
|
||
|
||
//global cos/sin tilt angle
|
||
gctang = cos(gtang);
|
||
gstang = sin(gtang);
|
||
if (fabs(gstang) < .001) //This hack avoids nasty precision bugs in domost()
|
||
{ gstang = 0; if (gctang > 0) gctang = 1.0; else gctang = -1.0; }
|
||
|
||
// Generate viewport trapezoid
|
||
px[0] = px[3] = 0-1; px[1] = px[2] = viewwidth+3;
|
||
py[0] = py[1] = 0-1; py[2] = py[3] = viewheight+3; n = 4;
|
||
for(i=0;i<n;i++)
|
||
{
|
||
ox = px[i]-ghalfx; oy = py[i]-ghoriz; oz = ghalfx;
|
||
|
||
//Tilt rotation (backwards)
|
||
ox2 = ox*gctang + oy*gstang;
|
||
oy2 = oy*gctang - ox*gstang;
|
||
oz2 = oz;
|
||
|
||
//Up/down rotation (backwards)
|
||
px[i] = ox2;
|
||
py[i] = oy2*gchang + oz2*gshang;
|
||
pz[i] = oz2*gchang - oy2*gshang;
|
||
}
|
||
|
||
//Clip to SCISDIST plane
|
||
n2 = 0;
|
||
bool clipped = false;
|
||
for(i=0;i<n;i++)
|
||
{
|
||
j = i+1; if (j >= n) j = 0;
|
||
if (pz[i] >= SCISDIST/16) { px2[n2] = px[i]; py2[n2] = py[i]; pz2[n2] = pz[i]; n2++; }
|
||
if ((pz[i] >= SCISDIST/16) != (pz[j] >= SCISDIST/16))
|
||
{
|
||
clipped = true;
|
||
r = (SCISDIST/16-pz[i])/(pz[j]-pz[i]);
|
||
px2[n2] = (px[j]-px[i])*r + px[i];
|
||
py2[n2] = (py[j]-py[i])*r + py[i];
|
||
pz2[n2] = SCISDIST/16;
|
||
if (backside) py2[n2] -= r;
|
||
n2++;
|
||
}
|
||
}
|
||
if (n2 < 3) { return true; }
|
||
for(i=0;i<n2;i++)
|
||
{
|
||
r = ghalfx / pz2[i];
|
||
sx[i] = px2[i]*r + ghalfx;
|
||
sy[i] = py2[i]*r + ghoriz;
|
||
}
|
||
Mosts.InitMosts (sx, sy, n2);
|
||
return clipped;
|
||
}
|
||
|
||
CVAR (Bool, r_nopolytilt, 0, 0)
|
||
|
||
static void wireframe (double *dpx, double *dpy, int n, void *data)
|
||
{
|
||
int wfc = (int)(size_t)data;
|
||
double f, r, ox, oy, oz, ox2, oy2, oz2;
|
||
float px[16], py[16];
|
||
int i, j, k;
|
||
|
||
if (n == 3)
|
||
{
|
||
if ((dpx[0]-dpx[1])*(dpy[2]-dpy[1]) >= (dpx[2]-dpx[1])*(dpy[0]-dpy[1])) return; //for triangle
|
||
}
|
||
else
|
||
{
|
||
f = 0; //f is area of polygon / 2
|
||
for(i=n-2,j=n-1,k=0;k<n;i=j,j=k,k++) f += (dpx[i]-dpx[k])*dpy[j];
|
||
if (f <= 0) return;
|
||
}
|
||
|
||
j = 0;
|
||
for(i=0;i<n;i++)
|
||
{
|
||
if (!r_nopolytilt)
|
||
{
|
||
ox = dpx[i]-ghalfx;
|
||
oy = dpy[i]-ghoriz;
|
||
oz = ghalfx;
|
||
|
||
//Up/down rotation
|
||
ox2 = ox;
|
||
oy2 = oy*gchang - oz*gshang;
|
||
oz2 = oy*gshang + oz*gchang;
|
||
|
||
//Tilt rotation
|
||
ox = ox2*gctang - oy2*gstang;
|
||
oy = ox2*gstang + oy2*gctang;
|
||
oz = oz2;
|
||
|
||
r = ghalfx / oz;
|
||
|
||
if (drawback)
|
||
{
|
||
ox = -ox;
|
||
oy = -oy;
|
||
}
|
||
px[j] = ox*r + ghalfx;
|
||
py[j] = oy*r + ghoriz;
|
||
}
|
||
else
|
||
{
|
||
px[j] = (dpx[i]-ghalfx)*0.5+ghalfx;
|
||
py[j] = (dpy[i]-ghoriz)*0.5+ghoriz;
|
||
}
|
||
if ((!j) || (px[j] != px[j-1]) || (py[j] != py[j-1])) j++;
|
||
}
|
||
if (r_polymost == 2 || r_polymost == 3)
|
||
{
|
||
fillconvpoly (px, py, j, wfc+4, r_polymost == 2 ? wfc : wfc+4);
|
||
}
|
||
if (r_polymost == 1)
|
||
{
|
||
for (i=0, k=j-1; i < j; k=i, ++i)
|
||
{
|
||
drawline2d (px[k], py[k], px[i], py[i], wfc);
|
||
}
|
||
}
|
||
}
|
||
|
||
void RP_AddLine (seg_t *line)
|
||
{
|
||
static sector_t tempsec; // killough 3/8/98: ceiling/water hack
|
||
bool solid;
|
||
fixed_t tx1, tx2, ty1, ty2;
|
||
fixed_t fcz0, ffz0, fcz1, ffz1, bcz0, bfz0, bcz1, bfz1;
|
||
double x0, x1, xp0, yp0, xp1, yp1, oxp0, oyp0, nx0, ny0, nx1, ny1, ryp0, ryp1;
|
||
double cy0, fy0, cy1, fy1, ocy0 = 0, ofy0 = 0, ocy1 = 0, ofy1 = 0;
|
||
double t0, t1;
|
||
double x, y;
|
||
|
||
curline = line;
|
||
|
||
if (line->linedef == NULL) return;
|
||
|
||
//Offset&Rotate 3D coordinates to screen 3D space
|
||
x = double(line->v1->x - viewx); y = double(line->v1->y - viewy);
|
||
xp0 = x*gsinang - y*gcosang;
|
||
yp0 = x*gcosang2 + y*gsinang2;
|
||
x = double(line->v2->x - viewx); y = double(line->v2->y - viewy);
|
||
xp1 = x*gsinang - y*gcosang;
|
||
yp1 = x*gcosang2 + y*gsinang2;
|
||
|
||
oxp0 = xp0; oyp0 = yp0;
|
||
|
||
//Clip to close parallel-screen plane
|
||
// [RH] Why oh why does clipping the left side of the wall against
|
||
// a small SCISDIST not work for me? Strictly speaking, it's not
|
||
// the clipping of the left side that's the problem, because if I
|
||
// rotate the view 180 degrees so the right side of the wall is on
|
||
// the left of the screen, then clipping the right side becomes
|
||
// problematic.
|
||
#define WCLIPDIST (SCISDIST*256.0)
|
||
if (yp0 < WCLIPDIST)
|
||
{
|
||
if (yp1 < WCLIPDIST) return;
|
||
t0 = (WCLIPDIST-yp0)/(yp1-yp0);
|
||
xp0 = (xp1-xp0)*t0+xp0;
|
||
yp0 = WCLIPDIST;
|
||
nx0 = (line->v2->x - line->v1->x)*t0 + line->v1->x;
|
||
ny0 = (line->v2->y - line->v1->y)*t0 + line->v1->y;
|
||
}
|
||
else { t0 = 0.f; nx0 = line->v1->x; ny0 = line->v1->y; }
|
||
if (yp1 < WCLIPDIST)
|
||
{
|
||
t1 = (WCLIPDIST-oyp0)/(yp1-oyp0);
|
||
xp1 = (xp1-oxp0)*t1+oxp0;
|
||
yp1 = WCLIPDIST;
|
||
nx1 = (line->v2->x - line->v1->x)*t1 + line->v1->x;
|
||
ny1 = (line->v2->y - line->v1->y)*t1 + line->v1->y;
|
||
}
|
||
else { t1 = 1.f; nx1 = line->v2->x; ny1 = line->v2->y; }
|
||
|
||
ryp0 = 1.0/yp0; ryp1 = 1.0/yp1;
|
||
|
||
//Generate screen coordinates for front side of wall
|
||
x0 = ghalfx*xp0*ryp0 + ghalfx;
|
||
x1 = ghalfx*xp1*ryp1 + ghalfx;
|
||
if (x1 <= x0) return;
|
||
|
||
ryp0 *= gyxscale; ryp1 *= gyxscale;
|
||
fixed_t fnx0 = fixed_t(nx0), fny0 = fixed_t(ny0);
|
||
fixed_t fnx1 = fixed_t(nx1), fny1 = fixed_t(ny1);
|
||
|
||
fcz0 = frontsector->ceilingplane.ZatPoint (fnx0, fny0);
|
||
ffz0 = frontsector->floorplane.ZatPoint (fnx0, fny0);
|
||
fcz1 = frontsector->ceilingplane.ZatPoint (fnx1, fny1);
|
||
ffz1 = frontsector->floorplane.ZatPoint (fnx1, fny1);
|
||
bool cc = (t0>0 && x1 > 0);
|
||
cy0 = ghoriz - double(fcz0 - viewz) * ryp0;
|
||
fy0 = ghoriz - double(ffz0 - viewz) * ryp0;
|
||
cy1 = ghoriz - double(fcz1 - viewz) * ryp1;
|
||
fy1 = ghoriz - double(ffz1 - viewz) * ryp1;
|
||
|
||
/*
|
||
tx1 = line->v1->x - viewx;
|
||
tx2 = line->v2->x - viewx;
|
||
ty1 = line->v1->y - viewy;
|
||
ty2 = line->v2->y - viewy;
|
||
// Reject lines not facing viewer
|
||
if (DMulScale32 (ty1, tx1-tx2, tx1, ty2-ty1) >= 0)
|
||
return;
|
||
|
||
WallTX1 = DMulScale20 (tx1, viewsin, -ty1, viewcos);
|
||
WallTX2 = DMulScale20 (tx2, viewsin, -ty2, viewcos);
|
||
|
||
WallTY1 = DMulScale20 (tx1, viewtancos, ty1, viewtansin);
|
||
WallTY2 = DMulScale20 (tx2, viewtancos, ty2, viewtansin);
|
||
|
||
if (MirrorFlags & RF_XFLIP)
|
||
{
|
||
int t = 256-WallTX1;
|
||
WallTX1 = 256-WallTX2;
|
||
WallTX2 = t;
|
||
swap (WallTY1, WallTY2);
|
||
}
|
||
|
||
if (WallTX1 >= -WallTY1)
|
||
{
|
||
if (WallTX1 > WallTY1) return; // left edge is off the right side
|
||
if (WallTY1 == 0) return;
|
||
WallSX1 = (centerxfrac + Scale (WallTX1, centerxfrac, WallTY1)) >> FRACBITS;
|
||
if (WallTX1 >= 0) WallSX1 = MIN (viewwidth, WallSX1+1); // fix for signed divide
|
||
WallSZ1 = WallTY1;
|
||
}
|
||
else
|
||
{
|
||
if (WallTX2 < -WallTY2) return; // wall is off the left side
|
||
fixed_t den = WallTX1 - WallTX2 - WallTY2 + WallTY1;
|
||
if (den == 0) return;
|
||
WallSX1 = 0;
|
||
WallSZ1 = WallTY1 + Scale (WallTY2 - WallTY1, WallTX1 + WallTY1, den);
|
||
}
|
||
|
||
if (WallSZ1 < 32)
|
||
return;
|
||
|
||
if (WallTX2 <= WallTY2)
|
||
{
|
||
if (WallTX2 < -WallTY2) return; // right edge is off the left side
|
||
if (WallTY2 == 0) return;
|
||
WallSX2 = (centerxfrac + Scale (WallTX2, centerxfrac, WallTY2)) >> FRACBITS;
|
||
if (WallTX2 >= 0) WallSX2 = MIN (viewwidth, WallSX2+1); // fix for signed divide
|
||
WallSZ2 = WallTY2;
|
||
}
|
||
else
|
||
{
|
||
if (WallTX1 > WallTY1) return; // wall is off the right side
|
||
fixed_t den = WallTY2 - WallTY1 - WallTX2 + WallTX1;
|
||
if (den == 0) return;
|
||
WallSX2 = viewwidth;
|
||
WallSZ2 = WallTY1 + Scale (WallTY2 - WallTY1, WallTX1 - WallTY1, den);
|
||
}
|
||
|
||
if (WallSZ2 < 32 || WallSX2 <= WallSX1)
|
||
return;
|
||
|
||
if (WallSX1 > WindowRight || WallSX2 < WindowLeft)
|
||
return;
|
||
if (line->linedef == NULL)
|
||
{
|
||
return;
|
||
}
|
||
*/
|
||
|
||
vertex_t *v1, *v2;
|
||
|
||
v1 = line->linedef->v1;
|
||
v2 = line->linedef->v2;
|
||
|
||
if ((v1 == line->v1 && v2 == line->v2) || (v2 == line->v1 && v1 == line->v2))
|
||
{ // The seg is the entire wall.
|
||
if (MirrorFlags & RF_XFLIP)
|
||
{
|
||
WallUoverZorg = (float)WallTX2 * WallTMapScale;
|
||
WallUoverZstep = (float)(-WallTY2) * 32.f;
|
||
WallInvZorg = (float)(WallTX2 - WallTX1) * WallTMapScale;
|
||
WallInvZstep = (float)(WallTY1 - WallTY2) * 32.f;
|
||
}
|
||
else
|
||
{
|
||
WallUoverZorg = (float)WallTX1 * WallTMapScale;
|
||
WallUoverZstep = (float)(-WallTY1) * 32.f;
|
||
WallInvZorg = (float)(WallTX1 - WallTX2) * WallTMapScale;
|
||
WallInvZstep = (float)(WallTY2 - WallTY1) * 32.f;
|
||
}
|
||
}
|
||
else
|
||
{ // The seg is only part of the wall.
|
||
if (line->linedef->sidedef[0] != line->sidedef)
|
||
{
|
||
swap (v1, v2);
|
||
}
|
||
tx1 = v1->x - viewx;
|
||
tx2 = v2->x - viewx;
|
||
ty1 = v1->y - viewy;
|
||
ty2 = v2->y - viewy;
|
||
|
||
fixed_t fullx1 = DMulScale20 (tx1, viewsin, -ty1, viewcos);
|
||
fixed_t fullx2 = DMulScale20 (tx2, viewsin, -ty2, viewcos);
|
||
fixed_t fully1 = DMulScale20 (tx1, viewtancos, ty1, viewtansin);
|
||
fixed_t fully2 = DMulScale20 (tx2, viewtancos, ty2, viewtansin);
|
||
|
||
if (MirrorFlags & RF_XFLIP)
|
||
{
|
||
fullx1 = -fullx1;
|
||
fullx2 = -fullx2;
|
||
}
|
||
|
||
WallUoverZorg = (float)fullx1 * WallTMapScale;
|
||
WallUoverZstep = (float)(-fully1) * 32.f;
|
||
WallInvZorg = (float)(fullx1 - fullx2) * WallTMapScale;
|
||
WallInvZstep = (float)(fully2 - fully1) * 32.f;
|
||
}
|
||
WallDepthScale = WallInvZstep * WallTMapScale2;
|
||
WallDepthOrg = -WallUoverZstep * WallTMapScale2;
|
||
|
||
backsector = line->backsector;
|
||
|
||
rw_mustmarkfloor = rw_mustmarkceiling = false;
|
||
rw_havehigh = rw_havelow = false;
|
||
|
||
// Single sided line?
|
||
if (backsector == NULL)
|
||
{
|
||
solid = true;
|
||
}
|
||
else
|
||
{
|
||
// killough 3/8/98, 4/4/98: hack for invisible ceilings / deep water
|
||
backsector = R_FakeFlat (backsector, &tempsec, NULL, NULL, true);
|
||
|
||
doorclosed = 0; // killough 4/16/98
|
||
|
||
bcz0 = backsector->ceilingplane.ZatPoint (fnx0, fny0);
|
||
bfz0 = backsector->floorplane.ZatPoint (fnx0, fny0);
|
||
bcz1 = backsector->ceilingplane.ZatPoint (fnx1, fny1);
|
||
bfz1 = backsector->floorplane.ZatPoint (fnx1, fny1);
|
||
ocy0 = ghoriz - double(bcz0 - viewz) * ryp0;
|
||
ofy0 = ghoriz - double(bfz0 - viewz) * ryp0;
|
||
ocy1 = ghoriz - double(bcz1 - viewz) * ryp1;
|
||
ofy1 = ghoriz - double(bfz1 - viewz) * ryp1;
|
||
|
||
if (fcz0 > bcz0 || fcz1 > bcz1)
|
||
{
|
||
rw_havehigh = true;
|
||
}
|
||
if (ffz0 < bfz0 ||ffz1 < bfz1)
|
||
{
|
||
rw_havelow = true;
|
||
}
|
||
|
||
// Closed door.
|
||
if ((bcz0 <= ffz0 && bcz1 <= ffz1) || (bfz0 >= fcz0 && bfz1 >= fcz1))
|
||
{
|
||
solid = true;
|
||
}
|
||
else if (
|
||
(backsector->GetTexture(sector_t::ceiling) != skyflatnum ||
|
||
frontsector->GetTexture(sector_t::ceiling) != skyflatnum)
|
||
|
||
// if door is closed because back is shut:
|
||
&& bcz0 <= bfz0 && bcz1 <= bfz1
|
||
|
||
// preserve a kind of transparent door/lift special effect:
|
||
&& bcz0 >= fcz0 && bcz1 >= fcz1
|
||
|
||
&& ((bfz0 <= ffz0 && bfz1 <= ffz1) || line->sidedef->GetTexture(side_t::bottom).isValid()))
|
||
{
|
||
// killough 1/18/98 -- This function is used to fix the automap bug which
|
||
// showed lines behind closed doors simply because the door had a dropoff.
|
||
//
|
||
// It assumes that Doom has already ruled out a door being closed because
|
||
// of front-back closure (e.g. front floor is taller than back ceiling).
|
||
|
||
// This fixes the automap floor height bug -- killough 1/18/98:
|
||
// killough 4/7/98: optimize: save result in doorclosed for use in r_segs.c
|
||
doorclosed = true;
|
||
solid = true;
|
||
}
|
||
else if (frontsector->ceilingplane != backsector->ceilingplane ||
|
||
frontsector->floorplane != backsector->floorplane)
|
||
{
|
||
// Window.
|
||
solid = false;
|
||
}
|
||
else if (backsector->lightlevel != frontsector->lightlevel
|
||
|| backsector->GetTexture(sector_t::floor) != frontsector->GetTexture(sector_t::floor)
|
||
|| backsector->GetTexture(sector_t::ceiling) != frontsector->GetTexture(sector_t::ceiling)
|
||
|| curline->sidedef->GetTexture(side_t::mid).isValid()
|
||
|
||
// killough 3/7/98: Take flats offsets into account:
|
||
|| backsector->GetXOffset(sector_t::floor) != frontsector->GetXOffset(sector_t::floor)
|
||
|| backsector->GetYOffset(sector_t::floor) != frontsector->GetYOffset(sector_t::floor)
|
||
|| backsector->GetXOffset(sector_t::ceiling) != frontsector->GetXOffset(sector_t::ceiling)
|
||
|| backsector->GetYOffset(sector_t::ceiling) != frontsector->GetYOffset(sector_t::ceiling)
|
||
|
||
|| backsector->GetPlaneLight(sector_t::floor) != frontsector->GetPlaneLight(sector_t::floor)
|
||
|| backsector->GetPlaneLight(sector_t::ceiling) != frontsector->GetPlaneLight(sector_t::ceiling)
|
||
|| backsector->GetFlags(sector_t::floor) != frontsector->GetFlags(sector_t::floor)
|
||
|| backsector->GetFlags(sector_t::ceiling) != frontsector->GetFlags(sector_t::ceiling)
|
||
|
||
// [RH] Also consider colormaps
|
||
|| backsector->ColorMap != frontsector->ColorMap
|
||
|
||
// [RH] and scaling
|
||
|| backsector->GetXScale(sector_t::floor) != frontsector->GetXScale(sector_t::floor)
|
||
|| backsector->GetYScale(sector_t::floor) != frontsector->GetYScale(sector_t::floor)
|
||
|| backsector->GetXScale(sector_t::ceiling) != frontsector->GetXScale(sector_t::ceiling)
|
||
|| backsector->GetYScale(sector_t::ceiling) != frontsector->GetYScale(sector_t::ceiling)
|
||
|
||
// [RH] and rotation
|
||
|| backsector->GetAngle(sector_t::floor) != frontsector->GetAngle(sector_t::floor)
|
||
|| backsector->GetAngle(sector_t::ceiling) != frontsector->GetAngle(sector_t::ceiling)
|
||
)
|
||
{
|
||
solid = false;
|
||
}
|
||
else
|
||
{
|
||
// Reject empty lines used for triggers and special events.
|
||
// Identical floor and ceiling on both sides, identical light levels
|
||
// on both sides, and no middle texture.
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (line->linedef->special == Line_Horizon)
|
||
{
|
||
// Be aware: Line_Horizon does not work properly with sloped planes
|
||
fcz1 = fcz0 = ffz1 = ffz0 = viewz;
|
||
markceiling = markfloor = true;
|
||
}
|
||
|
||
// must be fixed in case the polymost renderer ever gets developed further!
|
||
rw_offset = line->sidedef->GetTextureXOffset(side_t::mid);
|
||
|
||
R_NewWall (false);
|
||
if (rw_markmirror)
|
||
{
|
||
WallMirrors.Push (ds_p - drawsegs);
|
||
}
|
||
|
||
// render it
|
||
if (markceiling)
|
||
{
|
||
Mosts.DoMost (x1, cy1, x0, cy0, wireframe, !cc||1?(void *)0xc3:(void*)0xca);
|
||
}
|
||
if (markfloor)
|
||
{
|
||
Mosts.DoMost (x0, fy0, x1, fy1, wireframe, (void *)0xd3);
|
||
}
|
||
if (midtexture)
|
||
{ // one sided line
|
||
//if(line->linedef-lines==1)Printf ("%g %g %g -> %g %g %g : %g %g -> %g %g\n", yp0, x0, fy0, yp1, x1, fy1, nx0, ny0, nx1, ny1);
|
||
if (viewpitch > 0)
|
||
Mosts.DoMost (x0, -10000, x1, -10000, wireframe, !cc||1?(void *)0x83:(void*)0x93);
|
||
else
|
||
Mosts.DoMost (x1, 10000, x0, 10000, wireframe, !cc||1?(void *)0x83:(void*)0x93);
|
||
}
|
||
else
|
||
{ // two sided line
|
||
if (toptexture != NULL && toptexture->UseType != FTexture::TEX_Null)
|
||
{ // top wall
|
||
Mosts.DoMost (x1, ocy1, x0, ocy0, wireframe, (void *)0xa3);
|
||
}
|
||
if (bottomtexture != NULL && bottomtexture->UseType != FTexture::TEX_Null)
|
||
{ // bottom wall
|
||
Mosts.DoMost (x0, ofy0, x1, ofy1, wireframe, (void *)0x93);
|
||
/* float bfz2 = float(-(rw_backfz2 - viewz)) / 65536.f;
|
||
float bfz1 = float(-(rw_backfz1 - viewz)) / 65536.f;
|
||
Mosts.DoMost (WallSX1, bfz1 * izs / sz1 + ghoriz,
|
||
WallSX2, bfz2 * izs / sz2 + ghoriz,
|
||
wireframe, (void *)0x93);*/
|
||
}
|
||
}
|
||
}
|
||
|
||
void RP_Subsector (subsector_t *sub)
|
||
{
|
||
int count;
|
||
seg_t* line;
|
||
sector_t tempsec; // killough 3/7/98: deep water hack
|
||
int floorlightlevel; // killough 3/16/98: set floor lightlevel
|
||
int ceilinglightlevel; // killough 4/11/98
|
||
|
||
frontsector = sub->sector;
|
||
count = sub->numlines;
|
||
line = &segs[sub->firstline];
|
||
|
||
// killough 3/8/98, 4/4/98: Deep water / fake ceiling effect
|
||
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel,
|
||
&ceilinglightlevel, false); // killough 4/11/98
|
||
|
||
basecolormap = frontsector->ColorMap;
|
||
R_GetExtraLight (&ceilinglightlevel, frontsector->ceilingplane, frontsector->ExtraLights);
|
||
|
||
// [RH] set foggy flag
|
||
foggy = level.fadeto || frontsector->ColorMap->Fade || (level.flags & LEVEL_HASFADETABLE);
|
||
r_actualextralight = foggy ? 0 : extralight << 4;
|
||
basecolormap = frontsector->ColorMap;
|
||
/* ceilingplane = frontsector->ceilingplane.ZatPoint (viewx, viewy) > viewz ||
|
||
frontsector->ceilingpic == skyflatnum ||
|
||
(frontsector->CeilingSkyBox != NULL && frontsector->CeilingSkyBox->bAlways) ||
|
||
(frontsector->heightsec &&
|
||
!(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
|
||
frontsector->heightsec->floorpic == skyflatnum) ?
|
||
R_FindPlane(frontsector->ceilingplane, // killough 3/8/98
|
||
frontsector->ceilingpic,
|
||
ceilinglightlevel + r_actualextralight, // killough 4/11/98
|
||
frontsector->ceiling_xoffs, // killough 3/7/98
|
||
frontsector->ceiling_yoffs + frontsector->base_ceiling_yoffs,
|
||
frontsector->ceiling_xscale,
|
||
frontsector->ceiling_yscale,
|
||
frontsector->ceiling_angle + frontsector->base_ceiling_angle,
|
||
frontsector->sky,
|
||
frontsector->CeilingSkyBox
|
||
) : NULL;*/
|
||
|
||
basecolormap = frontsector->ColorMap;
|
||
R_GetExtraLight (&floorlightlevel, frontsector->floorplane, frontsector->ExtraLights);
|
||
|
||
// killough 3/7/98: Add (x,y) offsets to flats, add deep water check
|
||
// killough 3/16/98: add floorlightlevel
|
||
// killough 10/98: add support for skies transferred from sidedefs
|
||
/* floorplane = frontsector->floorplane.ZatPoint (viewx, viewy) < viewz || // killough 3/7/98
|
||
frontsector->floorpic == skyflatnum ||
|
||
(frontsector->FloorSkyBox != NULL && frontsector->FloorSkyBox->bAlways) ||
|
||
(frontsector->heightsec &&
|
||
!(frontsector->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
|
||
frontsector->heightsec->ceilingpic == skyflatnum) ?
|
||
R_FindPlane(frontsector->floorplane,
|
||
frontsector->floorpic,
|
||
floorlightlevel + r_actualextralight, // killough 3/16/98
|
||
frontsector->floor_xoffs, // killough 3/7/98
|
||
frontsector->floor_yoffs + frontsector->base_floor_yoffs,
|
||
frontsector->floor_xscale,
|
||
frontsector->floor_yscale,
|
||
frontsector->floor_angle + frontsector->base_floor_angle,
|
||
frontsector->sky,
|
||
frontsector->FloorSkyBox
|
||
) : NULL;*/
|
||
|
||
// killough 9/18/98: Fix underwater slowdown, by passing real sector
|
||
// instead of fake one. Improve sprite lighting by basing sprite
|
||
// lightlevels on floor & ceiling lightlevels in the surrounding area.
|
||
// [RH] Handle sprite lighting like Duke 3D: If the ceiling is a sky, sprites are lit by
|
||
// it, otherwise they are lit by the floor.
|
||
// R_AddSprites (sub->sector, frontsector->ceilingpic == skyflatnum ?
|
||
// ceilinglightlevel : floorlightlevel, FakeSide);
|
||
|
||
// [RH] Add particles
|
||
// int shade = LIGHT2SHADE((floorlightlevel + ceilinglightlevel)/2 + r_actualextralight);
|
||
// for (WORD i = ParticlesInSubsec[sub-subsectors]; i != NO_PARTICLE; i = Particles[i].snext)
|
||
// {
|
||
// R_ProjectParticle (Particles + i, subsectors[sub-subsectors].sector, shade, FakeSide);
|
||
// }
|
||
|
||
if (sub->poly)
|
||
{ // Render the polyobj in the subsector first
|
||
int polyCount = sub->poly->numsegs;
|
||
seg_t **polySeg = sub->poly->segs;
|
||
while (polyCount--)
|
||
{
|
||
RP_AddLine (*polySeg++);
|
||
}
|
||
}
|
||
|
||
while (count--)
|
||
{
|
||
if (!line->bPolySeg)
|
||
{
|
||
RP_AddLine (line);
|
||
}
|
||
line++;
|
||
}
|
||
}
|
||
|
||
extern "C" const int checkcoord[12][4];
|
||
|
||
static bool RP_CheckBBox (fixed_t *bspcoord)
|
||
{
|
||
int boxx;
|
||
int boxy;
|
||
int boxpos;
|
||
|
||
fixed_t x1, y1, x2, y2;
|
||
double x, y, xp0, yp0, xp1, yp1, t, sx0, sx1;
|
||
|
||
// Find the corners of the box
|
||
// that define the edges from current viewpoint.
|
||
if (viewx <= bspcoord[BOXLEFT])
|
||
boxx = 0;
|
||
else if (viewx < bspcoord[BOXRIGHT])
|
||
boxx = 1;
|
||
else
|
||
boxx = 2;
|
||
|
||
if (viewy >= bspcoord[BOXTOP])
|
||
boxy = 0;
|
||
else if (viewy > bspcoord[BOXBOTTOM])
|
||
boxy = 1;
|
||
else
|
||
boxy = 2;
|
||
|
||
boxpos = (boxy<<2)+boxx;
|
||
if (boxpos == 5)
|
||
return true;
|
||
|
||
x1 = bspcoord[checkcoord[boxpos][0]] - viewx;
|
||
y1 = bspcoord[checkcoord[boxpos][1]] - viewy;
|
||
x2 = bspcoord[checkcoord[boxpos][2]] - viewx;
|
||
y2 = bspcoord[checkcoord[boxpos][3]] - viewy;
|
||
|
||
// check clip list for an open space
|
||
|
||
// Sitting on a line?
|
||
if (DMulScale32 (y1, x1-x2, x1, y2-y1) >= 0)
|
||
return true;
|
||
|
||
//Offset&Rotate 3D coordinates to screen 3D space
|
||
x = double(x1); y = double(y1);
|
||
xp0 = x*gsinang - y*gcosang;
|
||
yp0 = x*gcosang2 + y*gsinang2;
|
||
x = double(x2); y = double(y2);
|
||
xp1 = x*gsinang - y*gcosang;
|
||
yp1 = x*gcosang2 + y*gsinang2;
|
||
|
||
//Clip to close parallel-screen plane
|
||
if (yp0 < SCISDIST)
|
||
{
|
||
if (yp1 < SCISDIST) return false;
|
||
t = (SCISDIST-yp0)/(yp1-yp0);
|
||
xp0 = (xp1-xp0)*t+xp0;
|
||
yp0 = SCISDIST;
|
||
}
|
||
if (yp1 < SCISDIST)
|
||
{
|
||
t = (SCISDIST-yp0)/(yp1-yp0);
|
||
xp1 = (xp1-xp0)*t+xp0;
|
||
yp1 = SCISDIST;
|
||
}
|
||
|
||
//Generate screen coordinates for front side of wall
|
||
sx0 = ghalfx*xp0/yp0 + ghalfx;
|
||
sx1 = ghalfx*xp1/yp1 + ghalfx;
|
||
|
||
// Does not cross a pixel.
|
||
if (sx1 <= sx0)
|
||
return false;
|
||
|
||
return Mosts.TestVisibleMost (sx0, sx1);
|
||
}
|
||
|
||
void RP_RenderBSPNode (void *node)
|
||
{
|
||
if (numnodes == 0)
|
||
{
|
||
RP_Subsector (subsectors);
|
||
return;
|
||
}
|
||
while (!((size_t)node & 1)) // Keep going until found a subsector
|
||
{
|
||
node_t *bsp = (node_t *)node;
|
||
|
||
// Decide which side the view point is on.
|
||
int side = R_PointOnSide (viewx, viewy, bsp);
|
||
|
||
// Recursively divide front space (toward the viewer).
|
||
RP_RenderBSPNode (bsp->children[side]);
|
||
|
||
// Possibly divide back space (away from the viewer).
|
||
side ^= 1;
|
||
if (!RP_CheckBBox (bsp->bbox[side]))
|
||
return;
|
||
|
||
node = bsp->children[side];
|
||
}
|
||
RP_Subsector ((subsector_t *)((BYTE *)node - 1));
|
||
}
|
||
|