ShapeVector.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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 "graphics/dgl.h"
  23. #include "console/consoleTypes.h"
  24. #include "2d/core/Utility.h"
  25. #include "ShapeVector.h"
  26. // Script bindings.
  27. #include "ShapeVector_ScriptBinding.h"
  28. //----------------------------------------------------------------------------
  29. IMPLEMENT_CONOBJECT(ShapeVector);
  30. //----------------------------------------------------------------------------
  31. ShapeVector::ShapeVector() :
  32. mLineColor(ColorF(1.0f,1.0f,1.0f,1.0f)),
  33. mFillColor(ColorF(0.5f,0.5f,0.5f,1.0f)),
  34. mFillMode(false),
  35. mIsCircle(false),
  36. mCircleRadius(1.0f),
  37. mFlipX(false),
  38. mFlipY(false)
  39. {
  40. // Set Vector Associations.
  41. VECTOR_SET_ASSOCIATION( mPolygonBasisList );
  42. VECTOR_SET_ASSOCIATION( mPolygonLocalList );
  43. // Use a static body by default.
  44. mBodyDefinition.type = b2_staticBody;
  45. }
  46. //----------------------------------------------------------------------------
  47. ShapeVector::~ShapeVector()
  48. {
  49. }
  50. //----------------------------------------------------------------------------
  51. void ShapeVector::initPersistFields()
  52. {
  53. addProtectedField("PolyList", TypePoint2FVector, Offset(mPolygonBasisList, ShapeVector), &setPolyList, &defaultProtectedGetFn, &writePolyList, "");
  54. addField("LineColor", TypeColorF, Offset(mLineColor, ShapeVector), &writeLineColor, "");
  55. addField("FillColor", TypeColorF, Offset(mFillColor, ShapeVector), &writeFillColor, "");
  56. addField("FillMode", TypeBool, Offset(mFillMode, ShapeVector), &writeFillMode, "");
  57. addField("IsCircle", TypeBool, Offset(mIsCircle, ShapeVector), &writeIsCircle, "");
  58. addField("CircleRadius", TypeF32, Offset(mCircleRadius, ShapeVector), &writeCircleRadius, "");
  59. Parent::initPersistFields();
  60. }
  61. //----------------------------------------------------------------------------
  62. void ShapeVector::copyTo(SimObject* obj)
  63. {
  64. Parent::copyTo(obj);
  65. AssertFatal(dynamic_cast<ShapeVector*>(obj), "ShapeVector::copyTo() - Object is not the correct type.");
  66. ShapeVector* object = static_cast<ShapeVector*>(obj);
  67. // Copy fields
  68. object->mFillMode = mFillMode;
  69. object->mFillColor = mFillColor;
  70. object->mLineColor = mLineColor;
  71. object->mIsCircle = mIsCircle;
  72. object->mCircleRadius = mCircleRadius;
  73. object->mFlipX = mFlipX;
  74. object->mFlipY = mFlipY;
  75. if (getPolyVertexCount() > 0)
  76. object->setPolyCustom(mPolygonBasisList.size(), getPoly());
  77. }
  78. //----------------------------------------------------------------------------
  79. bool ShapeVector::onAdd()
  80. {
  81. // Call Parent.
  82. if(!Parent::onAdd())
  83. return false;
  84. // Return Okay.
  85. return true;
  86. }
  87. //----------------------------------------------------------------------------
  88. void ShapeVector::onRemove()
  89. {
  90. // Call Parent.
  91. Parent::onRemove();
  92. }
  93. //----------------------------------------------------------------------------
  94. void ShapeVector::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
  95. {
  96. // Fetch Vertex Count.
  97. const U32 vertexCount = mPolygonLocalList.size();
  98. // Finish if not vertices.
  99. if ( vertexCount == 0 && !mIsCircle)
  100. return;
  101. // Disable Texturing.
  102. glDisable ( GL_TEXTURE_2D );
  103. // Save Model-view.
  104. glMatrixMode(GL_MODELVIEW);
  105. glPushMatrix();
  106. // Fetch Position/Rotation.
  107. const Vector2 position = getRenderPosition();
  108. // Set Blend Options.
  109. setBlendOptions();
  110. if (mIsCircle)
  111. {
  112. glRotatef( mRadToDeg(getRenderAngle()), 0.0f, 0.0f, 1.0f );
  113. // Render the shape.
  114. bool wireFrame = (pBatchRenderer->getWireframeMode() || this->getDebugMask() & Scene::SCENE_DEBUG_WIREFRAME_RENDER) ? true : false;
  115. renderCircleShape(position, mCircleRadius, wireFrame);
  116. }
  117. else
  118. {
  119. // Move into Vector-Space.
  120. glTranslatef( position.x, position.y, 0.0f );
  121. glRotatef( mRadToDeg(getRenderAngle()), 0.0f, 0.0f, 1.0f );
  122. // Render the shape.
  123. bool wireFrame = (pBatchRenderer->getWireframeMode() || this->getDebugMask() & Scene::SCENE_DEBUG_WIREFRAME_RENDER) ? true : false;
  124. renderPolygonShape(vertexCount, wireFrame);
  125. }
  126. // Restore color.
  127. glColor4f( 1,1,1,1 );
  128. // Restore Matrix.
  129. glPopMatrix();
  130. }
  131. void ShapeVector::renderCircleShape(Vector2 position, F32 radius, const bool wireFrame)
  132. {
  133. if (mFillMode)
  134. {
  135. // Set the fill color.
  136. glColor4f((GLfloat)mFillColor.red, (GLfloat)mFillColor.green, (GLfloat)mFillColor.blue, (GLfloat)mFillColor.alpha);
  137. // Draw the shape.
  138. const U32 k_segments = 32;
  139. const F32 k_increment = 2.0f * M_PI_F / k_segments;
  140. F32 theta = 0.0f;
  141. Vector<GLfloat> verts;
  142. for (U32 n = 0; n < k_segments; n++)
  143. {
  144. Vector2 v = position + radius * Vector2(mCos(theta), mSin(theta));
  145. verts.push_back((GLfloat)v.x);
  146. verts.push_back((GLfloat)v.y);
  147. theta += k_increment;
  148. }
  149. glVertexPointer(2, GL_FLOAT, 0, verts.address());
  150. glEnableClientState(GL_VERTEX_ARRAY);
  151. glDrawArrays(GL_TRIANGLE_FAN, 0, k_segments);
  152. // If mFillMode is enabled wireframe is also enabled, we'll draw a filled shape with a wire overlay.
  153. // Set the line color.
  154. if (wireFrame)
  155. {
  156. glColor4f((GLfloat)mLineColor.red, (GLfloat)mLineColor.green, (GLfloat)mLineColor.blue, (GLfloat)mLineColor.alpha);
  157. glDrawArrays(GL_LINE_LOOP, 0, k_segments);
  158. }
  159. glDisableClientState(GL_VERTEX_ARRAY);
  160. }
  161. else
  162. {
  163. // We emulate wireframe mode here by drawing lines between the verts.
  164. // Set the line color.
  165. glColor4f((GLfloat)mLineColor.red, (GLfloat)mLineColor.green, (GLfloat)mLineColor.blue, (GLfloat)mLineColor.alpha);
  166. // Draw the shape.
  167. const U32 k_segments = 32;
  168. const F32 k_increment = 2.0f * M_PI_F / k_segments;
  169. F32 theta = 0.0f;
  170. Vector<GLfloat> verts;
  171. for (U32 n = 0; n < k_segments; n++)
  172. {
  173. Vector2 v = position + radius * Vector2(mCos(theta), mSin(theta));
  174. verts.push_back((GLfloat)v.x);
  175. verts.push_back((GLfloat)v.y);
  176. theta += k_increment;
  177. }
  178. glVertexPointer(2, GL_FLOAT, 0, verts.address());
  179. glEnableClientState(GL_VERTEX_ARRAY);
  180. glDrawArrays(GL_LINE_LOOP, 0, k_segments);
  181. glDisableClientState(GL_VERTEX_ARRAY);
  182. }
  183. }
  184. void ShapeVector::renderPolygonShape(U32 vertexCount, const bool wireFrame)
  185. {
  186. // If fill mode is enabled, draw the polygon using GL_TRIANGLE_FAN, otherwise we draw with GL_LINE_LOOP.
  187. // We also draw with GL_LINE_LOOP if the scene/object is being rendered with wireframe enabled.
  188. if (mFillMode)
  189. {
  190. // Set the fill color.
  191. glColor4f((GLfloat)mFillColor.red, (GLfloat)mFillColor.green, (GLfloat)mFillColor.blue, (GLfloat)mFillColor.alpha);
  192. // Draw the shape.
  193. Vector<GLfloat> verts;
  194. for (U32 n = 0; n < vertexCount; n++)
  195. {
  196. verts.push_back((GLfloat)mPolygonLocalList[n].x);
  197. verts.push_back((GLfloat)mPolygonLocalList[n].y);
  198. }
  199. glVertexPointer(2, GL_FLOAT, 0, verts.address());
  200. glEnableClientState(GL_VERTEX_ARRAY);
  201. glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);
  202. // If mFillMode is enabled wireframe is also enabled, we'll draw a filled shape with a wire overlay.
  203. // Set the line color.
  204. if (wireFrame)
  205. {
  206. glColor4f((GLfloat)mLineColor.red, (GLfloat)mLineColor.green, (GLfloat)mLineColor.blue, (GLfloat)mLineColor.alpha);
  207. glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
  208. }
  209. glDisableClientState(GL_VERTEX_ARRAY);
  210. }
  211. else
  212. {
  213. // We emulate wireframe mode here by drawing lines between the verts.
  214. // Set the line color.
  215. glColor4f((GLfloat)mLineColor.red, (GLfloat)mLineColor.green, (GLfloat)mLineColor.blue, (GLfloat)mLineColor.alpha);
  216. // Draw the shape.
  217. Vector<GLfloat> verts;
  218. for (U32 n = 0; n < vertexCount; n++)
  219. {
  220. verts.push_back((GLfloat)mPolygonLocalList[n].x);
  221. verts.push_back((GLfloat)mPolygonLocalList[n].y);
  222. }
  223. glVertexPointer(2, GL_FLOAT, 0, verts.address());
  224. glEnableClientState(GL_VERTEX_ARRAY);
  225. glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
  226. glDisableClientState(GL_VERTEX_ARRAY);
  227. }
  228. }
  229. //----------------------------------------------------------------------------
  230. void ShapeVector::setSize( const Vector2& size )
  231. {
  232. F32 xDifference = mSize.x / size.x;
  233. // Call Parent.
  234. Parent::setSize( size );
  235. if (mIsCircle)
  236. {
  237. mCircleRadius /= xDifference;
  238. }
  239. else
  240. {
  241. // Generate Local Polygon.
  242. generateLocalPoly();
  243. }
  244. }
  245. //----------------------------------------------------------------------------
  246. void ShapeVector::setPolyPrimitive( const U32 polyVertexCount )
  247. {
  248. // Check it's not zero!
  249. if ( polyVertexCount == 0 )
  250. {
  251. // Warn.
  252. Con::warnf("ShapeVector::setPolyPrimitive() - Vertex count must be greater than zero!");
  253. // Finish Here.
  254. return;
  255. }
  256. // Clear Polygon List.
  257. mPolygonBasisList.clear();
  258. mPolygonBasisList.setSize( polyVertexCount );
  259. // Point?
  260. if ( polyVertexCount == 1 )
  261. {
  262. // Set Polygon Point.
  263. mPolygonBasisList[0].Set(0.0f, 0.0f);
  264. }
  265. // Special-Case Quad?
  266. else if ( polyVertexCount == 4 )
  267. {
  268. // Yes, so set Quad.
  269. mPolygonBasisList[0].Set(-0.5f, -0.5f);
  270. mPolygonBasisList[1].Set(+0.5f, -0.5f);
  271. mPolygonBasisList[2].Set(+0.5f, +0.5f);
  272. mPolygonBasisList[3].Set(-0.5f, +0.5f);
  273. }
  274. else
  275. {
  276. // No, so calculate Regular (Primitive) Polygon Stepping.
  277. //
  278. // NOTE:- The polygon sits on an circle that subscribes the interior
  279. // of the collision box.
  280. F32 angle = M_PI_F / polyVertexCount;
  281. const F32 angleStep = M_2PI_F / polyVertexCount;
  282. // Calculate Polygon.
  283. for ( U32 n = 0; n < polyVertexCount; n++ )
  284. {
  285. // Calculate Angle.
  286. angle += angleStep;
  287. // Store Polygon Vertex.
  288. mPolygonBasisList[n].Set(mCos(angle), mSin(angle));
  289. }
  290. }
  291. // Generation Local Poly.
  292. generateLocalPoly();
  293. }
  294. //----------------------------------------------------------------------------
  295. void ShapeVector::setPolyCustom( const U32 polyVertexCount, const char* pCustomPolygon )
  296. {
  297. // Validate Polygon.
  298. if ( polyVertexCount < 1 )
  299. {
  300. // Warn.
  301. Con::warnf("ShapeVector::setPolyCustom() - Vertex count must be greater than zero!");
  302. return;
  303. }
  304. // Fetch Custom Polygon Value Count.
  305. const U32 customCount = Utility::mGetStringElementCount(pCustomPolygon);
  306. // Validate Polygon Custom Length.
  307. if ( customCount != polyVertexCount*2 )
  308. {
  309. // Warn.
  310. Con::warnf("ShapeVector::setPolyCustom() - Invalid Custom Polygon Items '%d'; expected '%d'!", customCount, polyVertexCount*2 );
  311. return;
  312. }
  313. //// Validate Polygon Vertices.
  314. //for ( U32 n = 0; n < customCount; n+=2 )
  315. //{
  316. // // Fetch Coordinate.
  317. // const Vector2 coord = Utility::mGetStringElementVector(pCustomPolygon, n);
  318. // // Check Range.
  319. // if ( coord.x < -1.0f || coord.x > 1.0f || coord.y < -1.0f || coord.y > 1.0f )
  320. // {
  321. // // Warn.
  322. // Con::warnf("ShapeVector::setPolyCustom() - Invalid Polygon Coordinate range; Must be -1 to +1! '(%g,%g)'", coord.x, coord.y );
  323. // return;
  324. // }
  325. //}
  326. // Clear Polygon Basis List.
  327. mPolygonBasisList.clear();
  328. mPolygonBasisList.setSize( polyVertexCount );
  329. // Validate Polygon Vertices.
  330. for ( U32 n = 0; n < polyVertexCount; n++ )
  331. {
  332. // Fetch Coordinate.
  333. const F32 x = dAtof(Utility::mGetStringElement(pCustomPolygon, n*2));
  334. const F32 y = dAtof(Utility::mGetStringElement(pCustomPolygon, n*2+1));
  335. // Store Polygon Vertex.
  336. mPolygonBasisList[n].Set(x, y);
  337. }
  338. // Generation Local Poly.
  339. generateLocalPoly();
  340. }
  341. //----------------------------------------------------------------------------
  342. const char* ShapeVector::getPoly( void )
  343. {
  344. // Get Collision Polygon.
  345. const Vector2* pPoly = (getPolyVertexCount() > 0) ? getPolyBasis() : NULL;
  346. // Set Max Buffer Size.
  347. const U32 maxBufferSize = getPolyVertexCount() * 18 + 1;
  348. // Get Return Buffer.
  349. char* pReturnBuffer = Con::getReturnBuffer( maxBufferSize );
  350. // Check Buffer.
  351. if( !pReturnBuffer )
  352. {
  353. // Warn.
  354. Con::printf("ShapeVector::getPoly() - Unable to allocate buffer!");
  355. // Exit.
  356. return NULL;
  357. }
  358. // Set Buffer Counter.
  359. U32 bufferCount = 0;
  360. // Add Polygon Edges.
  361. for ( U32 n = 0; n < getPolyVertexCount(); n++ )
  362. {
  363. // Output Object ID.
  364. bufferCount += dSprintf( pReturnBuffer + bufferCount, maxBufferSize-bufferCount, "%0.5f %0.5f ", pPoly[n].x, pPoly[n].y );
  365. // Finish early if we run out of buffer space.
  366. if ( bufferCount >= maxBufferSize )
  367. {
  368. // Warn.
  369. Con::warnf("ShapeVector::getPoly() - Error writing to buffer!");
  370. break;
  371. }
  372. }
  373. // Return Buffer.
  374. return pReturnBuffer;
  375. }
  376. //----------------------------------------------------------------------------
  377. const char* ShapeVector::getWorldPoly( void )
  378. {
  379. // Get the object space polygon
  380. //const Vector2* pPoly = (getPolyVertexCount() > 0) ? getPolyBasis() : NULL;
  381. // Set the max buffer size
  382. const U32 maxBufferSize = getPolyVertexCount() * 18 + 1;
  383. // Get the return buffer.
  384. char* pReturnBuffer = Con::getReturnBuffer( maxBufferSize );
  385. // Check the buffer.
  386. if( !pReturnBuffer )
  387. {
  388. // Warn.
  389. Con::printf("ShapeVector::getWorldPoly() - Unable to allocate buffer!");
  390. // Exit.
  391. return NULL;
  392. }
  393. // Set Buffer Counter.
  394. U32 bufferCount = 0;
  395. // Add Polygon Edges.
  396. for ( U32 n = 0; n < getPolyVertexCount(); n++ )
  397. {
  398. // Convert the poly point to a world coordinate
  399. Vector2 worldPoint = getWorldPoint(mPolygonLocalList[n]);
  400. // Output the point
  401. bufferCount += dSprintf( pReturnBuffer + bufferCount, maxBufferSize-bufferCount, "%0.5f %0.5f ", worldPoint.x, worldPoint.y );
  402. // Finish early if we run out of buffer space.
  403. if ( bufferCount >= maxBufferSize )
  404. {
  405. // Warn.
  406. Con::warnf("ShapeVector::getWorldPoly() - Error writing to buffer!");
  407. break;
  408. }
  409. }
  410. // Return Buffer.
  411. return pReturnBuffer;
  412. }
  413. //----------------------------------------------------------------------------
  414. void ShapeVector::generateLocalPoly( void )
  415. {
  416. // Fetch Polygon Vertex Count.
  417. const U32 polyVertexCount = mPolygonBasisList.size();
  418. // Process Collision Polygon (if we've got one).
  419. if ( polyVertexCount > 0 )
  420. {
  421. // Clear Polygon List.
  422. mPolygonLocalList.clear();
  423. mPolygonLocalList.setSize( polyVertexCount );
  424. // Scale/Orientate Polygon.
  425. for ( U32 n = 0; n < polyVertexCount; n++ )
  426. {
  427. // Fetch Polygon Basis.
  428. Vector2 polyVertex = mPolygonBasisList[n];
  429. // Scale.
  430. polyVertex.Set( polyVertex.x * mSize.x * (mFlipX ? -1.0f : 1.0f),
  431. polyVertex.y * mSize.y * (mFlipY ? -1.0f : 1.0f));
  432. // Set Vertex.
  433. mPolygonLocalList[n] = polyVertex;
  434. }
  435. }
  436. }
  437. //----------------------------------------------------------------------------
  438. Vector2 ShapeVector::getBoxFromPoints()
  439. {
  440. Vector2 box(1.0f, 1.0f);
  441. // Fetch Polygon Vertex Count.
  442. const U32 polyVertexCount = mPolygonBasisList.size();
  443. F32 minX = 0;
  444. F32 minY = 0;
  445. F32 maxX = 0;
  446. F32 maxY = 0;
  447. // Process Collision Polygon (if we've got one).
  448. if ( polyVertexCount > 0 )
  449. {
  450. // Scale/Orientate Polygon.
  451. for ( U32 n = 0; n < polyVertexCount; n++ )
  452. {
  453. // Fetch Polygon Basis.
  454. Vector2 polyVertex = mPolygonBasisList[n];
  455. if (polyVertex.x > maxX)
  456. maxX = polyVertex.x;
  457. else if (polyVertex.x < minX)
  458. minX = polyVertex.x;
  459. if (polyVertex.y > maxY)
  460. maxY = polyVertex.y;
  461. else if (polyVertex.y < minY)
  462. minY = polyVertex.y;
  463. }
  464. }
  465. box.x = maxX - minX;
  466. box.y = maxY - minY;
  467. return box;
  468. }