QGIS API Documentation 4.3.0-Master (0978c174f8e)
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 setMode( Mode::PositionOnly );
47}
48
49void QgsBillboardGeometry::setMode( Mode mode )
50{
51 uint stride = 0;
52 switch ( mode )
53 {
54 case Mode::PositionOnly:
55 stride = 3 * sizeof( float );
56 break;
57 case Mode::PositionAndTextureData:
58 stride = ( 3 + 2 + 2 ) * sizeof( float );
59 break;
60 case Mode::PositionAndTextureDataWithPixelOffsets:
61 stride = ( 3 + 2 + 2 ) * sizeof( float ) + 2 * sizeof( int );
62 break;
63 }
64
65 if ( mPositionAttribute && mPositionAttribute->byteStride() == stride )
66 {
67 // already in the target mode
68 return;
69 }
70 else if ( mPositionAttribute )
71 {
72 removeAttribute( mPositionAttribute );
73 delete mPositionAttribute;
74 mPositionAttribute = nullptr;
75 }
76
77 mPositionAttribute = new Qt3DCore::QAttribute( this );
78 mPositionAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
79 mPositionAttribute->setBuffer( mVertexBuffer );
80 mPositionAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
81 mPositionAttribute->setVertexSize( 3 );
82 mPositionAttribute->setByteOffset( 0 );
83 mPositionAttribute->setByteStride( stride );
84 mPositionAttribute->setDivisor( 1 );
85 mPositionAttribute->setName( "instancePosition" );
86 addAttribute( mPositionAttribute );
87
88 switch ( mode )
89 {
90 case Mode::PositionOnly:
91 {
92 if ( mAtlasOffsetAttribute )
93 {
94 removeAttribute( mAtlasOffsetAttribute );
95 delete mAtlasOffsetAttribute;
96 mAtlasOffsetAttribute = nullptr;
97 }
98 if ( mAtlasSizeAttribute )
99 {
100 removeAttribute( mAtlasSizeAttribute );
101 delete mAtlasSizeAttribute;
102 mAtlasSizeAttribute = nullptr;
103 }
104 if ( mAtlasPixelOffsetAttribute )
105 {
106 removeAttribute( mAtlasPixelOffsetAttribute );
107 delete mAtlasPixelOffsetAttribute;
108 mAtlasPixelOffsetAttribute = nullptr;
109 }
110 break;
111 }
112
113 case Mode::PositionAndTextureData:
114 {
115 if ( mAtlasPixelOffsetAttribute )
116 {
117 removeAttribute( mAtlasPixelOffsetAttribute );
118 delete mAtlasPixelOffsetAttribute;
119 mAtlasPixelOffsetAttribute = nullptr;
120 }
121
122 mAtlasOffsetAttribute = new Qt3DCore::QAttribute( this );
123 mAtlasOffsetAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
124 mAtlasOffsetAttribute->setBuffer( mVertexBuffer );
125 mAtlasOffsetAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
126 mAtlasOffsetAttribute->setVertexSize( 2 );
127 mAtlasOffsetAttribute->setByteOffset( 3 * sizeof( float ) );
128 mAtlasOffsetAttribute->setByteStride( stride );
129 mAtlasOffsetAttribute->setDivisor( 1 );
130 mAtlasOffsetAttribute->setName( u"atlasOffset"_s );
131 addAttribute( mAtlasOffsetAttribute );
132
133 mAtlasSizeAttribute = new Qt3DCore::QAttribute( this );
134 mAtlasSizeAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
135 mAtlasSizeAttribute->setBuffer( mVertexBuffer );
136 mAtlasSizeAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
137 mAtlasSizeAttribute->setVertexSize( 2 );
138 mAtlasSizeAttribute->setByteOffset( ( 3 + 2 ) * sizeof( float ) );
139 mAtlasSizeAttribute->setByteStride( stride );
140 mAtlasSizeAttribute->setDivisor( 1 );
141 mAtlasSizeAttribute->setName( u"atlasSize"_s );
142 addAttribute( mAtlasSizeAttribute );
143 break;
144 }
145
146 case Mode::PositionAndTextureDataWithPixelOffsets:
147 {
148 mAtlasOffsetAttribute = new Qt3DCore::QAttribute( this );
149 mAtlasOffsetAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
150 mAtlasOffsetAttribute->setBuffer( mVertexBuffer );
151 mAtlasOffsetAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
152 mAtlasOffsetAttribute->setVertexSize( 2 );
153 mAtlasOffsetAttribute->setByteOffset( 3 * sizeof( float ) );
154 mAtlasOffsetAttribute->setByteStride( stride );
155 mAtlasOffsetAttribute->setDivisor( 1 );
156 mAtlasOffsetAttribute->setName( u"atlasOffset"_s );
157 addAttribute( mAtlasOffsetAttribute );
158
159 mAtlasSizeAttribute = new Qt3DCore::QAttribute( this );
160 mAtlasSizeAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
161 mAtlasSizeAttribute->setBuffer( mVertexBuffer );
162 mAtlasSizeAttribute->setVertexBaseType( Qt3DCore::QAttribute::Float );
163 mAtlasSizeAttribute->setVertexSize( 2 );
164 mAtlasSizeAttribute->setByteOffset( ( 3 + 2 ) * sizeof( float ) );
165 mAtlasSizeAttribute->setByteStride( stride );
166 mAtlasSizeAttribute->setDivisor( 1 );
167 mAtlasSizeAttribute->setName( u"atlasSize"_s );
168 addAttribute( mAtlasSizeAttribute );
169
170 mAtlasPixelOffsetAttribute = new Qt3DCore::QAttribute( this );
171 mAtlasPixelOffsetAttribute->setAttributeType( Qt3DCore::QAttribute::VertexAttribute );
172 mAtlasPixelOffsetAttribute->setBuffer( mVertexBuffer );
173 mAtlasPixelOffsetAttribute->setVertexBaseType( Qt3DCore::QAttribute::Int );
174 mAtlasPixelOffsetAttribute->setVertexSize( 2 );
175 mAtlasPixelOffsetAttribute->setByteOffset( ( 3 + 2 + 2 ) * sizeof( float ) );
176 mAtlasPixelOffsetAttribute->setByteStride( stride );
177 mAtlasPixelOffsetAttribute->setDivisor( 1 );
178 mAtlasPixelOffsetAttribute->setName( u"pixelOffset"_s );
179 addAttribute( mAtlasPixelOffsetAttribute );
180 break;
181 }
182 }
183}
184
185void QgsBillboardGeometry::setPositions( const QVector<QVector3D> &vertices )
186{
187 setMode( Mode::PositionOnly );
188
189 QByteArray vertexBufferData;
190 vertexBufferData.resize( vertices.size() * 3 * sizeof( float ) );
191 float *rawVertexArray = reinterpret_cast<float *>( vertexBufferData.data() );
192 int idx = 0;
193 for ( const auto &v : vertices )
194 {
195 rawVertexArray[idx++] = v.x();
196 rawVertexArray[idx++] = v.y();
197 rawVertexArray[idx++] = v.z();
198 }
199
200 mVertexCount = vertices.count();
201 mVertexBuffer->setData( vertexBufferData );
202
203 emit countChanged( mVertexCount );
204}
205
207#pragma pack( push, 1 )
208struct BillboardVertex
209{
210 float position[3];
211 float textureAtlasOffset[2];
212 float textureAtlasSize[2];
213};
214
215struct BillboardVertexWithPixelOffset : BillboardVertex
216{
217 int pixelOffset[2];
218};
219#pragma pack( pop )
220
221template<typename VertexType> QByteArray createVertexBuffer( const QVector<QgsBillboardGeometry::BillboardAtlasData> &billboards )
222{
223 QByteArray buffer;
224 buffer.resize( billboards.size() * sizeof( VertexType ) );
225 auto *vertexData = reinterpret_cast<VertexType *>( buffer.data() );
226
227 int idx = 0;
228 for ( const QgsBillboardGeometry::BillboardAtlasData &billboard : billboards )
229 {
230 VertexType &vertex = vertexData[idx++];
231
232 vertex.position[0] = billboard.position.x();
233 vertex.position[1] = billboard.position.y();
234 vertex.position[2] = billboard.position.z();
235
236 vertex.textureAtlasOffset[0] = billboard.textureAtlasOffset.x();
237 vertex.textureAtlasOffset[1] = billboard.textureAtlasOffset.y();
238
239 vertex.textureAtlasSize[0] = billboard.textureAtlasSize.x();
240 vertex.textureAtlasSize[1] = billboard.textureAtlasSize.y();
241
242 if constexpr ( std::is_same_v<VertexType, BillboardVertexWithPixelOffset> )
243 {
244 vertex.pixelOffset[0] = billboard.pixelOffset.x();
245 vertex.pixelOffset[1] = billboard.pixelOffset.y();
246 }
247 }
248 return buffer;
249}
251
252void QgsBillboardGeometry::setBillboardData( const QVector<BillboardAtlasData> &billboards, bool includePixelOffsets )
253{
254 if ( includePixelOffsets )
255 setMode( Mode::PositionAndTextureDataWithPixelOffsets );
256 else
257 setMode( Mode::PositionAndTextureData );
258
259
260 QByteArray vertexBufferData;
261 if ( includePixelOffsets )
262 {
263 vertexBufferData = createVertexBuffer<BillboardVertexWithPixelOffset>( billboards );
264 }
265 else
266 {
267 vertexBufferData = createVertexBuffer<BillboardVertex>( billboards );
268 }
269
270 mVertexCount = billboards.count();
271 mVertexBuffer->setData( vertexBufferData );
272
273 emit countChanged( mVertexCount );
274}
275
277{
278 return mVertexCount;
279}
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.
Contains the billboard positions and texture information.