- removed the Vector class in the GL renderer and replaced all its uses with FVector3.

- optimized the math to get a plane equation from a linedef. The original code used a generic algorithm that knew nothing about the fact that Doom walls are always perfectly vertical. With this knowledge the plane calculation can be reduced to a lot less code because retrieving the normal is trivial in this special case.
- use the SSE2 rsqrtss instruction to calculate a wall's length, because this is by far the most frequent use of square roots in the GL renderer. So far this is only active on x64, it may be activated on 32 bit later as well, but only after it has been decided if 32 bit builds should be x87 or SSE2.

# Conflicts:
#	src/gl/dynlights/gl_dynlight.cpp

# Conflicts:
#	src/g_shared/a_dynlightdata.cpp
This commit is contained in:
Christoph Oelckers 2017-03-12 19:44:00 +01:00
parent ef3421eee5
commit 4cd0d3d454
8 changed files with 136 additions and 428 deletions

View file

@ -177,6 +177,7 @@ if( MSVC )
# Use SSE 2 as minimum always as the true color drawers needs it for __vectorcall
#set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2") # This is already the default
# if( CMAKE_SIZEOF_VOID_P MATCHES "4")
# # SSE2 option (to allow x87 in 32 bit and disallow extended feature sets which have not yet been checked for precision)
# option (ZDOOM_USE_SSE2 "Use SSE2 instruction set")

View file

@ -372,10 +372,10 @@ void FRenderState::DrawColormapOverlay()
//
//==========================================================================
bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, Vector & nearPt, Vector & up, Vector & right,
bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, FVector3 & nearPt, FVector3 & up, FVector3 & right,
float & scale, bool checkside, bool additive)
{
Vector fn, pos;
FVector3 fn, pos;
DVector3 lpos = light->PosRelative(group);
@ -398,16 +398,12 @@ bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, Vector & nearPt,
// project light position onto plane (find closest point on plane)
pos.Set(lpos.X, lpos.Z, lpos.Y);
pos = { (float)lpos.X, (float)lpos.Z, (float)lpos.Y };
fn = p.Normal();
fn.GetRightUp(right, up);
#ifdef _MSC_VER
nearPt = pos + fn * dist;
#else
Vector tmpVec = fn * dist;
FVector3 tmpVec = fn * dist;
nearPt = pos + tmpVec;
#endif
float cs = 1.0f - (dist / radius);
if (additive) cs *= 0.2f; // otherwise the light gets too strong.
@ -417,13 +413,11 @@ bool gl_SetupLight(int group, Plane & p, ADynamicLight * light, Vector & nearPt,
if (light->IsSubtractive())
{
Vector v;
gl_RenderState.BlendEquation(GL_FUNC_REVERSE_SUBTRACT);
v.Set(r, g, b);
r = v.Length() - r;
g = v.Length() - g;
b = v.Length() - b;
float length = float(FVector3(r, g, b).Length());
r = length - r;
g = length - g;
b = length - b;
}
else
{
@ -564,7 +558,7 @@ void GLWall::RenderFogBoundaryCompat()
void GLFlat::DrawSubsectorLights(subsector_t * sub, int pass)
{
Plane p;
Vector nearPt, up, right, t1;
FVector3 nearPt, up, right, t1;
float scale;
FLightNode * node = sub->lighthead;
@ -604,11 +598,11 @@ void GLFlat::DrawSubsectorLights(subsector_t * sub, int pass)
ptr->x = vt->fX();
ptr->z = plane.plane.ZatPoint(vt) + dz;
ptr->y = vt->fY();
t1.Set(ptr->x, ptr->z, ptr->y);
Vector nearToVert = t1 - nearPt;
t1 = { ptr->x, ptr->z, ptr->y };
FVector3 nearToVert = t1 - nearPt;
ptr->u = (nearToVert.Dot(right) * scale) + 0.5f;
ptr->v = (nearToVert.Dot(up) * scale) + 0.5f;
ptr->u = ((nearToVert | right) * scale) + 0.5f;
ptr->v = ((nearToVert | up) * scale) + 0.5f;
ptr++;
}
GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_FAN);
@ -660,10 +654,10 @@ bool GLWall::PrepareLight(ADynamicLight * light, int pass)
{
float vtx[] = { glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2 };
Plane p;
Vector nearPt, up, right;
FVector3 nearPt, up, right;
float scale;
p.Init(vtx, 4);
p.Set(&glseg);
if (!p.ValidNormal())
{
@ -675,15 +669,15 @@ bool GLWall::PrepareLight(ADynamicLight * light, int pass)
return false;
}
Vector t1;
FVector3 t1;
int outcnt[4] = { 0,0,0,0 };
for (int i = 0; i<4; i++)
{
t1.Set(&vtx[i * 3]);
Vector nearToVert = t1 - nearPt;
tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f;
tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f;
t1 = &vtx[i * 3];
FVector3 nearToVert = t1 - nearPt;
tcs[i].u = ((nearToVert | right) * scale) + 0.5f;
tcs[i].v = ((nearToVert | up) * scale) + 0.5f;
// quick check whether the light touches this polygon
if (tcs[i].u<0) outcnt[0]++;

View file

@ -97,12 +97,12 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FD
if (light->IsSubtractive())
{
Vector v;
DVector3 v(r, g, b);
float length = (float)v.Length();
v.Set(r, g, b);
r = v.Length() - r;
g = v.Length() - g;
b = v.Length() - b;
r = length - r;
g = length - g;
b = length - b;
i = 1;
}

View file

@ -6,6 +6,7 @@
//
//==========================================================================
#include "r_defs.h"
#include "r_data/renderstyle.h"
#include "textures/textures.h"
#include "gl/renderer/gl_colormap.h"
@ -66,8 +67,15 @@ struct GLSeg
// we do not use the vector math inlines here because they are not optimized for speed but accuracy in the playsim
float x = y2 - y1;
float y = x1 - x2;
#if defined(__amd64__) || defined(_M_X64)
__m128 v;
v.m128_f32[0] = x*x + y*y;
float ilength = _mm_rsqrt_ss(v).m128_f32[0];
return FVector3(x * ilength, 0, y * ilength);
#else
float length = sqrtf(x*x + y*y);
return FVector3(x / length, 0, y / length);
#endif
}
};

View file

@ -74,12 +74,14 @@ void GLWall::SetupLights()
Plane p;
lightdata.Clear();
p.Init(vtx,4);
p.Set(&glseg);
/*
if (!p.ValidNormal())
{
return;
}
*/
FLightNode *node;
if (seg->sidedef == NULL)
{
@ -103,8 +105,6 @@ void GLWall::SetupLights()
{
iter_dlight++;
Vector fn, pos;
DVector3 posrel = node->lightsource->PosRelative(seg->frontsector);
float x = posrel.X;
float y = posrel.Y;
@ -112,29 +112,31 @@ void GLWall::SetupLights()
float dist = fabsf(p.DistToPoint(x, z, y));
float radius = node->lightsource->GetRadius();
float scale = 1.0f / ((2.f * radius) - dist);
FVector3 fn, pos;
if (radius > 0.f && dist < radius)
{
Vector nearPt, up, right;
FVector3 nearPt, up, right;
pos = { x, z, y };
fn = p.Normal();
pos.Set(x,z,y);
fn=p.Normal();
fn.GetRightUp(right, up);
Vector tmpVec = fn * dist;
FVector3 tmpVec = fn * dist;
nearPt = pos + tmpVec;
Vector t1;
FVector3 t1;
int outcnt[4]={0,0,0,0};
texcoord tcs[4];
// do a quick check whether the light touches this polygon
for(int i=0;i<4;i++)
{
t1.Set(&vtx[i*3]);
Vector nearToVert = t1 - nearPt;
tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f;
tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f;
t1 = FVector3(&vtx[i*3]);
FVector3 nearToVert = t1 - nearPt;
tcs[i].u = ((nearToVert | right) * scale) + 0.5f;
tcs[i].v = ((nearToVert | up) * scale) + 0.5f;
if (tcs[i].u<0) outcnt[0]++;
if (tcs[i].u>1) outcnt[1]++;

View file

@ -35,243 +35,27 @@
#include <math.h>
#include <float.h>
#include "gl/utility/gl_geometric.h"
#include "gl/scene/gl_wall.h"
static Vector axis[3] =
void Plane::Set(GLSeg *seg)
{
Vector(1.0f, 0.0f, 0.0f),
Vector(0.0f, 1.0f, 0.0f),
Vector(0.0f, 0.0f, 1.0f)
};
Vector Vector::Cross(Vector &v)
{
float x, y, z;
Vector cp;
x = Y() * v.Z() - Z() * v.Y();
y = Z() * v.X() - X() * v.Z();
z = X() * v.Y() - Y() * v.X();
cp.Set(x, y, z);
return cp;
m_normal = seg->Normal();
m_d = m_normal | FVector3(-seg->x1, 0, -seg->y1);
}
Vector Vector::operator- (Vector &v)
{
float x, y, z;
Vector vec;
x = X() - v.X();
y = Y() - v.Y();
z = Z() - v.Z();
vec.Set(x, y, z);
return vec;
}
Vector Vector::operator+ (Vector &v)
{
float x, y, z;
Vector vec;
x = X() + v.X();
y = Y() + v.Y();
z = Z() + v.Z();
vec.Set(x, y, z);
return vec;
}
Vector Vector::operator* (float f)
{
Vector vec(X(), Y(), Z());
vec.Scale(f);
return vec;
}
Vector Vector::operator/ (float f)
{
Vector vec(X(), Y(), Z());
vec.Scale(1.f / f);
return vec;
}
bool Vector::operator== (Vector &v)
{
return X() == v.X() && Y() == v.Y() && Z() == v.Z();
}
void Vector::GetRightUp(Vector &right, Vector &up)
{
Vector n(X(), Y(), Z());
Vector fn(fabsf(n.X()), fabsf(n.Y()), fabsf(n.Z()));
int major = 0;
if (fn[1] > fn[major]) major = 1;
if (fn[2] > fn[major]) major = 2;
// build right vector by hand
if (fabsf(fn[0]-1.0f) < FLT_EPSILON || fabsf(fn[1]-1.0f) < FLT_EPSILON || fabsf(fn[2]-1.0f) < FLT_EPSILON)
{
if (major == 0 && n[0] > 0.f)
{
right.Set(0.f, 0.f, -1.f);
}
else if (major == 0)
{
right.Set(0.f, 0.f, 1.f);
}
if (major == 1 || (major == 2 && n[2] > 0.f))
{
right.Set(1.f, 0.f, 0.f);
}
if (major == 2 && n[2] < 0.0f)
{
right.Set(-1.f, 0.f, 0.f);
}
}
else
{
right = axis[major].Cross(n);
}
up = n.Cross(right);
right.Normalize();
up.Normalize();
}
void Vector::Scale(float scale)
{
float x, y, z;
x = X() * scale;
y = Y() * scale;
z = Z() * scale;
Set(x, y, z);
}
Vector Vector::ProjectVector(Vector &a)
{
Vector res, b;
b.Set(X(), Y(), Z());
res.Set(a.X(), a.Y(), a.Z());
res.Scale(a.Dot(b) / a.Dot(a));
return res;
}
Vector Vector::ProjectPlane(Vector &right, Vector &up)
{
Vector src(X(), Y(), Z());
Vector t1, t2;
t1 = src.ProjectVector(right);
t2 = src.ProjectVector(up);
return t1 + t2;
}
void Plane::Init(float *v1, float *v2, float *v3)
{
Vector vec1, vec2, vec3;
vec1.Set(v1);
vec2.Set(v2);
vec3.Set(v3);
#ifdef _MSC_VER
m_normal = (vec2 - vec1).Cross(vec3 - vec1);
#else
Vector tmpVec = vec3 - vec1;
m_normal = (vec2 - vec1).Cross(tmpVec);
#endif
m_normal.Normalize();
m_d = vec3.Dot(m_normal) * -1.f;
}
#define FNOTEQUAL(a, b) (fabsf(a - b) > 0.001f)
void Plane::Init(float *verts, int numVerts)
{
float *v[3], *t;
int i, curVert;
if (numVerts < 3) return;
curVert = 1;
v[0] = verts + 0;
for (i = 1; i < numVerts; i++)
{
t = verts + (i * 3);
if (FNOTEQUAL(t[0], v[curVert - 1][0]) || FNOTEQUAL(t[1], v[curVert - 1][1]) || FNOTEQUAL(t[2], v[curVert - 1][2]))
{
v[curVert] = t;
curVert++;
}
if (curVert == 3) break;
}
if (curVert != 3)
{
// degenerate triangle, no valid normal
return;
}
Init(v[0], v[1], v[2]);
}
void Plane::Init(float a, float b, float c, float d)
{
m_normal.Set(a, b, c);
m_d = d / m_normal.Length();
m_normal.Normalize();
}
void Plane::Set(secplane_t &plane)
{
m_normal.Set((float)plane.Normal().X, (float)plane.Normal().Z, (float)plane.Normal().Y);
//m_normal.Normalize(); the vector is already normalized
m_normal = { (float)plane.Normal().X, (float)plane.Normal().Z, (float)plane.Normal().Y };
m_d = (float)plane.fD();
}
float Plane::DistToPoint(float x, float y, float z)
{
Vector p;
FVector3 p(x, y, z);
p.Set(x, y, z);
return m_normal.Dot(p) + m_d;
return (m_normal | p) + m_d;
}

View file

@ -37,141 +37,26 @@
#include "math.h"
#include "r_defs.h"
class Vector
{
public:
Vector()
{
SetX(0.f);
SetY(1.f);
SetZ(0.f);
m_length = 1.f;
}
Vector(float x, float y, float z)
{
SetX(x);
SetY(y);
SetZ(z);
m_length=-1.0f;
}
Vector(float *v)
{
SetX(v[0]);
SetY(v[1]);
SetZ(v[2]);
m_length=-1.0f;
}
Vector(vertex_t * v)
{
SetX((float)v->fX());
SetY((float)v->fY());
SetZ(0);
}
void Normalize()
{
float l = 1.f / Length();
SetX(X() * l);
SetY(Y() * l);
SetZ(Z() * l);
m_length=1.0f;
}
void UpdateLength()
{
m_length = sqrtf((X() * X()) + (Y() * Y()) + (Z() * Z()));
}
void Set(float *v)
{
SetX(v[0]);
SetY(v[1]);
SetZ(v[2]);
m_length=-1.0f;
}
void Set(float x, float y, float z)
{
SetX(x);
SetY(y);
SetZ(z);
m_length=-1.0f;
}
float Length()
{
if (m_length<0.0f) UpdateLength();
return m_length;
}
float Dist(Vector &v)
{
Vector t(X() - v.X(), Y() - v.Y(), Z() - v.Z());
return t.Length();
}
float Dot(Vector &v)
{
return (X() * v.X()) + (Y() * v.Y()) + (Z() * v.Z());
}
Vector Cross(Vector &v);
Vector operator- (Vector &v);
Vector operator+ (Vector &v);
Vector operator* (float f);
Vector operator/ (float f);
bool operator== (Vector &v);
bool operator!= (Vector &v) { return !((*this) == v); }
void GetRightUp(Vector &up, Vector &right);
float operator[] (int index) const { return m_vec[index]; }
float &operator[] (int index) { return m_vec[index]; }
float X() const { return m_vec[0]; }
float Y() const { return m_vec[1]; }
float Z() const { return m_vec[2]; }
void SetX(float x) { m_vec[0] = x; }
void SetY(float y) { m_vec[1] = y; }
void SetZ(float z) { m_vec[2] = z; }
void Scale(float scale);
Vector ProjectVector(Vector &a);
Vector ProjectPlane(Vector &right, Vector &up);
protected:
float m_vec[3];
float m_length;
};
struct GLSeg;
class Plane
{
public:
Plane()
{
m_normal.Set(0.f, 1.f, 0.f);
m_d = 0.f;
}
void Init(float *v1, float *v2, float *v3);
void Init(float a, float b, float c, float d);
void Init(float *verts, int numVerts);
void Set(GLSeg *seg);
void Set(secplane_t &plane);
float DistToPoint(float x, float y, float z);
bool PointOnSide(float x, float y, float z);
bool PointOnSide(Vector &v) { return PointOnSide(v.X(), v.Y(), v.Z()); }
bool ValidNormal() { return m_normal.Length() == 1.f; }
bool PointOnSide(FVector3 &v) { return PointOnSide(v.X, v.Y, v.Z); }
bool ValidNormal() { return m_normal.LengthSquared() == 1.f; }
float A() { return m_normal.X(); }
float B() { return m_normal.Y(); }
float C() { return m_normal.Z(); }
float A() { return m_normal.X; }
float B() { return m_normal.Y; }
float C() { return m_normal.Z; }
float D() { return m_d; }
const Vector &Normal() const { return m_normal; }
const FVector3 &Normal() const { return m_normal; }
protected:
Vector m_normal;
FVector3 m_normal;
float m_d;
};
@ -213,21 +98,21 @@ public:
{
Matrix3x4 m1;
Vector axis(ax, ay, az);
axis.Normalize();
FVector3 axis(ax, ay, az);
axis.MakeUnit();
double c = cos(angle * M_PI/180.), s = sin(angle * M_PI/180.), t = 1 - c;
double sx = s*axis.X(), sy = s*axis.Y(), sz = s*axis.Z();
double sx = s*axis.X, sy = s*axis.Y, sz = s*axis.Z;
double tx, ty, txx, tyy, u, v;
tx = t*axis.X();
m1.m[0][0] = float( (txx=tx*axis.X()) + c );
m1.m[0][1] = float( (u=tx*axis.Y()) - sz);
m1.m[0][2] = float( (v=tx*axis.Z()) + sy);
tx = t*axis.X;
m1.m[0][0] = float( (txx=tx*axis.X) + c );
m1.m[0][1] = float( (u=tx*axis.Y) - sz);
m1.m[0][2] = float( (v=tx*axis.Z) + sy);
ty = t*axis.Y();
ty = t*axis.Y;
m1.m[1][0] = float( u + sz);
m1.m[1][1] = float( (tyy=ty*axis.Y()) + c );
m1.m[1][2] = float( (u=ty*axis.Z()) - sx);
m1.m[1][1] = float( (tyy=ty*axis.Y) + c );
m1.m[1][2] = float( (u=ty*axis.Z) - sx);
m1.m[2][0] = float( v - sy);
m1.m[2][1] = float( u + sx);
@ -262,16 +147,6 @@ public:
return result;
}
Vector operator *(const Vector &vec)
{
Vector result;
result.SetX(vec.X()*m[0][0] + vec.Y()*m[0][1] + vec.Z()*m[0][2] + m[0][3]);
result.SetY(vec.X()*m[1][0] + vec.Y()*m[1][1] + vec.Z()*m[1][2] + m[1][3]);
result.SetZ(vec.X()*m[2][0] + vec.Y()*m[2][1] + vec.Z()*m[2][2] + m[2][3]);
return result;
}
FVector3 operator *(const FVector3 &vec)
{
FVector3 result;
@ -281,14 +156,6 @@ public:
result.Z = vec.X*m[2][0] + vec.Y*m[2][1] + vec.Z*m[2][2] + m[2][3];
return result;
}
void MultiplyVector(float *f3 , float *f3o)
{
float x = f3[0] * m[0][0] + f3[1] * m[0][1] + f3[2] * m[0][2] + m[0][3];
float y = f3[0] * m[1][0] + f3[1] * m[1][1] + f3[2] * m[1][2] + m[1][3];
float z = f3[0] * m[2][0] + f3[1] * m[2][1] + f3[2] * m[2][2] + m[2][3];
f3o[2] = z; f3o[1] = y; f3o[0] = x;
}
};
#endif

View file

@ -325,6 +325,11 @@ struct TVector3
{
}
TVector3(vec_t *o)
: X(o[0]), Y(o[1]), Z(o[2])
{
}
TVector3 (const TVector3 &other)
: X(other.X), Y(other.Y), Z(other.Z)
{
@ -520,6 +525,53 @@ struct TVector3
return Vector2(v2.X - v3.X, v2.Y - v3.Y);
}
void GetRightUp(TVector3 &right, TVector3 &up)
{
TVector3 n(X, Y, Z);
TVector3 fn(fabs(n.X), fabs(n.Y), fabs(n.Z));
int major = 0;
if (fn[1] > fn[major]) major = 1;
if (fn[2] > fn[major]) major = 2;
// build right vector by hand
if (fabs(fn[0] - 1.0f) < FLT_EPSILON || fabs(fn[1] - 1.0f) < FLT_EPSILON || fabs(fn[2] - 1.0f) < FLT_EPSILON)
{
if (major == 0 && n[0] > 0.f)
{
right = { 0.f, 0.f, -1.f };
}
else if (major == 0)
{
right = { 0.f, 0.f, 1.f };
}
if (major == 1 || (major == 2 && n[2] > 0.f))
{
right = { 1.f, 0.f, 0.f };
}
if (major == 2 && n[2] < 0.0f)
{
right = { -1.f, 0.f, 0.f };
}
}
else
{
static TVector3 axis[3] =
{
{ 1.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f },
{ 0.0f, 0.0f, 1.0f }
};
right = axis[major] ^ n;
}
up = n ^right;
right.MakeUnit();;
up.MakeUnit();
}
// Returns the angle (in radians) that the ray (0,0)-(X,Y) faces
@ -542,7 +594,7 @@ struct TVector3
{
double len = Length();
if (len != 0) len = 1 / len;
return *this * len;
return *this * (vec_t)len;
}
// Scales this vector into a unit vector
@ -550,7 +602,7 @@ struct TVector3
{
double len = Length();
if (len != 0) len = 1 / len;
*this *= len;
*this *= (vec_t)len;
}
// Resizes this vector to be the specified length (if it is not 0)
@ -582,7 +634,7 @@ struct TVector3
}
// Dot product
double operator | (const TVector3 &other) const
vec_t operator | (const TVector3 &other) const
{
return X*other.X + Y*other.Y + Z*other.Z;
}