Skip to content
Permalink
Browse files

Deleted the synchronous loading of terrain and texture

Now uses waitForFinished function
  • Loading branch information
NEDJIMAbelgacem committed Jul 10, 2020
1 parent 29c980e commit 059c9b476f49021c9552aafb427337abbb82c372
@@ -183,14 +183,14 @@ void Qgs3DSceneExporter::parseTerrain( QgsTerrainEntity *terrain )
for ( QgsChunkNode *node : leafs )
{
terrainTile = getDemTerrainEntity( terrain, node );
this->parseDemTile( terrainTile, textureGenerator );
this->parseDemTile( terrainTile );
}
break;
case QgsTerrainGenerator::Flat:
for ( QgsChunkNode *node : leafs )
{
terrainTile = getFlatTerrainEntity( terrain, node );
this->parseFlatTile( terrainTile, textureGenerator );
this->parseFlatTile( terrainTile );
}
break;
// TODO: implement other terrain types
@@ -205,27 +205,27 @@ void Qgs3DSceneExporter::parseTerrain( QgsTerrainEntity *terrain )
QgsTerrainTileEntity *Qgs3DSceneExporter::getFlatTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
{
QgsFlatTerrainGenerator *generator = dynamic_cast<QgsFlatTerrainGenerator *>( terrain->map3D().terrainGenerator() );
QgsChunkLoader *loader = generator->createSynchronousChunkLoader( node );
FlatTerrainChunkLoader *flatTerrainLoader = qobject_cast<FlatTerrainChunkLoader *>( loader );
if ( flatTerrainLoader == nullptr )
return nullptr;
// the entity we created should be deallocated when we deallocate the scene exporter
FlatTerrainChunkLoader *flatTerrainLoader = qobject_cast<FlatTerrainChunkLoader *>( generator->createChunkLoader( node ) );
if ( mExportTextures )
terrain->textureGenerator()->waitForFinished();
// the entity we created will be deallocated once the scene exporter is deallocated
Qt3DCore::QEntity *entity = flatTerrainLoader->createEntity( this );
QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( entity );
return tileEntity;
}

QgsTerrainTileEntity *Qgs3DSceneExporter::getDemTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node )
{
QgsTerrainTileEntity *tileEntity = nullptr;
// Just create a new tile (we don't need to export exact level of details as in the scene)
// create the entity synchronously and then it will be deleted once our scene exporter instance is deallocated
const Qgs3DMapSettings &map = terrain->map3D();
QgsDemTerrainGenerator *generator = static_cast<QgsDemTerrainGenerator *>( map.terrainGenerator() );
QgsDemTerrainGenerator *generator = static_cast<QgsDemTerrainGenerator *>( terrain->map3D().terrainGenerator() );
int oldResolution = generator->resolution();
generator->setResolution( mTerrainResolution );
QgsDemTerrainTileLoader *loader = qobject_cast<QgsDemTerrainTileLoader *>( generator->createSynchronousChunkLoader( node ) );
tileEntity = qobject_cast<QgsTerrainTileEntity *>( loader->createEntity( this ) );
QgsDemTerrainTileLoader *loader = qobject_cast<QgsDemTerrainTileLoader *>( generator->createChunkLoader( node ) );
generator->heightMapGenerator()->waitForFinished();
if ( mExportTextures )
terrain->textureGenerator()->waitForFinished();
QgsTerrainTileEntity *tileEntity = qobject_cast<QgsTerrainTileEntity *>( loader->createEntity( this ) );
generator->setResolution( oldResolution );
return tileEntity;
}
@@ -242,7 +242,7 @@ Component *findTypedComponent( Qt3DCore::QEntity *entity )
return nullptr;
}

void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity, QgsTerrainTextureGenerator *textureGenerator )
void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity )
{
Qt3DRender::QGeometryRenderer *mesh = findTypedComponent<Qt3DRender::QGeometryRenderer>( tileEntity );
Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( tileEntity );
@@ -289,15 +289,15 @@ void Qgs3DSceneExporter::parseFlatTile( QgsTerrainTileEntity *tileEntity, QgsTer
// Reuse vertex buffer data for texture coordinates
Qt3DRender::QAttribute *texCoordsAttribute = tileGeometry->texCoordAttribute();
QVector<float> texCoords = getAttributeData<float>( texCoordsAttribute, verticesBytes );

object->setupTextureCoordinates( texCoords );

QImage img = textureGenerator->renderSynchronously( tileEntity->textureImage()->imageExtent(), tileEntity->textureImage()->imageDebugText() );
QgsTerrainTextureImage *textureImage = tileEntity->textureImage();
QImage img = textureImage->getImage();
object->setTextureImage( img );
}
}

void Qgs3DSceneExporter::parseDemTile( QgsTerrainTileEntity *tileEntity, QgsTerrainTextureGenerator *textureGenerator )
void Qgs3DSceneExporter::parseDemTile( QgsTerrainTileEntity *tileEntity )
{
Qt3DRender::QGeometryRenderer *mesh = findTypedComponent<Qt3DRender::QGeometryRenderer>( tileEntity );
Qt3DCore::QTransform *transform = findTypedComponent<Qt3DCore::QTransform>( tileEntity );
@@ -342,7 +342,8 @@ void Qgs3DSceneExporter::parseDemTile( QgsTerrainTileEntity *tileEntity, QgsTerr
QVector<float> texCoordsBuffer = getAttributeData<float>( texCoordsAttribute, texCoordsBytes );
object->setupTextureCoordinates( texCoordsBuffer );

QImage img = textureGenerator->renderSynchronously( tileEntity->textureImage()->imageExtent(), tileEntity->textureImage()->imageDebugText() );
QgsTerrainTextureImage *textureImage = tileEntity->textureImage();
QImage img = textureImage->getImage();
object->setTextureImage( img );
}
}
@@ -96,9 +96,9 @@ class Qgs3DSceneExporter : public Qt3DCore::QEntity
QgsTerrainTileEntity *getDemTerrainEntity( QgsTerrainEntity *terrain, QgsChunkNode *node );

//! Constructs a Qgs3DExportObject from the DEM tile entity
void parseDemTile( QgsTerrainTileEntity *tileEntity, QgsTerrainTextureGenerator *textureGenerator );
void parseDemTile( QgsTerrainTileEntity *tileEntity );
//! Constructs a Qgs3DExportObject from the flat tile entity
void parseFlatTile( QgsTerrainTileEntity *tileEntity, QgsTerrainTextureGenerator *textureGenerator );
void parseFlatTile( QgsTerrainTileEntity *tileEntity );

QString getObjectName( const QString &name );
private:
@@ -101,10 +101,10 @@ QgsChunkLoader *QgsDemTerrainGenerator::createChunkLoader( QgsChunkNode *node )
return new QgsDemTerrainTileLoader( mTerrain, node );
}

QgsChunkLoader *QgsDemTerrainGenerator::createSynchronousChunkLoader( QgsChunkNode *node ) const
{
return new QgsDemTerrainTileLoader( mTerrain, node, true );
}
//QgsChunkLoader *QgsDemTerrainGenerator::createSynchronousChunkLoader( QgsChunkNode *node ) const
//{
// return new QgsDemTerrainTileLoader( mTerrain, node, true );
//}

void QgsDemTerrainGenerator::updateGenerator()
{
@@ -77,7 +77,7 @@ class _3D_EXPORT QgsDemTerrainGenerator : public QgsTerrainGenerator
QgsChunkLoader *createChunkLoader( QgsChunkNode *node ) const override SIP_FACTORY;

//! create a chunk loader that creates the node entity synchronously
QgsChunkLoader *createSynchronousChunkLoader( QgsChunkNode *node ) const;
// QgsChunkLoader *createSynchronousChunkLoader( QgsChunkNode *node ) const;

private:
void updateGenerator();
@@ -52,7 +52,7 @@ static void _heightMapMinMax( const QByteArray &heightMap, float &zMin, float &z
}


QgsDemTerrainTileLoader::QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, QgsChunkNode *node, bool loadSynchronously )
QgsDemTerrainTileLoader::QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, QgsChunkNode *node )
: QgsTerrainTileLoader( terrain, node )
, mResolution( 0 )
{
@@ -75,19 +75,10 @@ QgsDemTerrainTileLoader::QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, Qgs
else
Q_ASSERT( false );

if ( loadSynchronously )
{
mResolution = heightMapGenerator->resolution();
mHeightMap = heightMapGenerator->renderSynchronously( node->tileX(), node->tileY(), node->tileZ() );
loadTextureSynchronously();
}
else
{
// get heightmap asynchronously
connect( heightMapGenerator, &QgsDemHeightMapGenerator::heightMapReady, this, &QgsDemTerrainTileLoader::onHeightMapReady );
mHeightMapJobId = heightMapGenerator->render( node->tileX(), node->tileY(), node->tileZ() );
mResolution = heightMapGenerator->resolution();
}
// get heightmap asynchronously
connect( heightMapGenerator, &QgsDemHeightMapGenerator::heightMapReady, this, &QgsDemTerrainTileLoader::onHeightMapReady );
mHeightMapJobId = heightMapGenerator->render( node->tileX(), node->tileY(), node->tileZ() );
mResolution = heightMapGenerator->resolution();
}

Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *parent )
@@ -213,7 +204,6 @@ static QByteArray _readDtmData( QgsRasterDataProvider *provider, const QgsRectan
return data;
}


static QByteArray _readOnlineDtm( QgsTerrainDownloader *downloader, const QgsRectangle &extent, int res, const QgsCoordinateReferenceSystem &destCrs )
{
return downloader->getHeightMap( extent, res, destCrs );
@@ -254,27 +244,24 @@ int QgsDemHeightMapGenerator::render( int x, int y, int z )
return jd.jobId;
}

QByteArray QgsDemHeightMapGenerator::renderSynchronously( int x, int y, int z )
void QgsDemHeightMapGenerator::waitForFinished()
{
// extend the rect by half-pixel on each side? to get the values in "corners"
QgsRectangle extent = mTilingScheme.tileToExtent( x, y, z );
float mapUnitsPerPixel = extent.width() / mResolution;
extent.grow( mapUnitsPerPixel / 2 );
// but make sure not to go beyond the full extent (returns invalid values)
QgsRectangle fullExtent = mTilingScheme.tileToExtent( 0, 0, 0 );
extent = extent.intersect( fullExtent );

QByteArray data;
if ( mDtm )
QVector<QFutureWatcher<QByteArray>*> toBeDeleted;
for ( QFutureWatcher<QByteArray> *fw : mJobs.keys() )
{
data = _readDtmData( mClonedProvider, extent, mResolution, mTilingScheme.crs() );
fw->waitForFinished();
JobData jobData = mJobs.value( fw );
toBeDeleted.push_back( fw );

QByteArray data = jobData.future.result();
emit heightMapReady( jobData.jobId, data );
}
else

for ( QFutureWatcher<QByteArray> *fw : toBeDeleted )
{
data = _readOnlineDtm( mDownloader.get(), extent, mResolution, mTilingScheme.crs() );
mJobs.remove( fw );
fw->deleteLater();
}

return data;
}

float QgsDemHeightMapGenerator::heightAt( double x, double y )
@@ -52,7 +52,7 @@ class QgsDemTerrainTileLoader : public QgsTerrainTileLoader
Q_OBJECT
public:
//! Constructs loader for the given chunk node
QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, QgsChunkNode *node, bool loadSynchronously = false );
QgsDemTerrainTileLoader( QgsTerrainEntity *terrain, QgsChunkNode *node );

Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent ) override;

@@ -90,8 +90,8 @@ class QgsDemHeightMapGenerator : public QObject
//! asynchronous terrain read for a tile (array of floats)
int render( int x, int y, int z );

//! synchronous terrain read for a tile
QByteArray renderSynchronously( int x, int y, int z );
//! Waits for the tile to finish rendering
void waitForFinished();

//! Returns resolution(number of height values on each side of tile)
int resolution() const { return mResolution; }
@@ -28,13 +28,10 @@
//---------------


FlatTerrainChunkLoader::FlatTerrainChunkLoader( QgsTerrainEntity *terrain, QgsChunkNode *node, bool loadSynchronously )
FlatTerrainChunkLoader::FlatTerrainChunkLoader( QgsTerrainEntity *terrain, QgsChunkNode *node )
: QgsTerrainTileLoader( terrain, node )
{
if ( loadSynchronously )
loadTextureSynchronously();
else
loadTexture();
loadTexture();
}


@@ -86,11 +83,6 @@ QgsChunkLoader *QgsFlatTerrainGenerator::createChunkLoader( QgsChunkNode *node )
return new FlatTerrainChunkLoader( mTerrain, node );
}

QgsChunkLoader *QgsFlatTerrainGenerator::createSynchronousChunkLoader( QgsChunkNode *node ) const
{
return new FlatTerrainChunkLoader( mTerrain, node, true );
}

QgsTerrainGenerator *QgsFlatTerrainGenerator::clone() const
{
QgsFlatTerrainGenerator *cloned = new QgsFlatTerrainGenerator;
@@ -34,7 +34,7 @@ class FlatTerrainChunkLoader : public QgsTerrainTileLoader

public:
//! Construct the loader for a node
FlatTerrainChunkLoader( QgsTerrainEntity *terrain, QgsChunkNode *mNode, bool loadSynchronously = false );
FlatTerrainChunkLoader( QgsTerrainEntity *terrain, QgsChunkNode *mNode );

Qt3DCore::QEntity *createEntity( Qt3DCore::QEntity *parent ) override;

@@ -58,9 +58,6 @@ class _3D_EXPORT QgsFlatTerrainGenerator : public QgsTerrainGenerator

QgsChunkLoader *createChunkLoader( QgsChunkNode *node ) const override SIP_FACTORY;

//! create a chunk loader that loads synchronously
QgsChunkLoader *createSynchronousChunkLoader( QgsChunkNode *node ) const;

QgsTerrainGenerator *clone() const override SIP_FACTORY;
Type type() const override;
QgsRectangle extent() const override;
@@ -74,35 +74,38 @@ void QgsTerrainTextureGenerator::cancelJob( int jobId )
Q_ASSERT( false && "requested job ID does not exist!" );
}

QImage QgsTerrainTextureGenerator::renderSynchronously( const QgsRectangle &extent, const QString &debugText )
void QgsTerrainTextureGenerator::waitForFinished()
{
QgsMapSettings mapSettings( baseMapSettings() );
mapSettings.setExtent( extent );
QVector<QgsMapRendererSequentialJob *> toBeDeleted;
for ( QgsMapRendererSequentialJob *mapJob : mJobs.keys() )
{
mapJob->waitForFinished();
JobData jobData = mJobs.value( mapJob );
toBeDeleted.push_back( mapJob );

QImage img = QImage( mapSettings.outputSize(), mapSettings.outputImageFormat() );
img.setDotsPerMeterX( 1000 * mapSettings.outputDpi() / 25.4 );
img.setDotsPerMeterY( 1000 * mapSettings.outputDpi() / 25.4 );
img.fill( Qt::transparent );
QImage img = mapJob->renderedImage();

QPainter p( &img );
if ( mMap.showTerrainTilesInfo() )
{
// extra tile information for debugging
QPainter p( &img );
p.setPen( Qt::white );
p.drawRect( 0, 0, img.width() - 1, img.height() - 1 );
p.drawText( img.rect(), jobData.debugText, QTextOption( Qt::AlignCenter ) );
p.end();
}

QgsMapRendererCustomPainterJob job( mapSettings, &p );
job.renderSynchronously();
// pass QImage further
emit tileReady( jobData.jobId, img );
}

if ( mMap.showTerrainTilesInfo() )
for ( QgsMapRendererSequentialJob *mapJob : toBeDeleted )
{
// extra tile information for debugging
p.setPen( Qt::white );
p.drawRect( 0, 0, img.width() - 1, img.height() - 1 );
p.drawText( img.rect(), debugText, QTextOption( Qt::AlignCenter ) );
mJobs.remove( mapJob );
mapJob->deleteLater();
}

p.end();

return img;
}


void QgsTerrainTextureGenerator::onRenderingFinished()
{
QgsMapRendererSequentialJob *mapJob = static_cast<QgsMapRendererSequentialJob *>( sender() );
@@ -69,8 +69,8 @@ class QgsTerrainTextureGenerator : public QObject
//! Cancels a rendering job
void cancelJob( int jobId );

//! Renders a map and returns rendered image. Blocks until the map rendering has finished
QImage renderSynchronously( const QgsRectangle &extent, const QString &debugText = QString() );
//! Waits for the texture generator to finish
void waitForFinished();

//! Returns the generated texture size (in pixel)
QSize textureSize() const { return mTextureSize; }
@@ -56,6 +56,8 @@ class QgsTerrainTextureImage : public Qt3DRender::QAbstractTextureImage
void invalidate();
//! Stores a new map image and emits signal that data generator has changed
void setImage( const QImage &image );
//! Returns the stored image
QImage getImage() const { return mImage; }

//! Returns extent of the image in map coordinates
QgsRectangle imageExtent() const { return mExtent; }
@@ -64,11 +64,6 @@ void QgsTerrainTileLoader::loadTexture()
mTextureJobId = mTerrain->textureGenerator()->render( mExtentMapCrs, mNode->tileId(), mTileDebugText );
}

void QgsTerrainTileLoader::loadTextureSynchronously()
{
mTextureImage = mTerrain->textureGenerator()->renderSynchronously( mExtentMapCrs, mTileDebugText );
}

void QgsTerrainTileLoader::createTextureComponent( QgsTerrainTileEntity *entity, bool isShadingEnabled, const QgsPhongMaterialSettings &shadingMaterial )
{
Qt3DRender::QTexture2D *texture = createTexture( entity );
@@ -64,8 +64,6 @@ class QgsTerrainTileLoader : public QgsChunkLoader
protected:
//! Starts asynchronous rendering of map texture
void loadTexture();
//! Renders the map texture synchronously
void loadTextureSynchronously();

//! Creates a new texture thaht is linked to the entity
Qt3DRender::QTexture2D *createTexture( QgsTerrainTileEntity *entity );
@@ -74,8 +72,6 @@ class QgsTerrainTileLoader : public QgsChunkLoader
//! Gives access to the terain entity
QgsTerrainEntity *terrain() { return mTerrain; }



private slots:
void onImageReady( int jobId, const QImage &image );

0 comments on commit 059c9b4

Please sign in to comment.
You can’t perform that action at this time.