Renderer.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. static Renderer *sRenderer = nullptr;
  8. #ifdef JPH_PLATFORM_WINDOWS
  9. #include <shellscalingapi.h>
  10. //--------------------------------------------------------------------------------------
  11. // Called every time the application receives a message
  12. //--------------------------------------------------------------------------------------
  13. static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  14. {
  15. PAINTSTRUCT ps;
  16. switch (message)
  17. {
  18. case WM_PAINT:
  19. BeginPaint(hWnd, &ps);
  20. EndPaint(hWnd, &ps);
  21. break;
  22. case WM_SIZE:
  23. if (sRenderer != nullptr)
  24. sRenderer->OnWindowResize();
  25. break;
  26. case WM_DESTROY:
  27. PostQuitMessage(0);
  28. break;
  29. default:
  30. return DefWindowProc(hWnd, message, wParam, lParam);
  31. }
  32. return 0;
  33. }
  34. #endif // JPH_PLATFORM_WINDOWS
  35. void Renderer::Initialize()
  36. {
  37. #ifdef JPH_PLATFORM_WINDOWS
  38. // Prevent this window from auto scaling
  39. SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
  40. // Register class
  41. WNDCLASSEX wcex;
  42. wcex.cbSize = sizeof(WNDCLASSEX);
  43. wcex.style = CS_HREDRAW | CS_VREDRAW;
  44. wcex.lpfnWndProc = WndProc;
  45. wcex.cbClsExtra = 0;
  46. wcex.cbWndExtra = 0;
  47. wcex.hInstance = GetModuleHandle(nullptr);
  48. wcex.hIcon = nullptr;
  49. wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
  50. wcex.hbrBackground = nullptr;
  51. wcex.lpszMenuName = nullptr;
  52. wcex.lpszClassName = TEXT("TestFrameworkClass");
  53. wcex.hIconSm = nullptr;
  54. if (!RegisterClassEx(&wcex))
  55. FatalError("Failed to register window class");
  56. // Create window
  57. RECT rc = { 0, 0, mWindowWidth, mWindowHeight };
  58. AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
  59. mhWnd = CreateWindow(TEXT("TestFrameworkClass"), TEXT("TestFramework"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
  60. rc.right - rc.left, rc.bottom - rc.top, nullptr, nullptr, wcex.hInstance, nullptr);
  61. if (!mhWnd)
  62. FatalError("Failed to create window");
  63. // Show window
  64. ShowWindow(mhWnd, SW_SHOW);
  65. #elif defined(JPH_PLATFORM_LINUX)
  66. // Open connection to X server
  67. mDisplay = XOpenDisplay(nullptr);
  68. if (!mDisplay)
  69. FatalError("Failed to open X display");
  70. // Create a simple window
  71. int screen = DefaultScreen(mDisplay);
  72. mWindow = XCreateSimpleWindow(mDisplay, RootWindow(mDisplay, screen), 0, 0, mWindowWidth, mWindowHeight, 1, BlackPixel(mDisplay, screen), WhitePixel(mDisplay, screen));
  73. // Select input events
  74. XSelectInput(mDisplay, mWindow, ExposureMask | StructureNotifyMask | KeyPressMask);
  75. // Set window title
  76. XStoreName(mDisplay, mWindow, "TestFramework");
  77. // Register WM_DELETE_WINDOW to handle the close button
  78. mWmDeleteWindow = XInternAtom(mDisplay, "WM_DELETE_WINDOW", false);
  79. XSetWMProtocols(mDisplay, mWindow, &mWmDeleteWindow, 1);
  80. // Map the window (make it visible)
  81. XMapWindow(mDisplay, mWindow);
  82. // Flush the display to ensure commands are executed
  83. XFlush(mDisplay);
  84. #else
  85. #error Unsupported platform
  86. #endif
  87. // Store global renderer now that we're done initializing
  88. sRenderer = this;
  89. }
  90. bool Renderer::WindowUpdate()
  91. {
  92. #ifdef JPH_PLATFORM_WINDOWS
  93. // Main message loop
  94. MSG msg = {};
  95. while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
  96. {
  97. TranslateMessage(&msg);
  98. DispatchMessage(&msg);
  99. if (msg.message == WM_QUIT)
  100. {
  101. // Handle quit events
  102. return false;
  103. }
  104. }
  105. #elif defined(JPH_PLATFORM_LINUX)
  106. while (XPending(mDisplay) > 0)
  107. {
  108. XEvent event;
  109. XNextEvent(mDisplay, &event);
  110. if (event.type == ClientMessage && static_cast<Atom>(event.xclient.data.l[0]) == mWmDeleteWindow)
  111. {
  112. // Handle quit events
  113. return false;
  114. }
  115. else if (event.type == ConfigureNotify)
  116. {
  117. // Handle window resize events
  118. XConfigureEvent xce = event.xconfigure;
  119. if (xce.width != mWindowWidth || xce.height != mWindowHeight)
  120. {
  121. mWindowWidth = xce.width;
  122. mWindowHeight = xce.height;
  123. OnWindowResize();
  124. }
  125. }
  126. else
  127. mEventListener(event);
  128. }
  129. #else
  130. #error Unsupported platform
  131. #endif
  132. // Application should continue
  133. return true;
  134. }
  135. void Renderer::OnWindowResize()
  136. {
  137. JPH_ASSERT(!mInFrame);
  138. #ifdef JPH_PLATFORM_WINDOWS
  139. // Get new window size
  140. RECT rc;
  141. GetClientRect(mhWnd, &rc);
  142. mWindowWidth = max<LONG>(rc.right - rc.left, 8);
  143. mWindowHeight = max<LONG>(rc.bottom - rc.top, 8);
  144. #endif
  145. }
  146. static Mat44 sPerspectiveInfiniteReverseZ(float inFovY, float inAspect, float inNear, float inYSign)
  147. {
  148. float height = 1.0f / Tan(0.5f * inFovY);
  149. float width = height / inAspect;
  150. 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));
  151. }
  152. void Renderer::BeginFrame(const CameraState &inCamera, float inWorldScale)
  153. {
  154. // Mark that we're in the frame
  155. JPH_ASSERT(!mInFrame);
  156. mInFrame = true;
  157. // Store state
  158. mCameraState = inCamera;
  159. // Light properties
  160. Vec3 light_pos = inWorldScale * Vec3(250, 250, 250);
  161. Vec3 light_tgt = Vec3::sZero();
  162. Vec3 light_up = Vec3(0, 1, 0);
  163. Vec3 light_fwd = (light_tgt - light_pos).Normalized();
  164. float light_fov = DegreesToRadians(20.0f);
  165. float light_near = 1.0f;
  166. // Camera properties
  167. Vec3 cam_pos = Vec3(inCamera.mPos - mBaseOffset);
  168. float camera_fovy = inCamera.mFOVY;
  169. float camera_aspect = static_cast<float>(GetWindowWidth()) / GetWindowHeight();
  170. float camera_fovx = 2.0f * ATan(camera_aspect * Tan(0.5f * camera_fovy));
  171. float camera_near = 0.01f * inWorldScale;
  172. // Calculate camera frustum
  173. mCameraFrustum = Frustum(cam_pos, inCamera.mForward, inCamera.mUp, camera_fovx, camera_fovy, camera_near);
  174. // Calculate light frustum
  175. mLightFrustum = Frustum(light_pos, light_fwd, light_up, light_fov, light_fov, light_near);
  176. // Camera projection and view
  177. mVSBuffer.mProjection = sPerspectiveInfiniteReverseZ(camera_fovy, camera_aspect, camera_near, mPerspectiveYSign);
  178. Vec3 tgt = cam_pos + inCamera.mForward;
  179. mVSBuffer.mView = Mat44::sLookAt(cam_pos, tgt, inCamera.mUp);
  180. // Light projection and view
  181. mVSBuffer.mLightProjection = sPerspectiveInfiniteReverseZ(light_fov, 1.0f, light_near, mPerspectiveYSign);
  182. mVSBuffer.mLightView = Mat44::sLookAt(light_pos, light_tgt, light_up);
  183. // Camera ortho projection and view
  184. 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));
  185. mVSBufferOrtho.mView = Mat44::sIdentity();
  186. // Light projection and view are unused in ortho mode
  187. mVSBufferOrtho.mLightView = Mat44::sIdentity();
  188. mVSBufferOrtho.mLightProjection = Mat44::sIdentity();
  189. // Set constants for pixel shader
  190. mPSBuffer.mCameraPos = Vec4(cam_pos, 0);
  191. mPSBuffer.mLightPos = Vec4(light_pos, 0);
  192. }
  193. void Renderer::EndFrame()
  194. {
  195. // Mark that we're no longer in the frame
  196. JPH_ASSERT(mInFrame);
  197. mInFrame = false;
  198. }