Guest User

Untitled

a guest
Jul 4th, 2014
11
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <windows.h>
  2.  
  3. #include "BsApplication.h"
  4. #include "BsImporter.h"
  5. #include "BsGpuProgramImportOptions.h"
  6. #include "BsTextureImportOptions.h"
  7. #include "BsMaterial.h"
  8. #include "BsShader.h"
  9. #include "BsTechnique.h"
  10. #include "BsPass.h"
  11. #include "BsCoreThreadAccessor.h"
  12. #include "BsApplication.h"
  13. #include "BsVirtualInput.h"
  14. #include "BsCamera.h"
  15. #include "BsRenderable.h"
  16. #include "BsGUIWidget.h"
  17. #include "BsGUIArea.h"
  18. #include "BsGUILayoutX.h"
  19. #include "BsGUILayoutY.h"
  20. #include "BsGUISpace.h"
  21. #include "BsGUILabel.h"
  22. #include "BsGUIButton.h"
  23. #include "BsGUIListBox.h"
  24. #include "BsBuiltinResources.h"
  25. #include "BsRTTIType.h"
  26. #include "BsHString.h"
  27. #include "BsRenderWindow.h"
  28. #include "BsSceneObject.h"
  29. #include "BsCoreThread.h"
  30. #include "BsProfilerOverlay.h"
  31. #include "BsRenderer.h"
  32.  
  33. #include "CameraFlyer.h"
  34.  
  35. namespace BansheeEngine
  36. {
  37.     /**
  38.      * Imports all of ours assets and prepares GameObject that handle the example logic.
  39.      */
  40.     void setUpExample();
  41.  
  42.     /**
  43.      * Toggles the primary window between full-screen and windowed mode.
  44.      */
  45.     void toggleFullscreen();
  46.  
  47.     /**
  48.      * Triggered whenever a virtual button is released.
  49.      */
  50.     void buttonUp(const VirtualButton& button, UINT32 deviceIdx);
  51. }
  52.  
  53. using namespace BansheeEngine;
  54.  
  55. /**
  56.  * Main entry point into the application.
  57.  */
  58. int CALLBACK WinMain(
  59.     _In_  HINSTANCE hInstance,
  60.     _In_  HINSTANCE hPrevInstance,
  61.     _In_  LPSTR lpCmdLine,
  62.     _In_  int nCmdShow
  63.     )
  64. {
  65.     // Descriptor used for initializing the primary application window.
  66.     RENDER_WINDOW_DESC renderWindowDesc;
  67.     renderWindowDesc.videoMode = VideoMode(resolutionWidth, resolutionHeight);
  68.     renderWindowDesc.title = "Banshee Example App";
  69.     renderWindowDesc.fullscreen = false;
  70.  
  71.     // Initializes the application with primary window defined as above and DirectX 11 render system.
  72.     // You may use other render systems than DirectX 11, however this example for simplicity only uses DirectX 11.
  73.     // If you wanted other render systems you would need to create separate shaders for them and import them above
  74.     // along with (or replace) the DX11 ones.
  75.     Application::startUp(renderWindowDesc, RenderSystemPlugin::DX11);
  76.  
  77.     // Imports all of ours assets and prepares GameObject that handle the example logic.
  78.     setUpExample();
  79.    
  80.     // Runs the main loop that does most of the work. This method will exit when user closes the main
  81.     // window or exits in some other way.
  82.     Application::instance().runMainLoop();
  83.  
  84.     // Perform cleanup
  85.     Application::shutDown();
  86.  
  87.     return 0;
  88. }
  89.  
  90. namespace BansheeEngine
  91. {
  92.     Path exampleModelPath = "..\\..\\..\\..\\Data\\Examples\\Pyromancer.fbx";
  93.     Path exampleTexturePath = "..\\..\\..\\..\\Data\\Examples\\Pyromancer.psd";
  94.     Path exampleFragmentShaderPath = "..\\..\\..\\..\\Data\\Examples\\example_fs.gpuprog";
  95.     Path exampleVertexShaderPath = "..\\..\\..\\..\\Data\\Examples\\example_vs.gpuprog";
  96.  
  97.     GUIButton* toggleFullscreenButton = nullptr;
  98.     UINT32 resolutionWidth = 1280;
  99.     UINT32 resolutionHeight = 720;
  100.     bool fullscreen = false;
  101.     const VideoMode* videoMode = nullptr;
  102.  
  103.     HMesh exampleModel;
  104.     HTexture exampleTexture;
  105.     HGpuProgram exampleFragmentGPUProg;
  106.     HGpuProgram exampleVertexGPUProg;
  107.  
  108.     HCamera sceneCamera;
  109.     HProfilerOverlay profilerOverlay;
  110.  
  111.     VirtualButton toggleCPUProfilerBtn;
  112.     VirtualButton toggleGPUProfilerBtn;
  113.  
  114.     bool cpuProfilerActive = false;
  115.     bool gpuProfilerActive = false;
  116.  
  117.     void setUpExample()
  118.     {
  119.         /************************************************************************/
  120.         /*                              IMPORT ASSETS                           */
  121.         /************************************************************************/
  122.         // Import mesh, texture and shader from the disk. In a normal application you would want to save the imported assets
  123.         // so next time the application is ran you can just load them directly. This can be done with Resources::save/load.
  124.  
  125.         // Import an FBX mesh.
  126.         exampleModel = static_resource_cast<Mesh>(Importer::instance().import(exampleModelPath));
  127.  
  128.         // When importing you may specify optional import options that control how is the asset imported.
  129.         ImportOptionsPtr textureImportOptions = Importer::instance().createImportOptions(exampleTexturePath);
  130.  
  131.         // rtti_is_of_type checks if the import options are of valid type, in case the provided path is pointing to a non-texture resource.
  132.         // This is similar to dynamic_cast but uses Banshee internal RTTI system for type checking.
  133.         if (rtti_is_of_type<TextureImportOptions>(textureImportOptions))
  134.         {
  135.             TextureImportOptions* importOptions = static_cast<TextureImportOptions*>(textureImportOptions.get());
  136.  
  137.             // We want the texture to be compressed, just a basic non-alpha format
  138.             importOptions->setFormat(PF_BC1);
  139.  
  140.             // We want maximum number of mipmaps to be generated
  141.             importOptions->setGenerateMipmaps(true);
  142.         }
  143.  
  144.         // Import texture with specified import options
  145.         exampleTexture = static_resource_cast<Texture>(Importer::instance().import(exampleTexturePath, textureImportOptions));
  146.  
  147.         // Create import options for fragment GPU program
  148.         ImportOptionsPtr gpuProgImportOptions = Importer::instance().createImportOptions(exampleFragmentShaderPath);
  149.         if (rtti_is_of_type<GpuProgramImportOptions>(gpuProgImportOptions))
  150.         {
  151.             GpuProgramImportOptions* importOptions = static_cast<GpuProgramImportOptions*>(gpuProgImportOptions.get());
  152.  
  153.             // Name of the entry function in the GPU program
  154.             importOptions->setEntryPoint("ps_main");
  155.  
  156.             // Language the GPU program is written in. Can only be hlsl for DX11
  157.             importOptions->setLanguage("hlsl");
  158.  
  159.             // GPU program profile specifying what feature-set the shader code uses.
  160.             importOptions->setProfile(GPP_PS_4_0);
  161.  
  162.             // Type of the shader.
  163.             importOptions->setType(GPT_FRAGMENT_PROGRAM);
  164.         }
  165.  
  166.         // Import fragment GPU program
  167.         exampleFragmentGPUProg = static_resource_cast<GpuProgram>(Importer::instance().import(exampleFragmentShaderPath, gpuProgImportOptions));
  168.  
  169.         // Create import options for vertex GPU program. Similar as above.
  170.         gpuProgImportOptions = Importer::instance().createImportOptions(exampleVertexShaderPath);
  171.         if (rtti_is_of_type<GpuProgramImportOptions>(gpuProgImportOptions))
  172.         {
  173.             GpuProgramImportOptions* importOptions = static_cast<GpuProgramImportOptions*>(gpuProgImportOptions.get());
  174.  
  175.             importOptions->setEntryPoint("vs_main");
  176.             importOptions->setLanguage("hlsl");
  177.             importOptions->setProfile(GPP_VS_4_0);
  178.             importOptions->setType(GPT_VERTEX_PROGRAM);
  179.         }
  180.  
  181.         // Import vertex GPU program
  182.         exampleVertexGPUProg = static_resource_cast<GpuProgram>(Importer::instance().import(exampleVertexShaderPath, gpuProgImportOptions));
  183.  
  184.         /************************************************************************/
  185.         /*                          CREATE SHADER                               */
  186.         /************************************************************************/
  187.         // Create a shader that references our vertex and fragment GPU programs, and set
  188.         // up shader input parameters.
  189.         ShaderPtr exampleShader = Shader::create("ExampleShader");
  190.  
  191.         // Set up shader parameters and renderer semantics.
  192.         // Renderer semantics allow our renderer to automatically populate certain shader parameters (e.g. a world view projection matrix).
  193.         // These semantics are purely optional and depend on the renderer used. Certain renderers expect certain semantics to be set up
  194.         // otherwise they will not render the objects. You always have the option to populate all the parameters manually, but in this example
  195.         // we go with the semantics route as it allows for a "set up and forget" approach.
  196.  
  197.         // Add a world view projection matrix parameter, which will be populated by the renderer.
  198.         // We map our shader parameter name to the actual GPU program variable, both being "matWorldViewProj" in this case.
  199.         exampleShader->addParameter("matWorldViewProj", "matWorldViewProj", GPDT_MATRIX_4X4, RPS_WorldViewProjTfrm);
  200.  
  201.         // Add a sampler and a texture semantic that we will populate manually.
  202.         exampleShader->addParameter("samp", "samp", GPOT_SAMPLER2D);
  203.         exampleShader->addParameter("tex", "tex", GPOT_TEXTURE2D);
  204.  
  205.         // Our GPU programs use parameter blocks (constant buffers in DX11 lingo). Here we notify the renderer
  206.         // that this particular parameter block contains object-specific data (like the world view projection parameter
  207.         // we defined above).
  208.         exampleShader->setParamBlockAttribs("PerObject", true, GPBU_DYNAMIC, RBS_PerObject);
  209.  
  210.         /************************************************************************/
  211.         /*                          CREATE MATERIAL                             */
  212.         /************************************************************************/
  213.  
  214.         // Create a shader technique. Shader can have many different techniques and the renderer will automatically
  215.         // use the most appropriate technique depending on the active renderer and render system. e.g. you can have different
  216.         // techniques using HLSL9, HLSL11 and GLSL GPU programs for DirectX 9, DirectX 11 and OpenGL render systems respectively.
  217.         TechniquePtr technique = exampleShader->addTechnique(RenderSystemDX11, RendererDefault);
  218.  
  219.         // Add a new pass to the technique. Each technique can have multiple passes that allow you to render the same
  220.         // object multiple times using different shaders.
  221.         PassPtr pass = technique->addPass();
  222.         pass->setVertexProgram(exampleVertexGPUProg);
  223.         pass->setFragmentProgram(exampleFragmentGPUProg);
  224.  
  225.         // And finally create a material with the newly created shader
  226.         HMaterial exampleMaterial = Material::create(exampleShader);
  227.  
  228.         // And set the texture to be used by the "tex" shader parameter. We leave the "samp"
  229.         // parameter at its defaults.
  230.         exampleMaterial->setTexture("tex", exampleTexture);
  231.  
  232.         /************************************************************************/
  233.         /*                              SCENE OBJECT                            */
  234.         /************************************************************************/
  235.  
  236.         // Now we create a scene object that has a position, orientation, scale and optionally
  237.         // components to govern its logic. In this particular case we are creating a SceneObject
  238.         // with a Renderable component which will render a mesh at the position of the scene object
  239.         // with the provided material.
  240.  
  241.         // Create new scene object at (0, 0, 0)
  242.         HSceneObject pyromancerSO = SceneObject::create("Pyromancer");
  243.  
  244.         // Attach the Renderable component and hook up the mesh we imported earlier,
  245.         // and the material we created in the previous section.
  246.         HRenderable renderable = pyromancerSO->addComponent<Renderable>();
  247.         renderable->setMesh(exampleModel);
  248.         renderable->setMaterial(exampleMaterial);
  249.  
  250.         /************************************************************************/
  251.         /*                                  CAMERA                              */
  252.         /************************************************************************/
  253.  
  254.         // In order something to render on screen we need at least one camera.
  255.  
  256.         // Like before, we create a new scene object at (0, 0, 0).
  257.         HSceneObject sceneCameraSO = SceneObject::create("SceneCamera");
  258.  
  259.         // We retrieve the primary render window and add a Camera component that
  260.         // will output whatever it sees into that window (You could also use a render texture
  261.         // or another window you created).
  262.         RenderWindowPtr window = gApplication().getPrimaryWindow();
  263.         sceneCamera = sceneCameraSO->addComponent<Camera>(window);
  264.  
  265.         // Set up camera component properties
  266.  
  267.         // Priority determines in what order are cameras rendered in case multiple cameras render to the same render target.
  268.         // We raise the priority slightly because later in code we have defined a GUI camera that we want to render second.
  269.         sceneCamera->setPriority(1);
  270.  
  271.         // Set closest distance that is visible. Anything below that is clipped.
  272.         sceneCamera->setNearClipDistance(5);
  273.  
  274.         // Set aspect ratio depending on the current resolution
  275.         sceneCamera->setAspectRatio(resolutionWidth / (float)resolutionHeight);
  276.  
  277.         // Add a CameraFlyer component that allows us to move the camera. See CameraFlyer for more information.
  278.         sceneCameraSO->addComponent<CameraFlyer>();
  279.  
  280.         // Position and orient the camera scene object
  281.         sceneCameraSO->setPosition(Vector3(40.0f, 30.0f, 230.0f));
  282.         sceneCameraSO->lookAt(Vector3(0, 0, 0));
  283.  
  284.         /************************************************************************/
  285.         /*                                  INPUT                               */
  286.         /************************************************************************/
  287.  
  288.         // Register input configuration
  289.         // Banshee allows you to use VirtualInput system which will map input device buttons
  290.         // and axes to arbitrary names, which allows you to change input buttons without affecting
  291.         // the code that uses it, since the code is only aware of the virtual names.
  292.         // If you want more direct input, see Input class.
  293.         auto inputConfig = VirtualInput::instance().getConfiguration();
  294.  
  295.         // Camera controls for buttons (digital 0-1 input, e.g. keyboard or gamepad button)
  296.         inputConfig->registerButton("Forward", BC_W);
  297.         inputConfig->registerButton("Back", BC_S);
  298.         inputConfig->registerButton("Left", BC_A);
  299.         inputConfig->registerButton("Right", BC_D);
  300.         inputConfig->registerButton("Forward", BC_UP);
  301.         inputConfig->registerButton("Back", BC_BACK);
  302.         inputConfig->registerButton("Left", BC_LEFT);
  303.         inputConfig->registerButton("Right", BC_RIGHT);
  304.         inputConfig->registerButton("FastMove", BC_LSHIFT);
  305.         inputConfig->registerButton("RotateCam", BC_MOUSE_RIGHT);
  306.  
  307.         // Camera controls for axes (analog input, e.g. mouse or gamepad thumbstick)
  308.         // These return values in [-1.0, 1.0] range.
  309.         inputConfig->registerAxis("Horizontal", VIRTUAL_AXIS_DESC((UINT32)InputAxis::MouseX));
  310.         inputConfig->registerAxis("Vertical", VIRTUAL_AXIS_DESC((UINT32)InputAxis::MouseY));
  311.  
  312.         // Controls that toggle the profiler overlays
  313.         inputConfig->registerButton("CPUProfilerOverlay", BC_F1);
  314.         inputConfig->registerButton("GPUProfilerOverlay", BC_F2);
  315.  
  316.         // Cache the profiler overlay buttons so when a button is pressed we can quickly
  317.         // use these to determine its the one we want
  318.         toggleCPUProfilerBtn = VirtualButton("CPUProfilerOverlay");
  319.         toggleGPUProfilerBtn = VirtualButton("GPUProfilerOverlay");
  320.  
  321.         // Hook up a callback that gets triggered whenever a virtual button is released
  322.         VirtualInput::instance().onButtonUp.connect(&buttonUp);
  323.  
  324.         /************************************************************************/
  325.         /*                                  GUI                                 */
  326.         /************************************************************************/
  327.  
  328.         // Create a scene object that will contain GUI components
  329.         HSceneObject guiSO = SceneObject::create("Example");
  330.  
  331.         // First we want another camera that is responsible for rendering GUI
  332.         HCamera guiCamera = guiSO->addComponent<Camera>(window);
  333.  
  334.         // Set up GUI camera properties.
  335.         // We don't care about aspect ratio for GUI camera.
  336.         guiCamera->setAspectRatio(1.0f);
  337.  
  338.         // This camera should ignore any Renderable objects in the scene
  339.         guiCamera->setIgnoreSceneRenderables(true);
  340.  
  341.         // Don't clear this camera as that would clear anything the main camera has rendered.
  342.         guiCamera->getViewport()->setRequiresClear(false, false, false);
  343.  
  344.         // Add a GUIWidget, the top-level GUI component, parent to all GUI elements. GUI widgets
  345.         // require you to specify a viewport that they will output rendered GUI elements to.
  346.         HGUIWidget gui = guiSO->addComponent<GUIWidget>(guiCamera->getViewport().get());
  347.  
  348.         // Depth allows you to control how is a GUI widget rendered in relation to other widgets
  349.         // Lower depth means the widget will be rendered in front of those with higher. In this case we just
  350.         // make the depth mid-range as there are no other widgets.
  351.         gui->setDepth(128);
  352.  
  353.         // GUI skin defines how are all child elements of the GUI widget renderer. It contains all their styles
  354.         // and default layout properties. We use the default skin that comes built into Banshee.
  355.         gui->setSkin(BuiltinResources::instance().getGUISkin());
  356.  
  357.         // Create a GUI area that is used for displaying messages about buttons for toggling profiler overlays.
  358.         // This area will stretch the entire surface of its parent widget, even if the widget is resized.
  359.         GUIArea* topArea = GUIArea::createStretchedXY(*gui, 0, 0, 0, 0);
  360.  
  361.         // Add a vertical layout that will automatically position any child elements top to bottom.
  362.         GUILayout& topLayout = topArea->getLayout().addLayoutY();
  363.  
  364.         // Add a couple of labels to the layout with the needed messages. Labels expect a HString object that
  365.         // maps into a string table and allows for easily localization.
  366.         topLayout.addElement(GUILabel::create(HString(L"Press F1 to toggle CPU profiler overlay")));
  367.         topLayout.addElement(GUILabel::create(HString(L"Press F2 to toggle GPU profiler overlay")));
  368.  
  369.         // Add a flexible space that fills up any remaining area in the area, making the two labels above be aligned
  370.         // to the top of the GUI widget (and the screen).
  371.         topLayout.addFlexibleSpace();
  372.  
  373.         // Create a GUI area that is used for displaying resolution and fullscreen options.
  374.         GUIArea* rightArea = GUIArea::createStretchedXY(*gui, 0, 0, 0, 0);
  375.  
  376.         // We want all the GUI elements be right aligned, so we add a flexible space first.
  377.         rightArea->getLayout().addFlexibleSpace();
  378.  
  379.         // And we want the elements to be vertically placed, top to bottom
  380.         GUILayout& rightLayout = rightArea->getLayout().addLayoutY();
  381.  
  382.         // Add an empty space of 50 pixels
  383.         rightLayout.addSpace(50);
  384.  
  385.         // Add a button that will trigger a callback when clicked
  386.         toggleFullscreenButton = GUIButton::create(HString(L"Toggle fullscreen"));
  387.         toggleFullscreenButton->onClick.connect(&toggleFullscreen);
  388.         rightLayout.addElement(toggleFullscreenButton);
  389.  
  390.         // Add a profiler overlay object that is resposible for displaying CPU and GPU profiling GUI
  391.         profilerOverlay = guiSO->addComponent<ProfilerOverlay>(guiCamera->getViewport());
  392.     }
  393.  
  394.     void toggleFullscreen()
  395.     {
  396.         RenderWindowPtr window = gApplication().getPrimaryWindow();
  397.  
  398.         // In order to toggle between full-screen and windowed mode we need to use a CoreAccessor.
  399.         // Banshee is a multi-threaded engine and when you need to communicate between simulation and
  400.         // core thread you will use a CoreAccessor. Calling a core accessor method will essentially
  401.         // queue the method to be executed later. Since RenderWindow is a core object you need to use
  402.         // CoreAccessor to modify and access it from simulation thread, except where noted otherwise.
  403.  
  404.         // Classes where it is not clear if they are to be used on the core or simulation thread have
  405.         // it noted in their documentation. e.g. RenderWindow::setWindowed method is marked as "Core only".
  406.         // Additional asserts are normally in place for debug builds which make it harder for you to accidentally
  407.         // call something from the wrong thread.
  408.         if (fullscreen)
  409.         {
  410.             gCoreAccessor().setWindowed(window, resolutionWidth, resolutionHeight);
  411.         }
  412.         else
  413.         {
  414.             gCoreAccessor().setFullscreen(window, 1920, 1200);
  415.         }
  416.  
  417.         fullscreen = !fullscreen;
  418.     }
  419.  
  420.     void buttonUp(const VirtualButton& button, UINT32 deviceIdx)
  421.     {
  422.         // Check if the pressed button is one of the either buttons we defined
  423.         // in "setUpExample", and toggle profiler overlays accordingly.
  424.         // Device index is ignored for now, as it is assumed the user is using a single keyboard,
  425.         // but if you wanted support for multiple gamepads you would check deviceIdx.
  426.         if (button == toggleCPUProfilerBtn)
  427.         {
  428.             if (cpuProfilerActive)
  429.             {
  430.                 profilerOverlay->hide();
  431.                 cpuProfilerActive = false;
  432.             }
  433.             else
  434.             {
  435.                 profilerOverlay->show(ProfilerOverlayType::CPUSamples);
  436.                 cpuProfilerActive = true;
  437.                 gpuProfilerActive = false;
  438.             }
  439.         }
  440.         else if (button == toggleGPUProfilerBtn)
  441.         {
  442.             if (gpuProfilerActive)
  443.             {
  444.                 profilerOverlay->hide();
  445.                 gpuProfilerActive = false;
  446.             }
  447.             else
  448.             {
  449.                 profilerOverlay->show(ProfilerOverlayType::GPUSamples);
  450.                 gpuProfilerActive = true;
  451.                 cpuProfilerActive = false;
  452.             }
  453.         }
  454.     }
  455. }
Advertisement
Add Comment
Please, Sign In to add comment