123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- //
- // REDPolygonClippingNode.cpp
- // cocos2d_libs
- //
- // Created by RedInfinity on 2024/1/17.
- //
- #include "REDPolygonClippingNode.hpp"
- ///项目代码
- #include "base/ccMacros.h"
- #include "base/CCDirector.h"
- #include "base/CCStencilStateManager.h"
- #include "renderer/CCGLProgram.h"
- #include "renderer/CCGLProgramState.h"
- #include "renderer/ccGLStateCache.h"
- #include "platform/CCGL.h"
- #include "platform/CCFileUtils.h"
- #include "common/json11.hpp"
- NS_CC_BEGIN
- ///顶点着色器
- const char* kPolygonClippingNodeVsh = R"(
- attribute vec4 a_position;
- void main() {
- gl_Position = CC_MVPMatrix * a_position;
- }
- )";
- ///片段着色器
- const char* kPolygonClippingNodeFsh = R"(
- void main() {
- gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
- }
- )";
- PolygonClippingNode* PolygonClippingNode::create() {
- PolygonClippingNode* ret = new PolygonClippingNode();
- if (ret->_initWithData({}, false, false)) {
- ret->autorelease();
- } else {
- delete ret;
- ret = nullptr;
- }
- return ret;
- }
- PolygonClippingNode* PolygonClippingNode::createWithData(const std::vector<Vec2>& verts, const bool& close, const bool& clockwise) {
- PolygonClippingNode* ret = new PolygonClippingNode();
- if (ret->_initWithData(verts, close, clockwise)) {
- ret->autorelease();
- } else {
- delete ret;
- ret = nullptr;
- }
- return ret;
- }
- PolygonClippingNode* PolygonClippingNode::createWithFile(const std::string& fileName) {
- PolygonClippingNode* ret = new PolygonClippingNode();
- if (ret->_initWithFile(fileName)) {
- ret->autorelease();
- } else {
- delete ret;
- ret = nullptr;
- }
- return ret;
- }
- void PolygonClippingNode::setPolygonVerts(const std::vector<Vec2>& verts, const bool& close, const bool& clockwise) {
- ///通过数值赋值则将顶点数据文件设空
- _polygonFile = "";
- std::vector<Vec2> tVerts = verts;
- ///如果为多边形顶点数组闭合,则把最后一个元素舍弃。
- if (close) {
- tVerts.pop_back();
- }
- ///如果为顶点为顺时针填充,则需要置反使用OpenGL的逆时针顺序
- if (clockwise) {
- std::reverse(tVerts.begin(), tVerts.end());
- }
- ///更新OpenGL绘制的顶点数据
- _updateOpenGLDrawVerts(tVerts);
- }
- void PolygonClippingNode::setInverted(bool inverted) {
- _stencilStateManager->setInverted(inverted);
- }
- bool PolygonClippingNode::isInverted() const {
- return _stencilStateManager->isInverted();
- }
- void PolygonClippingNode::setPolygonFile(const std::string& fileName) {
- _polygonFile = fileName;
- ///解析数据文件内容
- std::vector<Vec2> verts = _parseFile(_polygonFile);
- ///更新OpenGL绘制的顶点数据
- _updateOpenGLDrawVerts(verts);
- }
- const std::string& PolygonClippingNode::getPolygonFile() const {
- return _polygonFile;
- }
- void PolygonClippingNode::visit(Renderer* renderer, const Mat4& parentTransform, uint32_t parentFlags) {
- ///节点不可见不绘制
- if (_visible == false) {
- return;
- }
- uint32_t flags = processParentFlags(parentTransform, parentFlags);
- Director* director = Director::getInstance();
- director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
- director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
- ///添加渲染组
- _groupCommand.init(_globalZOrder);
- renderer->addCommand(&_groupCommand);
- renderer->pushGroup(_groupCommand.getRenderQueueID());
- ///设置模版功能
- _beforeVisitCmd.init(_globalZOrder, _modelViewTransform, flags);
- _beforeVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onBeforeVisit, _stencilStateManager);
- renderer->addCommand(&_beforeVisitCmd);
- ///绘制自身的模版多边形
- bool visibleByCamera = isVisitableByVisitingCamera();
- if (visibleByCamera) {
- draw(renderer, _modelViewTransform, flags);
- }
- ///为渲染启用模板功能
- _afterDrawCmd.init(_globalZOrder, _modelViewTransform, flags);
- _afterDrawCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterDrawStencil, _stencilStateManager);
- renderer->addCommand(&_afterDrawCmd);
- ///遍历执行子节点的visit
- if (_children.empty() == false) {
- sortAllChildren();
- for (auto iter = _children.cbegin(); iter != _children.cend(); ++iter) {
- (*iter)->visit(renderer, _modelViewTransform, flags);
- }
- }
- ///关闭模版功能
- _afterVisitCmd.init(_globalZOrder, _modelViewTransform, flags);
- _afterVisitCmd.func = CC_CALLBACK_0(StencilStateManager::onAfterVisit, _stencilStateManager);
- renderer->addCommand(&_afterVisitCmd);
-
- renderer->popGroup();
- director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
- }
- void PolygonClippingNode::draw(Renderer* renderer, const Mat4 &transform, uint32_t flags) {
- if (_vertsCnt == 0) {
- return;
- }
- _customDrawCmd.init(_globalZOrder, transform, flags);
- _customDrawCmd.func = [this, transform](void) {
- ///顶点坐标发生变化
- if (_vertsDirty) {
- _bindVAOAndVBO();
- _vertsDirty = false;
- }
- GLProgramState* programState = getGLProgramState();
- programState->apply(transform);
- GL::bindVAO(_vao);
- glDrawArrays(GL_TRIANGLES, 0, _vertsCnt);
- GL::bindVAO(0);
- };
- renderer->addCommand(&_customDrawCmd);
- }
- PolygonClippingNode::PolygonClippingNode() {
- _verts = new Vec2[_vertsCnt];
- _stencilStateManager = new StencilStateManager();
- glGenVertexArrays(1, &_vao);
- glGenBuffers(1, &_vbo);
- }
- PolygonClippingNode::~PolygonClippingNode() {
- glDeleteBuffers(1, &_vbo);
- glDeleteVertexArrays(1, &_vao);
- delete _stencilStateManager;
- delete [] _verts;
- }
- bool PolygonClippingNode::_initWithData(const std::vector<Vec2>& verts, const bool& close, const bool& clockwise) {
- ///设置闭合多边形的顶点数据
- setPolygonVerts(verts, close, clockwise);
- ///创建着色器程序
- _createGLProgram();
- ///绑定vao和vbo
- _bindVAOAndVBO();
- return Node::init();
- }
- bool PolygonClippingNode::_initWithFile(const std::string& fileName) {
- ///设置闭合多边形的顶点数据文件
- setPolygonFile(fileName);
- ///创建着色器程序
- _createGLProgram();
- ///绑定vao和vbo
- _bindVAOAndVBO();
- return Node::init();
- }
- std::vector<Vec2> PolygonClippingNode::_parseFile(const std::string& fileName) {
- std::vector<Vec2> ret;
- const std::string& content = FileUtils::getInstance()->getStringFromFile(fileName);
- if (content.empty() == false) {
- std::string error = "";
- const json11::Json& jDoc = json11::Json::parse(content, error);
- if (error.empty()) {
- const json11::Json::object& jData = jDoc.object_items();
- const json11::Json::array& jVerts = jData.at("verts").array_items();
- for (int i = 0; i < jVerts.size(); ++i) {
- const json11::Json::array& jVert = jVerts.at(i).array_items();
- const float& x = jVert.at(0).number_value();
- const float& y = jVert.at(1).number_value();
- ret.emplace_back(x, y);
- }
- const bool& close = jData.at("close").bool_value();
- if (close) {
- ret.pop_back();
- }
- const bool& clockwise = jData.at("clockwise").bool_value();
- if (clockwise) {
- std::reverse(ret.begin(), ret.end());
- }
- } else {
- CCASSERT(false, "解析多边形顶点数据文件错误");
- }
- }
- return ret;
- }
- void PolygonClippingNode::_createGLProgram() {
- cocos2d::GLProgram* program = cocos2d::GLProgram::createWithByteArrays(kPolygonClippingNodeVsh, kPolygonClippingNodeFsh);
- cocos2d::GLProgramState* programState = cocos2d::GLProgramState::getOrCreateWithGLProgram(program);
- setGLProgramState(programState);
- }
- void PolygonClippingNode::_bindVAOAndVBO() {
- GL::bindVAO(_vao);
- glBindBuffer(GL_ARRAY_BUFFER, _vbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof(Vec2) * _vertsCnt, _verts, GL_STATIC_DRAW);
- glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
- glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(Vec2), nullptr);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- GL::bindVAO(0);
- }
- void PolygonClippingNode::_updateOpenGLDrawVerts(std::vector<Vec2> verts) {
- if (verts.size() < 3) {
- delete [] _verts;
- _vertsCnt = 0;
- _verts = new Vec2[_vertsCnt];
- _vertsDirty = true;
- return;
- }
- ///删除旧顶点数据
- delete [] _verts;
- _vertsCnt = 0;
- ///将多边形顶点分割成绘制三角形
- std::vector<Vec2> triangleVerts;
- while (verts.size() > 3) {
- ///找到一个凸位顶点
- const int& convexVertexIdx = _findConvexVertex(verts);
- ///分割一个凸位顶点构成的多边形内嵌三角形
- const int& vertsSize = static_cast<int>(verts.size());
- const int& leftVertIdx = (convexVertexIdx - 1 + vertsSize) % vertsSize;
- const int& rightVertIdx = (convexVertexIdx + 1) % vertsSize;
- triangleVerts.emplace_back(verts.at(leftVertIdx));
- triangleVerts.emplace_back(verts.at(convexVertexIdx));
- triangleVerts.emplace_back(verts.at(rightVertIdx));
- ///凸位顶点完成三角形的构建则从多边形顶点数组中移除
- verts.erase(verts.begin() + convexVertexIdx);
- }
- ///添加最后一组三角形
- triangleVerts.emplace_back(verts.at(0));
- triangleVerts.emplace_back(verts.at(1));
- triangleVerts.emplace_back(verts.at(2));
- ///转成OpenGL使用的数据
- _vertsCnt = static_cast<int>(triangleVerts.size());
- _verts = new Vec2[_vertsCnt];
- for (int i = 0; i < _vertsCnt; ++i) {
- _verts[i] = triangleVerts.at(i);
- }
- _vertsDirty = true;
- }
- int PolygonClippingNode::_findConvexVertex(const std::vector<Vec2>& verts) {
- int ret = 0;
- const int& vertsSize = static_cast<int>(verts.size());
- for (int i = 0; i < vertsSize; ++i) {
- ///取左索引使用 i - 1 + vertsSize ,能保证当 i = 0时左索引为数组最后一个元素的索引
- const int& leftVertIdx = (i - 1 + vertsSize) % vertsSize;
- const int& rightVertIdx = (i + 1) % vertsSize;
- ///获取三个相邻的顶点
- const Vec2& vert = verts.at(i);
- const Vec2& leftVert = verts.at(leftVertIdx);
- const Vec2& rightVert = verts.at(rightVertIdx);
- ///如果三个顶点构成的三角形为正面,表示三角形一定不在多边形外。
- ///如果三个顶点构成的三角形为多边形的内嵌三角形,表示当前顶点为凸位顶点。
- if (_isPositiveTriangle(leftVert, vert, rightVert)
- && _isEmbeddedTriangle(verts, leftVert, vert, rightVert)) {
- ret = i;
- break;
- }
- }
- return ret;
- }
- bool PolygonClippingNode::_isPositiveTriangle(const Vec2& vert1, const Vec2& vert2, const Vec2& vert3) {
- const float& val = (vert2.x - vert1.x) * (vert3.y - vert1.y) - (vert2.y - vert1.y) * (vert3.x - vert1.x);
- return val >= 0.0f;
- }
- bool PolygonClippingNode::_isEmbeddedTriangle(const std::vector<Vec2>& verts, const Vec2& vert1, const Vec2& vert2, const Vec2& vert3) {
- bool ret = true;
- for (const Vec2& vert : verts) {
- ///跳过自检
- if (vert == vert1 || vert == vert2 || vert == vert3) {
- continue;
- }
- ///多边形中存在任意一个其他顶点位于构造出的三角形内
- if (_isInteriorPoint(vert, vert1, vert2, vert3)) {
- ret = false;
- break;
- }
- }
- return ret;
- }
- bool PolygonClippingNode::_isInteriorPoint(const Vec2& point, const Vec2& vert1, const Vec2& vert2, const Vec2& vert3) {
- bool ret = false;
- ///以这个点为起始顶点按三角形顶点顺序依次取两个顶点绘制三角形,如果都为正面三角形则这个点在三角形内部
- if (_isPositiveTriangle(point, vert1, vert2)
- && _isPositiveTriangle(point, vert2, vert3)
- && _isPositiveTriangle(point, vert3, vert1)) {
- ret = true;
- }
- return ret;
- }
- NS_CC_END
|