1
+ // Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O.
2
+ // This file is part of the "Nabla Engine".
3
+ // For conditions of distribution and use, see copyright notice in nabla.h
4
+
5
+ #define _NBL_STATIC_LIB_
6
+ #include < iostream>
7
+ #include < cstdio>
8
+ #include < nabla.h>
9
+
10
+ #include " ../common/QToQuitEventReceiver.h"
11
+ #include " nbl/ext/ScreenShot/ScreenShot.h"
12
+
13
+ using namespace nbl ;
14
+ using namespace core ;
15
+
16
+ /*
17
+ Define below to write assets
18
+ */
19
+
20
+ // #define WRITE_ASSETS
21
+
22
+ int main ()
23
+ {
24
+ nbl::SIrrlichtCreationParameters params;
25
+ params.Bits = 24 ;
26
+ params.ZBufferBits = 24 ;
27
+ params.DriverType = video::EDT_OPENGL;
28
+ params.WindowSize = dimension2d<uint32_t >(1280 , 720 );
29
+ params.Fullscreen = false ;
30
+ params.Vsync = true ;
31
+ params.Doublebuffer = true ;
32
+ params.Stencilbuffer = false ;
33
+ auto device = createDeviceEx (params);
34
+
35
+ if (!device)
36
+ return 1 ;
37
+
38
+ device->getCursorControl ()->setVisible (false );
39
+
40
+ QToQuitEventReceiver receiver;
41
+ device->setEventReceiver (&receiver);
42
+
43
+ auto * driver = device->getVideoDriver ();
44
+ auto * smgr = device->getSceneManager ();
45
+
46
+ auto loadAndGetCpuMesh = [&](std::string path) -> std::pair<core::smart_refctd_ptr<asset::ICPUMesh>, const asset::IAssetMetadata*>
47
+ {
48
+ auto * am = device->getAssetManager ();
49
+ auto * fs = am->getFileSystem ();
50
+
51
+ asset::IAssetLoader::SAssetLoadParams lp;
52
+
53
+ auto meshes_bundle = am->getAsset (path, lp);
54
+
55
+ assert (!meshes_bundle.getContents ().empty ());
56
+
57
+ return std::make_pair (core::smart_refctd_ptr_static_cast<asset::ICPUMesh>(meshes_bundle.getContents ().begin ()[0 ]), meshes_bundle.getMetadata ());
58
+ };
59
+
60
+ auto & cpuBundlePLYData = loadAndGetCpuMesh (" ../../media/ply/Industrial_compressor.ply" );
61
+ auto & cpuBundleSTLData = loadAndGetCpuMesh (" ../../media/extrusionLogo_TEST_fixed.stl" );
62
+
63
+ core::smart_refctd_ptr<asset::ICPUMesh> cpuMeshPly = cpuBundlePLYData.first ;
64
+ auto metadataPly = cpuBundlePLYData.second ->selfCast <const asset::CPLYMetadata>();
65
+
66
+ core::smart_refctd_ptr<asset::ICPUMesh> cpuMeshStl = cpuBundleSTLData.first ;
67
+ auto metadataStl = cpuBundleSTLData.second ->selfCast <const asset::CSTLMetadata>();
68
+
69
+ #ifdef WRITE_ASSETS
70
+ {
71
+ asset::IAssetWriter::SAssetWriteParams wp (cpuMeshStl.get ());
72
+ device->getAssetManager ()->writeAsset (" extrusionLogo_TEST_fixedTest.stl" , wp);
73
+ }
74
+
75
+ {
76
+ asset::IAssetWriter::SAssetWriteParams wp (cpuMeshPly.get ());
77
+ device->getAssetManager ()->writeAsset (" IndustrialWriteTest.ply" , wp);
78
+ }
79
+ #endif // WRITE_ASSETS
80
+
81
+ /*
82
+ For the testing puposes we can safely assume all meshbuffers within mesh loaded from PLY & STL has same DS1 layout (used for camera-specific data)
83
+ */
84
+
85
+ using DependentDrawData = std::tuple<core::smart_refctd_ptr<video::IGPUMesh>, core::smart_refctd_ptr<video::IGPUBuffer>, core::smart_refctd_ptr<video::IGPUDescriptorSet>, uint32_t , const asset::IRenderpassIndependentPipelineMetadata*>;
86
+
87
+ auto getMeshDependentDrawData = [&](core::smart_refctd_ptr<asset::ICPUMesh> cpuMesh, bool isPLY) -> DependentDrawData
88
+ {
89
+ const asset::ICPUMeshBuffer* const firstMeshBuffer = cpuMesh->getMeshBuffers ().begin ()[0 ];
90
+ const asset::ICPUDescriptorSetLayout* ds1layout = firstMeshBuffer->getPipeline ()->getLayout ()->getDescriptorSetLayout (1u ); // ! DS1
91
+ const asset::IRenderpassIndependentPipelineMetadata* pipelineMetadata;
92
+ {
93
+ if (isPLY)
94
+ pipelineMetadata = metadataPly->getAssetSpecificMetadata (firstMeshBuffer->getPipeline ());
95
+ else
96
+ pipelineMetadata = metadataStl->getAssetSpecificMetadata (firstMeshBuffer->getPipeline ());
97
+ }
98
+
99
+ /*
100
+ So we can create just one DescriptorSet
101
+ */
102
+
103
+ auto getDS1UboBinding = [&]()
104
+ {
105
+ uint32_t ds1UboBinding = 0u ;
106
+ for (const auto & bnd : ds1layout->getBindings ())
107
+ if (bnd.type == asset::EDT_UNIFORM_BUFFER)
108
+ {
109
+ ds1UboBinding = bnd.binding ;
110
+ break ;
111
+ }
112
+ return ds1UboBinding;
113
+ };
114
+
115
+ const uint32_t ds1UboBinding = getDS1UboBinding ();
116
+
117
+ auto getNeededDS1UboByteSize = [&]()
118
+ {
119
+ size_t neededDS1UboSize = 0ull ;
120
+ {
121
+ for (const auto & shaderInputs : pipelineMetadata->m_inputSemantics )
122
+ if (shaderInputs.descriptorSection .type == asset::IRenderpassIndependentPipelineMetadata::ShaderInput::ET_UNIFORM_BUFFER && shaderInputs.descriptorSection .uniformBufferObject .set == 1u && shaderInputs.descriptorSection .uniformBufferObject .binding == ds1UboBinding)
123
+ neededDS1UboSize = std::max<size_t >(neededDS1UboSize, shaderInputs.descriptorSection .uniformBufferObject .relByteoffset + shaderInputs.descriptorSection .uniformBufferObject .bytesize );
124
+ }
125
+ return neededDS1UboSize;
126
+ };
127
+
128
+ const uint64_t uboDS1ByteSize = getNeededDS1UboByteSize ();
129
+
130
+ auto gpuds1layout = driver->getGPUObjectsFromAssets (&ds1layout, &ds1layout + 1 )->front ();
131
+
132
+ auto gpuubo = driver->createDeviceLocalGPUBufferOnDedMem (uboDS1ByteSize);
133
+ auto gpuds1 = driver->createGPUDescriptorSet (std::move (gpuds1layout));
134
+ {
135
+ video::IGPUDescriptorSet::SWriteDescriptorSet write;
136
+ write.dstSet = gpuds1.get ();
137
+ write.binding = ds1UboBinding;
138
+ write.count = 1u ;
139
+ write.arrayElement = 0u ;
140
+ write.descriptorType = asset::EDT_UNIFORM_BUFFER;
141
+ video::IGPUDescriptorSet::SDescriptorInfo info;
142
+ {
143
+ info.desc = gpuubo;
144
+ info.buffer .offset = 0ull ;
145
+ info.buffer .size = uboDS1ByteSize;
146
+ }
147
+ write.info = &info;
148
+ driver->updateDescriptorSets (1u , &write, 0u , nullptr );
149
+ }
150
+
151
+ auto gpuMesh = driver->getGPUObjectsFromAssets (&cpuMesh.get (), &cpuMesh.get () + 1 )->front ();
152
+
153
+ return std::make_tuple (gpuMesh, gpuubo, gpuds1, ds1UboBinding, pipelineMetadata);
154
+ };
155
+
156
+ auto & plyDrawData = getMeshDependentDrawData (cpuMeshPly, true );
157
+ auto & stlDrawData = getMeshDependentDrawData (cpuMeshStl, false );
158
+
159
+ scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS (0 , 100 .0f , 0 .5f );
160
+
161
+ camera->setPosition (core::vector3df (-4 , 0 , 0 ));
162
+ camera->setTarget (core::vector3df (0 , 0 , 0 ));
163
+ camera->setNearValue (1 .f );
164
+ camera->setFarValue (5000 .0f );
165
+
166
+ smgr->setActiveCamera (camera);
167
+
168
+ uint64_t lastFPSTime = 0 ;
169
+ while (device->run () && receiver.keepOpen ())
170
+ {
171
+ driver->beginScene (true , true , video::SColor (255 , 255 , 255 , 255 ));
172
+
173
+ camera->OnAnimate (std::chrono::duration_cast<std::chrono::milliseconds>(device->getTimer ()->getTime ()).count ());
174
+ camera->render ();
175
+
176
+ const auto viewProjection = camera->getConcatenatedMatrix ();
177
+
178
+ auto renderMesh = [&](DependentDrawData& drawData, uint32_t index)
179
+ {
180
+ core::smart_refctd_ptr<video::IGPUMesh> gpuMesh = std::get<0 >(drawData);
181
+ core::smart_refctd_ptr<video::IGPUBuffer> gpuubo = std::get<1 >(drawData);
182
+ core::smart_refctd_ptr<video::IGPUDescriptorSet> gpuds1 = std::get<2 >(drawData);
183
+ uint32_t ds1UboBinding = std::get<3 >(drawData);
184
+ const asset::IRenderpassIndependentPipelineMetadata* pipelineMetadata = std::get<4 >(drawData);
185
+
186
+ core::matrix3x4SIMD modelMatrix;
187
+ modelMatrix.setTranslation (nbl::core::vectorSIMDf (index * 5 , 0 , 0 , 0 ));
188
+
189
+ core::matrix4SIMD mvp = core::concatenateBFollowedByA (viewProjection, modelMatrix);
190
+
191
+ core::vector<uint8_t > uboData (gpuubo->getSize ());
192
+ for (const auto & shaderInputs : pipelineMetadata->m_inputSemantics )
193
+ {
194
+ if (shaderInputs.descriptorSection .type == asset::IRenderpassIndependentPipelineMetadata::ShaderInput::ET_UNIFORM_BUFFER && shaderInputs.descriptorSection .uniformBufferObject .set == 1u && shaderInputs.descriptorSection .uniformBufferObject .binding == ds1UboBinding)
195
+ {
196
+ switch (shaderInputs.type )
197
+ {
198
+ case asset::IRenderpassIndependentPipelineMetadata::ECSI_WORLD_VIEW_PROJ:
199
+ {
200
+ memcpy (uboData.data () + shaderInputs.descriptorSection .uniformBufferObject .relByteoffset , mvp.pointer (), shaderInputs.descriptorSection .uniformBufferObject .bytesize );
201
+ } break ;
202
+
203
+ case asset::IRenderpassIndependentPipelineMetadata::ECSI_WORLD_VIEW:
204
+ {
205
+ core::matrix3x4SIMD MV = camera->getViewMatrix ();
206
+ memcpy (uboData.data () + shaderInputs.descriptorSection .uniformBufferObject .relByteoffset , MV.pointer (), shaderInputs.descriptorSection .uniformBufferObject .bytesize );
207
+ } break ;
208
+
209
+ case asset::IRenderpassIndependentPipelineMetadata::ECSI_WORLD_VIEW_INVERSE_TRANSPOSE:
210
+ {
211
+ core::matrix3x4SIMD MV = camera->getViewMatrix ();
212
+ memcpy (uboData.data () + shaderInputs.descriptorSection .uniformBufferObject .relByteoffset , MV.pointer (), shaderInputs.descriptorSection .uniformBufferObject .bytesize );
213
+ } break ;
214
+ }
215
+ }
216
+ }
217
+ driver->updateBufferRangeViaStagingBuffer (gpuubo.get (), 0ull , gpuubo->getSize (), uboData.data ());
218
+
219
+ for (auto gpuMeshBuffer : gpuMesh->getMeshBuffers ())
220
+ {
221
+ const video::IGPURenderpassIndependentPipeline* gpuPipeline = gpuMeshBuffer->getPipeline ();
222
+ const video::IGPUDescriptorSet* gpuds3 = gpuMeshBuffer->getAttachedDescriptorSet ();
223
+
224
+ driver->bindGraphicsPipeline (gpuPipeline);
225
+ const video::IGPUDescriptorSet* gpuds1_ptr = gpuds1.get ();
226
+ driver->bindDescriptorSets (video::EPBP_GRAPHICS, gpuPipeline->getLayout (), 1u , 1u , &gpuds1_ptr, nullptr );
227
+
228
+ if (gpuds3) // ! Execute if we have a texture attached as DS
229
+ driver->bindDescriptorSets (video::EPBP_GRAPHICS, gpuPipeline->getLayout (), 3u , 1u , &gpuds3, nullptr );
230
+ driver->pushConstants (gpuPipeline->getLayout (), video::IGPUSpecializedShader::ESS_FRAGMENT, 0u , gpuMeshBuffer->MAX_PUSH_CONSTANT_BYTESIZE , gpuMeshBuffer->getPushConstantsDataPtr ());
231
+
232
+ driver->drawMeshBuffer (gpuMeshBuffer);
233
+ }
234
+ };
235
+
236
+ /*
237
+ Render PLY and STL
238
+ */
239
+
240
+ renderMesh (plyDrawData, 0 );
241
+ renderMesh (stlDrawData, 20 );
242
+
243
+ driver->endScene ();
244
+
245
+ /*
246
+ Display frames per second in window title
247
+ */
248
+
249
+ uint64_t time = device->getTimer ()->getRealTime ();
250
+ if (time - lastFPSTime > 1000 )
251
+ {
252
+ std::wostringstream str;
253
+ str << L" PLY & STL Test Demo - Nabla Engine [" << driver->getName () << " ] FPS:" << driver->getFPS () << " PrimitvesDrawn:" << driver->getPrimitiveCountDrawn ();
254
+
255
+ device->setWindowCaption (str.str ().c_str ());
256
+ lastFPSTime = time;
257
+ }
258
+ }
259
+
260
+ return 0 ;
261
+ }
0 commit comments