2016-01-29 03:31:54 -08:00
|
|
|
// Copyright © 2008-2016 Pioneer Developers. See AUTHORS.txt for details
|
2013-03-10 12:59:08 -07:00
|
|
|
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
|
|
|
|
|
|
|
|
#include "libs.h"
|
|
|
|
#include "GeoPatchContext.h"
|
|
|
|
#include "GeoPatch.h"
|
2013-03-27 14:33:37 -07:00
|
|
|
#include "GeoPatchJobs.h"
|
2013-03-10 12:59:08 -07:00
|
|
|
#include "GeoSphere.h"
|
|
|
|
#include "perlin.h"
|
|
|
|
#include "Pi.h"
|
|
|
|
#include "RefCounted.h"
|
|
|
|
#include "graphics/Material.h"
|
|
|
|
#include "graphics/Renderer.h"
|
|
|
|
#include "graphics/Frustum.h"
|
|
|
|
#include "graphics/Graphics.h"
|
|
|
|
#include "graphics/VertexArray.h"
|
2014-02-18 13:32:02 -08:00
|
|
|
#include "MathUtil.h"
|
2014-10-09 11:21:04 -07:00
|
|
|
#include "Sphere.h"
|
2013-03-10 12:59:08 -07:00
|
|
|
#include "vcacheopt/vcacheopt.h"
|
|
|
|
#include <deque>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
// tri edge lengths
|
2013-06-26 18:07:40 -07:00
|
|
|
static const double GEOPATCH_SUBDIVIDE_AT_CAMDIST = 5.0;
|
2013-03-10 12:59:08 -07:00
|
|
|
|
2013-06-26 18:07:40 -07:00
|
|
|
GeoPatch::GeoPatch(const RefCountedPtr<GeoPatchContext> &ctx_, GeoSphere *gs,
|
|
|
|
const vector3d &v0_, const vector3d &v1_, const vector3d &v2_, const vector3d &v3_,
|
|
|
|
const int depth, const GeoPatchID &ID_)
|
|
|
|
: ctx(ctx_), v0(v0_), v1(v1_), v2(v2_), v3(v3_),
|
2013-10-29 04:44:49 -07:00
|
|
|
heights(nullptr), normals(nullptr), colors(nullptr),
|
2014-03-01 05:04:18 -08:00
|
|
|
parent(nullptr), geosphere(gs),
|
2013-06-26 18:07:40 -07:00
|
|
|
m_depth(depth), mPatchID(ID_),
|
2014-02-08 05:02:20 -08:00
|
|
|
mHasJobRequest(false)
|
2013-03-10 12:59:08 -07:00
|
|
|
{
|
2013-06-26 18:07:40 -07:00
|
|
|
|
2013-03-10 12:59:08 -07:00
|
|
|
clipCentroid = (v0+v1+v2+v3) * 0.25;
|
|
|
|
centroid = clipCentroid.Normalized();
|
|
|
|
clipRadius = 0.0;
|
|
|
|
clipRadius = std::max(clipRadius, (v0-clipCentroid).Length());
|
|
|
|
clipRadius = std::max(clipRadius, (v1-clipCentroid).Length());
|
|
|
|
clipRadius = std::max(clipRadius, (v2-clipCentroid).Length());
|
|
|
|
clipRadius = std::max(clipRadius, (v3-clipCentroid).Length());
|
2013-04-17 14:01:24 -07:00
|
|
|
double distMult;
|
2014-03-05 12:28:17 -08:00
|
|
|
if (geosphere->GetSystemBody()->GetType() < SystemBody::TYPE_PLANET_ASTEROID) {
|
2013-04-17 14:01:24 -07:00
|
|
|
distMult = 10.0 / Clamp(depth, 1, 10);
|
2013-03-10 12:59:08 -07:00
|
|
|
} else {
|
2013-04-17 14:01:24 -07:00
|
|
|
distMult = 5.0 / Clamp(depth, 1, 5);
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
2013-04-17 14:01:24 -07:00
|
|
|
m_roughLength = GEOPATCH_SUBDIVIDE_AT_CAMDIST / pow(2.0, depth) * distMult;
|
2013-03-10 12:59:08 -07:00
|
|
|
m_needUpdateVBOs = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
GeoPatch::~GeoPatch() {
|
2013-05-08 11:22:41 -07:00
|
|
|
mHasJobRequest = false;
|
2013-03-17 10:22:59 -07:00
|
|
|
for (int i=0; i<NUM_KIDS; i++) {
|
2013-10-29 04:44:49 -07:00
|
|
|
kids[i].reset();
|
2013-03-17 10:22:59 -07:00
|
|
|
}
|
2013-10-29 04:44:49 -07:00
|
|
|
heights.reset();
|
|
|
|
normals.reset();
|
|
|
|
colors.reset();
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
|
|
|
|
2015-06-15 14:14:22 -07:00
|
|
|
void GeoPatch::UpdateVBOs(Graphics::Renderer *renderer)
|
2014-03-01 05:04:18 -08:00
|
|
|
{
|
2016-02-21 04:29:39 -08:00
|
|
|
PROFILE_SCOPED()
|
2013-03-10 12:59:08 -07:00
|
|
|
if (m_needUpdateVBOs) {
|
2014-03-01 05:04:18 -08:00
|
|
|
assert(renderer);
|
2013-03-10 12:59:08 -07:00
|
|
|
m_needUpdateVBOs = false;
|
2014-03-01 05:04:18 -08:00
|
|
|
|
|
|
|
//create buffer and upload data
|
|
|
|
Graphics::VertexBufferDesc vbd;
|
|
|
|
vbd.attrib[0].semantic = Graphics::ATTRIB_POSITION;
|
|
|
|
vbd.attrib[0].format = Graphics::ATTRIB_FORMAT_FLOAT3;
|
|
|
|
vbd.attrib[1].semantic = Graphics::ATTRIB_NORMAL;
|
|
|
|
vbd.attrib[1].format = Graphics::ATTRIB_FORMAT_FLOAT3;
|
|
|
|
vbd.attrib[2].semantic = Graphics::ATTRIB_DIFFUSE;
|
|
|
|
vbd.attrib[2].format = Graphics::ATTRIB_FORMAT_UBYTE4;
|
2014-09-08 13:04:54 -07:00
|
|
|
vbd.attrib[3].semantic = Graphics::ATTRIB_UV0;
|
|
|
|
vbd.attrib[3].format = Graphics::ATTRIB_FORMAT_FLOAT2;
|
2014-03-01 05:04:18 -08:00
|
|
|
vbd.numVertices = ctx->NUMVERTICES();
|
|
|
|
vbd.usage = Graphics::BUFFER_USAGE_STATIC;
|
|
|
|
m_vertexBuffer.reset(renderer->CreateVertexBuffer(vbd));
|
|
|
|
|
2015-12-13 10:15:08 -08:00
|
|
|
GeoPatchContext::VBOVertex* VBOVtxPtr = m_vertexBuffer->Map<GeoPatchContext::VBOVertex>(Graphics::BUFFER_MAP_WRITE);
|
2014-03-01 05:04:18 -08:00
|
|
|
assert(m_vertexBuffer->GetDesc().stride == sizeof(GeoPatchContext::VBOVertex));
|
|
|
|
|
2014-09-17 00:55:29 -07:00
|
|
|
const Sint32 edgeLen = ctx->GetEdgeLen();
|
|
|
|
const double frac = ctx->GetFrac();
|
2014-02-18 13:32:02 -08:00
|
|
|
const double *pHts = heights.get();
|
2013-10-29 04:44:49 -07:00
|
|
|
const vector3f *pNorm = normals.get();
|
|
|
|
const Color3ub *pColr = colors.get();
|
2015-12-13 10:15:08 -08:00
|
|
|
|
|
|
|
const Sint32 innerTop = 1;
|
|
|
|
const Sint32 innerBottom = edgeLen - 2;
|
|
|
|
const Sint32 innerLeft = 1;
|
|
|
|
const Sint32 innerRight = edgeLen - 2;
|
|
|
|
|
|
|
|
const Sint32 outerTop = 0;
|
|
|
|
const Sint32 outerBottom = edgeLen - 1;
|
|
|
|
const Sint32 outerLeft = 0;
|
|
|
|
const Sint32 outerRight = edgeLen - 1;
|
|
|
|
|
2016-02-20 09:23:34 -08:00
|
|
|
double minh = DBL_MAX;
|
|
|
|
|
2015-12-13 10:15:08 -08:00
|
|
|
// ----------------------------------------------------
|
|
|
|
// inner loops
|
|
|
|
for (Sint32 y = 1; y<edgeLen-1; y++) {
|
|
|
|
for (Sint32 x = 1; x<edgeLen-1; x++) {
|
2013-03-25 16:02:33 -07:00
|
|
|
const double height = *pHts;
|
2016-02-20 09:23:34 -08:00
|
|
|
minh = std::min(height, minh);
|
2015-12-13 10:15:08 -08:00
|
|
|
const double xFrac = double(x - 1) * frac;
|
|
|
|
const double yFrac = double(y - 1) * frac;
|
2014-03-01 05:04:18 -08:00
|
|
|
const vector3d p((GetSpherePoint(xFrac, yFrac) * (height + 1.0)) - clipCentroid);
|
2013-03-25 16:02:33 -07:00
|
|
|
clipRadius = std::max(clipRadius, p.Length());
|
2015-12-13 10:15:08 -08:00
|
|
|
|
|
|
|
GeoPatchContext::VBOVertex* vtxPtr = &VBOVtxPtr[x + (y*edgeLen)];
|
2014-03-01 05:04:18 -08:00
|
|
|
vtxPtr->pos = vector3f(p);
|
2013-03-25 16:02:33 -07:00
|
|
|
++pHts; // next height
|
|
|
|
|
2014-03-01 05:04:18 -08:00
|
|
|
const vector3f norma(pNorm->Normalized());
|
|
|
|
vtxPtr->norm = norma;
|
2013-03-25 16:02:33 -07:00
|
|
|
++pNorm; // next normal
|
|
|
|
|
2014-03-01 05:04:18 -08:00
|
|
|
vtxPtr->col[0] = pColr->r;
|
|
|
|
vtxPtr->col[1] = pColr->g;
|
|
|
|
vtxPtr->col[2] = pColr->b;
|
|
|
|
vtxPtr->col[3] = 255;
|
2013-03-25 16:02:33 -07:00
|
|
|
++pColr; // next colour
|
|
|
|
|
2014-09-08 13:04:54 -07:00
|
|
|
// uv coords
|
2015-12-13 10:15:08 -08:00
|
|
|
vtxPtr->uv.x = 1.0f - xFrac;
|
|
|
|
vtxPtr->uv.y = yFrac;
|
2014-09-08 13:04:54 -07:00
|
|
|
|
2014-03-01 05:04:18 -08:00
|
|
|
++vtxPtr; // next vertex
|
2013-03-25 16:02:33 -07:00
|
|
|
}
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
2016-02-21 08:29:33 -08:00
|
|
|
const double minhScale = (minh + 1.0) * 0.99999;
|
2015-12-13 10:15:08 -08:00
|
|
|
// ----------------------------------------------------
|
|
|
|
// vertical edges
|
|
|
|
// left-edge
|
|
|
|
for (Sint32 y = 1; y < edgeLen - 1; y++) {
|
|
|
|
const Sint32 x = innerLeft;
|
|
|
|
const double xFrac = double(x - 1) * frac;
|
|
|
|
const double yFrac = double(y - 1) * frac;
|
2016-02-20 09:23:34 -08:00
|
|
|
const vector3d p((GetSpherePoint(xFrac, yFrac) * minhScale) - clipCentroid);
|
2015-12-13 10:15:08 -08:00
|
|
|
|
|
|
|
GeoPatchContext::VBOVertex* vtxPtr = &VBOVtxPtr[outerLeft + (y*edgeLen)];
|
|
|
|
GeoPatchContext::VBOVertex* vtxInr = &VBOVtxPtr[innerLeft + (y*edgeLen)];
|
|
|
|
vtxPtr->pos = vector3f(p);
|
|
|
|
vtxPtr->norm = vtxInr->norm;
|
|
|
|
vtxPtr->col = vtxInr->col;
|
|
|
|
vtxPtr->uv = vtxInr->uv;
|
|
|
|
}
|
|
|
|
// right-edge
|
|
|
|
for (Sint32 y = 1; y < edgeLen - 1; y++) {
|
|
|
|
const Sint32 x = innerRight;
|
|
|
|
const double xFrac = double(x - 1) * frac;
|
|
|
|
const double yFrac = double(y - 1) * frac;
|
2016-02-20 09:23:34 -08:00
|
|
|
const vector3d p((GetSpherePoint(xFrac, yFrac) * minhScale) - clipCentroid);
|
2015-12-13 10:15:08 -08:00
|
|
|
|
|
|
|
GeoPatchContext::VBOVertex* vtxPtr = &VBOVtxPtr[outerRight + (y*edgeLen)];
|
|
|
|
GeoPatchContext::VBOVertex* vtxInr = &VBOVtxPtr[innerRight + (y*edgeLen)];
|
|
|
|
vtxPtr->pos = vector3f(p);
|
|
|
|
vtxPtr->norm = vtxInr->norm;
|
|
|
|
vtxPtr->col = vtxInr->col;
|
|
|
|
vtxPtr->uv = vtxInr->uv;
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
// horizontal edges
|
|
|
|
// top-edge
|
|
|
|
for (Sint32 x = 1; x < edgeLen - 1; x++)
|
|
|
|
{
|
|
|
|
const Sint32 y = innerTop;
|
|
|
|
const double xFrac = double(x - 1) * frac;
|
|
|
|
const double yFrac = double(y - 1) * frac;
|
2016-02-20 09:23:34 -08:00
|
|
|
const vector3d p((GetSpherePoint(xFrac, yFrac) * minhScale) - clipCentroid);
|
2015-12-13 10:15:08 -08:00
|
|
|
|
|
|
|
GeoPatchContext::VBOVertex* vtxPtr = &VBOVtxPtr[x + (outerTop*edgeLen)];
|
|
|
|
GeoPatchContext::VBOVertex* vtxInr = &VBOVtxPtr[x + (innerTop*edgeLen)];
|
|
|
|
vtxPtr->pos = vector3f(p);
|
|
|
|
vtxPtr->norm = vtxInr->norm;
|
|
|
|
vtxPtr->col = vtxInr->col;
|
|
|
|
vtxPtr->uv = vtxInr->uv;
|
|
|
|
}
|
|
|
|
// bottom-edge
|
|
|
|
for (Sint32 x = 1; x < edgeLen - 1; x++)
|
|
|
|
{
|
|
|
|
const Sint32 y = innerBottom;
|
|
|
|
const double xFrac = double(x - 1) * frac;
|
|
|
|
const double yFrac = double(y - 1) * frac;
|
2016-02-20 09:23:34 -08:00
|
|
|
const vector3d p((GetSpherePoint(xFrac, yFrac) * minhScale) - clipCentroid);
|
2015-12-13 10:15:08 -08:00
|
|
|
|
|
|
|
GeoPatchContext::VBOVertex* vtxPtr = &VBOVtxPtr[x + (outerBottom * edgeLen)];
|
|
|
|
GeoPatchContext::VBOVertex* vtxInr = &VBOVtxPtr[x + (innerBottom * edgeLen)];
|
|
|
|
vtxPtr->pos = vector3f(p);
|
|
|
|
vtxPtr->norm = vtxInr->norm;
|
|
|
|
vtxPtr->col = vtxInr->col;
|
|
|
|
vtxPtr->uv = vtxInr->uv;
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
|
|
// corners
|
|
|
|
{
|
|
|
|
// top left
|
|
|
|
GeoPatchContext::VBOVertex* tarPtr = &VBOVtxPtr[0];
|
|
|
|
GeoPatchContext::VBOVertex* srcPtr = &VBOVtxPtr[1];
|
|
|
|
(*tarPtr) = (*srcPtr);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// top right
|
|
|
|
GeoPatchContext::VBOVertex* tarPtr = &VBOVtxPtr[(edgeLen - 1)];
|
|
|
|
GeoPatchContext::VBOVertex* srcPtr = &VBOVtxPtr[(edgeLen - 2)];
|
|
|
|
(*tarPtr) = (*srcPtr);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// bottom left
|
|
|
|
GeoPatchContext::VBOVertex* tarPtr = &VBOVtxPtr[(edgeLen - 1) * edgeLen];
|
|
|
|
GeoPatchContext::VBOVertex* srcPtr = &VBOVtxPtr[(edgeLen - 2) * edgeLen];
|
|
|
|
(*tarPtr) = (*srcPtr);
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// bottom right
|
|
|
|
GeoPatchContext::VBOVertex* tarPtr = &VBOVtxPtr[(edgeLen - 1) + ((edgeLen - 1) * edgeLen)];
|
|
|
|
GeoPatchContext::VBOVertex* srcPtr = &VBOVtxPtr[(edgeLen - 1) + ((edgeLen - 2) * edgeLen)];
|
|
|
|
(*tarPtr) = (*srcPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------
|
|
|
|
// end of mapping
|
2014-03-01 05:04:18 -08:00
|
|
|
m_vertexBuffer->Unmap();
|
2014-10-11 08:24:50 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG_BOUNDING_SPHERES
|
|
|
|
RefCountedPtr<Graphics::Material> mat(Pi::renderer->CreateMaterial(Graphics::MaterialDescriptor()));
|
|
|
|
m_boundsphere.reset( new Graphics::Drawables::Sphere3D(Pi::renderer, mat, Pi::renderer->CreateRenderState(Graphics::RenderStateDesc()), 0, clipRadius) );
|
|
|
|
#endif
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-09 03:01:40 -07:00
|
|
|
// the default sphere we do the horizon culling against
|
2014-10-11 08:24:50 -07:00
|
|
|
static const SSphere s_sph;
|
2014-10-09 00:51:15 -07:00
|
|
|
void GeoPatch::Render(Graphics::Renderer *renderer, const vector3d &campos, const matrix4x4d &modelView, const Graphics::Frustum &frustum)
|
|
|
|
{
|
2016-02-21 04:29:39 -08:00
|
|
|
PROFILE_SCOPED()
|
2014-10-19 06:58:53 -07:00
|
|
|
// must update the VBOs to calculate the clipRadius...
|
2015-06-15 14:14:22 -07:00
|
|
|
UpdateVBOs(renderer);
|
2014-10-19 06:58:53 -07:00
|
|
|
// ...before doing the furstum culling that relies on it.
|
2014-10-11 08:24:50 -07:00
|
|
|
if (!frustum.TestPoint(clipCentroid, clipRadius))
|
2014-10-09 03:01:40 -07:00
|
|
|
return; // nothing below this patch is visible
|
2014-10-11 08:24:50 -07:00
|
|
|
|
|
|
|
// only want to horizon cull patches that can actually be over the horizon!
|
2014-10-19 06:58:53 -07:00
|
|
|
const vector3d camDir(campos - clipCentroid);
|
|
|
|
const vector3d camDirNorm(camDir.Normalized());
|
2014-10-11 08:24:50 -07:00
|
|
|
const vector3d cenDir(clipCentroid.Normalized());
|
2014-10-19 06:58:53 -07:00
|
|
|
const double dotProd = camDirNorm.Dot(cenDir);
|
2014-10-11 08:24:50 -07:00
|
|
|
|
2014-10-19 06:58:53 -07:00
|
|
|
if( dotProd < 0.25 && (camDir.LengthSqr() > (clipRadius*clipRadius)) ) {
|
2014-10-11 08:24:50 -07:00
|
|
|
SSphere obj;
|
|
|
|
obj.m_centre = clipCentroid;
|
|
|
|
obj.m_radius = clipRadius;
|
|
|
|
|
|
|
|
if( !s_sph.HorizonCulling(campos, obj) ) {
|
|
|
|
return; // nothing below this patch is visible
|
|
|
|
}
|
2014-10-09 00:51:15 -07:00
|
|
|
}
|
|
|
|
|
2013-03-10 12:59:08 -07:00
|
|
|
if (kids[0]) {
|
2013-06-29 08:44:43 -07:00
|
|
|
for (int i=0; i<NUM_KIDS; i++) kids[i]->Render(renderer, campos, modelView, frustum);
|
2013-10-29 04:44:49 -07:00
|
|
|
} else if (heights) {
|
2016-02-21 04:29:39 -08:00
|
|
|
RefCountedPtr<Graphics::Material> mat = geosphere->GetSurfaceMaterial();
|
2014-03-05 12:28:17 -08:00
|
|
|
Graphics::RenderState *rs = geosphere->GetSurfRenderState();
|
2014-03-01 05:04:18 -08:00
|
|
|
|
2013-06-29 08:44:43 -07:00
|
|
|
const vector3d relpos = clipCentroid - campos;
|
|
|
|
renderer->SetTransform(modelView * matrix4x4d::Translation(relpos));
|
2013-03-10 12:59:08 -07:00
|
|
|
|
2014-09-17 00:55:29 -07:00
|
|
|
Pi::statSceneTris += (ctx->GetNumTris());
|
2014-09-16 12:30:03 -07:00
|
|
|
++Pi::statNumPatches;
|
2013-03-10 12:59:08 -07:00
|
|
|
|
2015-09-05 08:57:40 -07:00
|
|
|
// per-patch detail texture scaling value
|
|
|
|
geosphere->GetMaterialParameters().patchDepth = m_depth;
|
2013-03-10 12:59:08 -07:00
|
|
|
|
2016-02-21 04:29:39 -08:00
|
|
|
renderer->DrawBufferIndexed(m_vertexBuffer.get(), ctx->GetIndexBuffer(), rs, mat.Get());
|
2014-10-11 08:24:50 -07:00
|
|
|
#ifdef DEBUG_BOUNDING_SPHERES
|
|
|
|
if(m_boundsphere.get()) {
|
|
|
|
renderer->SetWireFrameMode(true);
|
|
|
|
m_boundsphere->Draw(renderer);
|
|
|
|
renderer->SetWireFrameMode(false);
|
2015-09-05 09:31:41 -07:00
|
|
|
}
|
2014-10-11 08:24:50 -07:00
|
|
|
#endif
|
2015-03-21 17:07:47 -07:00
|
|
|
renderer->GetStats().AddToStatCount(Graphics::Stats::STAT_PATCHES, 1);
|
2015-09-05 09:31:41 -07:00
|
|
|
}
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
|
|
|
|
2015-12-13 14:05:00 -08:00
|
|
|
void GeoPatch::LODUpdate(const vector3d &campos, const Graphics::Frustum &frustum)
|
2014-10-09 00:51:15 -07:00
|
|
|
{
|
|
|
|
// there should be no LOD update when we have active split requests
|
2013-03-24 13:55:35 -07:00
|
|
|
if(mHasJobRequest)
|
2013-03-10 12:59:08 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
bool canSplit = true;
|
2013-10-29 04:44:49 -07:00
|
|
|
bool canMerge = bool(kids[0]);
|
2013-03-10 12:59:08 -07:00
|
|
|
|
|
|
|
// always split at first level
|
2015-07-13 03:34:46 -07:00
|
|
|
double centroidDist = DBL_MAX;
|
2013-03-10 12:59:08 -07:00
|
|
|
if (parent) {
|
2015-07-13 03:34:46 -07:00
|
|
|
centroidDist = (campos - centroid).Length();
|
2013-03-10 12:59:08 -07:00
|
|
|
const bool errorSplit = (centroidDist < m_roughLength);
|
2014-09-16 12:30:03 -07:00
|
|
|
if( !(canSplit && (m_depth < std::min(GEOPATCH_MAX_DEPTH, geosphere->GetMaxDepth())) && errorSplit) ) {
|
2013-03-10 12:59:08 -07:00
|
|
|
canSplit = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (canSplit) {
|
|
|
|
if (!kids[0]) {
|
2015-12-15 02:28:30 -08:00
|
|
|
// Test if this patch is visible
|
2015-12-13 14:05:00 -08:00
|
|
|
if (!frustum.TestPoint(clipCentroid, clipRadius))
|
|
|
|
return; // nothing below this patch is visible
|
|
|
|
|
2015-12-15 02:28:30 -08:00
|
|
|
// only want to horizon cull patches that can actually be over the horizon!
|
2015-12-13 14:05:00 -08:00
|
|
|
const vector3d camDir(campos - clipCentroid);
|
|
|
|
const vector3d camDirNorm(camDir.Normalized());
|
|
|
|
const vector3d cenDir(clipCentroid.Normalized());
|
|
|
|
const double dotProd = camDirNorm.Dot(cenDir);
|
|
|
|
|
|
|
|
if (dotProd < 0.25 && (camDir.LengthSqr() >(clipRadius*clipRadius))) {
|
|
|
|
SSphere obj;
|
|
|
|
obj.m_centre = clipCentroid;
|
|
|
|
obj.m_radius = clipRadius;
|
|
|
|
|
|
|
|
if (!s_sph.HorizonCulling(campos, obj)) {
|
|
|
|
return; // nothing below this patch is visible
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-15 02:28:30 -08:00
|
|
|
// we can see this patch so submit the jobs!
|
2015-12-13 14:05:00 -08:00
|
|
|
assert(!mHasJobRequest);
|
2013-03-24 13:55:35 -07:00
|
|
|
mHasJobRequest = true;
|
2013-04-24 14:42:43 -07:00
|
|
|
|
2013-03-24 13:55:35 -07:00
|
|
|
SQuadSplitRequest *ssrd = new SQuadSplitRequest(v0, v1, v2, v3, centroid.Normalized(), m_depth,
|
2015-12-13 10:15:08 -08:00
|
|
|
geosphere->GetSystemBody()->GetPath(), mPatchID, ctx->GetEdgeLen()-2,
|
2014-09-17 00:55:29 -07:00
|
|
|
ctx->GetFrac(), geosphere->GetTerrain());
|
2015-07-13 03:34:46 -07:00
|
|
|
|
|
|
|
// add to the GeoSphere to be processed at end of all LODUpdate requests
|
|
|
|
geosphere->AddQuadSplitRequest(centroidDist, ssrd, this);
|
2013-03-10 12:59:08 -07:00
|
|
|
} else {
|
|
|
|
for (int i=0; i<NUM_KIDS; i++) {
|
2015-12-13 14:05:00 -08:00
|
|
|
kids[i]->LODUpdate(campos, frustum);
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (canMerge) {
|
2013-06-26 18:07:40 -07:00
|
|
|
for (int i=0; i<NUM_KIDS; i++) {
|
|
|
|
canMerge &= kids[i]->canBeMerged();
|
2013-04-01 07:38:03 -07:00
|
|
|
}
|
|
|
|
if( canMerge ) {
|
2013-06-26 18:07:40 -07:00
|
|
|
for (int i=0; i<NUM_KIDS; i++) {
|
2013-10-29 04:44:49 -07:00
|
|
|
kids[i].reset();
|
2013-04-01 07:38:03 -07:00
|
|
|
}
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-12 15:46:58 -07:00
|
|
|
|
2013-03-24 13:55:35 -07:00
|
|
|
void GeoPatch::RequestSinglePatch()
|
|
|
|
{
|
2013-10-29 04:44:49 -07:00
|
|
|
if( !heights ) {
|
2013-04-23 15:46:32 -07:00
|
|
|
assert(!mHasJobRequest);
|
2013-03-24 13:55:35 -07:00
|
|
|
mHasJobRequest = true;
|
|
|
|
SSingleSplitRequest *ssrd = new SSingleSplitRequest(v0, v1, v2, v3, centroid.Normalized(), m_depth,
|
2015-12-13 10:15:08 -08:00
|
|
|
geosphere->GetSystemBody()->GetPath(), mPatchID, ctx->GetEdgeLen()-2, ctx->GetFrac(), geosphere->GetTerrain());
|
2014-04-18 08:05:15 -07:00
|
|
|
m_job = Pi::GetAsyncJobQueue()->Queue(new SinglePatchJob(ssrd));
|
2013-03-24 13:55:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-08 11:22:41 -07:00
|
|
|
void GeoPatch::ReceiveHeightmaps(SQuadSplitResult *psr)
|
2013-03-10 12:59:08 -07:00
|
|
|
{
|
2016-02-21 04:29:39 -08:00
|
|
|
PROFILE_SCOPED()
|
2013-05-08 11:22:41 -07:00
|
|
|
assert(NULL!=psr);
|
2013-03-14 14:52:10 -07:00
|
|
|
if (m_depth<psr->depth()) {
|
2013-03-10 12:59:08 -07:00
|
|
|
// this should work because each depth should have a common history
|
2014-02-18 13:32:02 -08:00
|
|
|
const Uint32 kidIdx = psr->data(0).patchID.GetPatchIdx(m_depth+1);
|
2013-05-08 11:22:41 -07:00
|
|
|
if( kids[kidIdx] ) {
|
|
|
|
kids[kidIdx]->ReceiveHeightmaps(psr);
|
|
|
|
} else {
|
|
|
|
psr->OnCancel();
|
|
|
|
}
|
2013-03-10 12:59:08 -07:00
|
|
|
} else {
|
2013-03-24 13:55:35 -07:00
|
|
|
assert(mHasJobRequest);
|
2013-03-10 12:59:08 -07:00
|
|
|
const int nD = m_depth+1;
|
|
|
|
for (int i=0; i<NUM_KIDS; i++)
|
|
|
|
{
|
2013-10-29 04:44:49 -07:00
|
|
|
assert(!kids[i]);
|
2013-03-24 13:55:35 -07:00
|
|
|
const SQuadSplitResult::SSplitResultData& data = psr->data(i);
|
2013-03-14 14:52:10 -07:00
|
|
|
assert(i==data.patchID.GetPatchIdx(nD));
|
|
|
|
assert(0==data.patchID.GetPatchIdx(nD+1));
|
2013-10-29 04:44:49 -07:00
|
|
|
kids[i].reset(new GeoPatch(ctx, geosphere,
|
2013-06-26 18:07:40 -07:00
|
|
|
data.v0, data.v1, data.v2, data.v3,
|
2013-03-17 10:22:59 -07:00
|
|
|
nD, data.patchID));
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
|
|
|
kids[0]->parent = kids[1]->parent = kids[2]->parent = kids[3]->parent = this;
|
|
|
|
|
|
|
|
for (int i=0; i<NUM_KIDS; i++)
|
|
|
|
{
|
2013-03-24 13:55:35 -07:00
|
|
|
const SQuadSplitResult::SSplitResultData& data = psr->data(i);
|
2013-10-29 04:44:49 -07:00
|
|
|
kids[i]->heights.reset(data.heights);
|
|
|
|
kids[i]->normals.reset(data.normals);
|
|
|
|
kids[i]->colors.reset(data.colors);
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
|
|
|
for (int i=0; i<NUM_KIDS; i++) {
|
2015-06-15 14:14:22 -07:00
|
|
|
kids[i]->NeedToUpdateVBOs();
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
2013-03-24 13:55:35 -07:00
|
|
|
mHasJobRequest = false;
|
2013-03-10 12:59:08 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-24 13:55:35 -07:00
|
|
|
void GeoPatch::ReceiveHeightmap(const SSingleSplitResult *psr)
|
2013-03-17 10:22:59 -07:00
|
|
|
{
|
2016-02-21 04:29:39 -08:00
|
|
|
PROFILE_SCOPED()
|
2013-10-29 04:44:49 -07:00
|
|
|
assert(nullptr == parent);
|
|
|
|
assert(nullptr != psr);
|
2013-03-24 13:55:35 -07:00
|
|
|
assert(mHasJobRequest);
|
2013-03-17 10:22:59 -07:00
|
|
|
{
|
2013-03-24 13:55:35 -07:00
|
|
|
const SSingleSplitResult::SSplitResultData& data = psr->data();
|
2013-10-29 04:44:49 -07:00
|
|
|
heights.reset(data.heights);
|
|
|
|
normals.reset(data.normals);
|
|
|
|
colors.reset(data.colors);
|
2013-03-17 10:22:59 -07:00
|
|
|
}
|
2013-03-24 13:55:35 -07:00
|
|
|
mHasJobRequest = false;
|
2013-03-17 10:22:59 -07:00
|
|
|
}
|
2015-07-13 03:34:46 -07:00
|
|
|
|
|
|
|
void GeoPatch::ReceiveJobHandle(Job::Handle job)
|
|
|
|
{
|
|
|
|
assert(!m_job.HasJob());
|
2015-07-26 09:48:51 -07:00
|
|
|
m_job = static_cast<Job::Handle&&>(job);
|
2015-07-13 03:34:46 -07:00
|
|
|
}
|