glfw_adapter.cc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // Copyright 2023 DeepMind Technologies Limited
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "glfw_adapter.h"
  15. #include <cstdlib>
  16. #include <utility>
  17. #include <GLFW/glfw3.h>
  18. #include <mujoco/mjui.h>
  19. #include <mujoco/mujoco.h>
  20. #include "glfw_dispatch.h"
  21. #ifdef __APPLE__
  22. #include "glfw_corevideo.h"
  23. #endif
  24. namespace mujoco {
  25. namespace {
  26. int MaybeGlfwInit() {
  27. static const int is_initialized = []() {
  28. auto success = Glfw().glfwInit();
  29. if (success == GLFW_TRUE) {
  30. std::atexit(Glfw().glfwTerminate);
  31. }
  32. return success;
  33. }();
  34. return is_initialized;
  35. }
  36. GlfwAdapter& GlfwAdapterFromWindow(GLFWwindow* window) {
  37. return *static_cast<GlfwAdapter*>(Glfw().glfwGetWindowUserPointer(window));
  38. }
  39. } // namespace
  40. GlfwAdapter::GlfwAdapter() {
  41. if (MaybeGlfwInit() != GLFW_TRUE) {
  42. mju_error("could not initialize GLFW");
  43. }
  44. // multisampling
  45. Glfw().glfwWindowHint(GLFW_SAMPLES, 4);
  46. Glfw().glfwWindowHint(GLFW_VISIBLE, 1);
  47. // get video mode and save
  48. vidmode_ = *Glfw().glfwGetVideoMode(Glfw().glfwGetPrimaryMonitor());
  49. // create window
  50. window_ = Glfw().glfwCreateWindow((2 * vidmode_.width) / 3,
  51. (2 * vidmode_.height) / 3,
  52. "MuJoCo", nullptr, nullptr);
  53. if (!window_) {
  54. mju_error("could not create window");
  55. }
  56. // save window position and size
  57. Glfw().glfwGetWindowPos(window_, &window_pos_.first, &window_pos_.second);
  58. Glfw().glfwGetWindowSize(window_, &window_size_.first, &window_size_.second);
  59. // set callbacks
  60. Glfw().glfwSetWindowUserPointer(window_, this);
  61. Glfw().glfwSetDropCallback(
  62. window_, +[](GLFWwindow* window, int count, const char** paths) {
  63. GlfwAdapterFromWindow(window).OnFilesDrop(count, paths);
  64. });
  65. Glfw().glfwSetKeyCallback(
  66. window_, +[](GLFWwindow* window, int key, int scancode, int act, int mods) {
  67. GlfwAdapterFromWindow(window).OnKey(key, scancode, act);
  68. });
  69. Glfw().glfwSetMouseButtonCallback(
  70. window_, +[](GLFWwindow* window, int button, int act, int mods) {
  71. GlfwAdapterFromWindow(window).OnMouseButton(button, act);
  72. });
  73. Glfw().glfwSetCursorPosCallback(
  74. window_, +[](GLFWwindow* window, double x, double y) {
  75. GlfwAdapterFromWindow(window).OnMouseMove(x, y);
  76. });
  77. Glfw().glfwSetScrollCallback(
  78. window_, +[](GLFWwindow* window, double xoffset, double yoffset) {
  79. GlfwAdapterFromWindow(window).OnScroll(xoffset, yoffset);
  80. });
  81. Glfw().glfwSetWindowRefreshCallback(
  82. window_, +[](GLFWwindow* window) {
  83. #ifdef __APPLE__
  84. auto& core_video = GlfwAdapterFromWindow(window).core_video_;
  85. if (core_video.has_value()) {
  86. core_video->UpdateDisplayLink();
  87. }
  88. #endif
  89. GlfwAdapterFromWindow(window).OnWindowRefresh();
  90. });
  91. Glfw().glfwSetWindowSizeCallback(
  92. window_, +[](GLFWwindow* window, int width, int height) {
  93. GlfwAdapterFromWindow(window).OnWindowResize(width, height);
  94. });
  95. // make context current
  96. Glfw().glfwMakeContextCurrent(window_);
  97. }
  98. GlfwAdapter::~GlfwAdapter() {
  99. FreeMjrContext();
  100. Glfw().glfwMakeContextCurrent(nullptr);
  101. Glfw().glfwDestroyWindow(window_);
  102. }
  103. std::pair<double, double> GlfwAdapter::GetCursorPosition() const {
  104. double x, y;
  105. Glfw().glfwGetCursorPos(window_, &x, &y);
  106. return {x, y};
  107. }
  108. double GlfwAdapter::GetDisplayPixelsPerInch() const {
  109. int width_mm, height_mm;
  110. Glfw().glfwGetMonitorPhysicalSize(
  111. Glfw().glfwGetPrimaryMonitor(), &width_mm, &height_mm);
  112. return 25.4 * vidmode_.width / width_mm;
  113. }
  114. std::pair<int, int> GlfwAdapter::GetFramebufferSize() const {
  115. int width, height;
  116. Glfw().glfwGetFramebufferSize(window_, &width, &height);
  117. return {width, height};
  118. }
  119. std::pair<int, int> GlfwAdapter::GetWindowSize() const {
  120. int width, height;
  121. Glfw().glfwGetWindowSize(window_, &width, &height);
  122. return {width, height};
  123. }
  124. bool GlfwAdapter::IsGPUAccelerated() const {
  125. return true;
  126. }
  127. void GlfwAdapter::PollEvents() {
  128. Glfw().glfwPollEvents();
  129. }
  130. void GlfwAdapter::SetClipboardString(const char* text) {
  131. Glfw().glfwSetClipboardString(window_, text);
  132. }
  133. void GlfwAdapter::SetVSync(bool enabled){
  134. #ifdef __APPLE__
  135. Glfw().glfwSwapInterval(0);
  136. if (enabled && !core_video_.has_value()) {
  137. core_video_.emplace(window_);
  138. } else if (!enabled && core_video_.has_value()) {
  139. core_video_.reset();
  140. }
  141. #else
  142. Glfw().glfwSwapInterval(enabled);
  143. #endif
  144. }
  145. void GlfwAdapter::SetWindowTitle(const char* title) {
  146. Glfw().glfwSetWindowTitle(window_, title);
  147. }
  148. bool GlfwAdapter::ShouldCloseWindow() const {
  149. return Glfw().glfwWindowShouldClose(window_);
  150. }
  151. void GlfwAdapter::SwapBuffers() {
  152. #ifdef __APPLE__
  153. if (core_video_.has_value()) {
  154. core_video_->WaitForDisplayRefresh();
  155. }
  156. #endif
  157. Glfw().glfwSwapBuffers(window_);
  158. }
  159. void GlfwAdapter::ToggleFullscreen() {
  160. // currently full screen: switch to windowed
  161. if (Glfw().glfwGetWindowMonitor(window_)) {
  162. // restore window from saved data
  163. Glfw().glfwSetWindowMonitor(window_, nullptr, window_pos_.first, window_pos_.second,
  164. window_size_.first, window_size_.second, 0);
  165. }
  166. // currently windowed: switch to full screen
  167. else {
  168. // save window data
  169. Glfw().glfwGetWindowPos(window_, &window_pos_.first, &window_pos_.second);
  170. Glfw().glfwGetWindowSize(window_, &window_size_.first,
  171. &window_size_.second);
  172. // switch
  173. Glfw().glfwSetWindowMonitor(window_, Glfw().glfwGetPrimaryMonitor(), 0,
  174. 0, vidmode_.width, vidmode_.height,
  175. vidmode_.refreshRate);
  176. }
  177. }
  178. bool GlfwAdapter::IsLeftMouseButtonPressed() const {
  179. return Glfw().glfwGetMouseButton(window_, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
  180. }
  181. bool GlfwAdapter::IsMiddleMouseButtonPressed() const {
  182. return Glfw().glfwGetMouseButton(window_, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS;
  183. }
  184. bool GlfwAdapter::IsRightMouseButtonPressed() const {
  185. return Glfw().glfwGetMouseButton(window_, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS;
  186. }
  187. bool GlfwAdapter::IsAltKeyPressed() const {
  188. return Glfw().glfwGetKey(window_, GLFW_KEY_LEFT_ALT) == GLFW_PRESS ||
  189. Glfw().glfwGetKey(window_, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS;
  190. }
  191. bool GlfwAdapter::IsCtrlKeyPressed() const {
  192. return Glfw().glfwGetKey(window_, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||
  193. Glfw().glfwGetKey(window_, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
  194. }
  195. bool GlfwAdapter::IsShiftKeyPressed() const {
  196. return Glfw().glfwGetKey(window_, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS ||
  197. Glfw().glfwGetKey(window_, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS;
  198. }
  199. bool GlfwAdapter::IsMouseButtonDownEvent(int act) const {
  200. return act == GLFW_PRESS;
  201. }
  202. bool GlfwAdapter::IsKeyDownEvent(int act) const { return act == GLFW_PRESS; }
  203. int GlfwAdapter::TranslateKeyCode(int key) const { return key; }
  204. mjtButton GlfwAdapter::TranslateMouseButton(int button) const {
  205. if (button == GLFW_MOUSE_BUTTON_LEFT) {
  206. return mjBUTTON_LEFT;
  207. } else if (button == GLFW_MOUSE_BUTTON_RIGHT) {
  208. return mjBUTTON_RIGHT;
  209. } else if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
  210. return mjBUTTON_MIDDLE;
  211. }
  212. return mjBUTTON_NONE;
  213. }
  214. } // namespace mujoco