Renderer.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Renderer/Renderer.h>
  6. #include <Utils/Log.h>
  7. #include <shellscalingapi.h>
  8. static Renderer *sRenderer = nullptr;
  9. //--------------------------------------------------------------------------------------
  10. // Called every time the application receives a message
  11. //--------------------------------------------------------------------------------------
  12. static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  13. {
  14. PAINTSTRUCT ps;
  15. switch (message)
  16. {
  17. case WM_PAINT:
  18. BeginPaint(hWnd, &ps);
  19. EndPaint(hWnd, &ps);
  20. break;
  21. case WM_SIZE:
  22. if (sRenderer != nullptr)
  23. sRenderer->OnWindowResize();
  24. break;
  25. case WM_DESTROY:
  26. PostQuitMessage(0);
  27. break;
  28. default:
  29. return DefWindowProc(hWnd, message, wParam, lParam);
  30. }
  31. return 0;
  32. }
  33. void Renderer::Initialize()
  34. {
  35. // Prevent this window from auto scaling
  36. SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
  37. // Register class
  38. WNDCLASSEX wcex;
  39. wcex.cbSize = sizeof(WNDCLASSEX);
  40. wcex.style = CS_HREDRAW | CS_VREDRAW;
  41. wcex.lpfnWndProc = WndProc;
  42. wcex.cbClsExtra = 0;
  43. wcex.cbWndExtra = 0;
  44. wcex.hInstance = GetModuleHandle(nullptr);
  45. wcex.hIcon = nullptr;
  46. wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
  47. wcex.hbrBackground = nullptr;
  48. wcex.lpszMenuName = nullptr;
  49. wcex.lpszClassName = TEXT("TestFrameworkClass");
  50. wcex.hIconSm = nullptr;
  51. if (!RegisterClassEx(&wcex))
  52. FatalError("Failed to register window class");
  53. // Create window
  54. RECT rc = { 0, 0, mWindowWidth, mWindowHeight };
  55. AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
  56. mhWnd = CreateWindow(TEXT("TestFrameworkClass"), TEXT("TestFramework"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
  57. rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, wcex.hInstance, nullptr);
  58. if (!mhWnd)
  59. FatalError("Failed to create window");
  60. // Show window
  61. ShowWindow(mhWnd, SW_SHOW);
  62. // Store global renderer now that we're done initializing
  63. sRenderer = this;
  64. }
  65. void Renderer::OnWindowResize()
  66. {
  67. JPH_ASSERT(!mInFrame);
  68. // Get new window size
  69. RECT rc;
  70. GetClientRect(mhWnd, &rc);
  71. mWindowWidth = max<LONG>(rc.right - rc.left, 8);
  72. mWindowHeight = max<LONG>(rc.bottom - rc.top, 8);
  73. }
  74. static Mat44 sPerspectiveInfiniteReverseZ(float inFovY, float inAspect, float inNear, float inYSign)
  75. {
  76. float height = 1.0f / Tan(0.5f * inFovY);
  77. float width = height / inAspect;
  78. return Mat44(Vec4(width, 0.0f, 0.0f, 0.0f), Vec4(0.0f, inYSign * height, 0.0f, 0.0f), Vec4(0.0f, 0.0f, 0.0f, -1.0f), Vec4(0.0f, 0.0f, inNear, 0.0f));
  79. }
  80. void Renderer::BeginFrame(const CameraState &inCamera, float inWorldScale)
  81. {
  82. // Mark that we're in the frame
  83. JPH_ASSERT(!mInFrame);
  84. mInFrame = true;
  85. // Store state
  86. mCameraState = inCamera;
  87. // Light properties
  88. Vec3 light_pos = inWorldScale * Vec3(250, 250, 250);
  89. Vec3 light_tgt = Vec3::sZero();
  90. Vec3 light_up = Vec3(0, 1, 0);
  91. Vec3 light_fwd = (light_tgt - light_pos).Normalized();
  92. float light_fov = DegreesToRadians(20.0f);
  93. float light_near = 1.0f;
  94. // Camera properties
  95. Vec3 cam_pos = Vec3(inCamera.mPos - mBaseOffset);
  96. float camera_fovy = inCamera.mFOVY;
  97. float camera_aspect = static_cast<float>(GetWindowWidth()) / GetWindowHeight();
  98. float camera_fovx = 2.0f * ATan(camera_aspect * Tan(0.5f * camera_fovy));
  99. float camera_near = 0.01f * inWorldScale;
  100. // Calculate camera frustum
  101. mCameraFrustum = Frustum(cam_pos, inCamera.mForward, inCamera.mUp, camera_fovx, camera_fovy, camera_near);
  102. // Calculate light frustum
  103. mLightFrustum = Frustum(light_pos, light_fwd, light_up, light_fov, light_fov, light_near);
  104. // Camera projection and view
  105. mVSBuffer.mProjection = sPerspectiveInfiniteReverseZ(camera_fovy, camera_aspect, camera_near, mPerspectiveYSign);
  106. Vec3 tgt = cam_pos + inCamera.mForward;
  107. mVSBuffer.mView = Mat44::sLookAt(cam_pos, tgt, inCamera.mUp);
  108. // Light projection and view
  109. mVSBuffer.mLightProjection = sPerspectiveInfiniteReverseZ(light_fov, 1.0f, light_near, mPerspectiveYSign);
  110. mVSBuffer.mLightView = Mat44::sLookAt(light_pos, light_tgt, light_up);
  111. // Camera ortho projection and view
  112. mVSBufferOrtho.mProjection = Mat44(Vec4(2.0f / mWindowWidth, 0.0f, 0.0f, 0.0f), Vec4(0.0f, -mPerspectiveYSign * 2.0f / mWindowHeight, 0.0f, 0.0f), Vec4(0.0f, 0.0f, -1.0f, 0.0f), Vec4(-1.0f, mPerspectiveYSign * 1.0f, 0.0f, 1.0f));
  113. mVSBufferOrtho.mView = Mat44::sIdentity();
  114. // Light projection and view are unused in ortho mode
  115. mVSBufferOrtho.mLightView = Mat44::sIdentity();
  116. mVSBufferOrtho.mLightProjection = Mat44::sIdentity();
  117. // Set constants for pixel shader
  118. mPSBuffer.mCameraPos = Vec4(cam_pos, 0);
  119. mPSBuffer.mLightPos = Vec4(light_pos, 0);
  120. }
  121. void Renderer::EndFrame()
  122. {
  123. // Mark that we're no longer in the frame
  124. JPH_ASSERT(mInFrame);
  125. mInFrame = false;
  126. }