1414#include " candlewick/multibody/RobotScene.h"
1515#include " candlewick/multibody/RobotDebug.h"
1616#include " candlewick/primitives/Primitives.h"
17+ #include " candlewick/utils/FileDialogGui.h"
1718#include " candlewick/utils/WriteTextureToImage.h"
1819
1920#include < imgui.h>
@@ -184,11 +185,17 @@ void eventLoop(const Renderer &renderer) {
184185 }
185186}
186187
187- Renderer createRenderer (Uint32 width, Uint32 height,
188- SDL_GPUTextureFormat depth_stencil_format) {
189- return Renderer{Device{auto_detect_shader_format_subset (), true },
190- Window (__FILE__, int (width), int (height), 0 ),
191- depth_stencil_format};
188+ static void screenshot_button_callback (Renderer &renderer,
189+ media::TransferBufferPool &pool,
190+ const char *filename) {
191+ const auto &device = renderer.device ;
192+ CommandBuffer command_buffer{device};
193+ renderer.waitAndAcquireSwapchain (command_buffer);
194+
195+ SDL_Log (" Saving screenshot at %s" , filename);
196+ media::writeToFile (command_buffer, device, pool, renderer.swapchain ,
197+ renderer.getSwapchainTextureFormat (), wWidth, wHeight,
198+ filename);
192199}
193200
194201int main (int argc, char **argv) {
@@ -206,8 +213,11 @@ int main(int argc, char **argv) {
206213 return 1 ;
207214
208215 // D16_UNORM works on macOS, D24_UNORM and D32_FLOAT break the depth prepass
209- Renderer renderer =
210- createRenderer (wWidth, wHeight, SDL_GPU_TEXTUREFORMAT_D16_UNORM);
216+ Renderer renderer{
217+ Device{auto_detect_shader_format_subset (), true },
218+ Window (__FILE__, wWidth, wHeight, 0 ),
219+ SDL_GPU_TEXTUREFORMAT_D16_UNORM,
220+ };
211221
212222 entt::registry registry{};
213223
@@ -313,6 +323,8 @@ int main(int argc, char **argv) {
313323
314324 FrustumBoundsDebugSystem frustumBoundsDebug{registry, renderer};
315325
326+ const char *screenshot_filename = nullptr ;
327+
316328 GuiSystem gui_system{
317329 renderer, [&](const Renderer &r) {
318330 IMGUI_CHECKVERSION ();
@@ -391,6 +403,13 @@ int main(int argc, char **argv) {
391403 ImGui::RadioButton (" Heatmap" , (int *)&depth_mode, 1 );
392404 }
393405
406+ ImGui::SeparatorText (" Screenshots" );
407+ static GuiFileSaveDialog scr_dialog;
408+ scr_dialog.addFileDialog (renderer.window );
409+ if (ImGui::Button (" Take screenshot" )) {
410+ screenshot_filename = scr_dialog.filename .c_str ();
411+ }
412+
394413 ImGui::SeparatorText (" Robot model" );
395414 ImGui::SetItemTooltip (" Information about the displayed robot model." );
396415 multibody::guiAddPinocchioModelInfo (registry, model, geom_model);
@@ -414,44 +433,43 @@ int main(int argc, char **argv) {
414433
415434 Uint32 frameNo = 0 ;
416435
417- srand (42 );
436+ std:: srand (42 );
418437 Eigen::VectorXd q0 = pin::neutral (model);
419438 Eigen::VectorXd q1 = pin::randomConfiguration (model);
420439
421440#ifdef CANDLEWICK_WITH_FFMPEG_SUPPORT
422441 media::VideoRecorder recorder{NoInit};
442+ media::TransferBufferPool transfer_buffer_pool{renderer.device };
423443 if (performRecording)
424- recorder = media::VideoRecorder{wWidth, wHeight, " ur5.mp4" };
444+ recorder = media::VideoRecorder{wWidth,
445+ wHeight,
446+ " ur5.mp4" ,
447+ {
448+ .fps = 50 ,
449+ }};
425450#endif
426451
427- auto record_callback = [&] {
428- #ifdef CANDLEWICK_WITH_FFMPEG_SUPPORT
429- auto swapchain_format = renderer.getSwapchainTextureFormat ();
430- media::videoWriteTextureToFrame (renderer.device , recorder,
431- renderer.swapchain , swapchain_format,
432- wWidth, wHeight);
433- #endif
434- };
435-
436452 AABB &worldSpaceBounds = robot_scene.worldSpaceBounds ;
437453 worldSpaceBounds.update ({-1 .f , -1 .f , 0 .f }, {+1 .f , +1 .f , 1 .f });
438454
439455 frustumBoundsDebug.addBounds (worldSpaceBounds);
440456 frustumBoundsDebug.addFrustum (shadowPassInfo.cam );
441457
442458 Eigen::VectorXd q = q0;
459+ Eigen::VectorXd qn = q;
460+ Eigen::VectorXd v{model.nv };
443461 const double dt = 1e-2 ;
444462
445463 while (!quitRequested) {
446464 // logic
447465 eventLoop (renderer);
448466 double alpha = 0.5 * (1 . + std::sin (frameNo * dt));
449- Eigen::VectorXd qn = q;
450- q = pin::interpolate (model, q0, q1, alpha);
451- Eigen::VectorXd v = pin::difference (model, q, qn) / dt;
452- pin::forwardKinematics (model, pin_data, q, v);
467+ pin::interpolate (model, q0, q1, alpha, qn);
468+ v = pin::difference (model, q, qn) / dt;
469+ pin::forwardKinematics (model, pin_data, qn, v);
453470 pin::updateFramePlacements (model, pin_data);
454471 pin::updateGeometryPlacements (model, pin_data, geom_model, geom_data);
472+ q = qn;
455473 debug_scene.update ();
456474
457475 // acquire command buffer and swapchain
@@ -494,7 +512,18 @@ int main(int argc, char **argv) {
494512 command_buffer.submit ();
495513
496514 if (performRecording) {
497- record_callback ();
515+ #ifdef CANDLEWICK_WITH_FFMPEG_SUPPORT
516+ CommandBuffer command_buffer = renderer.acquireCommandBuffer ();
517+ auto swapchain_format = renderer.getSwapchainTextureFormat ();
518+ media::videoWriteTextureToFrame (
519+ command_buffer, renderer.device , transfer_buffer_pool, recorder,
520+ renderer.swapchain , swapchain_format, wWidth, wHeight);
521+ #endif
522+ }
523+ if (screenshot_filename) {
524+ screenshot_button_callback (renderer, transfer_buffer_pool,
525+ screenshot_filename);
526+ screenshot_filename = nullptr ;
498527 }
499528 frameNo++;
500529 }
@@ -507,6 +536,10 @@ int main(int argc, char **argv) {
507536 robot_scene.release ();
508537 debug_scene.release ();
509538 gui_system.release ();
539+ #ifdef CANDLEWICK_WITH_FFMPEG_SUPPORT
540+ recorder.close ();
541+ transfer_buffer_pool.release ();
542+ #endif
510543 renderer.destroy ();
511544 SDL_Quit ();
512545 return 0 ;
0 commit comments