guiGraphCtrl.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "console/console.h"
  23. #include "console/consoleTypes.h"
  24. #include "graphics/dgl.h"
  25. #include "gui/editor/guiGraphCtrl.h"
  26. IMPLEMENT_CONOBJECT(GuiGraphCtrl);
  27. GuiGraphCtrl::GuiGraphCtrl()
  28. {
  29. for(int i = 0; i < MaxPlots; i++)
  30. {
  31. mPlots[i].mAutoPlot = NULL;
  32. mPlots[i].mAutoPlotDelay = 0;
  33. mPlots[i].mGraphColor = ColorF(1.0, 1.0, 1.0);
  34. VECTOR_SET_ASSOCIATION(mPlots[i].mGraphData);
  35. mPlots[i].mGraphMax = 1;
  36. mPlots[i].mGraphType = Polyline;
  37. for(int j = 0; j < MaxDataPoints; j++)
  38. mPlots[i].mGraphData.push_front(0.0);
  39. }
  40. AssertWarn(MaxPlots == 6, "Only 6 plot colors initialized. Update following code if you change MaxPlots.");
  41. mPlots[0].mGraphColor = ColorF(1.0, 1.0, 1.0);
  42. mPlots[1].mGraphColor = ColorF(1.0, 0.0, 0.0);
  43. mPlots[2].mGraphColor = ColorF(0.0, 1.0, 0.0);
  44. mPlots[3].mGraphColor = ColorF(0.0, 0.0, 1.0);
  45. mPlots[4].mGraphColor = ColorF(0.0, 1.0, 1.0);
  46. mPlots[5].mGraphColor = ColorF(0.0, 0.0, 0.0);
  47. }
  48. static EnumTable::Enums enumGraphTypes[] = {
  49. { GuiGraphCtrl::Bar, "bar" },
  50. { GuiGraphCtrl::Filled, "filled" },
  51. { GuiGraphCtrl::Point, "point" },
  52. { GuiGraphCtrl::Polyline , "polyline" },
  53. };
  54. static EnumTable gGraphTypeTable( 4, &enumGraphTypes[0] );
  55. bool GuiGraphCtrl::onWake()
  56. {
  57. if (! Parent::onWake())
  58. return false;
  59. setActive(true);
  60. return true;
  61. }
  62. void GuiGraphCtrl::onRender(Point2I offset, const RectI &updateRect)
  63. {
  64. /*if (mProfile->mBorder)
  65. {
  66. RectI rect(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
  67. dglDrawRect(rect, mProfile->mBorderColor);
  68. }*/
  69. glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);
  70. glEnable(GL_BLEND);
  71. ColorF color(1.0, 1.0, 1.0, 0.5);
  72. dglDrawRectFill(updateRect, color);
  73. glDisable(GL_BLEND);
  74. glBlendFunc(GL_ONE, GL_ZERO);
  75. for (int k = 0; k < MaxPlots; k++)
  76. {
  77. // Check if there is an autoplot and the proper amount of time has passed, if so add datum.
  78. if((mPlots[k].mAutoPlot!=NULL) &&
  79. (mPlots[k].mAutoPlotDelay < (Sim::getCurrentTime() - mPlots[k].mAutoPlotLastDisplay)))
  80. {
  81. mPlots[k].mAutoPlotLastDisplay = Sim::getCurrentTime();
  82. addDatum(k, Con::getFloatVariable(mPlots[k].mAutoPlot));
  83. Con::setIntVariable(mPlots[k].mAutoPlot, 0);
  84. }
  85. // Adjust scale to max value + 5% so we can see high values
  86. F32 Scale = (F32(getExtent().y) / (F32(mPlots[k].mGraphMax*1.05)));
  87. // Nothing to graph
  88. if (mPlots[k].mGraphData.size() == 0)
  89. continue;
  90. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
  91. // Bar graph
  92. if(mPlots[k].mGraphType == Bar)
  93. {
  94. //PUAP -Mat untested
  95. glColor4f( mPlots[k].mGraphColor.red, mPlots[k].mGraphColor.green,mPlots[k].mGraphColor.blue, 255 );//was a color3fv, so use full alpha
  96. S32 temp1,temp2;
  97. temp1 = 0;
  98. for (S32 sample = 0; sample < getExtent().x; sample++)
  99. {
  100. if(mPlots[k].mGraphData.size() >= getExtent().x)
  101. temp2 = sample;
  102. else
  103. temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
  104. GLfloat verts[] = {
  105. static_cast<GLfloat>(getPosition().x + temp1), static_cast<GLfloat>((getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale)),
  106. static_cast<GLfloat>(getPosition().x + temp2), static_cast<GLfloat>((getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale)),
  107. static_cast<GLfloat>(getPosition().x + temp2), static_cast<GLfloat>(getPosition().y + getExtent().y),//may need to switch these last two
  108. static_cast<GLfloat>(getPosition().x + temp1), static_cast<GLfloat>(getPosition().y + getExtent().y),
  109. };
  110. glVertexPointer(2, GL_FLOAT, 0, verts);
  111. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  112. temp1 = temp2;
  113. }
  114. }
  115. // Filled graph
  116. else if(mPlots[k].mGraphType == Filled)
  117. {
  118. //PUAP -Mat untested
  119. glColor4f( mPlots[k].mGraphColor.red, mPlots[k].mGraphColor.green,mPlots[k].mGraphColor.blue, 255 );//was a color3fv, so use full alpha
  120. S32 temp1,temp2;
  121. temp1 = 0;
  122. for (S32 sample = 0; sample < (getExtent().x-1); sample++)
  123. {
  124. if(mPlots[k].mGraphData.size() >= getExtent().x)
  125. temp2 = sample;
  126. else
  127. temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
  128. GLfloat verts[] = {
  129. static_cast<GLfloat>(getPosition().x + temp1), static_cast<GLfloat>((getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale)),
  130. static_cast<GLfloat>(getPosition().x + temp2), static_cast<GLfloat>((getPosition().y + getExtent().y) - (S32)(getDatum(k, sample+1) * Scale)),
  131. static_cast<GLfloat>(getPosition().x + temp2), static_cast<GLfloat>(getPosition().y + getExtent().y),//may need to switch these last two
  132. static_cast<GLfloat>(getPosition().x + temp1), static_cast<GLfloat>(getPosition().y + getExtent().y),
  133. };
  134. glVertexPointer(2, GL_FLOAT, 0, verts);
  135. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  136. temp1 = temp2;
  137. }
  138. // last point
  139. S32 sample = getExtent().x;
  140. if(mPlots[k].mGraphData.size() >= getExtent().x)
  141. temp2 = sample;
  142. else
  143. temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
  144. GLfloat last[] = {
  145. static_cast<GLfloat>(getPosition().x + temp1), static_cast<GLfloat>((getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale)),
  146. static_cast<GLfloat>(getPosition().x + temp2), static_cast<GLfloat>((getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale)),
  147. static_cast<GLfloat>(getPosition().x + temp2), static_cast<GLfloat>(getPosition().y + getExtent().y),
  148. static_cast<GLfloat>(getPosition().x + temp1), static_cast<GLfloat>(getPosition().y + getExtent().y),
  149. };
  150. glVertexPointer(2, GL_FLOAT, 0, last);
  151. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  152. }
  153. // Point or Polyline graph
  154. else if((mPlots[k].mGraphType == Point) || (mPlots[k].mGraphType == Polyline))
  155. {
  156. //PUAP -Mat untested
  157. glColor4f( mPlots[k].mGraphColor.red, mPlots[k].mGraphColor.green,mPlots[k].mGraphColor.blue, 255 );//was a color3fv, so use full alpha
  158. S32 temp;
  159. if(mPlots[k].mGraphData.size() >= getExtent().x)
  160. temp = 0;
  161. else
  162. temp = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)0);
  163. GLfloat verts[] = {
  164. static_cast<GLfloat>(getPosition().x + temp), static_cast<GLfloat>(getPosition().y + getExtent().y - (S32)(getDatum(k, 0) * Scale)),
  165. 0, 0
  166. };
  167. for (S32 sample = 1; sample < getExtent().x; sample++)
  168. {
  169. if(mPlots[k].mGraphData.size() >= getExtent().x)
  170. temp = sample;
  171. else
  172. temp = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
  173. verts[2] = getPosition().x + temp;
  174. verts[3] = getPosition().y + getExtent().y - (S32)(getDatum(k, sample) * Scale);
  175. }
  176. glVertexPointer(2, GL_FLOAT, 0, verts);
  177. if(mPlots[k].mGraphType == Point)
  178. glDrawArrays(GL_POINTS, 0, 4);
  179. else
  180. glDrawArrays(GL_LINE_STRIP, 0, 4);
  181. }
  182. }
  183. #else
  184. // Bar graph
  185. if(mPlots[k].mGraphType == Bar)
  186. {
  187. glBegin(GL_QUADS);
  188. glColor3fv(mPlots[k].mGraphColor.address());
  189. S32 temp1,temp2;
  190. temp1 = 0;
  191. for (S32 sample = 0; sample < getExtent().x; sample++)
  192. {
  193. if(mPlots[k].mGraphData.size() >= getExtent().x)
  194. temp2 = sample;
  195. else
  196. temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
  197. glVertex2i(getPosition().x + temp1,
  198. (getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
  199. glVertex2i(getPosition().x + temp2,
  200. (getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
  201. glVertex2i(getPosition().x + temp2,
  202. getPosition().y + getExtent().y);
  203. glVertex2i(getPosition().x + temp1,
  204. getPosition().y + getExtent().y);
  205. temp1 = temp2;
  206. }
  207. glEnd();
  208. }
  209. // Filled graph
  210. else if(mPlots[k].mGraphType == Filled)
  211. {
  212. glBegin(GL_QUADS);
  213. glColor3fv(mPlots[k].mGraphColor.address());
  214. S32 temp1,temp2;
  215. temp1 = 0;
  216. for (S32 sample = 0; sample < (getExtent().x-1); sample++)
  217. {
  218. if(mPlots[k].mGraphData.size() >= getExtent().x)
  219. temp2 = sample;
  220. else
  221. temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
  222. glVertex2i(getPosition().x + temp1,
  223. (getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
  224. glVertex2i(getPosition().x + temp2,
  225. (getPosition().y + getExtent().y) - (S32)(getDatum(k, sample+1) * Scale));
  226. glVertex2i(getPosition().x + temp2,
  227. getPosition().y + getExtent().y);
  228. glVertex2i(getPosition().x + temp1,
  229. getPosition().y + getExtent().y);
  230. temp1 = temp2;
  231. }
  232. // last point
  233. S32 sample = getExtent().x;
  234. if(mPlots[k].mGraphData.size() >= getExtent().x)
  235. temp2 = sample;
  236. else
  237. temp2 = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
  238. glVertex2i(getPosition().x + temp1,
  239. (getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
  240. glVertex2i(getPosition().x + temp2,
  241. (getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
  242. glVertex2i(getPosition().x + temp2,
  243. getPosition().y + getExtent().y);
  244. glVertex2i(getPosition().x + temp1,
  245. getPosition().y + getExtent().y);
  246. glEnd();
  247. }
  248. // Point or Polyline graph
  249. else if((mPlots[k].mGraphType == Point) || (mPlots[k].mGraphType == Polyline))
  250. {
  251. if(mPlots[k].mGraphType == Point)
  252. glBegin(GL_POINTS);
  253. else
  254. glBegin(GL_LINE_STRIP);
  255. glColor3fv(mPlots[k].mGraphColor.address());
  256. for (S32 sample = 0; sample < getExtent().x; sample++)
  257. {
  258. S32 temp;
  259. if(mPlots[k].mGraphData.size() >= getExtent().x)
  260. temp = sample;
  261. else
  262. temp = (S32)(((F32)getExtent().x / (F32)mPlots[k].mGraphData.size()) * (F32)sample);
  263. glVertex2i(getPosition().x + temp,
  264. (getPosition().y + getExtent().y) - (S32)(getDatum(k, sample) * Scale));
  265. }
  266. glEnd();
  267. }
  268. }
  269. #endif
  270. }
  271. void GuiGraphCtrl::addDatum(S32 plotID, F32 v)
  272. {
  273. AssertFatal(plotID > -1 && plotID < MaxPlots, "Invalid plot specified!");
  274. // Add the data and trim the vector...
  275. mPlots[plotID].mGraphData.push_front( v );
  276. if(mPlots[plotID].mGraphData.size() > MaxDataPoints)
  277. mPlots[plotID].mGraphData.pop_back();
  278. // Keep record of maximum data value for scaling purposes.
  279. if(v > mPlots[plotID].mGraphMax)
  280. mPlots[plotID].mGraphMax = v;
  281. }
  282. float GuiGraphCtrl::getDatum( int plotID, int sample)
  283. {
  284. AssertFatal(plotID > -1 && plotID < MaxPlots, "Invalid plot specified!");
  285. AssertFatal(sample > -1 && sample < MaxDataPoints, "Invalid sample specified!");
  286. return mPlots[plotID].mGraphData[sample];
  287. }
  288. void GuiGraphCtrl::addAutoPlot(S32 plotID, const char *variable, S32 update)
  289. {
  290. mPlots[plotID].mAutoPlot = StringTable->insert(variable);
  291. mPlots[plotID].mAutoPlotDelay = update;
  292. Con::setIntVariable(mPlots[plotID].mAutoPlot, 0);
  293. }
  294. void GuiGraphCtrl::removeAutoPlot(S32 plotID)
  295. {
  296. mPlots[plotID].mAutoPlot = NULL;
  297. }
  298. void GuiGraphCtrl::setGraphType(S32 plotID, const char *graphType)
  299. {
  300. AssertFatal(plotID > -1 && plotID < MaxPlots, "Invalid plot specified!");
  301. if(!dStricmp(graphType,"Bar"))
  302. mPlots[plotID].mGraphType = Bar;
  303. else if(!dStricmp(graphType,"Filled"))
  304. mPlots[plotID].mGraphType = Filled;
  305. else if(!dStricmp(graphType,"Point"))
  306. mPlots[plotID].mGraphType = Point;
  307. else if(!dStricmp(graphType,"Polyline"))
  308. mPlots[plotID].mGraphType = Polyline;
  309. else AssertWarn(true, "Invalid graph type!");
  310. }
  311. ConsoleMethod(GuiGraphCtrl, addDatum, void, 4, 4, "(int plotID, float v)"
  312. "Add a data point to the given plot.\n"
  313. "@return No return value.")
  314. {
  315. S32 plotID = dAtoi(argv[2]);
  316. if(plotID > object->MaxPlots)
  317. {
  318. Con::errorf("Invalid plotID.");
  319. return;
  320. }
  321. object->addDatum( plotID, dAtof(argv[3]));
  322. }
  323. ConsoleMethod(GuiGraphCtrl, getDatum, F32, 4, 4, "(int plotID, int samples)"
  324. "Get a data point from the plot specified, samples from the start of the graph.\n"
  325. "@return Returns the data point from the plot.")
  326. {
  327. S32 plotID = dAtoi(argv[2]);
  328. S32 samples = dAtoi(argv[3]);
  329. if(plotID > object->MaxPlots)
  330. {
  331. Con::errorf("Invalid plotID.");
  332. return -1;
  333. }
  334. if(samples > object->MaxDataPoints)
  335. {
  336. Con::errorf("Invalid sample.");
  337. return -1;
  338. }
  339. return object->getDatum(plotID, samples);
  340. }
  341. ConsoleMethod(GuiGraphCtrl, addAutoPlot, void, 5, 5, "(int plotID, string variable, int update)"
  342. "Adds a data point with value variable, every update ms.\n"
  343. "@return No return value.")
  344. {
  345. S32 plotID = dAtoi(argv[2]);
  346. if(plotID > object->MaxPlots)
  347. {
  348. Con::errorf("Invalid plotID.");
  349. return;
  350. }
  351. object->addAutoPlot(plotID,argv[3],dAtoi(argv[4]));
  352. }
  353. ConsoleMethod(GuiGraphCtrl, removeAutoPlot, void, 3, 3, "(int plotID)"
  354. "Stops automatic pointing over set interval.\n"
  355. "@return No return value.")
  356. {
  357. S32 plotID = dAtoi(argv[2]);
  358. if(plotID > object->MaxPlots)
  359. {
  360. Con::errorf("Invalid plotID.");
  361. return;
  362. }
  363. object->removeAutoPlot(plotID);
  364. }
  365. ConsoleMethod(GuiGraphCtrl, setGraphType, void, 4, 4, "(int plotID, string graphType)"
  366. "Change GraphType of plot plotID.\n"
  367. "@return No return value.")
  368. {
  369. S32 plotID = dAtoi(argv[2]);
  370. if(plotID > object->MaxPlots)
  371. {
  372. Con::errorf("Invalid plotID.");
  373. return;
  374. }
  375. object->setGraphType(dAtoi(argv[2]), argv[3]);
  376. }
  377. ConsoleMethod(GuiGraphCtrl, matchScale, void, 3, GuiGraphCtrl::MaxPlots+2, "(int plotID, int plotID, ...)"
  378. "Sets the scale of all specified plots to the maximum scale among them.\n"
  379. "@return No return value.")
  380. {
  381. F32 Max = 0;
  382. for(int i=0; i < (argc-2); i++)
  383. {
  384. if(dAtoi(argv[2+i]) > object->MaxPlots)
  385. {
  386. Con::errorf("Invalid plotID.");
  387. return;
  388. }
  389. if (object->mPlots[dAtoi(argv[2+i])].mGraphMax > Max)
  390. Max = object->mPlots[dAtoi(argv[2+i])].mGraphMax;
  391. }
  392. for(int i=0; i < (argc-2); i++)
  393. object->mPlots[dAtoi(argv[2+i])].mGraphMax = Max;
  394. }