Main.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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 "Input/BsVirtualInput.h"
  12. #include "Components/BsCCamera.h"
  13. #include "Components/BsCRenderable.h"
  14. #include "Components/BsCLight.h"
  15. #include "Components/BsCSkybox.h"
  16. #include "RenderAPI/BsRenderAPI.h"
  17. #include "RenderAPI/BsRenderWindow.h"
  18. #include "Scene/BsSceneObject.h"
  19. #include "BsEngineConfig.h"
  20. // Example includes
  21. #include "CameraFlyer.h"
  22. #include "ObjectRotator.h"
  23. #if BS_PLATFORM == BS_PLATFORM_WIN32
  24. #include <windows.h>
  25. #endif
  26. namespace bs
  27. {
  28. struct Assets;
  29. UINT32 windowResWidth = 1280;
  30. UINT32 windowResHeight = 720;
  31. /** Imports all of our assets and prepares GameObject that handle the example logic. */
  32. void setUpExample();
  33. /** Import mesh & textures used by the example. */
  34. void loadAssets(Assets& assets);
  35. /** Imports a mesh at the provided path and optionally scales it. */
  36. HMesh loadMesh(const Path& path, float scale = 1.0f);
  37. /**
  38. * Imports a texture at the provided path. Textures not in sRGB space (e.g. normal maps) need to be specially marked by
  39. * setting 'isSRGB' to false. Also allows for conversion of texture to cubemap by setting the 'isCubemap' parameter.
  40. * If the data should be imported in a floating point format, specify 'isHDR' to true.
  41. */
  42. HTexture loadTexture(const Path& path, bool isSRGB = true, bool isCubemap = false, bool isHDR = false);
  43. /** Create a material used by our example model. */
  44. void createMaterial(Assets& assets);
  45. /** Set up example scene objects. */
  46. void setUp3DScene(const Assets& assets);
  47. /** Set up input configuration and callbacks. */
  48. void setUpInput();
  49. /** Toggles the primary window between full-screen and windowed mode. */
  50. void toggleFullscreen();
  51. /** Called whenever the main render window is resized. */
  52. void renderWindowResized();
  53. /** Called when the selected video mode changes in the video mode list box. */
  54. void videoModeChanged(UINT32 idx, bool enabled);
  55. /** Triggered whenever a virtual button is released. */
  56. void buttonUp(const VirtualButton& button, UINT32 deviceIdx);
  57. }
  58. using namespace bs;
  59. /** Main entry point into the application. */
  60. #if BS_PLATFORM == BS_PLATFORM_WIN32
  61. int CALLBACK WinMain(
  62. _In_ HINSTANCE hInstance,
  63. _In_ HINSTANCE hPrevInstance,
  64. _In_ LPSTR lpCmdLine,
  65. _In_ int nCmdShow
  66. )
  67. #else
  68. int main()
  69. #endif
  70. {
  71. // Descriptor used for initializing the engine
  72. START_UP_DESC startUpDesc;
  73. // Use default values as specified by the build system
  74. startUpDesc.renderAPI = BS_RENDER_API_MODULE;
  75. startUpDesc.renderer = BS_RENDERER_MODULE;
  76. startUpDesc.audio = BS_AUDIO_MODULE;
  77. startUpDesc.physics = BS_PHYSICS_MODULE;
  78. startUpDesc.input = BS_INPUT_MODULE;
  79. // Descriptor used for initializing the primary application window.
  80. startUpDesc.primaryWindowDesc.videoMode = VideoMode(windowResWidth, windowResHeight);
  81. startUpDesc.primaryWindowDesc.title = "Banshee Example App";
  82. startUpDesc.primaryWindowDesc.fullscreen = false;
  83. startUpDesc.primaryWindowDesc.depthBuffer = false;
  84. // List of importer plugins we plan on using for importing various resources
  85. startUpDesc.importers.push_back("BansheeFreeImgImporter"); // For importing textures
  86. startUpDesc.importers.push_back("BansheeFBXImporter"); // For importing meshes
  87. startUpDesc.importers.push_back("BansheeFontImporter"); // For importing fonts
  88. startUpDesc.importers.push_back("BansheeSL"); // For importing shaders
  89. // Initializes the application with systems and primary window as defined above
  90. Application::startUp(startUpDesc);
  91. // Imports all of ours assets and prepares GameObjects that handle the example logic.
  92. setUpExample();
  93. // Runs the main loop that does most of the work. This method will exit when user closes the main
  94. // window or exits in some other way.
  95. Application::instance().runMainLoop();
  96. Application::shutDown();
  97. return 0;
  98. }
  99. namespace bs
  100. {
  101. Path dataPath = Paths::getRuntimeDataPath();
  102. Path exampleModelPath = dataPath + "Examples\\Pistol\\Pistol01.fbx";
  103. Path exampleAlbedoTexPath = dataPath + "Examples\\Pistol\\Pistol_DFS.png";
  104. Path exampleNormalsTexPath = dataPath + "Examples\\Pistol\\Pistol_NM.png";
  105. Path exampleRoughnessTexPath = dataPath + "Examples\\Pistol\\Pistol_RGH.png";
  106. Path exampleMetalnessTexPath = dataPath + "Examples\\Pistol\\Pistol_MTL.png";
  107. Path exampleSkyCubemapPath = dataPath + "Examples\\Environments\\PaperMill_E_3k.hdr";
  108. HCamera sceneCamera;
  109. /** Container for all resources used by the example. */
  110. struct Assets
  111. {
  112. HMesh exampleModel;
  113. HTexture exampleAlbedoTex;
  114. HTexture exampleNormalsTex;
  115. HTexture exampleRoughnessTex;
  116. HTexture exampleMetalnessTex;
  117. HTexture exampleSkyCubemap;
  118. HShader exampleShader;
  119. HMaterial exampleMaterial;
  120. };
  121. void setUpExample()
  122. {
  123. Assets assets;
  124. loadAssets(assets);
  125. createMaterial(assets);
  126. setUp3DScene(assets);
  127. setUpInput();
  128. }
  129. /**
  130. * Load the required resources. First try to load a pre-processed version of the resources. If they don't exist import
  131. * resources from the source formats into engine format, and save them for next time.
  132. */
  133. void loadAssets(Assets& assets)
  134. {
  135. // Load an FBX mesh.
  136. assets.exampleModel = loadMesh(exampleModelPath, 10.0f);
  137. // Load textures
  138. assets.exampleAlbedoTex = loadTexture(exampleAlbedoTexPath);
  139. assets.exampleNormalsTex = loadTexture(exampleNormalsTexPath, false);
  140. assets.exampleRoughnessTex = loadTexture(exampleRoughnessTexPath, false);
  141. assets.exampleMetalnessTex = loadTexture(exampleMetalnessTexPath, false);
  142. assets.exampleSkyCubemap = loadTexture(exampleSkyCubemapPath, false, true, true);
  143. // Load the default physically based shader for rendering opaque objects
  144. assets.exampleShader = BuiltinResources::instance().getBuiltinShader(BuiltinShader::Standard);
  145. }
  146. HMesh loadMesh(const Path& path, float scale)
  147. {
  148. Path assetPath = path;
  149. assetPath.setExtension(path.getExtension() + ".asset");
  150. HMesh model = gResources().load<Mesh>(assetPath);
  151. if (model == nullptr) // Mesh file doesn't exist, import from the source file.
  152. {
  153. // When importing you may specify optional import options that control how is the asset imported.
  154. SPtr<ImportOptions> meshImportOptions = Importer::instance().createImportOptions(path);
  155. // rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a
  156. // non-mesh resource. This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
  157. if (rtti_is_of_type<MeshImportOptions>(meshImportOptions))
  158. {
  159. MeshImportOptions* importOptions = static_cast<MeshImportOptions*>(meshImportOptions.get());
  160. importOptions->setImportScale(scale);
  161. }
  162. model = gImporter().import<Mesh>(path, meshImportOptions);
  163. // Save for later use, so we don't have to import on the next run.
  164. gResources().save(model, assetPath, true);
  165. }
  166. return model;
  167. }
  168. HTexture loadTexture(const Path& path, bool isSRGB, bool isCubemap, bool isHDR)
  169. {
  170. Path assetPath = path;
  171. assetPath.setExtension(path.getExtension() + ".asset");
  172. HTexture texture = gResources().load<Texture>(assetPath);
  173. if (texture == nullptr) // Texture file doesn't exist, import from the source file.
  174. {
  175. // When importing you may specify optional import options that control how is the asset imported.
  176. SPtr<ImportOptions> textureImportOptions = Importer::instance().createImportOptions(path);
  177. // rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a
  178. // non-texture resource. This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
  179. if (rtti_is_of_type<TextureImportOptions>(textureImportOptions))
  180. {
  181. TextureImportOptions* importOptions = static_cast<TextureImportOptions*>(textureImportOptions.get());
  182. // We want maximum number of mipmaps to be generated
  183. importOptions->setGenerateMipmaps(true);
  184. // If the texture is in sRGB space the system needs to know about it
  185. importOptions->setSRGB(isSRGB);
  186. // Ensures we can save the texture contents
  187. importOptions->setCPUCached(true);
  188. // Import as cubemap if needed
  189. importOptions->setIsCubemap(isCubemap);
  190. // If importing as cubemap, assume source is a panorama
  191. importOptions->setCubemapSourceType(CubemapSourceType::Cylindrical);
  192. // Importing using a HDR format if requested
  193. if (isHDR)
  194. importOptions->setFormat(PF_RG11B10F);
  195. }
  196. // Import texture with specified import options
  197. texture = gImporter().import<Texture>(path, textureImportOptions);
  198. // Save for later use, so we don't have to import on the next run.
  199. gResources().save(texture, assetPath, true);
  200. }
  201. return texture;
  202. }
  203. /** Create a material using the active shader, and assign the relevant textures to it. */
  204. void createMaterial(Assets& assets)
  205. {
  206. // Create a material with the active shader.
  207. HMaterial exampleMaterial = Material::create(assets.exampleShader);
  208. // Assign the four textures requires by the PBS shader
  209. exampleMaterial->setTexture("gAlbedoTex", assets.exampleAlbedoTex);
  210. exampleMaterial->setTexture("gNormalTex", assets.exampleNormalsTex);
  211. exampleMaterial->setTexture("gRoughnessTex", assets.exampleRoughnessTex);
  212. exampleMaterial->setTexture("gMetalnessTex", assets.exampleMetalnessTex);
  213. assets.exampleMaterial = exampleMaterial;
  214. }
  215. /** Set up the 3D object used by the example, and the camera to view the world through. */
  216. void setUp3DScene(const Assets& assets)
  217. {
  218. /************************************************************************/
  219. /* SCENE OBJECT */
  220. /************************************************************************/
  221. // Now we create a scene object that has a position, orientation, scale and optionally
  222. // components to govern its logic. In this particular case we are creating a SceneObject
  223. // with a Renderable component which will render a mesh at the position of the scene object
  224. // with the provided material.
  225. // Create new scene object at (0, 0, 0)
  226. HSceneObject pistolSO = SceneObject::create("Pistol");
  227. // Attach the Renderable component and hook up the mesh we imported earlier,
  228. // and the material we created in the previous section.
  229. HRenderable renderable = pistolSO->addComponent<CRenderable>();
  230. renderable->setMesh(assets.exampleModel);
  231. renderable->setMaterial(assets.exampleMaterial);
  232. // Add a rotator component so we can rotate the object during runtime
  233. pistolSO->addComponent<ObjectRotator>();
  234. /************************************************************************/
  235. /* SKYBOX */
  236. /************************************************************************/
  237. // Add a skybox texture for sky reflections
  238. HSceneObject skyboxSO = SceneObject::create("Skybox");
  239. HSkybox skybox = skyboxSO->addComponent<CSkybox>();
  240. skybox->setTexture(assets.exampleSkyCubemap);
  241. /************************************************************************/
  242. /* CAMERA */
  243. /************************************************************************/
  244. // In order something to render on screen we need at least one camera.
  245. // Like before, we create a new scene object at (0, 0, 0).
  246. HSceneObject sceneCameraSO = SceneObject::create("SceneCamera");
  247. // Get the primary render window we need for creating the camera. Additionally
  248. // hook up a callback so we are notified when user resizes the window.
  249. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  250. window->onResized.connect(&renderWindowResized);
  251. // Add a Camera component that will output whatever it sees into that window
  252. // (You could also use a render texture or another window you created).
  253. sceneCamera = sceneCameraSO->addComponent<CCamera>(window);
  254. // Set up camera component properties
  255. // Set closest distance that is visible. Anything below that is clipped.
  256. sceneCamera->setNearClipDistance(0.005f);
  257. // Set farthest distance that is visible. Anything above that is clipped.
  258. sceneCamera->setFarClipDistance(1000);
  259. // Set aspect ratio depending on the current resolution
  260. sceneCamera->setAspectRatio(windowResWidth / (float)windowResHeight);
  261. // Enable multi-sample anti-aliasing for better quality
  262. sceneCamera->setMSAACount(4);
  263. // Add a CameraFlyer component that allows us to move the camera. See CameraFlyer for more information.
  264. sceneCameraSO->addComponent<CameraFlyer>();
  265. // Position and orient the camera scene object
  266. sceneCameraSO->setPosition(Vector3(0.2f, 0.1f, 0.2f));
  267. sceneCameraSO->lookAt(Vector3(-0.1f, 0, 0));
  268. }
  269. /** Register mouse and keyboard inputs that will be used for controlling the camera. */
  270. void setUpInput()
  271. {
  272. // Register input configuration
  273. // Banshee allows you to use VirtualInput system which will map input device buttons
  274. // and axes to arbitrary names, which allows you to change input buttons without affecting
  275. // the code that uses it, since the code is only aware of the virtual names.
  276. // If you want more direct input, see Input class.
  277. auto inputConfig = VirtualInput::instance().getConfiguration();
  278. // Camera controls for buttons (digital 0-1 input, e.g. keyboard or gamepad button)
  279. inputConfig->registerButton("Forward", BC_W);
  280. inputConfig->registerButton("Back", BC_S);
  281. inputConfig->registerButton("Left", BC_A);
  282. inputConfig->registerButton("Right", BC_D);
  283. inputConfig->registerButton("Forward", BC_UP);
  284. inputConfig->registerButton("Back", BC_BACK);
  285. inputConfig->registerButton("Left", BC_LEFT);
  286. inputConfig->registerButton("Right", BC_RIGHT);
  287. inputConfig->registerButton("FastMove", BC_LSHIFT);
  288. inputConfig->registerButton("RotateObj", BC_MOUSE_LEFT);
  289. inputConfig->registerButton("RotateCam", BC_MOUSE_RIGHT);
  290. // Camera controls for axes (analog input, e.g. mouse or gamepad thumbstick)
  291. // These return values in [-1.0, 1.0] range.
  292. inputConfig->registerAxis("Horizontal", VIRTUAL_AXIS_DESC((UINT32)InputAxis::MouseX));
  293. inputConfig->registerAxis("Vertical", VIRTUAL_AXIS_DESC((UINT32)InputAxis::MouseY));
  294. }
  295. /** Callback triggered wheneve the user resizes the example window. */
  296. void renderWindowResized()
  297. {
  298. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  299. const RenderWindowProperties& rwProps = window->getProperties();
  300. windowResWidth = rwProps.width;
  301. windowResHeight = rwProps.height;
  302. sceneCamera->setAspectRatio(rwProps.width / (float)rwProps.height);
  303. }
  304. }