55
66#include " ../3rdparty/portable-file-dialogs/portable-file-dialogs.h"
77
8+ #ifdef NBL_BUILD_MITSUBA_LOADER
9+ #include " nbl/ext/MitsubaLoader/CSerializedLoader.h"
10+ #endif
811
912class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourcesApplication
1013{
@@ -14,12 +17,15 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc
1417 public:
1518 inline MeshLoadersApp (const path& _localInputCWD, const path& _localOutputCWD, const path& _sharedInputCWD, const path& _sharedOutputCWD)
1619 : IApplicationFramework(_localInputCWD, _localOutputCWD, _sharedInputCWD, _sharedOutputCWD),
17- device_base_t({1280 ,720 }, EF_UNKNOWN , _localInputCWD, _localOutputCWD, _sharedInputCWD, _sharedOutputCWD) {}
20+ device_base_t({1280 ,720 }, EF_D32_SFLOAT , _localInputCWD, _localOutputCWD, _sharedInputCWD, _sharedOutputCWD) {}
1821
1922 inline bool onAppInitialized (smart_refctd_ptr<ISystem>&& system) override
2023 {
2124 if (!asset_base_t::onAppInitialized (smart_refctd_ptr (system)))
2225 return false ;
26+ #ifdef NBL_BUILD_MITSUBA_LOADER
27+ m_assetMgr->addAssetLoader (make_smart_refctd_ptr<ext::MitsubaLoader::CSerializedLoader>());
28+ #endif
2329 if (!device_base_t::onAppInitialized (smart_refctd_ptr (system)))
2430 return false ;
2531
@@ -36,32 +42,15 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc
3642 return logFail (" Couldn't create Command Buffer!" );
3743 }
3844
39- // ! cache results -- speeds up mesh generation on second run
40- m_qnc->loadCacheFromFile <EF_R8G8B8_SNORM>(m_system.get (),sharedOutputCWD/" ../../tmp/normalCache888.sse" );
45+
46+ auto scRes = static_cast <CDefaultSwapchainFramebuffers*>(m_surface->getSwapchainResources ());
47+ m_renderer = CSimpleDebugRenderer::create (m_assetMgr.get (),scRes->getRenderpass (),0 ,{});
48+ if (!m_renderer)
49+ return logFail (" Failed to create renderer!" );
4150
4251 //
4352 if (!reloadModel ())
4453 return false ;
45- #if 0
46- const uint32_t addtionalBufferOwnershipFamilies[] = {getGraphicsQueue()->getFamilyIndex()};
47- // we want to use the vertex data through UTBs
48- using usage_f = IGPUBuffer::E_USAGE_FLAGS;
49- CAssetConverter::patch_t<asset::ICPUPolygonGeometry> patch = {};
50- patch.positionBufferUsages = usage_f::EUF_UNIFORM_TEXEL_BUFFER_BIT;
51- patch.indexBufferUsages = usage_f::EUF_INDEX_BUFFER_BIT;
52- patch.otherBufferUsages = usage_f::EUF_UNIFORM_TEXEL_BUFFER_BIT;
53- m_scene = CGeometryCreatorScene::create(
54- {
55- .transferQueue = getTransferUpQueue(),
56- .utilities = m_utils.get(),
57- .logger = m_logger.get(),
58- .addtionalBufferOwnershipFamilies = addtionalBufferOwnershipFamilies
59- },patch
60- );
61- #endif
62-
63- auto scRes = static_cast <CDefaultSwapchainFramebuffers*>(m_surface->getSwapchainResources ());
64- m_renderer = CSimpleDebugRenderer::create (m_assetMgr.get (),scRes->getRenderpass (),0 ,nullptr );
6554
6655 camera.mapKeysToArrows ();
6756
@@ -114,15 +103,21 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc
114103 }
115104 // late latch input
116105 {
106+ bool reload = false ;
117107 camera.beginInputProcessing (nextPresentationTimestamp);
118108 mouse.consumeEvents ([&](const IMouseEventChannel::range_t & events) -> void { camera.mouseProcess (events); }, m_logger.get ());
119109 keyboard.consumeEvents ([&](const IKeyboardEventChannel::range_t & events) -> void
120110 {
111+ for (const auto & event : events)
112+ if (event.keyCode ==E_KEY_CODE::EKC_R && event.action ==SKeyboardEvent::ECA_RELEASED)
113+ reload = true ;
121114 camera.keyboardProcess (events);
122115 },
123116 m_logger.get ()
124117 );
125118 camera.endInputProcessing (nextPresentationTimestamp);
119+ if (reload)
120+ reloadModel ();
126121 }
127122 // draw scene
128123 {
@@ -139,8 +134,6 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc
139134 }
140135 cb->end ();
141136
142- // updateGUIDescriptorSet();
143-
144137 IQueue::SSubmitInfo::SSemaphoreInfo retval =
145138 {
146139 .semaphore = m_semaphore.get (),
@@ -224,37 +217,193 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc
224217 }
225218
226219 private:
227- inline bool reloadModel ()
220+ // TODO: standardise this across examples, and take from `argv`
221+ bool m_nonInteractiveTest = false ;
222+
223+ bool reloadModel ()
228224 {
229- pfd::open_file file (" Choose a supported Model File" , " ../../media" , { " All Supported Formats" , " *.ply *.stl *.serialized *.obj" ,
230- " TODO (.ply)" , " *.ply" ,
231- " TODO (.stl)" , " *.stl" ,
232- " Mitsuba 0.6 Serialized (.serialized)" , " *.serialized" ,
233- " Wavefront Object (.obj)" , " *.obj"
234- });
235- if (file.result ().empty ())
236- return false ;
237- m_modelPath = file.result ()[0 ];
225+ if (m_nonInteractiveTest) // TODO: maybe also take from argv and argc
226+ m_modelPath = (sharedInputCWD/" ply/Spanner-ply.ply" ).string ();
227+ else
228+ {
229+ pfd::open_file file (" Choose a supported Model File" , sharedInputCWD.string (),
230+ {
231+ " All Supported Formats" , " *.ply *.stl *.serialized *.obj" ,
232+ " TODO (.ply)" , " *.ply" ,
233+ " TODO (.stl)" , " *.stl" ,
234+ " Mitsuba 0.6 Serialized (.serialized)" , " *.serialized" ,
235+ " Wavefront Object (.obj)" , " *.obj"
236+ },
237+ false
238+ );
239+ if (file.result ().empty ())
240+ return false ;
241+ m_modelPath = file.result ()[0 ];
242+ }
238243
239244 // free up
245+ m_renderer->m_instances .clear ();
246+ m_renderer->clearGeometries ({.semaphore =m_semaphore.get (),.value =m_realFrameIx});
240247 m_assetMgr->clearAllAssetCache ();
241248
242249 // ! load the geometry
243250 IAssetLoader::SAssetLoadParams params = {};
244- params.meshManipulatorOverride = nullptr ; // TODO
251+ params.logger = m_logger. get ();
245252 auto bundle = m_assetMgr->getAsset (m_modelPath,params);
246253 if (bundle.getContents ().empty ())
247254 return false ;
248- // ! cache results -- speeds up mesh generation on second run
249- m_qnc->saveCacheToFile <EF_R8G8B8_SNORM>(m_system.get (),sharedOutputCWD/" ../../tmp/normalCache888.sse" );
255+
256+ //
257+ core::vector<smart_refctd_ptr<const ICPUPolygonGeometry>> geometries;
258+ switch (bundle.getAssetType ())
259+ {
260+ case IAsset::E_TYPE::ET_GEOMETRY:
261+ for (const auto & item : bundle.getContents ())
262+ if (auto polyGeo=IAsset::castDown<ICPUPolygonGeometry>(item); polyGeo)
263+ geometries.push_back (polyGeo);
264+ break ;
265+ default :
266+ m_logger->log (" Asset loaded but not a supported type (ET_GEOMETRY,ET_GEOMETRY_COLLECTION)" ,ILogger::ELL_ERROR);
267+ break ;
268+ }
269+ if (geometries.empty ())
270+ return false ;
271+
272+ using aabb_t = hlsl::shapes::AABB<3 ,double >;
273+ auto printAABB = [&](const aabb_t & aabb, const char * extraMsg=" " )->void
274+ {
275+ m_logger->log (" %s AABB is (%f,%f,%f) -> (%f,%f,%f)" ,ILogger::ELL_INFO,extraMsg,aabb.minVx .x ,aabb.minVx .y ,aabb.minVx .z ,aabb.maxVx .x ,aabb.maxVx .y ,aabb.maxVx .z );
276+ };
277+ auto bound = aabb_t::create ();
278+ // convert the geometries
279+ {
280+ smart_refctd_ptr<CAssetConverter> converter = CAssetConverter::create ({.device =m_device.get ()});
281+
282+ const auto transferFamily = getTransferUpQueue ()->getFamilyIndex ();
283+
284+ struct SInputs : CAssetConverter::SInputs
285+ {
286+ virtual inline std::span<const uint32_t > getSharedOwnershipQueueFamilies (const size_t groupCopyID, const asset::ICPUBuffer* buffer, const CAssetConverter::patch_t <asset::ICPUBuffer>& patch) const
287+ {
288+ return sharedBufferOwnership;
289+ }
290+
291+ core::vector<uint32_t > sharedBufferOwnership;
292+ } inputs = {};
293+ core::vector<CAssetConverter::patch_t <ICPUPolygonGeometry>> patches (geometries.size (),CSimpleDebugRenderer::DefaultPolygonGeometryPatch);
294+ {
295+ inputs.logger = m_logger.get ();
296+ std::get<CAssetConverter::SInputs::asset_span_t <ICPUPolygonGeometry>>(inputs.assets ) = {&geometries.front ().get (),geometries.size ()};
297+ std::get<CAssetConverter::SInputs::patch_span_t <ICPUPolygonGeometry>>(inputs.patches ) = patches;
298+ // set up shared ownership so we don't have to
299+ core::unordered_set<uint32_t > families;
300+ families.insert (transferFamily);
301+ families.insert (getGraphicsQueue ()->getFamilyIndex ());
302+ if (families.size ()>1 )
303+ for (const auto fam : families)
304+ inputs.sharedBufferOwnership .push_back (fam);
305+ }
306+
307+ // reserve
308+ auto reservation = converter->reserve (inputs);
309+ if (!reservation)
310+ {
311+ m_logger->log (" Failed to reserve GPU objects for CPU->GPU conversion!" ,ILogger::ELL_ERROR);
312+ return false ;
313+ }
314+
315+ // convert
316+ {
317+ auto semaphore = m_device->createSemaphore (0u );
318+
319+ constexpr auto MultiBuffering = 2 ;
320+ std::array<smart_refctd_ptr<IGPUCommandBuffer>,MultiBuffering> commandBuffers = {};
321+ {
322+ auto pool = m_device->createCommandPool (transferFamily,IGPUCommandPool::CREATE_FLAGS::RESET_COMMAND_BUFFER_BIT|IGPUCommandPool::CREATE_FLAGS::TRANSIENT_BIT);
323+ pool->createCommandBuffers (IGPUCommandPool::BUFFER_LEVEL::PRIMARY,commandBuffers,smart_refctd_ptr (m_logger));
324+ }
325+ commandBuffers.front ()->begin (IGPUCommandBuffer::USAGE::ONE_TIME_SUBMIT_BIT);
326+
327+ std::array<IQueue::SSubmitInfo::SCommandBufferInfo,MultiBuffering> commandBufferSubmits;
328+ for (auto i=0 ; i<MultiBuffering; i++)
329+ commandBufferSubmits[i].cmdbuf = commandBuffers[i].get ();
330+
331+ SIntendedSubmitInfo transfer = {};
332+ transfer.queue = getTransferUpQueue ();
333+ transfer.scratchCommandBuffers = commandBufferSubmits;
334+ transfer.scratchSemaphore = {
335+ .semaphore = semaphore.get (),
336+ .value = 0u ,
337+ .stageMask = PIPELINE_STAGE_FLAGS::ALL_TRANSFER_BITS
338+ };
339+
340+ CAssetConverter::SConvertParams cpar = {};
341+ cpar.utilities = m_utils.get ();
342+ cpar.transfer = &transfer;
343+
344+ // basically it records all data uploads and submits them right away
345+ auto future = reservation.convert (cpar);
346+ if (future.copy ()!=IQueue::RESULT::SUCCESS)
347+ {
348+ m_logger->log (" Failed to await submission feature!" , ILogger::ELL_ERROR);
349+ return false ;
350+ }
351+ }
352+
353+ auto tmp = hlsl::float32_t4x3 (
354+ hlsl::float32_t3 (1 ,0 ,0 ),
355+ hlsl::float32_t3 (0 ,1 ,0 ),
356+ hlsl::float32_t3 (0 ,0 ,1 ),
357+ hlsl::float32_t3 (0 ,0 ,0 )
358+ );
359+ core::vector<hlsl::float32_t3x4> worldTforms;
360+ const auto & converted = reservation.getGPUObjects <ICPUPolygonGeometry>();
361+ for (const auto & geom : converted)
362+ {
363+ const auto promoted = geom.value ->getAABB <aabb_t >();
364+ printAABB (promoted," Geometry" );
365+ tmp[3 ].x += promoted.getExtent ().x ;
366+ const auto promotedWorld = hlsl::float64_t3x4 (worldTforms.emplace_back (hlsl::transpose (tmp)));
367+ const auto transformed = hlsl::shapes::util::transform (promotedWorld,promoted);
368+ printAABB (transformed," Transformed" );
369+ bound = hlsl::shapes::util::union_ (transformed,bound);
370+ }
371+ printAABB (bound," Total" );
372+ if (!m_renderer->addGeometries ({ &converted.front ().get (),converted.size () }))
373+ return false ;
374+
375+ auto worlTformsIt = worldTforms.begin ();
376+ for (const auto & geo : m_renderer->getGeometries ())
377+ m_renderer->m_instances .push_back ({
378+ .world = *(worlTformsIt++),
379+ .packedGeo = &geo
380+ });
381+ }
382+
383+ // get scene bounds and reset camera
384+ {
385+ const double distance = 0.05 ;
386+ const auto diagonal = bound.getExtent ();
387+ {
388+ const auto measure = hlsl::length (diagonal);
389+ const auto aspectRatio = float (m_window->getWidth ())/float (m_window->getHeight ());
390+ camera.setProjectionMatrix (core::matrix4SIMD::buildProjectionMatrixPerspectiveFovRH (1 .2f ,aspectRatio,distance*measure*0.1 ,measure*4.0 ));
391+ camera.setMoveSpeed (measure*0.04 );
392+ }
393+ const auto pos = bound.maxVx +diagonal*distance;
394+ camera.setPosition (vectorSIMDf (pos.x ,pos.y ,pos.z ));
395+ const auto center = (bound.minVx +bound.maxVx )*0.5 ;
396+ camera.setTarget (vectorSIMDf (center.x ,center.y ,center.z ));
397+ }
398+
399+ // TODO: write out the geometry
250400
251401 return true ;
252402 }
253403
254404 // Maximum frames which can be simultaneously submitted, used to cycle through our per-frame resources like command buffers
255405 constexpr static inline uint32_t MaxFramesInFlight = 3u ;
256406 //
257- smart_refctd_ptr<CQuantNormalCache> m_qnc;
258407 smart_refctd_ptr<CSimpleDebugRenderer> m_renderer;
259408 //
260409 smart_refctd_ptr<ISemaphore> m_semaphore;
0 commit comments