123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- //
- // TiledPolygonSprite.cpp
- // building
- //
- // Created by yanqian on 2023/4/17.
- //
- #include "TiledPolygonSprite.hpp"
- #include "common/CocosConfig.h"
- NS_CC_BEGIN
- GLProgram* TiledPolygonSprite::_tiledProgram = nullptr;
- TiledPolygonSprite* TiledPolygonSprite::create()
- {
- TiledPolygonSprite *sprite = new (std::nothrow) TiledPolygonSprite();
- if (sprite && sprite->init()) {
- sprite->autorelease();
- return sprite;
- }
- CC_SAFE_DELETE(sprite);
- return nullptr;
- }
- void TiledPolygonSprite::setPbvertsFile(const std::string& pbvertsFilePath)
- {
- if (_vertsFullPath == pbvertsFilePath) {
- return;
- }
- _vertsFullPath = pbvertsFilePath;
- _triangleInfo.Clear();
-
- std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pbvertsFilePath);
- if (fullPath.empty() || !FileUtils::getInstance()->isFileExist(fullPath)) {
- // 如果不选择文件或者文件不存在, 则认为要清空顶点数据和画面
- _clearVertexBuffer();
- return;
- }
- Data data = FileUtils::getInstance()->getDataFromFile(fullPath);
- if (data.isNull()) {
- return;
- }
-
- // 反序列化Protobuf消息
- if (_triangleInfo.ParseFromArray(data.getBytes(), static_cast<int>(data.getSize()))) {
- // 如果texture已设置,初始化渲染所需的参数
- if (_texture != nullptr) {
- _initParamForRender();
- }
- }
- }
- void TiledPolygonSprite::setSpriteFrame(const std::string &spriteFrameName)
- {
- SpriteFrameCache *cache = SpriteFrameCache::getInstance();
- SpriteFrame *spriteFrame = cache->getSpriteFrameByName(spriteFrameName);
- if (CocosConfig::getAutoAddSingleImage2Cache()) {
- if (spriteFrame == nullptr) {
- Texture2D * texture = Director::getInstance()->getTextureCache()->addImage(spriteFrameName.c_str());
- if (texture != nullptr) {
- Rect bounds = Rect(0, 0, texture->getContentSize().width, texture->getContentSize().height);
- spriteFrame = SpriteFrame::createWithTexture(texture, bounds);
- cache->addSpriteFrame(spriteFrame, spriteFrameName.c_str());
- }
- }
- }
- setSpriteFrame(spriteFrame);
- }
- void TiledPolygonSprite::setSpriteFrame(SpriteFrame* spriteFrame)
- {
- if (_spriteFrame != spriteFrame) {
- CC_SAFE_RELEASE(_spriteFrame);
- _spriteFrame = spriteFrame;
- CC_SAFE_RETAIN(spriteFrame);
-
- if (_customMaterial && _spriteFrame) {
- _customMaterial->setParamsTexture(_spriteFrame);
- }
- }
- // 加载纹理
- Texture2D *texture = spriteFrame->getTexture();
- if (texture == nullptr || (_texture && (texture->getName() == _texture->getName()))) {
- return;
- }
- _texture = texture;
- _spSize = spriteFrame->getOriginalSize();
-
- // 设置纹理参数
- Texture2D::TexParams texParams;
- texParams.magFilter = GL_LINEAR; // 线性滤波
- texParams.minFilter = GL_LINEAR;
- texParams.wrapS = GL_REPEAT; // 重复贴图
- texParams.wrapT = GL_REPEAT;
-
- // 设置图集中纹理的矩形偏移和尺寸信息
- Rect rect = spriteFrame->getRectInPixels();
- Size atlasSize = spriteFrame->getTexture()->getContentSizeInPixels();
- _texRectOffset = Vec2(rect.origin.x / atlasSize.width, rect.origin.y / atlasSize.height);
- _texRectSize = Vec2(rect.size.width / atlasSize.width, rect.size.height / atlasSize.height);
- _texture->setTexParameters(texParams);
-
- if (_triangleInfo.vertexcoords_size() != 0) {
- _initParamForRender();
- }
- }
- void TiledPolygonSprite::_initParamForRender()
- {
- // 解析三角形的顶点数据
- _initTriangleInfo();
-
- // 初始化着色器、VAO、VBO
- _setupVBOAndVAO();
- }
- std::pair<Vec2, Vec2> TiledPolygonSprite::_calBoundingBox(const google::protobuf::RepeatedPtrField<float>& vertices)
- {
- Vec2 minPoint(std::numeric_limits<float>::max(), std::numeric_limits<float>::max()); // 左下角的坐标
- Vec2 maxPoint(std::numeric_limits<float>::min(), std::numeric_limits<float>::min()); // 右上角的坐标
-
- for (int i = 0; i < vertices.size(); i++) {
- if (i % 2 == 0) {
- minPoint.x = std::min(minPoint.x, vertices[i]);
- maxPoint.x = std::max(maxPoint.x, vertices[i]);
- } else {
- minPoint.y = std::min(minPoint.y, vertices[i]);
- maxPoint.y = std::max(maxPoint.y, vertices[i]);
- }
- }
- return std::make_pair(minPoint, maxPoint);
- }
- void TiledPolygonSprite::_initTriangleInfo()
- {
- _verticesNumber = _triangleInfo.vertexindex_size();
-
- delete[] _vertices;
- _vertices = new TriangleVertexInfo[_verticesNumber];
-
- const google::protobuf::RepeatedPtrField<float> verticesPtr(_triangleInfo.vertexcoords().begin(), _triangleInfo.vertexcoords().end());
- Vec2 minPoint, maxPoint;
- std::tie(minPoint, maxPoint) = _calBoundingBox(verticesPtr);
- // 创建顶点和纹理坐标数组,uv根据最小包围盒计算
- for (int i = 0; i < _verticesNumber; i++) {
- int index = _triangleInfo.vertexindex(i);
- Vec2 vertex = Vec2(_triangleInfo.vertexcoords(index * 2), _triangleInfo.vertexcoords(index * 2 + 1));
- _vertices[i].vertices = vertex;
-
- // 计算纹理坐标
- float u = (vertex.x - minPoint.x) / (_spSize.width);
- float v = (maxPoint.y - vertex.y) / (_spSize.height);
- _vertices[i].texCoords = Tex2F(u, v);
- }
- }
- void TiledPolygonSprite::_setupVBOAndVAO()
- {
- const char* tilePolygonVert = R"(
- attribute vec4 a_position;
- attribute vec2 a_texCoord;
- attribute vec4 a_color;
- varying vec4 v_fragmentColor;
- varying vec4 v_scale;
- #ifdef GL_ES
- varying highp vec2 v_uv0;
- #else
- varying vec2 v_uv0;
- #endif
- uniform mat4 u_modelview;
- void main()
- {
- gl_Position = CC_PMatrix * u_modelview * a_position;
- v_fragmentColor = a_color;
- v_uv0 = a_texCoord;
- }
- )";
-
- const char* tilePolygonFrag = R"(
- varying vec4 v_fragmentColor;
- varying vec4 v_scale;
- #ifdef GL_ES
- varying highp vec2 v_uv0;
- #else
- varying vec2 v_uv0;
- #endif
-
- uniform sampler2D u_tex_r;
- uniform vec2 u_texRectOffset;
- uniform vec2 u_texRectSize;
- void main()
- {
- vec2 texCoord = fract(v_uv0) * u_texRectSize + u_texRectOffset;
- vec4 r = texture2D(u_tex_r, texCoord);
- gl_FragColor = vec4((r).rgb, 1.0);
- }
- )";
- // 创建着色器程序
- if (_tiledProgram == nullptr) {
- _tiledProgram = GLProgram::createWithByteArrays(tilePolygonVert, tilePolygonFrag);
- _tiledProgram->retain();
- }
- setGLProgramState(GLProgramState::getOrCreateWithGLProgram(_tiledProgram));
-
- // 创建并绑定顶点数组对象
- glGenVertexArrays(1, &_vao);
- glBindVertexArray(_vao);
- // 创建并绑定顶点缓冲对象
- glGenBuffers(1, &_vbo);
- glBindBuffer(GL_ARRAY_BUFFER, _vbo);
- glBufferData(GL_ARRAY_BUFFER, sizeof(TriangleVertexInfo) * _verticesNumber, _vertices, GL_STATIC_DRAW);
-
- // 启用并指定顶点坐标属性
- glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_POSITION);
- glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(TriangleVertexInfo), (GLvoid *)offsetof(TriangleVertexInfo, vertices));
-
- // 启用并指定纹理坐标属性
- glEnableVertexAttribArray(GLProgram::VERTEX_ATTRIB_TEX_COORD);
- glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(TriangleVertexInfo), (GLvoid *)offsetof(TriangleVertexInfo, texCoords));
- }
- void TiledPolygonSprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
- {
- // 将自定义的渲染命令添加到渲染队列中
- _customCommand.init(_globalZOrder, transform, flags);
- _customCommand.func = CC_CALLBACK_0(TiledPolygonSprite::onDraw, this, transform, flags);
- renderer->addCommand(&_customCommand);
- }
- void TiledPolygonSprite::onDraw(const Mat4 &transform, uint32_t flags)
- {
- if (_customMaterial != nullptr && _materialEnable == true) {
- for (auto technique: _customMaterial->getTechniques()) {
- for (auto pass: technique->getPasses()) {
- GLProgramState* passProgramState = pass->getGLProgramState();
- if (passProgramState != nullptr) {
- // 保存一下sprite创建时默认的state, 关闭材质球功能时可以恢复原有着色器
- if (_defaultProgramState == nullptr) {
- _defaultProgramState = getGLProgramState();
- }
- setGLProgramState(passProgramState);
- }
-
- float deltaTime = _director->getDeltaTime();
- _customMaterial->updateUniformTime(deltaTime);
- }
- }
- } else {
- // 中途关闭材质球后的处理, 如果不启用材质的话, 也不会进入到这个if中
- if (_defaultProgramState != nullptr && getGLProgramState() != _defaultProgramState) {
- setGLProgramState(_defaultProgramState);
- }
- }
-
- GLProgramState* programState = getGLProgramState();
-
- // 设置着色器中的变换矩阵
- programState->setUniformMat4("u_modelview", transform);
- programState->apply(transform);
-
- // 设置纹理在图集中的偏移和尺寸
- programState->setUniformVec2("u_texRectOffset", _texRectOffset);
- programState->setUniformVec2("u_texRectSize", _texRectSize);
-
- // 绑定顶点数组对象
- glBindVertexArray(_vao);
-
- // 没有材质时,为默认着色器绑定纹理
- if (_customMaterial == nullptr || _materialEnable == false) {
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, _texture->getName());
- // 设置着色器中的uniform变量
- GLint textureLocation = glGetUniformLocation(programState->getGLProgram()->getProgram(), "u_tex_r");
- glUniform1i(textureLocation, 0);
- }
- // 绘制
- glDrawArrays(GL_TRIANGLES, 0, _verticesNumber);
-
- GLenum error = glGetError();
- if (error != GL_NO_ERROR) {
- CCASSERT(false, "多边形平铺出现OPENGL错误");
- CCLOG("OpenGL error 0x%04X in %s %s %d\n", error, __FILE__, __FUNCTION__, __LINE__);
- }
-
- // 取消绑定
- glBindVertexArray(0);
- if (_customMaterial == nullptr || _materialEnable == false) {
- glBindTexture(GL_TEXTURE_2D, 0);
- }
- }
- void TiledPolygonSprite::_clearVertexBuffer()
- {
- glDeleteVertexArrays(1, &_vao);
- glDeleteBuffers(1, &_vbo);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- }
- TiledPolygonSprite::~TiledPolygonSprite()
- {
- _clearVertexBuffer();
- delete [] _vertices;
- }
- NS_CC_END
|