2019-12-31 05:05:16 -08:00
// Copyright © 2008-2020 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 "GeoPatch.h"
2019-05-03 17:53:44 -07:00
2019-01-02 08:59:07 -08:00
# include "GeoPatchContext.h"
2013-03-27 14:33:37 -07:00
# include "GeoPatchJobs.h"
2013-03-10 12:59:08 -07:00
# include "GeoSphere.h"
2019-01-02 08:59:07 -08:00
# include "MathUtil.h"
2013-03-10 12:59:08 -07:00
# include "Pi.h"
# include "RefCounted.h"
2019-01-02 08:59:07 -08:00
# include "Sphere.h"
2019-05-27 10:47:21 -07:00
# include "galaxy/SystemBody.h"
2013-03-10 12:59:08 -07:00
# include "graphics/Frustum.h"
# include "graphics/Graphics.h"
2019-01-02 08:59:07 -08:00
# include "graphics/Material.h"
# include "graphics/Renderer.h"
2019-10-16 12:10:22 -07:00
# include "graphics/VertexBuffer.h"
2019-01-02 08:59:07 -08:00
# include "perlin.h"
2013-03-10 12:59:08 -07:00
# include "vcacheopt/vcacheopt.h"
# include <algorithm>
2019-01-02 08:59:07 -08:00
# include <deque>
2013-03-10 12:59:08 -07:00
2019-05-27 14:03:58 -07:00
# ifdef DEBUG_BOUNDING_SPHERES
# include "graphics/RenderState.h"
# endif
2013-03-10 12:59:08 -07:00
// 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_ ,
2019-01-02 08:59:07 -08:00
const int depth , const GeoPatchID & ID_ ) :
2019-05-27 10:42:54 -07:00
m_ctx ( ctx_ ) ,
m_v0 ( v0_ ) ,
m_v1 ( v1_ ) ,
m_v2 ( v2_ ) ,
m_v3 ( v3_ ) ,
m_heights ( nullptr ) ,
m_normals ( nullptr ) ,
m_colors ( nullptr ) ,
m_parent ( nullptr ) ,
m_geosphere ( gs ) ,
2019-01-02 08:59:07 -08:00
m_depth ( depth ) ,
2019-05-27 10:42:54 -07:00
m_PatchID ( ID_ ) ,
m_HasJobRequest ( false )
2013-03-10 12:59:08 -07:00
{
2013-06-26 18:07:40 -07:00
2019-05-27 10:42:54 -07:00
m_clipCentroid = ( m_v0 + m_v1 + m_v2 + m_v3 ) * 0.25 ;
m_centroid = m_clipCentroid . Normalized ( ) ;
m_clipRadius = 0.0 ;
m_clipRadius = std : : max ( m_clipRadius , ( m_v0 - m_clipCentroid ) . Length ( ) ) ;
m_clipRadius = std : : max ( m_clipRadius , ( m_v1 - m_clipCentroid ) . Length ( ) ) ;
m_clipRadius = std : : max ( m_clipRadius , ( m_v2 - m_clipCentroid ) . Length ( ) ) ;
m_clipRadius = std : : max ( m_clipRadius , ( m_v3 - m_clipCentroid ) . Length ( ) ) ;
2013-04-17 14:01:24 -07:00
double distMult ;
2019-05-27 10:42:54 -07:00
if ( m_geosphere - > GetSystemBody ( ) - > GetType ( ) < SystemBody : : TYPE_PLANET_ASTEROID ) {
distMult = 10.0 / Clamp ( m_depth , 1 , 10 ) ;
2019-01-02 08:59:07 -08:00
} else {
2019-05-27 10:42:54 -07:00
distMult = 5.0 / Clamp ( m_depth , 1 , 5 ) ;
2019-01-02 08:59:07 -08:00
}
2019-05-27 10:42:54 -07:00
m_roughLength = GEOPATCH_SUBDIVIDE_AT_CAMDIST / pow ( 2.0 , m_depth ) * distMult ;
2013-03-10 12:59:08 -07:00
m_needUpdateVBOs = false ;
}
2019-01-02 08:59:07 -08:00
GeoPatch : : ~ GeoPatch ( )
{
2019-05-27 10:42:54 -07:00
m_HasJobRequest = false ;
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_KIDS ; i + + ) {
2019-05-27 10:42:54 -07:00
m_kids [ i ] . reset ( ) ;
2013-03-17 10:22:59 -07:00
}
2019-05-27 10:42:54 -07:00
m_heights . reset ( ) ;
m_normals . reset ( ) ;
m_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 ;
2019-01-02 08:59:07 -08:00
vbd . attrib [ 0 ] . format = Graphics : : ATTRIB_FORMAT_FLOAT3 ;
2014-03-01 05:04:18 -08:00
vbd . attrib [ 1 ] . semantic = Graphics : : ATTRIB_NORMAL ;
2019-01-02 08:59:07 -08:00
vbd . attrib [ 1 ] . format = Graphics : : ATTRIB_FORMAT_FLOAT3 ;
2014-03-01 05:04:18 -08:00
vbd . attrib [ 2 ] . semantic = Graphics : : ATTRIB_DIFFUSE ;
2019-01-02 08:59:07 -08:00
vbd . attrib [ 2 ] . format = Graphics : : ATTRIB_FORMAT_UBYTE4 ;
2014-09-08 13:04:54 -07:00
vbd . attrib [ 3 ] . semantic = Graphics : : ATTRIB_UV0 ;
2019-01-02 08:59:07 -08:00
vbd . attrib [ 3 ] . format = Graphics : : ATTRIB_FORMAT_FLOAT2 ;
2019-05-27 10:42:54 -07:00
vbd . numVertices = m_ctx - > NUMVERTICES ( ) ;
2014-03-01 05:04:18 -08:00
vbd . usage = Graphics : : BUFFER_USAGE_STATIC ;
m_vertexBuffer . reset ( renderer - > CreateVertexBuffer ( vbd ) ) ;
2019-01-02 08:59:07 -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 ) ) ;
2019-05-27 10:42:54 -07:00
const Sint32 edgeLen = m_ctx - > GetEdgeLen ( ) ;
const double frac = m_ctx - > GetFrac ( ) ;
const double * pHts = m_heights . get ( ) ;
const vector3f * pNorm = m_normals . get ( ) ;
const Color3ub * pColr = m_colors . get ( ) ;
2015-12-13 10:15:08 -08:00
2016-02-20 09:23:34 -08:00
double minh = DBL_MAX ;
2015-12-13 10:15:08 -08:00
// ----------------------------------------------------
// inner loops
2019-01-02 08:59:07 -08:00
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 ;
2019-05-27 10:42:54 -07:00
const vector3d p ( ( GetSpherePoint ( xFrac , yFrac ) * ( height + 1.0 ) ) - m_clipCentroid ) ;
m_clipRadius = std : : max ( m_clipRadius , p . Length ( ) ) ;
2015-12-13 10:15:08 -08:00
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * vtxPtr = & VBOVtxPtr [ x + ( y * edgeLen ) ] ;
2014-03-01 05:04:18 -08:00
vtxPtr - > pos = vector3f ( p ) ;
2019-01-02 08:59:07 -08:00
+ + pHts ; // next height
2013-03-25 16:02:33 -07:00
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
}
2017-09-08 08:55:45 -07:00
const double minhScale = ( minh + 1.0 ) * 0.999995 ;
2015-12-13 10:15:08 -08:00
// ----------------------------------------------------
2017-09-08 08:55:45 -07:00
const Sint32 innerLeft = 1 ;
const Sint32 innerRight = edgeLen - 2 ;
const Sint32 outerLeft = 0 ;
const Sint32 outerRight = edgeLen - 1 ;
2015-12-13 10:15:08 -08:00
// vertical edges
// left-edge
for ( Sint32 y = 1 ; y < edgeLen - 1 ; y + + ) {
2019-01-02 08:59:07 -08:00
const Sint32 x = innerLeft - 1 ;
2015-12-13 10:15:08 -08:00
const double xFrac = double ( x - 1 ) * frac ;
const double yFrac = double ( y - 1 ) * frac ;
2019-05-27 10:42:54 -07:00
const vector3d p ( ( GetSpherePoint ( xFrac , yFrac ) * minhScale ) - m_clipCentroid ) ;
2015-12-13 10:15:08 -08:00
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * vtxPtr = & VBOVtxPtr [ outerLeft + ( y * edgeLen ) ] ;
GeoPatchContext : : VBOVertex * vtxInr = & VBOVtxPtr [ innerLeft + ( y * edgeLen ) ] ;
2015-12-13 10:15:08 -08:00
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 + + ) {
2019-01-02 08:59:07 -08:00
const Sint32 x = innerRight + 1 ;
2015-12-13 10:15:08 -08:00
const double xFrac = double ( x - 1 ) * frac ;
const double yFrac = double ( y - 1 ) * frac ;
2019-05-27 10:42:54 -07:00
const vector3d p ( ( GetSpherePoint ( xFrac , yFrac ) * minhScale ) - m_clipCentroid ) ;
2015-12-13 10:15:08 -08:00
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * vtxPtr = & VBOVtxPtr [ outerRight + ( y * edgeLen ) ] ;
GeoPatchContext : : VBOVertex * vtxInr = & VBOVtxPtr [ innerRight + ( y * edgeLen ) ] ;
2015-12-13 10:15:08 -08:00
vtxPtr - > pos = vector3f ( p ) ;
vtxPtr - > norm = vtxInr - > norm ;
vtxPtr - > col = vtxInr - > col ;
vtxPtr - > uv = vtxInr - > uv ;
}
// ----------------------------------------------------
2017-09-08 08:55:45 -07:00
const Sint32 innerTop = 1 ;
const Sint32 innerBottom = edgeLen - 2 ;
const Sint32 outerTop = 0 ;
const Sint32 outerBottom = edgeLen - 1 ;
2015-12-13 10:15:08 -08:00
// horizontal edges
// top-edge
2019-01-02 08:59:07 -08:00
for ( Sint32 x = 1 ; x < edgeLen - 1 ; x + + ) {
const Sint32 y = innerTop - 1 ;
2015-12-13 10:15:08 -08:00
const double xFrac = double ( x - 1 ) * frac ;
const double yFrac = double ( y - 1 ) * frac ;
2019-05-27 10:42:54 -07:00
const vector3d p ( ( GetSpherePoint ( xFrac , yFrac ) * minhScale ) - m_clipCentroid ) ;
2015-12-13 10:15:08 -08:00
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * vtxPtr = & VBOVtxPtr [ x + ( outerTop * edgeLen ) ] ;
GeoPatchContext : : VBOVertex * vtxInr = & VBOVtxPtr [ x + ( innerTop * edgeLen ) ] ;
2015-12-13 10:15:08 -08:00
vtxPtr - > pos = vector3f ( p ) ;
vtxPtr - > norm = vtxInr - > norm ;
vtxPtr - > col = vtxInr - > col ;
vtxPtr - > uv = vtxInr - > uv ;
}
// bottom-edge
2019-01-02 08:59:07 -08:00
for ( Sint32 x = 1 ; x < edgeLen - 1 ; x + + ) {
const Sint32 y = innerBottom + 1 ;
2015-12-13 10:15:08 -08:00
const double xFrac = double ( x - 1 ) * frac ;
const double yFrac = double ( y - 1 ) * frac ;
2019-05-27 10:42:54 -07:00
const vector3d p ( ( GetSpherePoint ( xFrac , yFrac ) * minhScale ) - m_clipCentroid ) ;
2015-12-13 10:15:08 -08:00
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * vtxPtr = & VBOVtxPtr [ x + ( outerBottom * edgeLen ) ] ;
GeoPatchContext : : VBOVertex * vtxInr = & VBOVtxPtr [ x + ( innerBottom * edgeLen ) ] ;
2015-12-13 10:15:08 -08:00
vtxPtr - > pos = vector3f ( p ) ;
vtxPtr - > norm = vtxInr - > norm ;
vtxPtr - > col = vtxInr - > col ;
vtxPtr - > uv = vtxInr - > uv ;
}
// ----------------------------------------------------
// corners
{
// top left
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * tarPtr = & VBOVtxPtr [ 0 ] ;
GeoPatchContext : : VBOVertex * srcPtr = & VBOVtxPtr [ 1 ] ;
2015-12-13 10:15:08 -08:00
( * tarPtr ) = ( * srcPtr ) ;
}
{
// top right
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * tarPtr = & VBOVtxPtr [ ( edgeLen - 1 ) ] ;
GeoPatchContext : : VBOVertex * srcPtr = & VBOVtxPtr [ ( edgeLen - 2 ) ] ;
2015-12-13 10:15:08 -08:00
( * tarPtr ) = ( * srcPtr ) ;
}
{
// bottom left
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * tarPtr = & VBOVtxPtr [ ( edgeLen - 1 ) * edgeLen ] ;
GeoPatchContext : : VBOVertex * srcPtr = & VBOVtxPtr [ ( edgeLen - 2 ) * edgeLen ] ;
2015-12-13 10:15:08 -08:00
( * tarPtr ) = ( * srcPtr ) ;
}
{
// bottom right
2019-01-02 08:59:07 -08:00
GeoPatchContext : : VBOVertex * tarPtr = & VBOVtxPtr [ ( edgeLen - 1 ) + ( ( edgeLen - 1 ) * edgeLen ) ] ;
GeoPatchContext : : VBOVertex * srcPtr = & VBOVtxPtr [ ( edgeLen - 1 ) + ( ( edgeLen - 2 ) * edgeLen ) ] ;
2015-12-13 10:15:08 -08:00
( * tarPtr ) = ( * srcPtr ) ;
}
// ----------------------------------------------------
// end of mapping
2014-03-01 05:04:18 -08:00
m_vertexBuffer - > Unmap ( ) ;
2017-03-05 05:15:55 -08:00
2016-10-16 15:17:46 -07:00
// Don't need this anymore so throw it away
2019-05-27 10:42:54 -07:00
m_normals . reset ( ) ;
m_colors . reset ( ) ;
2014-10-11 08:24:50 -07:00
# ifdef DEBUG_BOUNDING_SPHERES
RefCountedPtr < Graphics : : Material > mat ( Pi : : renderer - > CreateMaterial ( Graphics : : MaterialDescriptor ( ) ) ) ;
2019-05-27 14:03:58 -07:00
switch ( m_depth ) {
case 0 : mat - > diffuse = Color : : WHITE ; break ;
case 1 : mat - > diffuse = Color : : RED ; break ;
case 2 : mat - > diffuse = Color : : GREEN ; break ;
case 3 : mat - > diffuse = Color : : BLUE ; break ;
default : mat - > diffuse = Color : : BLACK ; break ;
}
m_boundsphere . reset ( new Graphics : : Drawables : : Sphere3D ( Pi : : renderer , mat , Pi : : renderer - > CreateRenderState ( Graphics : : RenderStateDesc ( ) ) , 2 , m_clipRadius ) ) ;
2014-10-11 08:24:50 -07:00
# 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.
2019-05-27 10:42:54 -07:00
if ( ! frustum . TestPoint ( m_clipCentroid , m_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!
2019-05-27 10:42:54 -07:00
const vector3d camDir ( campos - m_clipCentroid ) ;
2014-10-19 06:58:53 -07:00
const vector3d camDirNorm ( camDir . Normalized ( ) ) ;
2019-05-27 10:42:54 -07:00
const vector3d cenDir ( m_clipCentroid . Normalized ( ) ) ;
2014-10-19 06:58:53 -07:00
const double dotProd = camDirNorm . Dot ( cenDir ) ;
2014-10-11 08:24:50 -07:00
2019-05-27 10:42:54 -07:00
if ( dotProd < 0.25 & & ( camDir . LengthSqr ( ) > ( m_clipRadius * m_clipRadius ) ) ) {
2014-10-11 08:24:50 -07:00
SSphere obj ;
2019-05-27 10:42:54 -07:00
obj . m_centre = m_clipCentroid ;
obj . m_radius = m_clipRadius ;
2014-10-11 08:24:50 -07:00
2019-01-02 08:59:07 -08:00
if ( ! s_sph . HorizonCulling ( campos , obj ) ) {
2014-10-11 08:24:50 -07:00
return ; // nothing below this patch is visible
}
2014-10-09 00:51:15 -07:00
}
2019-05-27 10:42:54 -07:00
if ( m_kids [ 0 ] ) {
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_KIDS ; i + + )
2019-05-27 10:42:54 -07:00
m_kids [ i ] - > Render ( renderer , campos , modelView , frustum ) ;
} else if ( m_heights ) {
RefCountedPtr < Graphics : : Material > mat = m_geosphere - > GetSurfaceMaterial ( ) ;
Graphics : : RenderState * rs = m_geosphere - > GetSurfRenderState ( ) ;
2014-03-01 05:04:18 -08:00
2019-05-27 10:42:54 -07:00
const vector3d relpos = m_clipCentroid - campos ;
2020-08-30 13:21:55 -07:00
renderer - > SetTransform ( matrix4x4f ( modelView * matrix4x4d : : Translation ( relpos ) ) ) ;
2013-03-10 12:59:08 -07:00
2019-05-27 10:42:54 -07:00
Pi : : statSceneTris + = ( m_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
2019-05-27 10:42:54 -07:00
m_geosphere - > GetMaterialParameters ( ) . patchDepth = m_depth ;
2013-03-10 12:59:08 -07:00
2019-05-27 10:42:54 -07:00
renderer - > DrawBufferIndexed ( m_vertexBuffer . get ( ) , m_ctx - > GetIndexBuffer ( ) , rs , mat . Get ( ) ) ;
2014-10-11 08:24:50 -07:00
# ifdef DEBUG_BOUNDING_SPHERES
2019-01-02 08:59:07 -08:00
if ( m_boundsphere . get ( ) ) {
2014-10-11 08:24:50 -07:00
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
2019-05-27 10:42:54 -07:00
if ( m_HasJobRequest )
2013-03-10 12:59:08 -07:00
return ;
bool canSplit = true ;
2019-05-27 10:42:54 -07:00
bool canMerge = bool ( m_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 ;
2019-05-27 10:42:54 -07:00
if ( m_parent ) {
2020-04-12 15:34:20 -07:00
centroidDist = ( campos - m_centroid ) . Length ( ) ; // distance from camera to centre of the patch
const bool tooFar = ( centroidDist > = m_roughLength ) ; // check if the distance is greater than the rough length, which is how far it should be before it can split
if ( m_depth > = std : : min ( GEOPATCH_MAX_DEPTH , m_geosphere - > GetMaxDepth ( ) ) | | tooFar ) {
canSplit = false ; // we're too deep in the quadtree or too far away so cannot split
2013-03-10 12:59:08 -07:00
}
}
if ( canSplit ) {
2019-05-27 10:42:54 -07:00
if ( ! m_kids [ 0 ] ) {
2015-12-15 02:28:30 -08:00
// Test if this patch is visible
2019-05-27 10:42:54 -07:00
if ( ! frustum . TestPoint ( m_clipCentroid , m_clipRadius ) )
2015-12-13 14:05:00 -08:00
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!
2019-05-27 10:42:54 -07:00
const vector3d camDir ( campos - m_clipCentroid ) ;
2015-12-13 14:05:00 -08:00
const vector3d camDirNorm ( camDir . Normalized ( ) ) ;
2019-05-27 10:42:54 -07:00
const vector3d cenDir ( m_clipCentroid . Normalized ( ) ) ;
2015-12-13 14:05:00 -08:00
const double dotProd = camDirNorm . Dot ( cenDir ) ;
2019-05-27 10:42:54 -07:00
if ( dotProd < 0.25 & & ( camDir . LengthSqr ( ) > ( m_clipRadius * m_clipRadius ) ) ) {
2015-12-13 14:05:00 -08:00
SSphere obj ;
2019-05-27 10:42:54 -07:00
obj . m_centre = m_clipCentroid ;
obj . m_radius = m_clipRadius ;
2015-12-13 14:05:00 -08:00
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!
2019-05-27 10:42:54 -07:00
assert ( ! m_HasJobRequest ) ;
m_HasJobRequest = true ;
2013-04-24 14:42:43 -07:00
2019-05-27 10:42:54 -07:00
SQuadSplitRequest * ssrd = new SQuadSplitRequest ( m_v0 , m_v1 , m_v2 , m_v3 , m_centroid . Normalized ( ) , m_depth ,
m_geosphere - > GetSystemBody ( ) - > GetPath ( ) , m_PatchID , m_ctx - > GetEdgeLen ( ) - 2 ,
m_ctx - > GetFrac ( ) , m_geosphere - > GetTerrain ( ) ) ;
2015-07-13 03:34:46 -07:00
// add to the GeoSphere to be processed at end of all LODUpdate requests
2019-05-27 10:42:54 -07:00
m_geosphere - > AddQuadSplitRequest ( centroidDist , ssrd , this ) ;
2013-03-10 12:59:08 -07:00
} else {
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_KIDS ; i + + ) {
2019-05-27 10:42:54 -07:00
m_kids [ i ] - > LODUpdate ( campos , frustum ) ;
2013-03-10 12:59:08 -07:00
}
}
} else if ( canMerge ) {
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_KIDS ; i + + ) {
2019-05-27 10:42:54 -07:00
canMerge & = m_kids [ i ] - > canBeMerged ( ) ;
2013-04-01 07:38:03 -07:00
}
2019-01-02 08:59:07 -08:00
if ( canMerge ) {
for ( int i = 0 ; i < NUM_KIDS ; i + + ) {
2019-05-27 10:42:54 -07:00
m_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 ( )
{
2019-05-27 10:42:54 -07:00
if ( ! m_heights ) {
2019-05-30 13:45:57 -07:00
assert ( ! m_HasJobRequest ) ;
2019-05-27 10:42:54 -07:00
m_HasJobRequest = true ;
SSingleSplitRequest * ssrd = new SSingleSplitRequest ( m_v0 , m_v1 , m_v2 , m_v3 , m_centroid . Normalized ( ) , m_depth ,
m_geosphere - > GetSystemBody ( ) - > GetPath ( ) , m_PatchID , m_ctx - > GetEdgeLen ( ) - 2 , m_ctx - > GetFrac ( ) , m_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 ( )
2019-01-02 08:59:07 -08:00
assert ( NULL ! = psr ) ;
if ( m_depth < psr - > depth ( ) ) {
2013-03-10 12:59:08 -07:00
// this should work because each depth should have a common history
2019-01-02 08:59:07 -08:00
const Uint32 kidIdx = psr - > data ( 0 ) . patchID . GetPatchIdx ( m_depth + 1 ) ;
2019-05-27 10:42:54 -07:00
if ( m_kids [ kidIdx ] ) {
m_kids [ kidIdx ] - > ReceiveHeightmaps ( psr ) ;
2013-05-08 11:22:41 -07:00
} else {
psr - > OnCancel ( ) ;
}
2013-03-10 12:59:08 -07:00
} else {
2019-05-27 10:42:54 -07:00
assert ( m_HasJobRequest ) ;
const int newDepth = m_depth + 1 ;
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_KIDS ; i + + ) {
2019-05-30 13:45:57 -07:00
assert ( ! m_kids [ i ] ) ;
2019-01-02 08:59:07 -08:00
const SQuadSplitResult : : SSplitResultData & data = psr - > data ( i ) ;
2019-05-30 13:45:57 -07:00
assert ( i = = data . patchID . GetPatchIdx ( newDepth ) ) ;
assert ( 0 = = data . patchID . GetPatchIdx ( newDepth + 1 ) ) ;
2019-05-27 10:42:54 -07:00
m_kids [ i ] . reset ( new GeoPatch ( m_ctx , m_geosphere ,
2013-06-26 18:07:40 -07:00
data . v0 , data . v1 , data . v2 , data . v3 ,
2019-05-27 10:42:54 -07:00
newDepth , data . patchID ) ) ;
2013-03-10 12:59:08 -07:00
}
2019-05-27 10:42:54 -07:00
m_kids [ 0 ] - > m_parent = m_kids [ 1 ] - > m_parent = m_kids [ 2 ] - > m_parent = m_kids [ 3 ] - > m_parent = this ;
2013-03-10 12:59:08 -07:00
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_KIDS ; i + + ) {
const SQuadSplitResult : : SSplitResultData & data = psr - > data ( i ) ;
2019-05-27 10:42:54 -07:00
m_kids [ i ] - > m_heights . reset ( data . heights ) ;
m_kids [ i ] - > m_normals . reset ( data . normals ) ;
m_kids [ i ] - > m_colors . reset ( data . colors ) ;
2013-03-10 12:59:08 -07:00
}
2019-01-02 08:59:07 -08:00
for ( int i = 0 ; i < NUM_KIDS ; i + + ) {
2019-05-27 10:42:54 -07:00
m_kids [ i ] - > NeedToUpdateVBOs ( ) ;
2013-03-10 12:59:08 -07:00
}
2019-05-27 10:42:54 -07:00
m_HasJobRequest = 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 ( )
2019-05-30 13:45:57 -07:00
assert ( nullptr = = m_parent ) ;
2013-10-29 04:44:49 -07:00
assert ( nullptr ! = psr ) ;
2019-05-27 10:42:54 -07:00
assert ( m_HasJobRequest ) ;
2013-03-17 10:22:59 -07:00
{
2019-01-02 08:59:07 -08:00
const SSingleSplitResult : : SSplitResultData & data = psr - > data ( ) ;
2019-05-27 10:42:54 -07:00
m_heights . reset ( data . heights ) ;
m_normals . reset ( data . normals ) ;
m_colors . reset ( data . colors ) ;
2013-03-17 10:22:59 -07:00
}
2019-05-27 10:42:54 -07:00
m_HasJobRequest = 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 ( ) ) ;
2019-01-02 08:59:07 -08:00
m_job = static_cast < Job : : Handle & & > ( job ) ;
2015-07-13 03:34:46 -07:00
}