2006-02-24 04:48:15 +00:00
|
|
|
|
/**************************************************************************************************
|
|
|
|
|
"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"
|
2008-06-15 18:36:26 +00:00
|
|
|
|
#include "r_sky.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
|
|
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];
|
2006-12-29 03:38:37 +00:00
|
|
|
|
vsptype *vsp, *nvsp, *vcnt = NULL, *ni;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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;
|
- Fixed compilation with mingw again.
- Added multiple-choice sound sequences. These overcome one of the major
deficiences of the Hexen-inherited SNDSEQ system while still being Hexen
compatible: Custom door sounds can now use different opening and closing
sequences, for both normal and blazing speeds.
- Added a serializer for TArray.
- Added a countof macro to doomtype.h. See the1's blog to find out why
it's implemented the way it is.
<http://blogs.msdn.com/the1/articles/210011.aspx>
- Added a new method to FRandom for getting random numbers larger than 255,
which lets me:
- Fixed: SNDSEQ delayrand commands could delay for no more than 255 tics.
- Fixed: If you're going to have sector_t.SoundTarget, then they need to
be included in the pointer cleanup scans.
- Ported back newer name code from 2.1.
- Fixed: Using -warp with only one parameter in Doom and Heretic to
select a map on episode 1 no longer worked.
- New: Loading a multiplayer save now restores the players based on
their names rather than on their connection order. Using connection
order was sensible when -net was the only way to start a network game,
but with -host/-join, it's not so nice. Also, if there aren't enough
players in the save, then the extra players will be spawned normally,
so you can continue a saved game with more players than you started it
with.
- Added some new SNDSEQ commands to make it possible to define Heretic's
ambient sounds in SNDSEQ: volumerel, volumerand, slot, randomsequence,
delayonce, and restart. With these, it is basically possible to obsolete
all of the $ambient SNDINFO commands.
- Fixed: Sound sequences would only execute one command each time they were
ticked.
- Fixed: No bounds checking was done on the volume sound sequences played at.
- Fixed: The tic parameter to playloop was useless and caused it to
act like a redundant playrepeat. I have removed all the logic that
caused playloop to play repeating sounds, and now it acts like an
infinite sequence of play/delay commands until the sequence is
stopped.
- Fixed: Sound sequences were ticked every frame, not every tic, so all
the delay commands were timed incorrectly and varied depending on your
framerate. Since this is useful for restarting looping sounds that got
cut off, I have not changed this. Instead, the delay commands now
record the tic when execution should resume, not the number of tics
left to delay.
SVN r57 (trunk)
2006-04-21 01:22:55 +00:00
|
|
|
|
static struct polypt { float x, y; } polypts[80];
|
2006-09-14 00:02:31 +00:00
|
|
|
|
static BYTE polysize[32];
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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]; sprintf (foo, "%d", num);
|
|
|
|
|
RenderTarget->DrawText (CR_WHITE, x, y, foo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void drawpolymosttest()
|
|
|
|
|
{
|
2006-12-29 03:38:37 +00:00
|
|
|
|
float cx0 = 0, cy0 = 0, fx0 = 0, fy0 = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
int ccol, fcol;
|
|
|
|
|
PolyClipper::vsptype *vsp, *ovsp = &TestPoly.UsedList, *nvsp;
|
|
|
|
|
|
|
|
|
|
fcol = 0; ccol = 0;
|
|
|
|
|
|
2007-12-22 04:52:51 +00:00
|
|
|
|
RenderTarget->Clear(0, 0, RenderTarget->GetWidth(), RenderTarget->GetHeight(), 0, 0);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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;
|
- Fixed compilation with mingw again.
- Added multiple-choice sound sequences. These overcome one of the major
deficiences of the Hexen-inherited SNDSEQ system while still being Hexen
compatible: Custom door sounds can now use different opening and closing
sequences, for both normal and blazing speeds.
- Added a serializer for TArray.
- Added a countof macro to doomtype.h. See the1's blog to find out why
it's implemented the way it is.
<http://blogs.msdn.com/the1/articles/210011.aspx>
- Added a new method to FRandom for getting random numbers larger than 255,
which lets me:
- Fixed: SNDSEQ delayrand commands could delay for no more than 255 tics.
- Fixed: If you're going to have sector_t.SoundTarget, then they need to
be included in the pointer cleanup scans.
- Ported back newer name code from 2.1.
- Fixed: Using -warp with only one parameter in Doom and Heretic to
select a map on episode 1 no longer worked.
- New: Loading a multiplayer save now restores the players based on
their names rather than on their connection order. Using connection
order was sensible when -net was the only way to start a network game,
but with -host/-join, it's not so nice. Also, if there aren't enough
players in the save, then the extra players will be spawned normally,
so you can continue a saved game with more players than you started it
with.
- Added some new SNDSEQ commands to make it possible to define Heretic's
ambient sounds in SNDSEQ: volumerel, volumerand, slot, randomsequence,
delayonce, and restart. With these, it is basically possible to obsolete
all of the $ambient SNDINFO commands.
- Fixed: Sound sequences would only execute one command each time they were
ticked.
- Fixed: No bounds checking was done on the volume sound sequences played at.
- Fixed: The tic parameter to playloop was useless and caused it to
act like a redundant playrepeat. I have removed all the logic that
caused playloop to play repeating sounds, and now it acts like an
infinite sequence of play/delay commands until the sequence is
stopped.
- Fixed: Sound sequences were ticked every frame, not every tic, so all
the delay commands were timed incorrectly and varied depending on your
framerate. Since this is useful for restarting looping sounds that got
cut off, I have not changed this. Instead, the delay commands now
record the tic when execution should resume, not the number of tics
left to delay.
SVN r57 (trunk)
2006-04-21 01:22:55 +00:00
|
|
|
|
if (size_t(polypt + n) > countof(polypts)) return;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2008-06-25 22:16:04 +00:00
|
|
|
|
if (pt == 1) { if (px0 != px1) pt++; else pt--; }
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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;
|
2006-12-29 03:38:37 +00:00
|
|
|
|
double cy0, fy0, cy1, fy1, ocy0 = 0, ofy0 = 0, ocy1 = 0, ofy1 = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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.
|
2006-12-09 00:16:10 +00:00
|
|
|
|
if (line->linedef->sidenum[0] != DWORD(line->sidedef - sides))
|
2006-02-24 04:48:15 +00:00
|
|
|
|
{
|
|
|
|
|
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->ceilingpic != skyflatnum ||
|
|
|
|
|
frontsector->ceilingpic != 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
|
|
|
|
|
|
2008-06-15 18:36:26 +00:00
|
|
|
|
&& ((bfz0 <= ffz0 && bfz1 <= ffz1) || line->sidedef->GetTexture(side_t::bottom).isValid()))
|
2006-02-24 04:48:15 +00:00
|
|
|
|
{
|
|
|
|
|
// 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->floorpic != frontsector->floorpic
|
|
|
|
|
|| backsector->ceilingpic != frontsector->ceilingpic
|
2008-06-15 18:36:26 +00:00
|
|
|
|
|| curline->sidedef->GetTexture(side_t::mid).isValid()
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
|
|
// killough 3/7/98: Take flats offsets into account:
|
2008-06-14 15:26:16 +00:00
|
|
|
|
|| 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)
|
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|| backsector->FloorLight != frontsector->FloorLight
|
|
|
|
|
|| backsector->CeilingLight != frontsector->CeilingLight
|
|
|
|
|
|| backsector->FloorFlags != frontsector->FloorFlags
|
|
|
|
|
|| backsector->CeilingFlags != frontsector->CeilingFlags
|
|
|
|
|
|
|
|
|
|
// [RH] Also consider colormaps
|
|
|
|
|
|| backsector->ColorMap != frontsector->ColorMap
|
|
|
|
|
|
|
|
|
|
// [RH] and scaling
|
2008-06-14 15:26:16 +00:00
|
|
|
|
|| 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)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
|
|
// [RH] and rotation
|
2008-06-14 15:26:16 +00:00
|
|
|
|
|| backsector->GetAngle(sector_t::floor) != frontsector->GetAngle(sector_t::floor)
|
|
|
|
|
|| backsector->GetAngle(sector_t::ceiling) != frontsector->GetAngle(sector_t::ceiling)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-21 17:35:49 +00:00
|
|
|
|
// must be fixed in case the polymost renderer ever gets developed further!
|
|
|
|
|
rw_offset = line->sidedef->GetTextureXOffset(side_t::mid);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
- Updated lempar.c to v1.31.
- Added .txt files to the list of types (wad, zip, and pk3) that can be
loaded without listing them after -file.
- Fonts that are created by the ACS setfont command to wrap a texture now
support animated textures.
- FON2 fonts can now use their full palette for CR_UNTRANSLATED when drawn
with the hardware 2D path instead of being restricted to the game palette.
- Fixed: Toggling vid_vsync would reset the displayed fullscreen gamma to 1
on a Radeon 9000.
- Added back the off-by-one palette handling, but in a much more limited
scope than before. The skipped entry is assumed to always be at 248, and
it is assumed that all Shader Model 1.4 cards suffer from this. That's
because all SM1.4 cards are based on variants of the ATI R200 core, and the
RV250 in a Radeon 9000 craps up like this. I see no reason to assume that
other flavors of the R200 are any different. (Interesting note: With the
Radeon 9000, D3DTADDRESS_CLAMP is an invalid address mode when using the
debug Direct3D 9 runtime, but it works perfectly fine with the retail
Direct3D 9 runtime.) (Insight: The R200 probably uses bytes for all its
math inside pixel shaders. That would explain perfectly why I can't use
constants greater than 1 with PS1.4 and why it can't do an exact mapping to
every entry in the color palette.
- Fixed: The software shaded drawer did not work for 2D, because its selected
"color"map was replaced with the identitymap before being used.
- Fixed: I cannot use Printf to output messages before the framebuffer was
completely setup, meaning that Shader Model 1.4 cards could not change
resolution.
- I have decided to let remap palettes specify variable alpha values for
their colors. D3DFB no longer forces them to 255.
- Updated re2c to version 0.12.3.
- Fixed: A_Wander used threshold as a timer, when it should have used
reactiontime.
- Fixed: A_CustomRailgun would not fire at all for actors without a target
when the aim parameter was disabled.
- Made the warp command work in multiplayer, again courtesy of Karate Chris.
- Fixed: Trying to spawn a bot while not in a game made for a crashing time.
(Patch courtesy of Karate Chris.)
- Removed some floating point math from hu_scores.cpp that somebody's GCC
gave warnings for (not mine, though).
- Fixed: The SBarInfo drawbar command crashed if the sprite image was
unavailable.
- Fixed: FString::operator=(const char *) did not release its old buffer when
being assigned to the null string.
- The scanner no longer has an upper limit on the length of strings it
accepts, though short strings will be faster than long ones.
- Moved all the text scanning functions into a class. Mainly, this means that
multiple script scanner states can be stored without being forced to do so
recursively. I think I might be taking advantage of that in the near
future. Possibly. Maybe.
- Removed some potential buffer overflows from the decal parser.
- Applied Blzut3's SBARINFO update #9:
* Fixed: When using even length values in drawnumber it would cap to a 98
value instead of a 99 as intended.
* The SBarInfo parser can now accept negatives for coordinates. This
doesn't allow much right now, but later I plan to add better fullscreen
hud support in which the negatives will be more useful. This also cleans
up the source a bit since all calls for (x, y) coordinates are with the
function getCoordinates().
- Added support for stencilling actors.
- Added support for non-black colors specified with DTA_ColorOverlay to the
software renderer.
- Fixed: The inverse, gold, red, and green fixed colormaps each allocated
space for 32 different colormaps, even though each only used the first one.
- Added two new blending flags to make reverse subtract blending more useful:
STYLEF_InvertSource and STYLEF_InvertOverlay. These invert the color that
gets blended with the background, since that seems like a good idea for
reverse subtraction. They also work with the other two blending operations.
- Added subtract and reverse subtract blending operations to the renderer.
Since the ERenderStyle enumeration was getting rather unwieldy, I converted
it into a new FRenderStyle structure that lets each parameter of the
blending equation be set separately. This simplified the set up for the
blend quite a bit, and it means a number of new combinations are available
by setting the parameters properly.
SVN r710 (trunk)
2008-01-25 23:57:44 +00:00
|
|
|
|
basecolormap = frontsector->ColorMap;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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;
|
- Updated lempar.c to v1.31.
- Added .txt files to the list of types (wad, zip, and pk3) that can be
loaded without listing them after -file.
- Fonts that are created by the ACS setfont command to wrap a texture now
support animated textures.
- FON2 fonts can now use their full palette for CR_UNTRANSLATED when drawn
with the hardware 2D path instead of being restricted to the game palette.
- Fixed: Toggling vid_vsync would reset the displayed fullscreen gamma to 1
on a Radeon 9000.
- Added back the off-by-one palette handling, but in a much more limited
scope than before. The skipped entry is assumed to always be at 248, and
it is assumed that all Shader Model 1.4 cards suffer from this. That's
because all SM1.4 cards are based on variants of the ATI R200 core, and the
RV250 in a Radeon 9000 craps up like this. I see no reason to assume that
other flavors of the R200 are any different. (Interesting note: With the
Radeon 9000, D3DTADDRESS_CLAMP is an invalid address mode when using the
debug Direct3D 9 runtime, but it works perfectly fine with the retail
Direct3D 9 runtime.) (Insight: The R200 probably uses bytes for all its
math inside pixel shaders. That would explain perfectly why I can't use
constants greater than 1 with PS1.4 and why it can't do an exact mapping to
every entry in the color palette.
- Fixed: The software shaded drawer did not work for 2D, because its selected
"color"map was replaced with the identitymap before being used.
- Fixed: I cannot use Printf to output messages before the framebuffer was
completely setup, meaning that Shader Model 1.4 cards could not change
resolution.
- I have decided to let remap palettes specify variable alpha values for
their colors. D3DFB no longer forces them to 255.
- Updated re2c to version 0.12.3.
- Fixed: A_Wander used threshold as a timer, when it should have used
reactiontime.
- Fixed: A_CustomRailgun would not fire at all for actors without a target
when the aim parameter was disabled.
- Made the warp command work in multiplayer, again courtesy of Karate Chris.
- Fixed: Trying to spawn a bot while not in a game made for a crashing time.
(Patch courtesy of Karate Chris.)
- Removed some floating point math from hu_scores.cpp that somebody's GCC
gave warnings for (not mine, though).
- Fixed: The SBarInfo drawbar command crashed if the sprite image was
unavailable.
- Fixed: FString::operator=(const char *) did not release its old buffer when
being assigned to the null string.
- The scanner no longer has an upper limit on the length of strings it
accepts, though short strings will be faster than long ones.
- Moved all the text scanning functions into a class. Mainly, this means that
multiple script scanner states can be stored without being forced to do so
recursively. I think I might be taking advantage of that in the near
future. Possibly. Maybe.
- Removed some potential buffer overflows from the decal parser.
- Applied Blzut3's SBARINFO update #9:
* Fixed: When using even length values in drawnumber it would cap to a 98
value instead of a 99 as intended.
* The SBarInfo parser can now accept negatives for coordinates. This
doesn't allow much right now, but later I plan to add better fullscreen
hud support in which the negatives will be more useful. This also cleans
up the source a bit since all calls for (x, y) coordinates are with the
function getCoordinates().
- Added support for stencilling actors.
- Added support for non-black colors specified with DTA_ColorOverlay to the
software renderer.
- Fixed: The inverse, gold, red, and green fixed colormaps each allocated
space for 32 different colormaps, even though each only used the first one.
- Added two new blending flags to make reverse subtract blending more useful:
STYLEF_InvertSource and STYLEF_InvertOverlay. These invert the color that
gets blended with the background, since that seems like a good idea for
reverse subtraction. They also work with the other two blending operations.
- Added subtract and reverse subtract blending operations to the renderer.
Since the ERenderStyle enumeration was getting rather unwieldy, I converted
it into a new FRenderStyle structure that lets each parameter of the
blending equation be set separately. This simplified the set up for the
blend quite a bit, and it means a number of new combinations are available
by setting the parameters properly.
SVN r710 (trunk)
2008-01-25 23:57:44 +00:00
|
|
|
|
basecolormap = frontsector->ColorMap;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
/* 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
|
2008-06-15 18:36:26 +00:00
|
|
|
|
frontsector->ceilingpic,
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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,
|
2008-06-15 18:36:26 +00:00
|
|
|
|
frontsector->sky,
|
2006-02-24 04:48:15 +00:00
|
|
|
|
frontsector->CeilingSkyBox
|
|
|
|
|
) : NULL;*/
|
|
|
|
|
|
- Updated lempar.c to v1.31.
- Added .txt files to the list of types (wad, zip, and pk3) that can be
loaded without listing them after -file.
- Fonts that are created by the ACS setfont command to wrap a texture now
support animated textures.
- FON2 fonts can now use their full palette for CR_UNTRANSLATED when drawn
with the hardware 2D path instead of being restricted to the game palette.
- Fixed: Toggling vid_vsync would reset the displayed fullscreen gamma to 1
on a Radeon 9000.
- Added back the off-by-one palette handling, but in a much more limited
scope than before. The skipped entry is assumed to always be at 248, and
it is assumed that all Shader Model 1.4 cards suffer from this. That's
because all SM1.4 cards are based on variants of the ATI R200 core, and the
RV250 in a Radeon 9000 craps up like this. I see no reason to assume that
other flavors of the R200 are any different. (Interesting note: With the
Radeon 9000, D3DTADDRESS_CLAMP is an invalid address mode when using the
debug Direct3D 9 runtime, but it works perfectly fine with the retail
Direct3D 9 runtime.) (Insight: The R200 probably uses bytes for all its
math inside pixel shaders. That would explain perfectly why I can't use
constants greater than 1 with PS1.4 and why it can't do an exact mapping to
every entry in the color palette.
- Fixed: The software shaded drawer did not work for 2D, because its selected
"color"map was replaced with the identitymap before being used.
- Fixed: I cannot use Printf to output messages before the framebuffer was
completely setup, meaning that Shader Model 1.4 cards could not change
resolution.
- I have decided to let remap palettes specify variable alpha values for
their colors. D3DFB no longer forces them to 255.
- Updated re2c to version 0.12.3.
- Fixed: A_Wander used threshold as a timer, when it should have used
reactiontime.
- Fixed: A_CustomRailgun would not fire at all for actors without a target
when the aim parameter was disabled.
- Made the warp command work in multiplayer, again courtesy of Karate Chris.
- Fixed: Trying to spawn a bot while not in a game made for a crashing time.
(Patch courtesy of Karate Chris.)
- Removed some floating point math from hu_scores.cpp that somebody's GCC
gave warnings for (not mine, though).
- Fixed: The SBarInfo drawbar command crashed if the sprite image was
unavailable.
- Fixed: FString::operator=(const char *) did not release its old buffer when
being assigned to the null string.
- The scanner no longer has an upper limit on the length of strings it
accepts, though short strings will be faster than long ones.
- Moved all the text scanning functions into a class. Mainly, this means that
multiple script scanner states can be stored without being forced to do so
recursively. I think I might be taking advantage of that in the near
future. Possibly. Maybe.
- Removed some potential buffer overflows from the decal parser.
- Applied Blzut3's SBARINFO update #9:
* Fixed: When using even length values in drawnumber it would cap to a 98
value instead of a 99 as intended.
* The SBarInfo parser can now accept negatives for coordinates. This
doesn't allow much right now, but later I plan to add better fullscreen
hud support in which the negatives will be more useful. This also cleans
up the source a bit since all calls for (x, y) coordinates are with the
function getCoordinates().
- Added support for stencilling actors.
- Added support for non-black colors specified with DTA_ColorOverlay to the
software renderer.
- Fixed: The inverse, gold, red, and green fixed colormaps each allocated
space for 32 different colormaps, even though each only used the first one.
- Added two new blending flags to make reverse subtract blending more useful:
STYLEF_InvertSource and STYLEF_InvertOverlay. These invert the color that
gets blended with the background, since that seems like a good idea for
reverse subtraction. They also work with the other two blending operations.
- Added subtract and reverse subtract blending operations to the renderer.
Since the ERenderStyle enumeration was getting rather unwieldy, I converted
it into a new FRenderStyle structure that lets each parameter of the
blending equation be set separately. This simplified the set up for the
blend quite a bit, and it means a number of new combinations are available
by setting the parameters properly.
SVN r710 (trunk)
2008-01-25 23:57:44 +00:00
|
|
|
|
basecolormap = frontsector->ColorMap;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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,
|
2008-06-15 18:36:26 +00:00
|
|
|
|
frontsector->floorpic,
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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,
|
2008-06-15 18:36:26 +00:00
|
|
|
|
frontsector->sky,
|
2006-02-24 04:48:15 +00:00
|
|
|
|
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];
|
|
|
|
|
|
2006-09-14 00:02:31 +00:00
|
|
|
|
static bool RP_CheckBBox (fixed_t *bspcoord)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
{
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|