Commit 278fab0e by NTAuthority

World/related: messy changes, a simpler frustum management thing, and ignoring…

World/related: messy changes, a simpler frustum management thing, and ignoring LODs/alpha models - the latter as lack of depth sorting is all sorts of fun
parent d82c5b6f
Pipeline #64 skipped
......@@ -58,12 +58,12 @@ struct SectorGrid
}
template <typename callbackType>
inline void VisitSectorsByFrustum( const math::Quader& frustum, callbackType& cb ) const
inline void VisitSectorsByFrustum( const math::Frustum& frustum, callbackType& cb ) const
{
// For each visible sector, actually call our callback.
LIST_FOREACH_BEGIN( Sector, this->sectorList.root, node )
if ( item->sectorQuader.intersectWith( frustum ) )
if ( frustum.intersectWith(item->sectorQuader) )
{
// This sector is visible, that means we have to check for visible sub data entries.
item->content.root.ForAllEntries(
......@@ -71,7 +71,7 @@ struct SectorGrid
{
if ( sectorData.IsValid() )
{
if ( sectorData.entryQuader.intersectWith( frustum ) )
if ( frustum.intersectWith(sectorData.entryQuader) )
{
// This area on the map is visible, so lets give it to the callback.
cb( sectorData.data );
......
......@@ -64,6 +64,59 @@ private:
rw::Matrix rearPlane_inv_planeSpace_bottom, rearPlane_inv_planeSpace_top;
};
// this is actually a plane. get your air miles today!
struct SimplePlane
{
inline SimplePlane()
: normal(0.0f, 0.0f, 0.0f), dist(0.0f)
{
}
inline SimplePlane(rw::V3d normal, float dist)
: normal(normal), dist(dist)
{
}
inline SimplePlane(float a, float b, float c, float d)
: SimplePlane(rw::V3d(a, b, c), d)
{
}
inline void normalize()
{
float factor = 1.0f / rw::length(normal);
normal.x *= factor;
normal.y *= factor;
normal.z *= factor;
dist *= factor;
}
rw::V3d normal;
float dist;
};
struct Frustum
{
Frustum(const rw::Matrix& matrix);
bool isPointInside(const rw::V3d& point) const;
// assumes it's axis-aligned, silly Martin with his weird 'ingenuity'
bool intersectWith(const Quader& right) const;
bool intersectWith(const Sphere& right) const;
public:
SimplePlane planes[6];
rw::V3d corners[8];
private:
void createCorners();
};
// A function to test our math.
// Should succeed, eh.
void Tests( void );
......
......@@ -49,40 +49,20 @@ inline rw::V3d corvec( rw::V3d rwvec )
return rw::V3d( rwvec.x, rwvec.z, rwvec.y );
}
inline math::Quader getCameraFrustum( rw::Camera *camera, float fov_angle )
inline math::Frustum getCameraFrustum( rw::Camera *camera, float fov_angle )
{
// Calculate it ourselves.
float farPlaneDist = camera->farPlane;
float nearPlaneDist = camera->nearPlane;
rw::Matrix viewMat;
rw::Matrix cameraWorldMat = *camera->getFrame()->getLTM();
rw::Matrix::invert(&viewMat, &cameraWorldMat);
double fov = DEG2RAD(fov_angle);
double ar = 16.0f / 9.0f;
// why???
rw::Matrix cameraProjMat;
memcpy(&cameraProjMat, camera->projMat, sizeof(rw::Matrix));
double Hnear = 2 * tan( fov / 2 ) * nearPlaneDist;
double Wnear = Hnear * ar;
rw::Matrix viewProj;
rw::Matrix::mult(&viewProj, &cameraProjMat, &viewMat);
double Hfar = 2 * tan( fov / 2 ) * farPlaneDist;
double Wfar = Hfar * ar;
rw::Matrix cameraWorldMat = *camera->getFrame()->getLTM();
float half_Wnear = (float)( Wnear / 2 );
float half_Hnear = (float)( Hnear / 2 );
float half_Wfar = (float)( Wfar / 2 );
float half_Hfar = (float)( Hfar / 2 );
rw::V3d brl = cameraWorldMat.transPoint( rw::V3d( -half_Wnear, -half_Hnear, nearPlaneDist ) );
rw::V3d brr = cameraWorldMat.transPoint( rw::V3d( half_Wnear, -half_Hnear, nearPlaneDist ) );
rw::V3d trl = cameraWorldMat.transPoint( rw::V3d( -half_Wnear, half_Hnear, nearPlaneDist ) );
rw::V3d trr = cameraWorldMat.transPoint( rw::V3d( half_Wnear, half_Hnear, nearPlaneDist ) );
rw::V3d bfl = cameraWorldMat.transPoint( rw::V3d( -half_Wfar, -half_Hfar, farPlaneDist ) );
rw::V3d bfr = cameraWorldMat.transPoint( rw::V3d( half_Wfar, -half_Hfar, farPlaneDist ) );
rw::V3d tfl = cameraWorldMat.transPoint( rw::V3d( -half_Wfar, half_Hfar, farPlaneDist ) );
rw::V3d tfr = cameraWorldMat.transPoint( rw::V3d( half_Wfar, half_Hfar, farPlaneDist ) );
// Construct a view frustum.
return math::Quader( corvec( brl ), corvec( brr ), corvec( bfl ), corvec( bfr ), corvec( trl ), corvec( trr ), corvec( tfl ), corvec( tfr ) );
return math::Frustum(viewProj);
}
void World::DepopulateEntities( void )
......@@ -100,7 +80,11 @@ void World::PutEntitiesOnGrid( void )
// Try putting all the world entities on the grid.
LIST_FOREACH_BEGIN( Entity, this->entityList.root, worldNode )
this->staticEntityGrid.PutEntity( item );
// ignore LODs and transparent models (the latter as there's no depth sorting yet)
if (item->GetModelInfo() && item->GetModelInfo()->GetLODDistance() < 300.0f && (item->GetModelInfo()->GetFlags() & 12) == 0)
{
this->staticEntityGrid.PutEntity(item);
}
LIST_FOREACH_END
}
......@@ -115,24 +99,24 @@ static ConsoleCommand putGridCmd( "pgrid",
printf( "populated static entity grid\n" );
});
#include <windows.h>
#include <windows.h>
#include <d3d9.h>
void World::RenderWorld( void *gfxDevice )
{
// Thank you Bas for figuring out that rendering gunk!
// perform rendering
IDirect3DDevice9* device = reinterpret_cast<IDirect3DDevice9*>(gfxDevice);
device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 0, 0x99, 0xff), 1.0f, 0);
// perform rendering
IDirect3DDevice9* device = reinterpret_cast<IDirect3DDevice9*>(gfxDevice);
device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 0, 0x99, 0xff), 1.0f, 0);
device->BeginScene();
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
device->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
device->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
// Create a test frustum and see how it intersects with things.
......@@ -140,7 +124,7 @@ void World::RenderWorld( void *gfxDevice )
assert( testCamera != NULL );
testCamera->farPlane = 600.0f;
testCamera->farPlane = 2000.0f;
testCamera->nearPlane = 1.0f;
//testCamera->projection = rw::Camera::PERSPECTIVE;
......@@ -165,40 +149,40 @@ void World::RenderWorld( void *gfxDevice )
testCamera->updateProjectionMatrix();
{
rw::V3d cameraPosition(500.0f, 50.0f, 100.0f);
rw::V3d objectPosition(0.0f, 0.0f, 100.0f);
rw::Frame* frame = testCamera->getFrame();
if (frame)
{
rw::V3d forward = rw::normalize(rw::sub(objectPosition, cameraPosition));
rw::V3d left = rw::normalize(rw::cross(rw::V3d(0.0f, 0.0f, 1.0f), forward));
rw::V3d up = rw::cross(forward, left);
frame->matrix.right = left;
frame->matrix.up = up;
frame->matrix.at = forward;
frame->matrix.pos = cameraPosition;
frame->updateObjects();
rw::V3d cameraPosition(500.0f, 50.0f, 100.0f);
rw::V3d objectPosition(0.0f, 0.0f, 0.0f);
rw::Frame* frame = testCamera->getFrame();
if (frame)
{
rw::V3d forward = rw::normalize(rw::sub(objectPosition, cameraPosition));
rw::V3d left = rw::normalize(rw::cross(rw::V3d(0.0f, 0.0f, 1.0f), forward));
rw::V3d up = rw::cross(forward, left);
frame->matrix.right = left;
frame->matrix.up = up;
frame->matrix.at = forward;
frame->matrix.pos = cameraPosition;
frame->updateObjects();
}
}
rw::Matrix viewmat;
rw::Matrix::invert(&viewmat, testCamera->getFrame()->getLTM());
//viewmat.right.x = -viewmat.right.x;
viewmat.rightw = 0.0;
//viewmat.up.x = -viewmat.up.x;
viewmat.upw = 0.0;
//viewmat.at.x = -viewmat.at.x;
viewmat.atw = 0.0;
//viewmat.pos.x = -viewmat.pos.x;
viewmat.posw = 1.0;
device->SetTransform(D3DTS_VIEW, (D3DMATRIX*)&viewmat);
device->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)testCamera->projMat);
rw::Matrix viewmat;
rw::Matrix::invert(&viewmat, testCamera->getFrame()->getLTM());
viewmat.right.x = -viewmat.right.x;
viewmat.rightw = 0.0;
viewmat.up.x = -viewmat.up.x;
viewmat.upw = 0.0;
viewmat.at.x = -viewmat.at.x;
viewmat.atw = 0.0;
viewmat.pos.x = -viewmat.pos.x;
viewmat.posw = 1.0;
device->SetTransform(D3DTS_VIEW, (D3DMATRIX*)&viewmat);
device->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)testCamera->projMat);
// Get its frustum.
math::Quader frustum = getCameraFrustum( testCamera, fov_angle );
math::Frustum frustum = getCameraFrustum( testCamera, fov_angle );
streaming::StreamMan& streaming = theGame->GetStreaming();
......
......@@ -2032,6 +2032,141 @@ inline bool Sphere::intersectLine( const rw::V3d& pos, const rw::V3d& dir, doubl
return intersectSphereWithLine( dir, pos, this->point, this->radius, first, second );
}
Frustum::Frustum(const rw::Matrix& matrix)
{
planes[0] = SimplePlane(-matrix.right.z, -matrix.up.z, -matrix.at.z, -matrix.pos.z);
planes[1] = SimplePlane(matrix.right.z - matrix.rightw, matrix.up.z - matrix.upw, matrix.at.z - matrix.atw, matrix.pos.z - matrix.posw);
planes[2] = SimplePlane(-matrix.rightw - matrix.right.x, -matrix.upw - matrix.up.x, -matrix.atw - matrix.at.x, -matrix.posw - matrix.pos.x);
planes[3] = SimplePlane(matrix.right.x - matrix.rightw, matrix.up.x - matrix.upw, matrix.at.x - matrix.atw, matrix.pos.x - matrix.posw);
planes[4] = SimplePlane(matrix.right.y - matrix.rightw, matrix.up.y - matrix.upw, matrix.at.y - matrix.atw, matrix.pos.y - matrix.posw);
planes[5] = SimplePlane(-matrix.rightw - matrix.right.y, -matrix.upw - matrix.up.y, -matrix.atw - matrix.at.y, -matrix.posw - matrix.pos.y);
planes[0].normalize();
planes[1].normalize();
planes[2].normalize();
planes[3].normalize();
planes[4].normalize();
planes[5].normalize();
createCorners();
}
static rw::V3d IntersectionPoint(const SimplePlane& a, const SimplePlane& b, const SimplePlane& c)
{
rw::V3d v1, v2, v3;
rw::V3d cross;
float f;
cross = rw::cross(b.normal, c.normal);
f = rw::dot(a.normal, cross);
f *= -1.0f;
v1 = rw::scale(cross, a.dist);
cross = rw::cross(c.normal, a.normal);
v2 = rw::scale(cross, b.dist);
cross = rw::cross(a.normal, b.normal);
v3 = rw::scale(cross, c.dist);
return rw::V3d(
(v1.x + v2.x + v3.x) / f,
(v1.y + v2.y + v3.y) / f,
(v1.z + v2.z + v3.z) / f
);
}
void Frustum::createCorners()
{
corners[0] = IntersectionPoint(planes[0], planes[2], planes[4]);
corners[1] = IntersectionPoint(planes[0], planes[3], planes[4]);
corners[2] = IntersectionPoint(planes[0], planes[3], planes[5]);
corners[3] = IntersectionPoint(planes[0], planes[2], planes[5]);
corners[4] = IntersectionPoint(planes[1], planes[2], planes[4]);
corners[5] = IntersectionPoint(planes[1], planes[3], planes[4]);
corners[6] = IntersectionPoint(planes[1], planes[3], planes[5]);
corners[7] = IntersectionPoint(planes[1], planes[2], planes[5]);
}
bool Frustum::isPointInside(const rw::V3d& point) const
{
for (size_t i : irange<size_t>(6))
{
if ((rw::dot(point, planes[i].normal) + planes[i].dist) <= 0)
{
return false;
}
}
return true;
}
bool Frustum::intersectWith(const Sphere& right) const
{
for (size_t i : irange<size_t>(6))
{
if ((rw::dot(planes[i].normal, right.point) + planes[i].dist) > right.radius)
{
return false;
}
}
return true;
}
bool Frustum::intersectWith(const Quader& right) const
{
for (size_t i : irange<size_t>(6))
{
rw::V3d posVert;
rw::V3d negVert;
if (planes[i].normal.x >= 0)
{
posVert.x = right.tfr.x;
negVert.x = right.brl.x;
}
else
{
posVert.x = right.brl.x;
negVert.x = right.tfr.x;
}
if (planes[i].normal.y >= 0)
{
posVert.y = right.tfr.y;
negVert.y = right.brl.y;
}
else
{
posVert.y = right.brl.y;
negVert.y = right.tfr.y;
}
if (planes[i].normal.z >= 0)
{
posVert.z = right.tfr.z;
negVert.z = right.brl.z;
}
else
{
posVert.z = right.brl.z;
negVert.z = right.tfr.z;
}
float distance = rw::dot(planes[i].normal, negVert) + planes[i].dist;
if (distance > 0.0f)
{
return false;
}
}
return true;
}
// A cool testing thing, meow.
void Tests( void )
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment