QGIS API Documentation 4.3.0-Master (90cb4ecf9ef)
Loading...
Searching...
No Matches
qgsbillboardgeometry.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsbillboardgeometry.cpp
3 --------------------------------------
4 Date : Jul 2019
5 Copyright : (C) 2019 by Ismail Sunni
6 Email : imajimatika at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include <QString>
19#include <QVector3D>
20#include <Qt3DCore/QAttribute>
21#include <Qt3DCore/QBuffer>
22
23#include "moc_qgsbillboardgeometry.cpp"
24
25using namespace Qt::StringLiterals;
26
28 : QGeometry( parent )
29 , mVertexBuffer( new Qt3DCore::QBuffer( this ) )
30{
31 static constexpr float quadVertices[] = { -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
32 Qt3DCore::QBuffer *quadVertexBuffer = new Qt3DCore::QBuffer( this );
33 quadVertexBuffer->setData( QByteArray( reinterpret_cast<const char *>( quadVertices ), sizeof( quadVertices ) ) );
34
35 Qt3DCore::QAttribute *quadVertexAttribute = new Qt3DCore::QAttribute( this );
36 quadVertexAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
37 quadVertexAttribute->setBuffer( quadVertexBuffer );
38 quadVertexAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
39 quadVertexAttribute->setVertexSize( 2 );
40 quadVertexAttribute->setByteOffset( 0 );
41 quadVertexAttribute->setByteStride( 2 * sizeof( float ) );
42 quadVertexAttribute->setCount( 4 );
43 quadVertexAttribute->setName( u"vertexPosition"_s );
44 addAttribute( quadVertexAttribute );
45
46 setAttributes( Attribute::Position );
47}
48
49void QgsBillboardGeometry::setAttributes( QgsBillboardGeometry::Attributes attributes )
50{
51 // position must always be present
52 Q_ASSERT( attributes.testFlag( Attribute::Position ) );
53
54 if ( mAttributes == attributes )
55 return;
56
57 mAttributes = attributes;
58
59 // position is always present
60 uint stride = 3 * sizeof( float );
61 if ( attributes.testFlag( Attribute::Size ) )
62 {
63 stride += 2 * sizeof( float );
64 }
65 if ( attributes.testFlag( Attribute::TextureData ) )
66 {
67 stride += ( 2 + 2 ) * sizeof( float );
68 }
69 if ( attributes.testFlag( Attribute::PixelOffsets ) )
70 {
71 stride += 2 * sizeof( int );
72 }
73
74 if ( mPositionAttribute )
75 {
76 removeAttribute( mPositionAttribute );
77 delete mPositionAttribute;
78 mPositionAttribute = nullptr;
79 }
80
81 uint offset = 0;
82 mPositionAttribute = new Qt3DCore::QAttribute( this );
83 mPositionAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
84 mPositionAttribute->setBuffer( mVertexBuffer );
85 mPositionAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
86 mPositionAttribute->setVertexSize( 3 );
87 mPositionAttribute->setByteOffset( offset );
88 mPositionAttribute->setByteStride( stride );
89 mPositionAttribute->setDivisor( 1 );
90 mPositionAttribute->setName( "instancePosition" );
91 addAttribute( mPositionAttribute );
92 setBoundingVolumePositionAttribute( mPositionAttribute );
93 offset += 3 * sizeof( float );
94
95 if ( attributes.testFlag( Attribute::Size ) )
96 {
97 mSizeAttribute = new Qt3DCore::QAttribute( this );
98 mSizeAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
99 mSizeAttribute->setBuffer( mVertexBuffer );
100 mSizeAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
101 mSizeAttribute->setVertexSize( 2 );
102 mSizeAttribute->setByteOffset( offset );
103 mSizeAttribute->setByteStride( stride );
104 mSizeAttribute->setDivisor( 1 );
105 mSizeAttribute->setName( u"instanceSize"_s );
106 addAttribute( mSizeAttribute );
107 offset += 2 * sizeof( float );
108 }
109 else
110 {
111 removeAttribute( mSizeAttribute );
112 delete mSizeAttribute;
113 mSizeAttribute = nullptr;
114 }
115
116 if ( attributes.testFlag( Attribute::TextureData ) )
117 {
118 mAtlasOffsetAttribute = new Qt3DCore::QAttribute( this );
119 mAtlasOffsetAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
120 mAtlasOffsetAttribute->setBuffer( mVertexBuffer );
121 mAtlasOffsetAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
122 mAtlasOffsetAttribute->setVertexSize( 2 );
123 mAtlasOffsetAttribute->setByteOffset( offset );
124 mAtlasOffsetAttribute->setByteStride( stride );
125 mAtlasOffsetAttribute->setDivisor( 1 );
126 mAtlasOffsetAttribute->setName( u"atlasOffset"_s );
127 addAttribute( mAtlasOffsetAttribute );
128 offset += 2 * sizeof( float );
129
130 mAtlasSizeAttribute = new Qt3DCore::QAttribute( this );
131 mAtlasSizeAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
132 mAtlasSizeAttribute->setBuffer( mVertexBuffer );
133 mAtlasSizeAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
134 mAtlasSizeAttribute->setVertexSize( 2 );
135 mAtlasSizeAttribute->setByteOffset( offset );
136 mAtlasSizeAttribute->setByteStride( stride );
137 mAtlasSizeAttribute->setDivisor( 1 );
138 mAtlasSizeAttribute->setName( u"atlasSize"_s );
139 addAttribute( mAtlasSizeAttribute );
140 offset += 2 * sizeof( float );
141 }
142 else
143 {
144 if ( mAtlasOffsetAttribute )
145 {
146 removeAttribute( mAtlasOffsetAttribute );
147 delete mAtlasOffsetAttribute;
148 mAtlasOffsetAttribute = nullptr;
149 }
150 if ( mAtlasSizeAttribute )
151 {
152 removeAttribute( mAtlasSizeAttribute );
153 delete mAtlasSizeAttribute;
154 mAtlasSizeAttribute = nullptr;
155 }
156 }
157
158 if ( attributes.testFlag( Attribute::PixelOffsets ) )
159 {
160 mAtlasPixelOffsetAttribute = new Qt3DCore::QAttribute( this );
161 mAtlasPixelOffsetAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
162 mAtlasPixelOffsetAttribute->setBuffer( mVertexBuffer );
163 mAtlasPixelOffsetAttribute->setVertexBaseType( Qt3DCore::QAttribute::Int );
164 mAtlasPixelOffsetAttribute->setVertexSize( 2 );
165 mAtlasPixelOffsetAttribute->setByteOffset( offset );
166 mAtlasPixelOffsetAttribute->setByteStride( stride );
167 mAtlasPixelOffsetAttribute->setDivisor( 1 );
168 mAtlasPixelOffsetAttribute->setName( u"pixelOffset"_s );
169 addAttribute( mAtlasPixelOffsetAttribute );
170 offset += 2 * sizeof( int );
171 }
172 else
173 {
174 removeAttribute( mAtlasPixelOffsetAttribute );
175 delete mAtlasPixelOffsetAttribute;
176 mAtlasPixelOffsetAttribute = nullptr;
177 }
178}
179
180void QgsBillboardGeometry::setPositions( const QVector<QVector3D> &vertices )
181{
182 setAttributes( Attribute::Position );
183
184 QByteArray vertexBufferData;
185 vertexBufferData.resize( vertices.size() * 3 * sizeof( float ) );
186 float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
187 int idx = 0;
188 for ( const auto &v : vertices )
189 {
190 rawVertexArray[idx++] = v.x();
191 rawVertexArray[idx++] = v.y();
192 rawVertexArray[idx++] = v.z();
193 }
194
195 mVertexCount = vertices.count();
196 mVertexBuffer->setData( vertexBufferData );
197 mPositionAttribute->setCount( mVertexCount );
198
199 emit countChanged( mVertexCount );
200}
201
202void QgsBillboardGeometry::setPositionsAndSizes( const QVector<QVector3D> &positions, const QVector<QSizeF> &sizes )
203{
204 Attributes attributes = Attribute::Position;
205 attributes.setFlag( Attribute::Size );
206 setAttributes( attributes );
207
208 const qsizetype size = std::min( positions.size(), sizes.size() );
209 QByteArray vertexBufferData;
210 vertexBufferData.resize( size * ( 3 + 2 ) * sizeof( float ) );
211 float *rawArray = reinterpret_cast<float *>( vertexBufferData.data() );
212 int idx = 0;
213 for ( qsizetype i = 0; i < size; ++i )
214 {
215 rawArray[idx++] = positions[i].x();
216 rawArray[idx++] = positions[i].y();
217 rawArray[idx++] = positions[i].z();
218
219 rawArray[idx++] = sizes[i].width();
220 rawArray[idx++] = sizes[i].height();
221 }
222
223 mVertexCount = size;
224 mVertexBuffer->setData( vertexBufferData );
225 mPositionAttribute->setCount( mVertexCount );
226 mSizeAttribute->setCount( mVertexCount );
227
228 emit countChanged( mVertexCount );
229}
230
232#pragma pack( push, 1 )
233struct BillboardVertex
234{
235 float position[3];
236 float textureAtlasOffset[2];
237 float textureAtlasSize[2];
238};
239
240struct BillboardVertexWithPixelOffset : BillboardVertex
241{
242 int pixelOffset[2];
243};
244#pragma pack( pop )
245
246template<typename VertexType> QByteArray createVertexBuffer( const QVector<QgsBillboardGeometry::BillboardAtlasData> &billboards )
247{
248 QByteArray buffer;
249 buffer.resize( billboards.size() * sizeof( VertexType ) );
250 auto *vertexData = reinterpret_cast<VertexType *>( buffer.data() );
251
252 int idx = 0;
253 for ( const QgsBillboardGeometry::BillboardAtlasData &billboard : billboards )
254 {
255 VertexType &vertex = vertexData[idx++];
256
257 vertex.position[0] = billboard.position.x();
258 vertex.position[1] = billboard.position.y();
259 vertex.position[2] = billboard.position.z();
260
261 vertex.textureAtlasOffset[0] = billboard.textureAtlasOffset.x();
262 vertex.textureAtlasOffset[1] = billboard.textureAtlasOffset.y();
263
264 vertex.textureAtlasSize[0] = billboard.textureAtlasSize.x();
265 vertex.textureAtlasSize[1] = billboard.textureAtlasSize.y();
266
267 if constexpr ( std::is_same_v<VertexType, BillboardVertexWithPixelOffset> )
268 {
269 vertex.pixelOffset[0] = billboard.pixelOffset.x();
270 vertex.pixelOffset[1] = billboard.pixelOffset.y();
271 }
272 }
273 return buffer;
274}
276
277void QgsBillboardGeometry::setBillboardData( const QVector<BillboardAtlasData> &billboards, bool includePixelOffsets )
278{
279 Attributes attributes = Attribute::Position;
280 attributes.setFlag( Attribute::TextureData, true );
281 attributes.setFlag( Attribute::PixelOffsets, includePixelOffsets );
282 setAttributes( attributes );
283
284 QByteArray vertexBufferData;
285 if ( includePixelOffsets )
286 {
287 vertexBufferData = createVertexBuffer<BillboardVertexWithPixelOffset>( billboards );
288 }
289 else
290 {
291 vertexBufferData = createVertexBuffer<BillboardVertex>( billboards );
292 }
293
294 mVertexCount = billboards.count();
295 mVertexBuffer->setData( vertexBufferData );
296 mPositionAttribute->setCount( mVertexCount );
297
298 emit countChanged( mVertexCount );
299}
300
302{
303 return mVertexCount;
304}
void countChanged(int count)
Signal when the number of points changed.
void setBillboardData(const QVector< QgsBillboardGeometry::BillboardAtlasData > &billboards, bool includePixelOffsets=false)
Set the position and texture data for the billboard.
void setPositions(const QVector< QVector3D > &vertices)
Sets the vertex positions for the billboards.
QgsBillboardGeometry(Qt3DCore::QNode *parent=nullptr)
Constructor of QgsBillboardGeometry.
void setPositionsAndSizes(const QVector< QVector3D > &positions, const QVector< QSizeF > &sizes)
Sets per-instance positions and sizes for billboards sharing a single texture.
Contains the billboard positions and texture information.