Main.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. // Engine includes
  4. #include "BsApplication.h"
  5. #include "Resources/BsResources.h"
  6. #include "Resources/BsBuiltinResources.h"
  7. #include "Importer/BsImporter.h"
  8. #include "Importer/BsTextureImportOptions.h"
  9. #include "Importer/BsMeshImportOptions.h"
  10. #include "Material/BsMaterial.h"
  11. #include "Material/BsShader.h"
  12. #include "Input/BsVirtualInput.h"
  13. #include "Components/BsCCamera.h"
  14. #include "Components/BsCRenderable.h"
  15. #include "Components/BsCLight.h"
  16. #include "GUI/BsCGUIWidget.h"
  17. #include "GUI/BsGUILayoutX.h"
  18. #include "GUI/BsGUILayoutY.h"
  19. #include "GUI/BsGUIPanel.h"
  20. #include "GUI/BsGUISpace.h"
  21. #include "GUI/BsGUILabel.h"
  22. #include "GUI/BsGUIButton.h"
  23. #include "GUI/BsGUIListBox.h"
  24. #include "GUI/BsProfilerOverlay.h"
  25. #include "RenderAPI/BsRenderAPI.h"
  26. #include "RenderAPI/BsRenderWindow.h"
  27. #include "Scene/BsSceneObject.h"
  28. #include "BsEngineConfig.h"
  29. #if BS_PLATFORM == BS_PLATFORM_WIN32
  30. #include <windows.h>
  31. #endif
  32. // Example includes
  33. #include "CameraFlyer.h"
  34. namespace bs
  35. {
  36. UINT32 windowResWidth = 1280;
  37. UINT32 windowResHeight = 720;
  38. /** Imports all of our assets and prepares GameObject that handle the example logic. */
  39. void setUpExample();
  40. /** Import mesh/texture/GPU programs used by the example. */
  41. void loadAssets(HMesh& model, HTexture& texture, HShader& shader);
  42. /** Create a material used by our example model. */
  43. HMaterial createMaterial(const HTexture& texture, const HShader& shader);
  44. /** Set up example scene objects. */
  45. void setUp3DScene(const HMesh& mesh, const HMaterial& material);
  46. /** Set up example GUI. */
  47. void setUpGUI();
  48. /** Set up input configuration and callbacks. */
  49. void setUpInput();
  50. /** Toggles the primary window between full-screen and windowed mode. */
  51. void toggleFullscreen();
  52. /** Called whenever the main render window is resized. */
  53. void renderWindowResized();
  54. /** Called when the selected video mode changes in the video mode list box. */
  55. void videoModeChanged(UINT32 idx, bool enabled);
  56. /** Triggered whenever a virtual button is released. */
  57. void buttonUp(const VirtualButton& button, UINT32 deviceIdx);
  58. }
  59. using namespace bs;
  60. /** Main entry point into the application. */
  61. #if BS_PLATFORM == BS_PLATFORM_WIN32
  62. int CALLBACK WinMain(
  63. _In_ HINSTANCE hInstance,
  64. _In_ HINSTANCE hPrevInstance,
  65. _In_ LPSTR lpCmdLine,
  66. _In_ int nCmdShow
  67. )
  68. #else
  69. int main()
  70. #endif
  71. {
  72. // Ensure all errors are reported properly
  73. CrashHandler::startUp();
  74. // Descriptor used for initializing the engine
  75. START_UP_DESC startUpDesc;
  76. // Use default values as specified by the build system
  77. startUpDesc.renderAPI = BS_RENDER_API_MODULE;
  78. startUpDesc.renderer = BS_RENDERER_MODULE;
  79. startUpDesc.audio = BS_AUDIO_MODULE;
  80. startUpDesc.physics = BS_PHYSICS_MODULE;
  81. startUpDesc.input = BS_INPUT_MODULE;
  82. // Descriptor used for initializing the primary application window.
  83. startUpDesc.primaryWindowDesc.videoMode = VideoMode(windowResWidth, windowResHeight);
  84. startUpDesc.primaryWindowDesc.title = "Banshee Example App";
  85. startUpDesc.primaryWindowDesc.fullscreen = false;
  86. startUpDesc.primaryWindowDesc.depthBuffer = false;
  87. // List of importer plugins we plan on using for importing various resources
  88. startUpDesc.importers.push_back("BansheeFreeImgImporter"); // For importing textures
  89. startUpDesc.importers.push_back("BansheeFBXImporter"); // For importing meshes
  90. startUpDesc.importers.push_back("BansheeFontImporter"); // For importing fonts
  91. startUpDesc.importers.push_back("BansheeSL"); // For importing shaders
  92. // Initializes the application with systems and primary window as defined above
  93. Application::startUp(startUpDesc);
  94. // Imports all of ours assets and prepares GameObjects that handle the example logic.
  95. setUpExample();
  96. // Runs the main loop that does most of the work. This method will exit when user closes the main
  97. // window or exits in some other way.
  98. Application::instance().runMainLoop();
  99. Application::shutDown();
  100. CrashHandler::shutDown();
  101. return 0;
  102. }
  103. namespace bs
  104. {
  105. Path dataPath = Paths::getRuntimeDataPath();
  106. Path exampleModelPath = dataPath + "Examples\\Dragon.fbx";
  107. Path exampleTexturePath = dataPath + "Examples\\Dragon.tga";
  108. Path exampleShaderPath = dataPath + "Examples\\Example.bsl";
  109. GUIButton* toggleFullscreenButton = nullptr;
  110. bool fullscreen = false;
  111. const VideoMode* selectedVideoMode = nullptr;
  112. Vector<const VideoMode*> videoModes;
  113. HCamera sceneCamera;
  114. HProfilerOverlay profilerOverlay;
  115. VirtualButton toggleCPUProfilerBtn;
  116. VirtualButton toggleGPUProfilerBtn;
  117. bool cpuProfilerActive = false;
  118. bool gpuProfilerActive = false;
  119. void setUpExample()
  120. {
  121. HMesh exampleModel;
  122. HTexture exampleTexture;
  123. HShader exampleShader;
  124. loadAssets(exampleModel, exampleTexture, exampleShader);
  125. HMaterial exampleMaterial = createMaterial(exampleTexture, exampleShader);
  126. setUp3DScene(exampleModel, exampleMaterial);
  127. setUpGUI();
  128. setUpInput();
  129. }
  130. /**
  131. * Load the required resources. First try to load a pre-processed version of the resources. If they don't exist import
  132. * resources from the source formats into engine format, and save them for next time.
  133. */
  134. void loadAssets(HMesh& model, HTexture& texture, HShader& shader)
  135. {
  136. // Set up paths to pre-processed versions of example resources.
  137. Path exampleModelAssetPath = exampleModelPath;
  138. Path exampleTextureAssetPath = exampleTexturePath;
  139. Path exampleShaderAssetPath = exampleShaderPath;
  140. exampleModelAssetPath.setExtension(exampleModelAssetPath.getExtension() + ".asset");
  141. exampleTextureAssetPath.setExtension(exampleTextureAssetPath.getExtension() + ".asset");
  142. exampleShaderAssetPath.setExtension(exampleShaderAssetPath.getExtension() + ".asset");
  143. // Load an FBX mesh.
  144. model = gResources().load<Mesh>(exampleModelAssetPath);
  145. if(model == nullptr) // Mesh file doesn't exist, import from the source file.
  146. {
  147. // When importing you may specify optional import options that control how is the asset imported.
  148. SPtr<ImportOptions> meshImportOptions = Importer::instance().createImportOptions(exampleModelPath);
  149. // rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a
  150. // non-mesh resource. This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
  151. if (rtti_is_of_type<MeshImportOptions>(meshImportOptions))
  152. {
  153. MeshImportOptions* importOptions = static_cast<MeshImportOptions*>(meshImportOptions.get());
  154. // Ensures we can save the mesh contents
  155. importOptions->setCPUCached(true);
  156. }
  157. model = gImporter().import<Mesh>(exampleModelPath, meshImportOptions);
  158. // Save for later use, so we don't have to import on the next run.
  159. gResources().save(model, exampleModelAssetPath, true);
  160. }
  161. // Load an TGA texture.
  162. texture = gResources().load<Texture>(exampleTextureAssetPath);
  163. if (texture == nullptr) // Texture file doesn't exist, import from the source file.
  164. {
  165. // When importing you may specify optional import options that control how is the asset imported.
  166. SPtr<ImportOptions> textureImportOptions = Importer::instance().createImportOptions(exampleTexturePath);
  167. // rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a
  168. // non-texture resource. This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
  169. if (rtti_is_of_type<TextureImportOptions>(textureImportOptions))
  170. {
  171. TextureImportOptions* importOptions = static_cast<TextureImportOptions*>(textureImportOptions.get());
  172. // We want maximum number of mipmaps to be generated
  173. importOptions->setGenerateMipmaps(true);
  174. // The texture is in sRGB space
  175. importOptions->setSRGB(true);
  176. // Ensures we can save the texture contents
  177. importOptions->setCPUCached(true);
  178. }
  179. // Import texture with specified import options
  180. texture = gImporter().import<Texture>(exampleTexturePath, textureImportOptions);
  181. // Save for later use, so we don't have to import on the next run.
  182. gResources().save(texture, exampleTextureAssetPath, true);
  183. }
  184. // Load a shader.
  185. shader = gResources().load<Shader>(exampleShaderAssetPath);
  186. if (shader == nullptr) // Mesh file doesn't exist, import from the source file.
  187. {
  188. shader = gImporter().import<Shader>(exampleShaderPath);
  189. // Save for later use, so we don't have to import on the next run.
  190. gResources().save(shader, exampleShaderAssetPath, true);
  191. }
  192. }
  193. /** Create a material using the provided shader, and assign the provided texture to it. */
  194. HMaterial createMaterial(const HTexture& texture, const HShader& shader)
  195. {
  196. // Create a material with the provided shader.
  197. HMaterial exampleMaterial = Material::create(shader);
  198. // And set the texture to be used by the "tex" shader parameter. We leave the "samp"
  199. // parameter at its defaults. These parameters are defined in the shader (.bsl) file.
  200. exampleMaterial->setTexture("tex", texture);
  201. return exampleMaterial;
  202. }
  203. /** Set up the 3D object used by the example, and the camera to view the world through. */
  204. void setUp3DScene(const HMesh& mesh, const HMaterial& material)
  205. {
  206. /************************************************************************/
  207. /* SCENE OBJECT */
  208. /************************************************************************/
  209. // Now we create a scene object that has a position, orientation, scale and optionally
  210. // components to govern its logic. In this particular case we are creating a SceneObject
  211. // with a Renderable component which will render a mesh at the position of the scene object
  212. // with the provided material.
  213. // Create new scene object at (0, 0, 0)
  214. HSceneObject dragonSO = SceneObject::create("Dragon");
  215. // Attach the Renderable component and hook up the mesh we imported earlier,
  216. // and the material we created in the previous section.
  217. HRenderable renderable = dragonSO->addComponent<CRenderable>();
  218. renderable->setMesh(mesh);
  219. renderable->setMaterial(material);
  220. /************************************************************************/
  221. /* LIGHTS */
  222. /************************************************************************/
  223. // Add a couple of lights so that our object isn't completely in the dark.
  224. HSceneObject lightASO = SceneObject::create("Light A");
  225. HSceneObject lightBSO = SceneObject::create("Light B");
  226. lightASO->setPosition(Vector3(0, 50, 0));
  227. lightBSO->setPosition(Vector3(-130, 140, 450));
  228. HLight lightA = lightASO->addComponent<CLight>();
  229. HLight lightB = lightBSO->addComponent<CLight>();
  230. // Disable physically based attentuation because we want to set our own range
  231. lightA->setUseAutoAttenuation(false);
  232. lightB->setUseAutoAttenuation(false);
  233. lightA->setAttenuationRadius(500.0f);
  234. lightB->setAttenuationRadius(300.0f);
  235. lightA->setIntensity(10000.0f);
  236. lightB->setIntensity(10000.0f);
  237. /************************************************************************/
  238. /* CAMERA */
  239. /************************************************************************/
  240. // In order something to render on screen we need at least one camera.
  241. // Like before, we create a new scene object at (0, 0, 0).
  242. HSceneObject sceneCameraSO = SceneObject::create("SceneCamera");
  243. // Get the primary render window we need for creating the camera. Additionally
  244. // hook up a callback so we are notified when user resizes the window.
  245. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  246. window->onResized.connect(&renderWindowResized);
  247. // Add a Camera component that will output whatever it sees into that window
  248. // (You could also use a render texture or another window you created).
  249. sceneCamera = sceneCameraSO->addComponent<CCamera>(window);
  250. // Set up camera component properties
  251. // Priority determines in what order are cameras rendered in case multiple cameras render to the same render target.
  252. // We raise the priority slightly because later in code we have defined a GUI camera that we want to render second.
  253. sceneCamera->setPriority(1);
  254. // Set closest distance that is visible. Anything below that is clipped.
  255. sceneCamera->setNearClipDistance(5);
  256. // Set farthest distance that is visible. Anything above that is clipped.
  257. sceneCamera->setFarClipDistance(10000);
  258. // Set aspect ratio depending on the current resolution
  259. sceneCamera->setAspectRatio(windowResWidth / (float)windowResHeight);
  260. // Add a CameraFlyer component that allows us to move the camera. See CameraFlyer for more information.
  261. sceneCameraSO->addComponent<CameraFlyer>();
  262. // Position and orient the camera scene object
  263. sceneCameraSO->setPosition(Vector3(-130.0f, 140.0f, 650.0f));
  264. sceneCameraSO->lookAt(Vector3(0, 0, 0));
  265. }
  266. /** Register mouse and keyboard inputs that will be used for controlling the camera. */
  267. void setUpInput()
  268. {
  269. // Register input configuration
  270. // Banshee allows you to use VirtualInput system which will map input device buttons
  271. // and axes to arbitrary names, which allows you to change input buttons without affecting
  272. // the code that uses it, since the code is only aware of the virtual names.
  273. // If you want more direct input, see Input class.
  274. auto inputConfig = VirtualInput::instance().getConfiguration();
  275. // Camera controls for buttons (digital 0-1 input, e.g. keyboard or gamepad button)
  276. inputConfig->registerButton("Forward", BC_W);
  277. inputConfig->registerButton("Back", BC_S);
  278. inputConfig->registerButton("Left", BC_A);
  279. inputConfig->registerButton("Right", BC_D);
  280. inputConfig->registerButton("Forward", BC_UP);
  281. inputConfig->registerButton("Back", BC_BACK);
  282. inputConfig->registerButton("Left", BC_LEFT);
  283. inputConfig->registerButton("Right", BC_RIGHT);
  284. inputConfig->registerButton("FastMove", BC_LSHIFT);
  285. inputConfig->registerButton("RotateCam", BC_MOUSE_RIGHT);
  286. // Camera controls for axes (analog input, e.g. mouse or gamepad thumbstick)
  287. // These return values in [-1.0, 1.0] range.
  288. inputConfig->registerAxis("Horizontal", VIRTUAL_AXIS_DESC((UINT32)InputAxis::MouseX));
  289. inputConfig->registerAxis("Vertical", VIRTUAL_AXIS_DESC((UINT32)InputAxis::MouseY));
  290. // Controls that toggle the profiler overlays
  291. inputConfig->registerButton("CPUProfilerOverlay", BC_F1);
  292. inputConfig->registerButton("GPUProfilerOverlay", BC_F2);
  293. // Cache the profiler overlay buttons so when a button is pressed we can quickly
  294. // use these to determine its the one we want
  295. toggleCPUProfilerBtn = VirtualButton("CPUProfilerOverlay");
  296. toggleGPUProfilerBtn = VirtualButton("GPUProfilerOverlay");
  297. // Hook up a callback that gets triggered whenever a virtual button is released
  298. VirtualInput::instance().onButtonUp.connect(&buttonUp);
  299. }
  300. /** Set up graphical user interface used by the example. */
  301. void setUpGUI()
  302. {
  303. // Create a scene object that will contain GUI components
  304. HSceneObject guiSO = SceneObject::create("Example");
  305. // Get the primary render window we need for creating the camera.
  306. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  307. // First we want another camera that is responsible for rendering GUI
  308. HCamera guiCamera = guiSO->addComponent<CCamera>(window);
  309. // Notify the renderer that the camera will only be used for overlays (e.g. GUI) so it can optimize its usage
  310. SPtr<RenderSettings> settings = guiCamera->getRenderSettings();
  311. settings->overlayOnly = true;
  312. // Set up GUI camera properties.
  313. // We don't care about aspect ratio for GUI camera.
  314. guiCamera->setAspectRatio(1.0f);
  315. // This camera should ignore any Renderable objects in the scene
  316. guiCamera->setLayers(0);
  317. // Don't clear this camera as that would clear anything the main camera has rendered.
  318. guiCamera->getViewport()->setRequiresClear(false, false, false);
  319. // Add a GUIWidget, the top-level GUI component, parent to all GUI elements. GUI widgets
  320. // require you to specify a viewport that they will output rendered GUI elements to.
  321. HGUIWidget gui = guiSO->addComponent<CGUIWidget>(guiCamera);
  322. // Depth allows you to control how is a GUI widget rendered in relation to other widgets
  323. // Lower depth means the widget will be rendered in front of those with higher. In this case we just
  324. // make the depth mid-range as there are no other widgets.
  325. gui->setDepth(128);
  326. // GUI skin defines how are all child elements of the GUI widget renderered. It contains all their styles
  327. // and default layout properties. We use the default skin that comes built into Banshee.
  328. gui->setSkin(BuiltinResources::instance().getGUISkin());
  329. // Get the primary GUI panel that stretches over the entire window and add to it a vertical layout
  330. // that will be using for vertically positioning messages about toggling profiler overlay.
  331. GUILayout* bottomLayout = gui->getPanel()->addNewElement<GUILayoutY>();
  332. // Add a flexible space that fills up any remaining area in the layout, making the two labels above be aligned
  333. // to the bottom of the GUI widget (and the screen).
  334. bottomLayout->addNewElement<GUIFlexibleSpace>();
  335. // Add a couple of labels to the layout with the needed messages. Labels expect a HString object that
  336. // maps into a string table and allows for easily localization.
  337. bottomLayout->addElement(GUILabel::create(HString(L"Press F1 to toggle CPU profiler overlay")));
  338. bottomLayout->addElement(GUILabel::create(HString(L"Press F2 to toggle GPU profiler overlay")));
  339. // Create a GUI panel that is used for displaying resolution and fullscreen options.
  340. GUILayout* rightLayout = gui->getPanel()->addNewElement<GUILayoutX>();
  341. // We want all the GUI elements be right aligned, so we add a flexible space first.
  342. rightLayout->addNewElement<GUIFlexibleSpace>();
  343. // And we want the elements to be vertically placed, top to bottom
  344. GUILayout* elemLayout = rightLayout->addNewElement<GUILayoutY>();
  345. // Leave 30 pixels to the right free
  346. rightLayout->addNewElement<GUIFixedSpace>(30);
  347. // Add a button that will trigger a callback when clicked
  348. toggleFullscreenButton = GUIButton::create(HString(L"Toggle fullscreen"));
  349. toggleFullscreenButton->onClick.connect(&toggleFullscreen);
  350. elemLayout->addElement(toggleFullscreenButton);
  351. // Add a profiler overlay object that is responsible for displaying CPU and GPU profiling GUI
  352. profilerOverlay = guiSO->addComponent<CProfilerOverlay>(guiCamera->_getCamera());
  353. // Set up video mode list box
  354. // First get a list of output devices
  355. const VideoModeInfo& videoModeInfo = RenderAPI::getVideoModeInfo();
  356. // Get video mode info for the primary monitor
  357. const VideoOutputInfo& primaryMonitorInfo = videoModeInfo.getOutputInfo(0);
  358. // Make the current desktop mode the default video mode
  359. selectedVideoMode = &primaryMonitorInfo.getDesktopVideoMode();
  360. // Create list box elements for each available video mode
  361. UINT32 numVideoModes = primaryMonitorInfo.getNumVideoModes();
  362. Vector<HString> videoModeLabels(numVideoModes);
  363. UINT32 selectedVideoModeIdx = 0;
  364. for (UINT32 i = 0; i < numVideoModes; i++)
  365. {
  366. const VideoMode& curVideoMode = primaryMonitorInfo.getVideoMode(i);
  367. HString videoModeLabel(L"{0} x {1} at {2}Hz");
  368. videoModeLabel.setParameter(0, toWString(curVideoMode.getWidth()));
  369. videoModeLabel.setParameter(1, toWString(curVideoMode.getHeight()));
  370. videoModeLabel.setParameter(2, toWString(Math::roundToInt(curVideoMode.getRefreshRate())));
  371. videoModeLabels[i] = videoModeLabel;
  372. videoModes.push_back(&curVideoMode);
  373. if (curVideoMode == *selectedVideoMode)
  374. selectedVideoModeIdx = i;
  375. }
  376. // Create the list box
  377. GUIListBox* videoModeListBox = GUIListBox::create(videoModeLabels);
  378. elemLayout->addElement(videoModeListBox);
  379. // Select the default (desktop) video mode
  380. videoModeListBox->selectElement(selectedVideoModeIdx);
  381. // Set up a callback to be notified when video mode changes
  382. videoModeListBox->onSelectionToggled.connect(&videoModeChanged);
  383. }
  384. /** Callback method that toggles between fullscreen and windowed modes. */
  385. void toggleFullscreen()
  386. {
  387. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  388. if (fullscreen)
  389. window->setWindowed(windowResWidth, windowResHeight);
  390. else
  391. window->setFullscreen(*selectedVideoMode);
  392. fullscreen = !fullscreen;
  393. }
  394. /** Callback triggered wheneve the user resizes the example window. */
  395. void renderWindowResized()
  396. {
  397. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  398. const RenderWindowProperties& rwProps = window->getProperties();
  399. if (!fullscreen)
  400. {
  401. windowResWidth = rwProps.width;
  402. windowResHeight = rwProps.height;
  403. }
  404. sceneCamera->setAspectRatio(rwProps.width / (float)rwProps.height);
  405. }
  406. /** Callback triggered when the user selects a new video mode from the GUI drop down element. */
  407. void videoModeChanged(UINT32 idx, bool enabled)
  408. {
  409. if (!enabled)
  410. return;
  411. selectedVideoMode = videoModes[idx];
  412. if (fullscreen)
  413. {
  414. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  415. window->setFullscreen(*selectedVideoMode);
  416. }
  417. }
  418. /** Callback triggered when a user hits a button. */
  419. void buttonUp(const VirtualButton& button, UINT32 deviceIdx)
  420. {
  421. // Check if the pressed button is one of the either buttons we defined in "setUpExample", and toggle profiler
  422. // overlays accordingly. Device index is ignored for now, as it is assumed the user is using a single keyboard,
  423. // but if you wanted support for multiple gamepads you would check deviceIdx.
  424. if (button == toggleCPUProfilerBtn)
  425. {
  426. if (cpuProfilerActive)
  427. {
  428. profilerOverlay->hide();
  429. cpuProfilerActive = false;
  430. }
  431. else
  432. {
  433. profilerOverlay->show(ProfilerOverlayType::CPUSamples);
  434. cpuProfilerActive = true;
  435. gpuProfilerActive = false;
  436. }
  437. }
  438. else if (button == toggleGPUProfilerBtn)
  439. {
  440. if (gpuProfilerActive)
  441. {
  442. profilerOverlay->hide();
  443. gpuProfilerActive = false;
  444. }
  445. else
  446. {
  447. profilerOverlay->show(ProfilerOverlayType::GPUSamples);
  448. gpuProfilerActive = true;
  449. cpuProfilerActive = false;
  450. }
  451. }
  452. }
  453. }