The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

339 lines
9.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-12 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #include "../JuceDemoHeader.h"
  19. // (These classes and random functions are used inside the 3rd-party Box2D demo code)
  20. inline float32 RandomFloat() { return Random::getSystemRandom().nextFloat() * 2.0f - 1.0f; }
  21. inline float32 RandomFloat (float32 lo, float32 hi) { return Random::getSystemRandom().nextFloat() * (hi - lo) + lo; }
  22. struct Settings
  23. {
  24. Settings()
  25. : viewCenter (0.0f, 20.0f),
  26. hz (60.0f),
  27. velocityIterations (8),
  28. positionIterations (3),
  29. drawShapes (1),
  30. drawJoints (1),
  31. drawAABBs (0),
  32. drawPairs (0),
  33. drawContactPoints (0),
  34. drawContactNormals (0),
  35. drawContactForces (0),
  36. drawFrictionForces (0),
  37. drawCOMs (0),
  38. drawStats (0),
  39. drawProfile (0),
  40. enableWarmStarting (1),
  41. enableContinuous (1),
  42. enableSubStepping (0),
  43. pause (0),
  44. singleStep (0)
  45. {}
  46. b2Vec2 viewCenter;
  47. float32 hz;
  48. int velocityIterations;
  49. int positionIterations;
  50. int drawShapes;
  51. int drawJoints;
  52. int drawAABBs;
  53. int drawPairs;
  54. int drawContactPoints;
  55. int drawContactNormals;
  56. int drawContactForces;
  57. int drawFrictionForces;
  58. int drawCOMs;
  59. int drawStats;
  60. int drawProfile;
  61. int enableWarmStarting;
  62. int enableContinuous;
  63. int enableSubStepping;
  64. int pause;
  65. int singleStep;
  66. };
  67. struct Test
  68. {
  69. Test() : m_world (new b2World (b2Vec2 (0.0f, -10.0f))) {}
  70. virtual ~Test() {}
  71. virtual void Keyboard (unsigned char /*key*/) {}
  72. virtual void KeyboardUp (unsigned char /*key*/) {}
  73. ScopedPointer<b2World> m_world;
  74. };
  75. #include "Box2DTests/AddPair.h"
  76. #include "Box2DTests/ApplyForce.h"
  77. #include "Box2DTests/Dominos.h"
  78. #include "Box2DTests/Chain.h"
  79. //==============================================================================
  80. /** This list box just displays a StringArray and broadcasts a change message when the
  81. selected row changes.
  82. */
  83. class Box2DTestList : public ListBoxModel,
  84. public ChangeBroadcaster
  85. {
  86. public:
  87. Box2DTestList (const StringArray& testList) : tests (testList)
  88. {
  89. }
  90. int getNumRows() override { return tests.size(); }
  91. void paintListBoxItem (int row, Graphics& g, int w, int h, bool rowIsSelected) override
  92. {
  93. if (rowIsSelected)
  94. g.fillAll (LookAndFeel::getDefaultLookAndFeel().findColour (TextEditor::highlightColourId));
  95. const Font f (h * 0.7f);
  96. g.setColour (Colours::black);
  97. g.setFont (f);
  98. g.drawText (tests[row], Rectangle<int> (0, 0, w, h).reduced (2),
  99. Justification::centredLeft, true);
  100. }
  101. void selectedRowsChanged (int /*lastRowSelected*/) override
  102. {
  103. sendChangeMessage();
  104. }
  105. private:
  106. StringArray tests;
  107. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Box2DTestList)
  108. };
  109. //==============================================================================
  110. struct Box2DRenderComponent : public Component
  111. {
  112. Box2DRenderComponent()
  113. {
  114. setOpaque (true);
  115. }
  116. void paint (Graphics& g)
  117. {
  118. g.fillAll (Colours::white);
  119. if (currentTest != nullptr)
  120. {
  121. Box2DRenderer renderer;
  122. renderer.render (g, *currentTest->m_world,
  123. -16.0f, 30.0f, 16.0f, -1.0f,
  124. getLocalBounds().toFloat().reduced (8.0f));
  125. }
  126. }
  127. ScopedPointer<Test> currentTest;
  128. };
  129. //==============================================================================
  130. class Box2DDemo : public Component,
  131. private Timer,
  132. private ChangeListener
  133. {
  134. public:
  135. enum Demos
  136. {
  137. addPair = 0,
  138. applyForce,
  139. dominoes,
  140. chain,
  141. numTests
  142. };
  143. Box2DDemo()
  144. : testsList (getTestsList()),
  145. testsListModel (testsList)
  146. {
  147. setOpaque (true);
  148. setWantsKeyboardFocus (true);
  149. testsListModel.addChangeListener (this);
  150. addAndMakeVisible (renderComponent);
  151. addAndMakeVisible (testsListBox);
  152. testsListBox.setModel (&testsListModel);
  153. testsListBox.selectRow (dominoes);
  154. testsListBox.setColour (ListBox::backgroundColourId, Colours::lightgrey);
  155. addAndMakeVisible (instructions);
  156. instructions.setMultiLine (true);
  157. instructions.setReadOnly (true);
  158. instructions.setColour (TextEditor::backgroundColourId, Colours::lightgrey);
  159. startTimerHz (60);
  160. }
  161. ~Box2DDemo()
  162. {
  163. testsListModel.removeChangeListener (this);
  164. }
  165. void paint (Graphics& g) override
  166. {
  167. fillTiledBackground (g);
  168. }
  169. void resized() override
  170. {
  171. Rectangle<int> r (getLocalBounds().reduced (4));
  172. Rectangle<int> area (r.removeFromBottom (150));
  173. testsListBox.setBounds (area.removeFromLeft (150));
  174. area.removeFromLeft (4);
  175. instructions.setBounds (area);
  176. r.removeFromBottom (6);
  177. renderComponent.setBounds (r);
  178. }
  179. bool keyPressed (const KeyPress& key) override
  180. {
  181. if (renderComponent.currentTest != nullptr)
  182. {
  183. // We override this to avoid the system beeping for an unused keypress
  184. switch (key.getTextCharacter())
  185. {
  186. case 'a':
  187. case 'w':
  188. case 'd':
  189. return true;
  190. default:
  191. break;
  192. }
  193. }
  194. return false;
  195. }
  196. private:
  197. StringArray testsList;
  198. Box2DTestList testsListModel;
  199. Box2DRenderComponent renderComponent;
  200. ListBox testsListBox;
  201. TextEditor instructions;
  202. static Test* createTest (int index)
  203. {
  204. switch (index)
  205. {
  206. case addPair: return new AddPair();
  207. case applyForce: return new ApplyForce();
  208. case dominoes: return new Dominos();
  209. case chain: return new Chain();
  210. default: break;
  211. }
  212. return nullptr;
  213. }
  214. static String getInstructions (int index)
  215. {
  216. switch (index)
  217. {
  218. case applyForce:
  219. {
  220. String s;
  221. s << "Keys:" << newLine << newLine << "Left: \'a\'" << newLine << "Right: \'d\'" << newLine << "Forward: \'w\'";
  222. return s;
  223. }
  224. default:
  225. break;
  226. }
  227. return String::empty;
  228. }
  229. void checkKeys()
  230. {
  231. if (renderComponent.currentTest == nullptr)
  232. return;
  233. checkKeyCode ('a');
  234. checkKeyCode ('w');
  235. checkKeyCode ('d');
  236. }
  237. void checkKeyCode (const int keyCode)
  238. {
  239. if (KeyPress::isKeyCurrentlyDown (keyCode))
  240. renderComponent.currentTest->Keyboard ((unsigned char) keyCode);
  241. }
  242. void timerCallback() override
  243. {
  244. if (renderComponent.currentTest == nullptr)
  245. return;
  246. grabKeyboardFocus();
  247. checkKeys();
  248. renderComponent.currentTest->m_world->Step (1.0f / 60.0f, 6, 2);
  249. repaint();
  250. }
  251. void changeListenerCallback (ChangeBroadcaster* source) override
  252. {
  253. if (source == &testsListModel)
  254. {
  255. const int index = testsListBox.getSelectedRow();
  256. renderComponent.currentTest = createTest (index);
  257. instructions.setText (getInstructions (index));
  258. repaint();
  259. }
  260. }
  261. static StringArray getTestsList()
  262. {
  263. const char* tests[] =
  264. {
  265. "Add Pair Stress Test",
  266. "Apply Force",
  267. "Dominoes",
  268. "Chain"
  269. };
  270. jassert (numElementsInArray (tests) == numTests);
  271. return StringArray (tests, numElementsInArray (tests));
  272. }
  273. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Box2DDemo)
  274. };
  275. // This static object will register this demo type in a global list of demos..
  276. static JuceDemoType<Box2DDemo> demo ("29 Graphics: Box 2D");