Main.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsApplication.h"
  4. #include "Material/BsMaterial.h"
  5. #include "CoreThread/BsCoreThread.h"
  6. #include "RenderAPI/BsRenderAPI.h"
  7. #include "RenderAPI/BsRenderWindow.h"
  8. #include "RenderAPI/BsCommandBuffer.h"
  9. #include "RenderAPI/BsGpuProgram.h"
  10. #include "RenderAPI/BsGpuPipelineState.h"
  11. #include "RenderAPI/BsBlendState.h"
  12. #include "RenderAPI/BsDepthStencilState.h"
  13. #include "RenderAPI/BsGpuParamBlockBuffer.h"
  14. #include "RenderAPI/BsIndexBuffer.h"
  15. #include "RenderAPI/BsVertexDataDesc.h"
  16. #include "Mesh/BsMeshData.h"
  17. #include "Math/BsQuaternion.h"
  18. #include "Utility/BsTime.h"
  19. #include "Renderer/BsRendererUtility.h"
  20. #include "BsEngineConfig.h"
  21. #if BS_PLATFORM == BS_PLATFORM_WIN32
  22. #include <windows.h>
  23. #endif
  24. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  25. // This example uses the low-level rendering API to render a textured cube mesh. This is opposed to using scene objects
  26. // and components, in which case objects are rendered automatically based on their transform and other properties.
  27. //
  28. // Using low-level rendering API gives you full control over rendering, similar to using Vulkan, DirectX or OpenGL APIs.
  29. //
  30. // In order to use the low-level rendering system we need to override the Application class so we get notified of updates
  31. // and start-up/shut-down events. This is normally not necessary for a high level scene object based model.
  32. //
  33. // The rendering is performed on the core (i.e. rendering) thread, as opposed to the main thread, where majority of
  34. // Banshee's code executes.
  35. //
  36. // The example first sets up necessary resources, like GPU programs, pipeline state, vertex & index buffers. Then every
  37. // frame it binds the necessary rendering resources and executes the draw call.
  38. //
  39. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  40. namespace bs
  41. {
  42. UINT32 windowResWidth = 1280;
  43. UINT32 windowResHeight = 720;
  44. // Declare the methods we'll use to do work on the core thread. Note the "ct" namespace, which we use because we render
  45. // on the core thread (ct = core thread). Every object usable on the core thread lives in this namespace.
  46. namespace ct
  47. {
  48. void setup(const SPtr<RenderWindow>& renderWindow);
  49. void render();
  50. void shutdown();
  51. }
  52. // Override the default Application so we can get notified when engine starts-up, shuts-down and when it executes
  53. // every frame
  54. class MyApplication : public Application
  55. {
  56. public:
  57. // Pass along the start-up structure to the parent, we don't need to handle it
  58. MyApplication(const START_UP_DESC& desc)
  59. :Application(desc)
  60. { }
  61. private:
  62. // Called when the engine is first started up
  63. void onStartUp() override
  64. {
  65. // Ensure all parent systems are initialized first
  66. Application::onStartUp();
  67. // Get the primary window that was created during start-up. This will be the final destination for all our
  68. // rendering.
  69. SPtr<RenderWindow> renderWindow = getPrimaryWindow();
  70. // Get the version of the render window usable on the core thread, and send it along to setup()
  71. SPtr<ct::RenderWindow> renderWindowCore = renderWindow->getCore();
  72. // Initialize all the resources we need for rendering. Since we do rendering on a separate thread (the "core
  73. // thread"), we don't call the method directly, but rather queue it for execution using the CoreThread class.
  74. gCoreThread().queueCommand(std::bind(&ct::setup, renderWindowCore));
  75. }
  76. // Called when the engine is about to be shut down
  77. void onShutDown() override
  78. {
  79. gCoreThread().queueCommand(&ct::shutdown);
  80. // Shut-down engine components
  81. Application::onShutDown();
  82. }
  83. // Called every frame, before any other engine system (optionally use postUpdate())
  84. void preUpdate() override
  85. {
  86. gCoreThread().queueCommand(&ct::render);
  87. }
  88. };
  89. }
  90. using namespace bs;
  91. // Main entry point into the application
  92. #if BS_PLATFORM == BS_PLATFORM_WIN32
  93. int CALLBACK WinMain(
  94. _In_ HINSTANCE hInstance,
  95. _In_ HINSTANCE hPrevInstance,
  96. _In_ LPSTR lpCmdLine,
  97. _In_ int nCmdShow
  98. )
  99. #else
  100. int main()
  101. #endif
  102. {
  103. // Define a video mode for the resolution of the primary rendering window.
  104. VideoMode videoMode(windowResWidth, windowResHeight);
  105. // Start-up the engine using our custom MyApplication class. This will also create the primary rendering window.
  106. // We provide the initial resolution of the window, its title and fullscreen state.
  107. Application::startUp<MyApplication>(videoMode, "Banshee Example App", false);
  108. // Runs the main loop that does most of the work. This method will exit when user closes the main
  109. // window or exits in some other way.
  110. Application::instance().runMainLoop();
  111. Application::shutDown();
  112. return 0;
  113. }
  114. namespace bs { namespace ct
  115. {
  116. // Declarations for some helper methods we'll use during setup
  117. void writeBoxVertices(const AABox& box, UINT8* positions, UINT8* uvs, UINT32 stride);
  118. void writeBoxIndices(UINT32* indices);
  119. const char* getVertexProgSource();
  120. const char* getFragmentProgSource();
  121. Matrix4 createWorldViewProjectionMatrix();
  122. // Fields where we'll store the resources required during calls to render(). These are initialized in setup()
  123. // and cleaned up in shutDown()
  124. SPtr<GraphicsPipelineState> gPipelineState;
  125. SPtr<Texture> gSurfaceTex;
  126. SPtr<SamplerState> gSurfaceSampler;
  127. SPtr<GpuParams> gGpuParams;
  128. SPtr<VertexDeclaration> gVertexDecl;
  129. SPtr<VertexBuffer> gVertexBuffer;
  130. SPtr<IndexBuffer> gIndexBuffer;
  131. SPtr<RenderTexture> gRenderTarget;
  132. SPtr<RenderWindow> gRenderWindow;
  133. bool gUseHLSL = true;
  134. bool gUseVKSL = false;
  135. const UINT32 NUM_VERTICES = 24;
  136. const UINT32 NUM_INDICES = 36;
  137. // Structure that will hold uniform block variables for the GPU programs
  138. struct UniformBlock
  139. {
  140. Matrix4 gMatWVP; // World view projection matrix
  141. Color gTint; // Tint to apply on top of the texture
  142. };
  143. // Initializes any resources required for rendering
  144. void setup(const SPtr<RenderWindow>& renderWindow)
  145. {
  146. // Determine which shading language to use (depending on the RenderAPI chosen during build)
  147. gUseHLSL = strcmp(BS_RENDER_API_MODULE, "BansheeD3D11RenderAPI") == 0;
  148. gUseVKSL = strcmp(BS_RENDER_API_MODULE, "BansheeVulkanRenderAPI") == 0;
  149. // This will be the primary output for our rendering (created by the main thread on start-up)
  150. gRenderWindow = renderWindow;
  151. // Create a vertex GPU program
  152. const char* vertProgSrc = getVertexProgSource();
  153. GPU_PROGRAM_DESC vertProgDesc;
  154. vertProgDesc.type = GPT_VERTEX_PROGRAM;
  155. vertProgDesc.entryPoint = "main";
  156. vertProgDesc.language = gUseHLSL ? "hlsl" : gUseVKSL ? "vksl" : "glsl4_1";
  157. vertProgDesc.source = vertProgSrc;
  158. SPtr<GpuProgram> vertProg = GpuProgram::create(vertProgDesc);
  159. // Create a fragment GPU program
  160. const char* fragProgSrc = getFragmentProgSource();
  161. GPU_PROGRAM_DESC fragProgDesc;
  162. fragProgDesc.type = GPT_FRAGMENT_PROGRAM;
  163. fragProgDesc.entryPoint = "main";
  164. fragProgDesc.language = gUseHLSL ? "hlsl" : gUseVKSL ? "vksl" : "glsl4_1";
  165. fragProgDesc.source = fragProgSrc;
  166. SPtr<GpuProgram> fragProg = GpuProgram::create(fragProgDesc);
  167. // Create a graphics pipeline state
  168. BLEND_STATE_DESC blendDesc;
  169. blendDesc.renderTargetDesc[0].blendEnable = true;
  170. blendDesc.renderTargetDesc[0].renderTargetWriteMask = 0b0111; // RGB, don't write to alpha
  171. blendDesc.renderTargetDesc[0].blendOp = BO_ADD;
  172. blendDesc.renderTargetDesc[0].srcBlend = BF_SOURCE_ALPHA;
  173. blendDesc.renderTargetDesc[0].dstBlend = BF_INV_SOURCE_ALPHA;
  174. DEPTH_STENCIL_STATE_DESC depthStencilDesc;
  175. depthStencilDesc.depthWriteEnable = false;
  176. depthStencilDesc.depthReadEnable = false;
  177. PIPELINE_STATE_DESC pipelineDesc;
  178. pipelineDesc.blendState = BlendState::create(blendDesc);
  179. pipelineDesc.depthStencilState = DepthStencilState::create(depthStencilDesc);
  180. pipelineDesc.vertexProgram = vertProg;
  181. pipelineDesc.fragmentProgram = fragProg;
  182. gPipelineState = GraphicsPipelineState::create(pipelineDesc);
  183. // Create an object containing GPU program parameters
  184. gGpuParams = GpuParams::create(gPipelineState);
  185. // Create a vertex declaration for shader inputs
  186. SPtr<VertexDataDesc> vertexDesc = VertexDataDesc::create();
  187. vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  188. vertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
  189. gVertexDecl = VertexDeclaration::create(vertexDesc);
  190. // Create & fill the vertex buffer for a box mesh
  191. UINT32 vertexStride = vertexDesc->getVertexStride();
  192. VERTEX_BUFFER_DESC vbDesc;
  193. vbDesc.numVerts = NUM_VERTICES;
  194. vbDesc.vertexSize = vertexStride;
  195. gVertexBuffer = VertexBuffer::create(vbDesc);
  196. UINT8* vbData = (UINT8*)gVertexBuffer->lock(0, vertexStride * NUM_VERTICES, GBL_WRITE_ONLY_DISCARD);
  197. UINT8* positions = vbData + vertexDesc->getElementOffsetFromStream(VES_POSITION);
  198. UINT8* uvs = vbData + vertexDesc->getElementOffsetFromStream(VES_TEXCOORD);
  199. AABox box(Vector3::ONE * -10.0f, Vector3::ONE * 10.0f);
  200. writeBoxVertices(box, positions, uvs, vertexStride);
  201. gVertexBuffer->unlock();
  202. // Create & fill the index buffer for a box mesh
  203. INDEX_BUFFER_DESC ibDesc;
  204. ibDesc.numIndices = NUM_INDICES;
  205. ibDesc.indexType = IT_32BIT;
  206. gIndexBuffer = IndexBuffer::create(ibDesc);
  207. UINT32* ibData = (UINT32*)gIndexBuffer->lock(0, NUM_INDICES * sizeof(UINT32), GBL_WRITE_ONLY_DISCARD);
  208. writeBoxIndices(ibData);
  209. gIndexBuffer->unlock();
  210. // Create a simple 2x2 checkerboard texture to map to the object we're about to render
  211. SPtr<PixelData> pixelData = PixelData::create(2, 2, 1, PF_RGBA8);
  212. pixelData->setColorAt(Color::White, 0, 0);
  213. pixelData->setColorAt(Color::Black, 1, 0);
  214. pixelData->setColorAt(Color::White, 1, 1);
  215. pixelData->setColorAt(Color::Black, 0, 1);
  216. gSurfaceTex = Texture::create(pixelData);
  217. // Create a sampler state for the texture above
  218. SAMPLER_STATE_DESC samplerDesc;
  219. samplerDesc.minFilter = FO_POINT;
  220. samplerDesc.magFilter = FO_POINT;
  221. gSurfaceSampler = SamplerState::create(samplerDesc);
  222. // Create a color attachment texture for the render surface
  223. TEXTURE_DESC colorAttDesc;
  224. colorAttDesc.width = windowResWidth;
  225. colorAttDesc.height = windowResHeight;
  226. colorAttDesc.format = PF_RGBA8;
  227. colorAttDesc.usage = TU_RENDERTARGET;
  228. SPtr<Texture> colorAtt = Texture::create(colorAttDesc);
  229. // Create a depth attachment texture for the render surface
  230. TEXTURE_DESC depthAttDesc;
  231. depthAttDesc.width = windowResWidth;
  232. depthAttDesc.height = windowResHeight;
  233. depthAttDesc.format = PF_D32;
  234. depthAttDesc.usage = TU_DEPTHSTENCIL;
  235. SPtr<Texture> depthAtt = Texture::create(depthAttDesc);
  236. // Create the render surface
  237. RENDER_TEXTURE_DESC desc;
  238. desc.colorSurfaces[0].texture = colorAtt;
  239. desc.depthStencilSurface.texture = depthAtt;
  240. gRenderTarget = RenderTexture::create(desc);
  241. }
  242. // Render the box, called every frame
  243. void render()
  244. {
  245. // Fill out the uniform block variables
  246. UniformBlock uniformBlock;
  247. uniformBlock.gMatWVP = createWorldViewProjectionMatrix();
  248. uniformBlock.gTint = Color(1.0f, 1.0f, 1.0f, 0.5f);
  249. // Create a uniform block buffer for holding the uniform variables
  250. SPtr<GpuParamBlockBuffer> uniformBuffer = GpuParamBlockBuffer::create(sizeof(UniformBlock));
  251. uniformBuffer->write(0, &uniformBlock, sizeof(uniformBlock));
  252. // Assign the uniform buffer & texture
  253. gGpuParams->setParamBlockBuffer(GPT_FRAGMENT_PROGRAM, "Params", uniformBuffer);
  254. gGpuParams->setParamBlockBuffer(GPT_VERTEX_PROGRAM, "Params", uniformBuffer);
  255. gGpuParams->setTexture(GPT_FRAGMENT_PROGRAM, "gMainTexture", gSurfaceTex);
  256. // HLSL uses separate sampler states, so we need to use a different name for the sampler
  257. if(gUseHLSL)
  258. gGpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gMainTexSamp", gSurfaceSampler);
  259. else
  260. gGpuParams->setSamplerState(GPT_FRAGMENT_PROGRAM, "gMainTexture", gSurfaceSampler);
  261. // Create a command buffer
  262. SPtr<CommandBuffer> cmds = CommandBuffer::create(GQT_GRAPHICS);
  263. // Get the primary render API access point
  264. RenderAPI& rapi = RenderAPI::instance();
  265. // Bind render surface & clear it
  266. rapi.setRenderTarget(gRenderTarget, 0, RT_NONE, cmds);
  267. rapi.clearRenderTarget(FBT_COLOR | FBT_DEPTH, Color::Blue, 1, 0, 0xFF, cmds);
  268. // Bind the pipeline state
  269. rapi.setGraphicsPipeline(gPipelineState, cmds);
  270. // Set the vertex & index buffers, as well as vertex declaration and draw type
  271. rapi.setVertexBuffers(0, &gVertexBuffer, 1, cmds);
  272. rapi.setIndexBuffer(gIndexBuffer, cmds);
  273. rapi.setVertexDeclaration(gVertexDecl, cmds);
  274. rapi.setDrawOperation(DOT_TRIANGLE_LIST, cmds);
  275. // Bind the GPU program parameters (i.e. resource descriptors)
  276. rapi.setGpuParams(gGpuParams, cmds);
  277. // Draw
  278. rapi.drawIndexed(0, NUM_INDICES, 0, NUM_VERTICES, 1, cmds);
  279. // Submit the command buffer
  280. rapi.submitCommandBuffer(cmds);
  281. // Blit the image from the render texture, to the render window
  282. rapi.setRenderTarget(gRenderWindow);
  283. // Get the color attachment
  284. SPtr<Texture> colorTexture = gRenderTarget->getColorTexture(0);
  285. // Use the helper RendererUtility to draw a full-screen quad of the provided texture and output it to the currently
  286. // bound render target. Internally this uses the same calls we used above, just with a different pipeline and mesh.
  287. gRendererUtility().blit(colorTexture);
  288. // Present the rendered image to the user
  289. rapi.swapBuffers(gRenderWindow);
  290. }
  291. // Clean up any resources
  292. void shutdown()
  293. {
  294. gPipelineState = nullptr;
  295. gSurfaceTex = nullptr;
  296. gGpuParams = nullptr;
  297. gVertexDecl = nullptr;
  298. gVertexBuffer = nullptr;
  299. gIndexBuffer = nullptr;
  300. gRenderTarget = nullptr;
  301. gRenderWindow = nullptr;
  302. gSurfaceSampler = nullptr;
  303. }
  304. /////////////////////////////////////////////////////////////////////////////////////
  305. //////////////////////////////////HELPER METHODS/////////////////////////////////////
  306. /////////////////////////////////////////////////////////////////////////////////////
  307. void writeBoxVertices(const AABox& box, UINT8* positions, UINT8* uvs, UINT32 stride)
  308. {
  309. AABox::Corner vertOrder[] =
  310. {
  311. AABox::NEAR_LEFT_BOTTOM, AABox::NEAR_RIGHT_BOTTOM, AABox::NEAR_RIGHT_TOP, AABox::NEAR_LEFT_TOP,
  312. AABox::FAR_RIGHT_BOTTOM, AABox::FAR_LEFT_BOTTOM, AABox::FAR_LEFT_TOP, AABox::FAR_RIGHT_TOP,
  313. AABox::FAR_LEFT_BOTTOM, AABox::NEAR_LEFT_BOTTOM, AABox::NEAR_LEFT_TOP, AABox::FAR_LEFT_TOP,
  314. AABox::NEAR_RIGHT_BOTTOM, AABox::FAR_RIGHT_BOTTOM, AABox::FAR_RIGHT_TOP, AABox::NEAR_RIGHT_TOP,
  315. AABox::FAR_LEFT_TOP, AABox::NEAR_LEFT_TOP, AABox::NEAR_RIGHT_TOP, AABox::FAR_RIGHT_TOP,
  316. AABox::FAR_LEFT_BOTTOM, AABox::FAR_RIGHT_BOTTOM, AABox::NEAR_RIGHT_BOTTOM, AABox::NEAR_LEFT_BOTTOM
  317. };
  318. for (auto& entry : vertOrder)
  319. {
  320. Vector3 pos = box.getCorner(entry);
  321. memcpy(positions, &pos, sizeof(pos));
  322. positions += stride;
  323. }
  324. for (UINT32 i = 0; i < 6; i++)
  325. {
  326. Vector2 uv;
  327. uv = Vector2(0.0f, 1.0f);
  328. memcpy(uvs, &uv, sizeof(uv));
  329. uvs += stride;
  330. uv = Vector2(1.0f, 1.0f);
  331. memcpy(uvs, &uv, sizeof(uv));
  332. uvs += stride;
  333. uv = Vector2(1.0f, 0.0f);
  334. memcpy(uvs, &uv, sizeof(uv));
  335. uvs += stride;
  336. uv = Vector2(0.0f, 0.0f);
  337. memcpy(uvs, &uv, sizeof(uv));
  338. uvs += stride;
  339. }
  340. }
  341. void writeBoxIndices(UINT32* indices)
  342. {
  343. for (UINT32 face = 0; face < 6; face++)
  344. {
  345. UINT32 faceVertOffset = face * 4;
  346. indices[face * 6 + 0] = faceVertOffset + 2;
  347. indices[face * 6 + 1] = faceVertOffset + 1;
  348. indices[face * 6 + 2] = faceVertOffset + 0;
  349. indices[face * 6 + 3] = faceVertOffset + 0;
  350. indices[face * 6 + 4] = faceVertOffset + 3;
  351. indices[face * 6 + 5] = faceVertOffset + 2;
  352. }
  353. }
  354. const char* getVertexProgSource()
  355. {
  356. if(gUseHLSL)
  357. {
  358. static const char* src = R"(
  359. cbuffer Params
  360. {
  361. float4x4 gMatWVP;
  362. float4 gTint;
  363. }
  364. void main(
  365. in float3 inPos : POSITION,
  366. in float2 uv : TEXCOORD0,
  367. out float4 oPosition : SV_Position,
  368. out float2 oUv : TEXCOORD0)
  369. {
  370. oPosition = mul(gMatWVP, float4(inPos.xyz, 1));
  371. oUv = uv;
  372. }
  373. )";
  374. return src;
  375. }
  376. else if(gUseVKSL)
  377. {
  378. static const char* src = R"(
  379. layout (binding = 0, std140) uniform Params
  380. {
  381. mat4 gMatWVP;
  382. vec4 gTint;
  383. };
  384. layout (location = 0) in vec3 bs_position;
  385. layout (location = 1) in vec2 bs_texcoord0;
  386. layout (location = 0) out vec2 texcoord0;
  387. out gl_PerVertex
  388. {
  389. vec4 gl_Position;
  390. };
  391. void main()
  392. {
  393. gl_Position = gMatWVP * vec4(bs_position.xyz, 1);
  394. texcoord0 = bs_texcoord0;
  395. }
  396. )";
  397. return src;
  398. }
  399. else
  400. {
  401. static const char* src = R"(
  402. layout (std140) uniform Params
  403. {
  404. mat4 gMatWVP;
  405. vec4 gTint;
  406. };
  407. in vec3 bs_position;
  408. in vec2 bs_texcoord0;
  409. out vec2 texcoord0;
  410. out gl_PerVertex
  411. {
  412. vec4 gl_Position;
  413. };
  414. void main()
  415. {
  416. gl_Position = gMatWVP * vec4(bs_position.xyz, 1);
  417. texcoord0 = bs_texcoord0;
  418. }
  419. )";
  420. return src;
  421. }
  422. }
  423. const char* getFragmentProgSource()
  424. {
  425. if (gUseHLSL)
  426. {
  427. static const char* src = R"(
  428. cbuffer Params
  429. {
  430. float4x4 gMatWVP;
  431. float4 gTint;
  432. }
  433. SamplerState gMainTexSamp : register(s0);
  434. Texture2D gMainTexture : register(t0);
  435. float4 main(in float4 inPos : SV_Position, float2 uv : TEXCOORD0) : SV_Target
  436. {
  437. float4 color = gMainTexture.Sample(gMainTexSamp, uv);
  438. return color * gTint;
  439. }
  440. )";
  441. return src;
  442. }
  443. else if(gUseVKSL)
  444. {
  445. static const char* src = R"(
  446. layout (binding = 0, std140) uniform Params
  447. {
  448. mat4 gMatWVP;
  449. vec4 gTint;
  450. };
  451. layout (binding = 1) uniform sampler2D gMainTexture;
  452. layout (location = 0) in vec2 texcoord0;
  453. layout (location = 0) out vec4 fragColor;
  454. void main()
  455. {
  456. vec4 color = texture(gMainTexture, texcoord0.st);
  457. fragColor = color * gTint;
  458. }
  459. )";
  460. return src;
  461. }
  462. else
  463. {
  464. static const char* src = R"(
  465. layout (std140) uniform Params
  466. {
  467. mat4 gMatWVP;
  468. vec4 gTint;
  469. };
  470. uniform sampler2D gMainTexture;
  471. in vec2 texcoord0;
  472. out vec4 fragColor;
  473. void main()
  474. {
  475. vec4 color = texture(gMainTexture, texcoord0.st);
  476. fragColor = color * gTint;
  477. }
  478. )";
  479. return src;
  480. }
  481. }
  482. Matrix4 createWorldViewProjectionMatrix()
  483. {
  484. Matrix4 proj = Matrix4::projectionPerspective(Degree(75.0f), 16.0f / 9.0f, 0.05f, 1000.0f);
  485. bs::RenderAPI::convertProjectionMatrix(proj, proj);
  486. Vector3 cameraPos = Vector3(0.0f, -20.0f, 50.0f);
  487. Vector3 lookDir = -Vector3::normalize(cameraPos);
  488. Quaternion cameraRot(BsIdentity);
  489. cameraRot.lookRotation(lookDir);
  490. Matrix4 view = Matrix4::view(cameraPos, cameraRot);
  491. Quaternion rotation(Vector3::UNIT_Y, Degree(gTime().getTime() * 90.0f));
  492. Matrix4 world = Matrix4::TRS(Vector3::ZERO, rotation, Vector3::ONE);
  493. Matrix4 viewProj = proj * view * world;
  494. // GLSL uses column major matrices, so transpose
  495. if(!gUseHLSL)
  496. viewProj = viewProj.transpose();
  497. return viewProj;
  498. }
  499. }}