REDPolygonClippingNode.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. //
  2. // REDPolygonClippingNode.cpp
  3. // cocos2d_libs
  4. //
  5. // Created by RedInfinity on 2024/1/17.
  6. //
  7. #include "REDPolygonClippingNode.hpp"
  8. ///项目代码
  9. #include "base/ccMacros.h"
  10. #include "base/CCDirector.h"
  11. #include "base/CCStencilStateManager.h"
  12. #include "renderer/CCGLProgram.h"
  13. #include "renderer/CCGLProgramState.h"
  14. #include "renderer/ccGLStateCache.h"
  15. #include "platform/CCGL.h"
  16. #include "platform/CCFileUtils.h"
  17. #include "common/json11.hpp"
  18. NS_CC_BEGIN
  19. ///顶点着色器
  20. const char* kPolygonClippingNodeVsh = R"(
  21. attribute vec4 a_position;
  22. void main() {
  23. gl_Position = CC_MVPMatrix * a_position;
  24. }
  25. )";
  26. ///片段着色器
  27. const char* kPolygonClippingNodeFsh = R"(
  28. void main() {
  29. gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
  30. }
  31. )";
  32. PolygonClippingNode* PolygonClippingNode::create() {
  33. PolygonClippingNode* ret = new PolygonClippingNode();
  34. if (ret->_initWithData({}, false, false)) {
  35. ret->autorelease();
  36. } else {
  37. delete ret;
  38. ret = nullptr;
  39. }
  40. return ret;
  41. }
  42. PolygonClippingNode* PolygonClippingNode::createWithData(const std::vector<Vec2>& verts, const bool& close, const bool& clockwise) {
  43. PolygonClippingNode* ret = new PolygonClippingNode();
  44. if (ret->_initWithData(verts, close, clockwise)) {
  45. ret->autorelease();
  46. } else {
  47. delete ret;
  48. ret = nullptr;
  49. }
  50. return ret;
  51. }
  52. PolygonClippingNode* PolygonClippingNode::createWithFile(const std::string& fileName) {
  53. PolygonClippingNode* ret = new PolygonClippingNode();
  54. if (ret->_initWithFile(fileName)) {
  55. ret->autorelease();
  56. } else {
  57. delete ret;
  58. ret = nullptr;
  59. }
  60. return ret;
  61. }
  62. void PolygonClippingNode::setPolygonVerts(const std::vector<Vec2>& verts, const bool& close, const bool& clockwise) {
  63. ///通过数值赋值则将顶点数据文件设空
  64. _polygonFile = "";
  65. std::vector<Vec2> tVerts = verts;
  66. ///如果为多边形顶点数组闭合,则把最后一个元素舍弃。
  67. if (close) {
  68. tVerts.pop_back();
  69. }
  70. ///如果为顶点为顺时针填充,则需要置反使用OpenGL的逆时针顺序
  71. if (clockwise) {
  72. std::reverse(tVerts.begin(), tVerts.end());
  73. }
  74. ///更新OpenGL绘制的顶点数据
  75. _updateOpenGLDrawVerts(tVerts);
  76. }
  77. void PolygonClippingNode::setInverted(bool inverted) {
  78. _stencilStateManager->setInverted(inverted);
  79. }
  80. bool PolygonClippingNode::isInverted() const {
  81. return _stencilStateManager->isInverted();
  82. }
  83. void PolygonClippingNode::setPolygonFile(const std::string& fileName) {
  84. _polygonFile = fileName;
  85. ///解析数据文件内容
  86. std::vector<Vec2> verts = _parseFile(_polygonFile);
  87. ///更新OpenGL绘制的顶点数据
  88. _updateOpenGLDrawVerts(verts);
  89. }
  90. const std::string& PolygonClippingNode::getPolygonFile() const {
  91. return _polygonFile;
  92. }
  93. void PolygonClippingNode::visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags) {
  94. ///节点不可见不绘制
  95. if (_visible == false) {
  96. return;
  97. }
  98. uint32_t flags = processParentFlags(parentTransform, parentFlags);
  99. Director* director = Director::getInstance();
  100. director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  101. director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
  102. ///添加渲染组
  103. _groupCommand.init(_globalZOrder);
  104. renderer->addCommand(&_groupCommand);
  105. renderer->pushGroup(_groupCommand.getRenderQueueID());
  106. ///设置模版功能
  107. _beforeVisitCmd.init(_globalZOrder, _modelViewTransform, flags);
  108. _beforeVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onBeforeVisit, _stencilStateManager);
  109. renderer->addCommand(&_beforeVisitCmd);
  110. ///绘制自身的模版多边形
  111. bool visibleByCamera = isVisitableByVisitingCamera();
  112. if (visibleByCamera) {
  113. draw(renderer, _modelViewTransform, flags);
  114. }
  115. ///为渲染启用模板功能
  116. _afterDrawCmd.init(_globalZOrder, _modelViewTransform, flags);
  117. _afterDrawCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterDrawStencil, _stencilStateManager);
  118. renderer->addCommand(&_afterDrawCmd);
  119. ///遍历执行子节点的visit
  120. if (_children.empty() == false) {
  121. sortAllChildren();
  122. for (auto iter = _children.cbegin(); iter != _children.cend(); ++iter) {
  123. (*iter)->visit(renderer, _modelViewTransform, flags);
  124. }
  125. }
  126. ///关闭模版功能
  127. _afterVisitCmd.init(_globalZOrder, _modelViewTransform, flags);
  128. _afterVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterVisit, _stencilStateManager);
  129. renderer->addCommand(&_afterVisitCmd);
  130. renderer->popGroup();
  131. director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
  132. }
  133. void PolygonClippingNode::draw(Renderer* renderer, const Mat4 &transform, uint32_t flags) {
  134. if (_vertsCnt == 0) {
  135. return;
  136. }
  137. _customDrawCmd.init(_globalZOrder, transform, flags);
  138. _customDrawCmd.func = [this, transform](void) {
  139. ///顶点坐标发生变化
  140. if (_vertsDirty) {
  141. _bindVAOAndVBO();
  142. _vertsDirty = false;
  143. }
  144. GLProgramState* programState = getGLProgramState();
  145. programState->apply(transform);
  146. GL::bindVAO(_vao);
  147. glDrawArrays(GL_TRIANGLES, 0, _vertsCnt);
  148. GL::bindVAO(0);
  149. };
  150. renderer->addCommand(&_customDrawCmd);
  151. }
  152. PolygonClippingNode::PolygonClippingNode() {
  153. _verts = new Vec2[_vertsCnt];
  154. _stencilStateManager = new StencilStateManager();
  155. glGenVertexArrays(1, &_vao);
  156. glGenBuffers(1, &_vbo);
  157. }
  158. PolygonClippingNode::~PolygonClippingNode() {
  159. glDeleteBuffers(1, &_vbo);
  160. glDeleteVertexArrays(1, &_vao);
  161. delete _stencilStateManager;
  162. delete [] _verts;
  163. }
  164. bool PolygonClippingNode::_initWithData(const std::vector<Vec2>& verts, const bool& close, const bool& clockwise) {
  165. ///设置闭合多边形的顶点数据
  166. setPolygonVerts(verts, close, clockwise);
  167. ///创建着色器程序
  168. _createGLProgram();
  169. ///绑定vao和vbo
  170. _bindVAOAndVBO();
  171. return Node::init();
  172. }
  173. bool PolygonClippingNode::_initWithFile(const std::string& fileName) {
  174. ///设置闭合多边形的顶点数据文件
  175. setPolygonFile(fileName);
  176. ///创建着色器程序
  177. _createGLProgram();
  178. ///绑定vao和vbo
  179. _bindVAOAndVBO();
  180. return Node::init();
  181. }
  182. std::vector<Vec2> PolygonClippingNode::_parseFile(const std::string& fileName) {
  183. std::vector<Vec2> ret;
  184. const std::string& content = FileUtils::getInstance()->getStringFromFile(fileName);
  185. if (content.empty() == false) {
  186. std::string error = "";
  187. const json11::Json& jDoc = json11::Json::parse(content, error);
  188. if (error.empty()) {
  189. const json11::Json::object& jData = jDoc.object_items();
  190. const json11::Json::array& jVerts = jData.at("verts").array_items();
  191. for (int i = 0; i < jVerts.size(); ++i) {
  192. const json11::Json::array& jVert = jVerts.at(i).array_items();
  193. const float& x = jVert.at(0).number_value();
  194. const float& y = jVert.at(1).number_value();
  195. ret.emplace_back(x, y);
  196. }
  197. const bool& close = jData.at("close").bool_value();
  198. if (close) {
  199. ret.pop_back();
  200. }
  201. const bool& clockwise = jData.at("clockwise").bool_value();
  202. if (clockwise) {
  203. std::reverse(ret.begin(), ret.end());
  204. }
  205. } else {
  206. CCASSERT(false, "解析多边形顶点数据文件错误");
  207. }
  208. }
  209. return ret;
  210. }
  211. void PolygonClippingNode::_createGLProgram() {
  212. cocos2d::GLProgram* program = cocos2d::GLProgram::createWithByteArrays(kPolygonClippingNodeVsh, kPolygonClippingNodeFsh);
  213. cocos2d::GLProgramState* programState = cocos2d::GLProgramState::getOrCreateWithGLProgram(program);
  214. setGLProgramState(programState);
  215. }
  216. void PolygonClippingNode::_bindVAOAndVBO() {
  217. GL::bindVAO(_vao);
  218. glBindBuffer(GL_ARRAY_BUFFER, _vbo);
  219. glBufferData(GL_ARRAY_BUFFER, sizeof(Vec2) * _vertsCnt, _verts, GL_STATIC_DRAW);
  220. glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
  221. glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(Vec2), nullptr);
  222. glBindBuffer(GL_ARRAY_BUFFER, 0);
  223. GL::bindVAO(0);
  224. }
  225. void PolygonClippingNode::_updateOpenGLDrawVerts(std::vector<Vec2> verts) {
  226. if (verts.size() < 3) {
  227. delete [] _verts;
  228. _vertsCnt = 0;
  229. _verts = new Vec2[_vertsCnt];
  230. _vertsDirty = true;
  231. return;
  232. }
  233. ///删除旧顶点数据
  234. delete [] _verts;
  235. _vertsCnt = 0;
  236. ///将多边形顶点分割成绘制三角形
  237. std::vector<Vec2> triangleVerts;
  238. while (verts.size() > 3) {
  239. ///找到一个凸位顶点
  240. const int& convexVertexIdx = _findConvexVertex(verts);
  241. ///分割一个凸位顶点构成的多边形内嵌三角形
  242. const int& vertsSize = static_cast<int>(verts.size());
  243. const int& leftVertIdx = (convexVertexIdx - 1 + vertsSize) % vertsSize;
  244. const int& rightVertIdx = (convexVertexIdx + 1) % vertsSize;
  245. triangleVerts.emplace_back(verts.at(leftVertIdx));
  246. triangleVerts.emplace_back(verts.at(convexVertexIdx));
  247. triangleVerts.emplace_back(verts.at(rightVertIdx));
  248. ///凸位顶点完成三角形的构建则从多边形顶点数组中移除
  249. verts.erase(verts.begin() + convexVertexIdx);
  250. }
  251. ///添加最后一组三角形
  252. triangleVerts.emplace_back(verts.at(0));
  253. triangleVerts.emplace_back(verts.at(1));
  254. triangleVerts.emplace_back(verts.at(2));
  255. ///转成OpenGL使用的数据
  256. _vertsCnt = static_cast<int>(triangleVerts.size());
  257. _verts = new Vec2[_vertsCnt];
  258. for (int i = 0; i < _vertsCnt; ++i) {
  259. _verts[i] = triangleVerts.at(i);
  260. }
  261. _vertsDirty = true;
  262. }
  263. int PolygonClippingNode::_findConvexVertex(const std::vector<Vec2>& verts) {
  264. int ret = 0;
  265. const int& vertsSize = static_cast<int>(verts.size());
  266. for (int i = 0; i < vertsSize; ++i) {
  267. ///取左索引使用 i - 1 + vertsSize ,能保证当 i = 0时左索引为数组最后一个元素的索引
  268. const int& leftVertIdx = (i - 1 + vertsSize) % vertsSize;
  269. const int& rightVertIdx = (i + 1) % vertsSize;
  270. ///获取三个相邻的顶点
  271. const Vec2& vert = verts.at(i);
  272. const Vec2& leftVert = verts.at(leftVertIdx);
  273. const Vec2& rightVert = verts.at(rightVertIdx);
  274. ///如果三个顶点构成的三角形为正面,表示三角形一定不在多边形外。
  275. ///如果三个顶点构成的三角形为多边形的内嵌三角形,表示当前顶点为凸位顶点。
  276. if (_isPositiveTriangle(leftVert, vert, rightVert)
  277. && _isEmbeddedTriangle(verts, leftVert, vert, rightVert)) {
  278. ret = i;
  279. break;
  280. }
  281. }
  282. return ret;
  283. }
  284. bool PolygonClippingNode::_isPositiveTriangle(const Vec2& vert1, const Vec2& vert2, const Vec2& vert3) {
  285. const float& val = (vert2.x - vert1.x) * (vert3.y - vert1.y) - (vert2.y - vert1.y) * (vert3.x - vert1.x);
  286. return val >= 0.0f;
  287. }
  288. bool PolygonClippingNode::_isEmbeddedTriangle(const std::vector<Vec2>& verts, const Vec2& vert1, const Vec2& vert2, const Vec2& vert3) {
  289. bool ret = true;
  290. for (const Vec2& vert : verts) {
  291. ///跳过自检
  292. if (vert == vert1 || vert == vert2 || vert == vert3) {
  293. continue;
  294. }
  295. ///多边形中存在任意一个其他顶点位于构造出的三角形内
  296. if (_isInteriorPoint(vert, vert1, vert2, vert3)) {
  297. ret = false;
  298. break;
  299. }
  300. }
  301. return ret;
  302. }
  303. bool PolygonClippingNode::_isInteriorPoint(const Vec2& point, const Vec2& vert1, const Vec2& vert2, const Vec2& vert3) {
  304. bool ret = false;
  305. ///以这个点为起始顶点按三角形顶点顺序依次取两个顶点绘制三角形,如果都为正面三角形则这个点在三角形内部
  306. if (_isPositiveTriangle(point, vert1, vert2)
  307. && _isPositiveTriangle(point, vert2, vert3)
  308. && _isPositiveTriangle(point, vert3, vert1)) {
  309. ret = true;
  310. }
  311. return ret;
  312. }
  313. NS_CC_END