You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

326 lines
7.7KB

  1. #include <unistd.h>
  2. #include "rack.hpp"
  3. #include <GL/glew.h>
  4. #include <GLFW/glfw3.h>
  5. // #define NANOVG_GLEW
  6. #define NANOVG_IMPLEMENTATION
  7. #include "../ext/nanovg/src/nanovg.h"
  8. #define NANOVG_GL2_IMPLEMENTATION
  9. #include "../ext/nanovg/src/nanovg_gl.h"
  10. #define BLENDISH_IMPLEMENTATION
  11. #include "../ext/oui/blendish.h"
  12. extern "C" {
  13. #include "../ext/noc/noc_file_dialog.h"
  14. }
  15. namespace rack {
  16. Scene *gScene = NULL;
  17. RackWidget *gRackWidget = NULL;
  18. Vec gMousePos;
  19. Widget *gHoveredWidget = NULL;
  20. Widget *gDraggedWidget = NULL;
  21. Widget *gSelectedWidget = NULL;
  22. int gGuiFrame;
  23. static GLFWwindow *window = NULL;
  24. static NVGcontext *vg = NULL;
  25. void windowSizeCallback(GLFWwindow* window, int width, int height) {
  26. gScene->box.size = Vec(width, height);
  27. }
  28. void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) {
  29. if (action == GLFW_PRESS) {
  30. // onMouseDown
  31. Widget *w = gScene->onMouseDown(gMousePos, button);
  32. gSelectedWidget = w;
  33. if (button == GLFW_MOUSE_BUTTON_LEFT) {
  34. gDraggedWidget = w;
  35. if (gDraggedWidget) {
  36. // onDragStart
  37. gDraggedWidget->onDragStart();
  38. }
  39. }
  40. }
  41. else if (action == GLFW_RELEASE) {
  42. // onMouseUp
  43. Widget *w = gScene->onMouseUp(gMousePos, button);
  44. if (button == GLFW_MOUSE_BUTTON_LEFT) {
  45. if (gDraggedWidget) {
  46. // onDragDrop
  47. w->onDragDrop(gDraggedWidget);
  48. }
  49. // gDraggedWidget might have been set to null in the last event, recheck here
  50. if (gDraggedWidget) {
  51. // onDragEnd
  52. gDraggedWidget->onDragEnd();
  53. }
  54. gDraggedWidget = NULL;
  55. }
  56. }
  57. }
  58. void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) {
  59. Vec mousePos = Vec(xpos, ypos).round();
  60. Vec mouseRel = mousePos.minus(gMousePos);
  61. gMousePos = mousePos;
  62. if (glfwGetInputMode(window, GLFW_CURSOR) != GLFW_CURSOR_DISABLED) {
  63. // TODO Lock gMousePos
  64. }
  65. // onScroll
  66. // int middleButton = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE);
  67. // if (middleButton == GLFW_PRESS) {
  68. // gScene->scrollWidget->onScroll(mouseRel.neg());
  69. // }
  70. if (gDraggedWidget) {
  71. // onDragMove
  72. // Drag slower if Ctrl is held
  73. bool fine = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
  74. float factor = fine ? 1.0/8.0 : 1.0;
  75. gDraggedWidget->onDragMove(mouseRel.mult(factor));
  76. }
  77. else {
  78. // onMouseMove
  79. Widget *hovered = gScene->onMouseMove(gMousePos, mouseRel);
  80. if (hovered != gHoveredWidget) {
  81. if (gHoveredWidget) {
  82. // onMouseLeave
  83. gHoveredWidget->onMouseLeave();
  84. }
  85. if (hovered) {
  86. // onMouseEnter
  87. hovered->onMouseEnter();
  88. }
  89. }
  90. gHoveredWidget = hovered;
  91. }
  92. }
  93. void cursorEnterCallback(GLFWwindow* window, int entered) {
  94. if (!entered) {
  95. if (gHoveredWidget) {
  96. gHoveredWidget->onMouseLeave();
  97. }
  98. gHoveredWidget = NULL;
  99. }
  100. }
  101. void scrollCallback(GLFWwindow *window, double x, double y) {
  102. Vec scrollRel = Vec(x, y);
  103. // onScroll
  104. gScene->onScroll(gMousePos, scrollRel.mult(-95));
  105. }
  106. void charCallback(GLFWwindow *window, unsigned int value) {
  107. }
  108. static int lastWindowX, lastWindowY, lastWindowWidth, lastWindowHeight;
  109. void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
  110. if (action == GLFW_PRESS) {
  111. if (key == GLFW_KEY_F11 || key == GLFW_KEY_ESCAPE) {
  112. // Toggle fullscreen
  113. GLFWmonitor *monitor = glfwGetWindowMonitor(window);
  114. if (monitor) {
  115. // Window mode
  116. glfwSetWindowMonitor(window, NULL, lastWindowX, lastWindowY, lastWindowWidth, lastWindowHeight, 0);
  117. }
  118. else {
  119. // Fullscreen
  120. glfwGetWindowPos(window, &lastWindowX, &lastWindowY);
  121. glfwGetWindowSize(window, &lastWindowWidth, &lastWindowHeight);
  122. monitor = glfwGetPrimaryMonitor();
  123. assert(monitor);
  124. const GLFWvidmode *mode = glfwGetVideoMode(monitor);
  125. glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);
  126. }
  127. }
  128. }
  129. }
  130. void renderGui() {
  131. int width, height;
  132. glfwGetFramebufferSize(window, &width, &height);
  133. // glfwGetWindowSize(window, &width, &height);
  134. // Update and render
  135. glViewport(0, 0, width, height);
  136. glClearColor(1.0, 1.0, 1.0, 1.0);
  137. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  138. nvgBeginFrame(vg, width, height, 1.0);
  139. gScene->draw(vg);
  140. nvgEndFrame(vg);
  141. glfwSwapBuffers(window);
  142. }
  143. void guiInit() {
  144. int err;
  145. // Set up GLFW
  146. err = glfwInit();
  147. assert(err);
  148. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
  149. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
  150. window = glfwCreateWindow(1020, 700, gApplicationName.c_str(), NULL, NULL);
  151. assert(window);
  152. glfwMakeContextCurrent(window);
  153. glfwSwapInterval(1);
  154. glfwSetWindowSizeCallback(window, windowSizeCallback);
  155. glfwSetMouseButtonCallback(window, mouseButtonCallback);
  156. // glfwSetCursorPosCallback(window, cursorPosCallback);
  157. glfwSetCursorEnterCallback(window, cursorEnterCallback);
  158. glfwSetScrollCallback(window, scrollCallback);
  159. glfwSetCharCallback(window, charCallback);
  160. glfwSetKeyCallback(window, keyCallback);
  161. // Set up GLEW
  162. glewExperimental = GL_TRUE;
  163. err = glewInit();
  164. assert(err == GLEW_OK);
  165. // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
  166. glGetError();
  167. glfwSetWindowSizeLimits(window, 240, 160, GLFW_DONT_CARE, GLFW_DONT_CARE);
  168. // Set up NanoVG
  169. vg = nvgCreateGL2(NVG_ANTIALIAS);
  170. assert(vg);
  171. // Set up Blendish
  172. bndSetFont(loadFont("res/DejaVuSans.ttf"));
  173. // bndSetIconImage(loadImage("res/icons.png"));
  174. gScene = new Scene();
  175. }
  176. void guiDestroy() {
  177. delete gScene;
  178. nvgDeleteGL2(vg);
  179. glfwDestroyWindow(window);
  180. glfwTerminate();
  181. }
  182. void guiRun() {
  183. assert(window);
  184. {
  185. int width, height;
  186. glfwGetWindowSize(window, &width, &height);
  187. windowSizeCallback(window, width, height);
  188. }
  189. gGuiFrame = 0;
  190. double lastTime = 0.0;
  191. while(!glfwWindowShouldClose(window)) {
  192. gGuiFrame++;
  193. glfwPollEvents();
  194. {
  195. double xpos, ypos;
  196. glfwGetCursorPos(window, &xpos, &ypos);
  197. cursorPosCallback(window, xpos, ypos);
  198. }
  199. gScene->step();
  200. renderGui();
  201. double currTime = glfwGetTime();
  202. // printf("%lf fps\n", 1.0/(currTime - lastTime));
  203. lastTime = currTime;
  204. (void) lastTime;
  205. }
  206. }
  207. void guiCursorLock() {
  208. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
  209. }
  210. void guiCursorUnlock() {
  211. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
  212. }
  213. const char *guiSaveDialog(const char *filters, const char *filename) {
  214. return noc_file_dialog_open(NOC_FILE_DIALOG_SAVE, filters, NULL, filename);
  215. }
  216. const char *guiOpenDialog(const char *filters, const char *filename) {
  217. return noc_file_dialog_open(NOC_FILE_DIALOG_OPEN, filters, NULL, filename);
  218. }
  219. std::map<std::string, int> images;
  220. std::map<std::string, int> fonts;
  221. int loadImage(std::string filename) {
  222. assert(vg);
  223. int imageId;
  224. auto it = images.find(filename);
  225. if (it == images.end()) {
  226. // Load image
  227. imageId = nvgCreateImage(vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
  228. if (imageId == 0) {
  229. printf("Failed to load image %s\n", filename.c_str());
  230. }
  231. else {
  232. printf("Loaded image %s\n", filename.c_str());
  233. }
  234. images[filename] = imageId;
  235. }
  236. else {
  237. imageId = it->second;
  238. }
  239. return imageId;
  240. }
  241. int loadFont(std::string filename) {
  242. assert(vg);
  243. int fontId;
  244. auto it = fonts.find(filename);
  245. if (it == fonts.end()) {
  246. fontId = nvgCreateFont(vg, filename.c_str(), filename.c_str());
  247. if (fontId < 0) {
  248. printf("Failed to load font %s\n", filename.c_str());
  249. }
  250. else {
  251. printf("Loaded font %s\n", filename.c_str());
  252. }
  253. fonts[filename] = fontId;
  254. }
  255. else {
  256. fontId = it->second;
  257. }
  258. return fontId;
  259. }
  260. void drawImage(NVGcontext *vg, Vec pos, int imageId) {
  261. int width, height;
  262. nvgImageSize(vg, imageId, &width, &height);
  263. NVGpaint paint = nvgImagePattern(vg, pos.x, pos.y, width, height, 0, imageId, 1.0);
  264. nvgFillPaint(vg, paint);
  265. nvgRect(vg, pos.x, pos.y, width, height);
  266. nvgFill(vg);
  267. }
  268. } // namespace rack