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.

204 lines
4.8KB

  1. #include "app.hpp"
  2. #include "engine.hpp"
  3. #include "componentlibrary.hpp"
  4. #include "gui.hpp"
  5. namespace rack {
  6. static void drawPlug(NVGcontext *vg, Vec pos, NVGcolor color) {
  7. NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5);
  8. // Plug solid
  9. nvgBeginPath(vg);
  10. nvgCircle(vg, pos.x, pos.y, 9);
  11. nvgFillColor(vg, color);
  12. nvgFill(vg);
  13. // Border
  14. nvgStrokeWidth(vg, 1.0);
  15. nvgStrokeColor(vg, colorOutline);
  16. nvgStroke(vg);
  17. // Hole
  18. nvgBeginPath(vg);
  19. nvgCircle(vg, pos.x, pos.y, 5);
  20. nvgFillColor(vg, nvgRGBf(0.0, 0.0, 0.0));
  21. nvgFill(vg);
  22. }
  23. static void drawWire(NVGcontext *vg, Vec pos1, Vec pos2, NVGcolor color, float tension, float opacity) {
  24. NVGcolor colorShadow = nvgRGBAf(0, 0, 0, 0.08);
  25. NVGcolor colorOutline = nvgLerpRGBA(color, nvgRGBf(0.0, 0.0, 0.0), 0.5);
  26. // Wire
  27. if (opacity > 0.0) {
  28. nvgSave(vg);
  29. nvgGlobalAlpha(vg, powf(opacity, 1.5));
  30. float dist = pos1.minus(pos2).norm();
  31. Vec slump;
  32. slump.y = (1.0 - tension) * (150.0 + 1.0*dist);
  33. Vec pos3 = pos1.plus(pos2).div(2).plus(slump);
  34. nvgLineJoin(vg, NVG_ROUND);
  35. // Shadow
  36. Vec pos4 = pos3.plus(slump.mult(0.08));
  37. nvgBeginPath(vg);
  38. nvgMoveTo(vg, pos1.x, pos1.y);
  39. nvgQuadTo(vg, pos4.x, pos4.y, pos2.x, pos2.y);
  40. nvgStrokeColor(vg, colorShadow);
  41. nvgStrokeWidth(vg, 5);
  42. nvgStroke(vg);
  43. // Wire outline
  44. nvgBeginPath(vg);
  45. nvgMoveTo(vg, pos1.x, pos1.y);
  46. nvgQuadTo(vg, pos3.x, pos3.y, pos2.x, pos2.y);
  47. nvgStrokeColor(vg, colorOutline);
  48. nvgStrokeWidth(vg, 5);
  49. nvgStroke(vg);
  50. // Wire solid
  51. nvgStrokeColor(vg, color);
  52. nvgStrokeWidth(vg, 3);
  53. nvgStroke(vg);
  54. nvgRestore(vg);
  55. }
  56. }
  57. static const NVGcolor wireColors[] = {
  58. nvgRGB(0xc9, 0xb7, 0x0e), // yellow
  59. nvgRGB(0xc9, 0x18, 0x47), // red
  60. nvgRGB(0x0c, 0x8e, 0x15), // green
  61. nvgRGB(0x09, 0x86, 0xad), // blue
  62. // nvgRGB(0x44, 0x44, 0x44), // black
  63. // nvgRGB(0x66, 0x66, 0x66), // gray
  64. // nvgRGB(0x88, 0x88, 0x88), // light gray
  65. // nvgRGB(0xaa, 0xaa, 0xaa), // white
  66. };
  67. static int lastWireColorId = -1;
  68. WireWidget::WireWidget() {
  69. lastWireColorId = (lastWireColorId + 1) % LENGTHOF(wireColors);
  70. color = wireColors[lastWireColorId];
  71. }
  72. WireWidget::~WireWidget() {
  73. outputPort = NULL;
  74. inputPort = NULL;
  75. updateWire();
  76. }
  77. void WireWidget::updateWire() {
  78. if (inputPort && outputPort) {
  79. // Check correct types
  80. assert(inputPort->type == Port::INPUT);
  81. assert(outputPort->type == Port::OUTPUT);
  82. if (!wire) {
  83. wire = new Wire();
  84. wire->outputModule = outputPort->module;
  85. wire->outputId = outputPort->portId;
  86. wire->inputModule = inputPort->module;
  87. wire->inputId = inputPort->portId;
  88. engineAddWire(wire);
  89. }
  90. }
  91. else {
  92. if (wire) {
  93. engineRemoveWire(wire);
  94. delete wire;
  95. wire = NULL;
  96. }
  97. }
  98. }
  99. Vec WireWidget::getOutputPos() {
  100. if (outputPort) {
  101. return outputPort->getRelativeOffset(outputPort->box.zeroPos().getCenter(), gRackWidget);
  102. }
  103. else if (hoveredOutputPort) {
  104. return hoveredOutputPort->getRelativeOffset(hoveredOutputPort->box.zeroPos().getCenter(), gRackWidget);
  105. }
  106. else {
  107. return gRackWidget->lastMousePos;
  108. }
  109. }
  110. Vec WireWidget::getInputPos() {
  111. if (inputPort) {
  112. return inputPort->getRelativeOffset(inputPort->box.zeroPos().getCenter(), gRackWidget);
  113. }
  114. else if (hoveredInputPort) {
  115. return hoveredInputPort->getRelativeOffset(hoveredInputPort->box.zeroPos().getCenter(), gRackWidget);
  116. }
  117. else {
  118. return gRackWidget->lastMousePos;
  119. }
  120. }
  121. json_t *WireWidget::toJson() {
  122. json_t *rootJ = json_object();
  123. json_object_set_new(rootJ, "color", colorToJson(color));
  124. return rootJ;
  125. }
  126. void WireWidget::fromJson(json_t *rootJ) {
  127. json_t *colorJ = json_object_get(rootJ, "color");
  128. if (colorJ)
  129. color = jsonToColor(colorJ);
  130. }
  131. void WireWidget::draw(NVGcontext *vg) {
  132. float opacity = gToolbar->wireOpacitySlider->value / 100.0;
  133. float tension = gToolbar->wireTensionSlider->value;
  134. WireWidget *activeWire = gRackWidget->wireContainer->activeWire;
  135. if (activeWire) {
  136. // Draw as opaque if the wire is active
  137. if (activeWire == this)
  138. opacity = 1.0;
  139. }
  140. else {
  141. Port *hoveredPort = dynamic_cast<Port*>(gHoveredWidget);
  142. if (hoveredPort && (hoveredPort == outputPort || hoveredPort == inputPort))
  143. opacity = 1.0;
  144. }
  145. Vec outputPos = getOutputPos();
  146. Vec inputPos = getInputPos();
  147. drawWire(vg, outputPos, inputPos, color, tension, opacity);
  148. }
  149. void WireWidget::drawPlugs(NVGcontext *vg) {
  150. // TODO Figure out a way to draw plugs first and wires last, and cut the plug portion of the wire off.
  151. Vec outputPos = getOutputPos();
  152. Vec inputPos = getInputPos();
  153. drawPlug(vg, outputPos, color);
  154. drawPlug(vg, inputPos, color);
  155. // Draw plug light
  156. // TODO
  157. // Only draw this when light is on top of the plug stack
  158. if (outputPort) {
  159. nvgSave(vg);
  160. nvgTranslate(vg, outputPos.x - 4, outputPos.y - 4);
  161. outputPort->plugLight->draw(vg);
  162. nvgRestore(vg);
  163. }
  164. if (inputPort) {
  165. nvgSave(vg);
  166. nvgTranslate(vg, inputPos.x - 4, inputPos.y - 4);
  167. inputPort->plugLight->draw(vg);
  168. nvgRestore(vg);
  169. }
  170. }
  171. } // namespace rack