void BGGraphics::pushCirclePart(ofMesh& mesh, ofVec2f position, float nodeRadius, float minAngle, float deltaAngle) { mesh.setMode(OF_PRIMITIVE_TRIANGLES); pushVertex(mesh, position.x, position.y, 1, 0, 0, 1, 0, 0); float innerRadius = nodeRadius - NETWORK_OFFSET; float internalOffsetY = .5;// innerRadius / nodeRadius; int samples = (int)(15 * deltaAngle / M_PI); samples = max(1, samples); for(int i=0; i<samples; ++i) { float angle = minAngle + deltaAngle * i / (float)(samples - 1); ofVec2f to(cosf(angle), sinf(angle)); ofVec2f p1 = position + to * innerRadius; ofVec2f p2 = position + to * nodeRadius; //pushVertex(ofMesh & mesh, float x, float y, float z, float nx, float ny, float nz, float offsetX, float offsetY) pushVertex(mesh, p1.x, p1.y, 1, 0, 0, 1, 0, internalOffsetY); pushVertex(mesh, p2.x, p2.y, 0, to.x, to.y, 0, 0, 1); if(i > 0) { int offset = 1 + 2 * i; mesh.addTriangle(0, offset - 2, offset); mesh.addTriangle(offset - 2, offset - 1, offset); mesh.addTriangle(offset - 1, offset, offset + 1); } } }
void BGGraphics::pushDoubleConnectedNode(ofMesh& mesh, ofVec2f position, ofVec2f startEdgePoint, ofVec2f endEdgePoint) { int samples = 10; for(int i=0; i<samples; ++i) { float t = i / (float)(samples - 1); float localDepth = -.5 + t; ofVec2f pt, normal; sampleSpline(startEdgePoint, position, endEdgePoint, t, pt, normal); pushVertex(mesh, pt.x + NETWORK_OFFSET * normal.x, pt.y + NETWORK_OFFSET * normal.y, 0, normal.x, normal.y, 0, localDepth, 1); pushVertex(mesh, pt.x, pt.y, 1, 0, 0, 1, localDepth, 0); pushVertex(mesh, pt.x - NETWORK_OFFSET * normal.x, pt.y - NETWORK_OFFSET * normal.y, 0, -normal.x, -normal.y, 0, localDepth, 1); if(i > 0) { int offset = 3 * i; for(int j=0; j<2; ++j) { mesh.addTriangle(offset + j, offset - 3 + j, offset - 2 + j); mesh.addTriangle(offset + j, offset + 1 + j, offset - 2 + j); } } } }
void Canvas::drawLine(const float width, Color const& color, geom::Point const& start, geom::Point const& end, const float depth) { if(color.isInvalid() || !(width > 0)){ return; } this->setLineWidth(width); this->setColor(color); this->setOperation(Lines); pushVertex(start.x(), start.y(), depth); pushVertex(end.x() , end.y(), depth); }
void OpenGLTextureBuilder::push4Vertices(CUSTOMVERTEX2D *pVertices, int pPosVert, int pPosX, int pPosY, int pPosZ, int pWidthBlock, int pHeightBlock, float pU, float pV){ // Push the 4 vertex of the quad // The pushing order is important // Upper-right pushVertex(pVertices, pPosVert, pPosX + pWidthBlock, pPosY - pHeightBlock, pPosZ, pU, pV); // Lower-right pushVertex(pVertices, pPosVert + 1, pPosX + pWidthBlock, pPosY, pPosZ, pU, 0.0f); // Upper-left pushVertex(pVertices, pPosVert + 2, pPosX, pPosY - pHeightBlock, pPosZ, 0.0f, pV); // Lower-left pushVertex(pVertices, pPosVert + 3, pPosX, pPosY, pPosZ, 0.0f, 0.0f); }
/* ================== Push 4 vertices into the buffer creating a quad ================== */ void IND_Surface::push4Vertices(CUSTOMVERTEX2D *pVertices, int pPosVert, int pX, int pY, int pZ, int pWidthBlock, int pHeightBlock, int pWidth, int pHeight) { // Push the 4 vertex of the quad // The pushing order is important // Upper-right pushVertex(pVertices, pPosVert, pX + pWidthBlock, pY - pHeightBlock, pZ, (float)(pX + pWidthBlock) / pWidth, 1.0f - ((float)(pY - pHeightBlock) / pHeight)); // Lower-right pushVertex(pVertices, pPosVert + 1, pX + pWidthBlock, pY, pZ, (float)(pX + pWidthBlock) / pWidth, 1.0f - ((float) pY / pHeight)); // Upper-left pushVertex(pVertices, pPosVert + 2, pX, pY - pHeightBlock, pZ, (float) pX / pWidth, 1.0f - ((float)(pY - pHeightBlock) / pHeight)); // Lower-left pushVertex(pVertices, pPosVert + 3, pX, pY, pZ, (float) pX / pWidth, 1.0f - ((float) pY / pHeight)); }
void Canvas::drawLines(const float width, Color const& color, std::vector<geom::Point> const& pts, const float depth) { if(color.isInvalid() || !(width > 0)){ return; } this->setLineWidth(width); this->setColor(color); this->setOperation(LineStrip); for(geom::Point const& pt : pts){ pushVertex(pt.x(), pt.y(), depth); } flushGL(); }
void polyFixWidth::addPoint( ofPoint pt ) { if( pts.size() < 2) { pushVertex( pt ); selectedPoint = pts.size()-1; } if( pts.size() == 2 ) makeRectangle(); //cout << "pts added " << pts.size() << endl; }
void polyEditable::addPoint( ofPoint pt ) { if( bUseClosePoly && pts.size() > 2) { if( abs( (int)(pts[0].x-pt.x) ) <= selectDist && abs( (int)(pts[0].y-pt.y) ) <= selectDist ) { bClosed = true; } } if(!bClosed) pushVertex( pt ); selectedPoint = pts.size()-1; //cout << "editable add " << endl; }
void ShapeCube::rebuildVerts(){ if (m_t1 < 1){ m_t1 = 1; } m_vertices.clear(); //2 * t1 * t1 triangles per face for (int face = 0; face < 6; face++){ //do same generation for each face, just rotate glm::mat4 faceMat; switch (face){ case 0: faceMat = glm::mat4(); //identity break; case 1: faceMat = glm::rotate(static_cast<float>(M_PI), glm::vec3(0.f, 1.f, 0.f)); break; case 2: faceMat = glm::rotate(static_cast<float>(M_PI/2.f), glm::vec3(0, 1, 0)); break; case 3: faceMat = glm::rotate(static_cast<float>(-M_PI/2.f), glm::vec3(0, 1, 0)); break; case 4: faceMat = glm::rotate(static_cast<float>(M_PI/2.f), glm::vec3(1, 0, 0)); break; case 5: faceMat = glm::rotate(static_cast<float>(-M_PI/2.f), glm::vec3(1, 0, 0)); break; } for (float ind1 = 0; ind1 < m_t1; ind1++){ for (float ind2 = 0; ind2 < m_t1; ind2++){ float i = -.5 + ind1 * 1.f/m_t1; //x/y values float j = -.5 + ind2 * 1.f/m_t1; glm::vec4 normal = faceMat * glm::vec4(0, 0, 1, 1); glm::vec4 botleft = faceMat * glm::vec4(i, j, .5f, 1); glm::vec4 botright = faceMat * glm::vec4(i + 1.f/m_t1, j, .5f, 1); glm::vec4 topright = faceMat * glm::vec4(i + 1.f/m_t1, j + 1.f/m_t1, .5f, 1); glm::vec4 topleft = faceMat * glm::vec4(i, j + 1.f/m_t1, .5f, 1); pushVertex(botleft, normal); pushVertex(botright, normal); pushVertex(topleft, normal); pushVertex(topleft, normal); pushVertex(botright, normal); pushVertex(topright, normal); } } } }
void Canvas::drawRect(const float width, Color const& color, geom::Area const& area, const float depth) { if(color.isInvalid() || !(width > 0)){ return; } float const sx = area.x(); float const ex = area.x()+area.width(); float const sy = area.y(); float const ey = area.y()+area.height(); this->setColor(color); this->setLineWidth(width); this->setOperation(Lines); pushVertex(sx, sy, depth); pushVertex(ex, sy, depth); pushVertex(ex, sy, depth); pushVertex(ex, ey, depth); pushVertex(ex, ey, depth); pushVertex(sx, ey, depth); pushVertex(sx, ey, depth); pushVertex(sx, sy, depth); }
void CMC_MeshData::loadFromTZW(const rapidjson::Value &value) { //load material index. m_materialIndex = value["material_index"].GetInt (); //load vertices auto& verticesObj = value["vertices"]; for(auto iter = verticesObj.Begin ();iter!= verticesObj.End ();iter++) { auto& vertexObj = *iter; CMC_Vertex vertex; vertex.loadFromTZW (vertexObj); pushVertex (vertex); } //load indices auto& indicesObj = value["indices"]; for(auto iter = indicesObj.Begin ();iter != indicesObj.End ();iter++) { auto& indexObj = * iter; pushIndex (indexObj.GetInt ()); } }
void Canvas::fillRect(Color const& color, geom::Area const& area, const float depth) { if(color.isInvalid() || area.empty()){ return; } float const sx = area.x(); float const ex = area.x()+area.width(); float const sy = area.y(); float const ey = area.y()+area.height(); this->setColor(color); this->setOperation(Rect); pushVertex(sx, sy, depth); pushVertex(sx, ey, depth); pushVertex(ex, sy, depth); pushVertex(ex, sy, depth); pushVertex(sx, ey, depth); pushVertex(ex, ey, depth); }
Pan::Pan(const glm::vec2 &repeat) : AGeometry::AGeometry("pan.geo") { pushVertex(glm::vec3(1.0f, 1.0f, 0.0f)).pushNormal(glm::vec3(0.0, 0.0, -1.0)); pushVertex(glm::vec3(-1.0f, 1.0f, 0.0f)).pushNormal(glm::vec3(0.0, 0.0, -1.0)); pushVertex(glm::vec3(-1.0f, -1.0f, 0.0f)).pushNormal(glm::vec3(0.0, 0.0, -1.0)); pushVertex(glm::vec3(-1.0f, -1.0f, 0.0f)).pushNormal(glm::vec3(0.0, 0.0, -1.0)); pushVertex(glm::vec3(1.0f, -1.0f, 0.0f)).pushNormal(glm::vec3(0.0, 0.0, -1.0)); pushVertex(glm::vec3(1.0f, 1.0f, 0.0f)).pushNormal(glm::vec3(0.0, 0.0, -1.0)); pushUv(glm::vec2(0.0f, 0.0f)); pushUv(glm::vec2(repeat.y, 0.0f)); pushUv(glm::vec2(repeat.y, repeat.x)); pushUv(glm::vec2(repeat.y, repeat.x)); pushUv(glm::vec2(0.0f, repeat.x)); pushUv(glm::vec2(0.0f, 0.0f)); build(); }
void Canvas::drawTexture(unsigned int texId, geom::Area const& areaInRoot, geom::Area const& coordinateInSprite, const float depth, Color const& color) { const float x=areaInRoot.x(); const float y=areaInRoot.y(); const float width = areaInRoot.width(); const float height = areaInRoot.height(); const float top = coordinateInSprite.y(); const float left = coordinateInSprite.x(); const float right = coordinateInSprite.x()+coordinateInSprite.width(); const float bottom = coordinateInSprite.y()+coordinateInSprite.height(); this->bindTexture(texId); this->setColor(color); this->setOperation(Texture); pushTexCoord(left ,top );pushVertex(x , y , depth); pushTexCoord(left ,bottom);pushVertex(x , y+height, depth); pushTexCoord(right,top );pushVertex(x+width, y , depth); pushTexCoord(right,top );pushVertex(x+width, y , depth); pushTexCoord(left ,bottom);pushVertex(x , y+height, depth); pushTexCoord(right,bottom);pushVertex(x+width, y+height, depth); flushGL(); }
void BGGraphics::pushTripleConnectedNode(ofMesh& mesh, ofVec2f position, ofVec2f startEdgePoint, ofVec2f endEdgePoint1, ofVec2f endEdgePoint2) { ofVec2f orderedPts[3] = { startEdgePoint, endEdgePoint1, endEdgePoint2 }; /* ofMesh centerTriangleMesh; centerTriangleMesh.setMode(OF_PRIMITIVE_TRIANGLE_FAN); ofVec2f centerTriangleTexPt = calculateInternalTexOffset(0.5, true, true, -1); pushVertex(centerTriangleMesh, position.x, position.y, 1, 0, 0, 1, centerTriangleTexPt.x, centerTriangleTexPt.y); */ ofVec2f sumCenterPosition(0,0); int centerIndices[9]; int halfSamples = 8; for(int idx=0; idx<3; ++idx) { int prevIdx = idx == 0 ? 2 : (idx - 1); int nextIdx = (idx + 1) % 3; //ofVec2f focus1 = focusPts[idx]; //ofVec2f focus2 = focusPts[prevIdx]; for(int i=0; i<halfSamples; ++i) { float t = .5 * i / (float)(halfSamples - 1); ofVec2f pt1, normal1, pt2, normal2; sampleSpline(orderedPts[idx], position, orderedPts[nextIdx], t, pt1, normal1); sampleSpline(orderedPts[idx], position, orderedPts[prevIdx], t, pt2, normal2); normal2 = -normal2; ofVec2f center = (pt1 + pt2) / 2.0; /* float offAngle1 = focusAngles[idx] + t * deltaAngle; ofVec2f offVector1 = ofVec2f(cosf(offAngle1), sinf(offAngle1)); float offAngle2 = focusAngles[prevIdx] + (1. - t) * deltaAngle; ofVec2f offVector2 = ofVec2f(cosf(offAngle2), sinf(offAngle2)); */ //ofVec2f BGGraphics::calculateInternalTexOffset(float t, bool isSourceSpline, int offsetIndex) bool isSourceSegment = idx == 0; bool isSourceSpline1 = true, isSourceSpline2 = true; float t1 = t, t2 = t; if(idx == 1) { isSourceSpline1 = false; t2 = 1. - t; } else if(idx == 2) { //mirrored version of idx == 1 isSourceSpline2 = false; t1 = 1. - t; } ofVec2f centerTexPt = calculateInternalTexOffset(t1, isSourceSpline1, isSourceSegment, 0); ofVec2f innerTexPt1 = calculateInternalTexOffset(t1, isSourceSpline1, isSourceSegment, 1); ofVec2f outerTexPt1 = calculateInternalTexOffset(t1, isSourceSpline1, isSourceSegment, 2); ofVec2f innerTexPt2 = calculateInternalTexOffset(t2, isSourceSpline2, isSourceSegment, 1); ofVec2f outerTexPt2 = calculateInternalTexOffset(t2, isSourceSpline2, isSourceSegment, 2); //TODO: remove!! //centerTexPt = (innerTexPt1 + innerTexPt2) / 2.0; //innerTexPt2 = ofVec2f(-10000,-10000); //outerTexPt2 = innerTexPt2; /* ofVec2f innerTexPt1 = focus1 + baseSize * offVector1; ofVec2f outerTexPt1 = focus1 + .5 * baseSize * offVector1; ofVec2f innerTexPt2 = focus2 + baseSize * offVector2; ofVec2f outerTexPt2 = focus2 + .5 * baseSize * offVector2; ofVec2f centerTexPt = (innerTexPt1 + innerTexPt2) / 2.0; */ pushVertex(mesh, pt1.x + NETWORK_OFFSET * normal1.x, pt1.y + NETWORK_OFFSET * normal1.y, 0, normal1.x, normal1.y, 0, outerTexPt1.x, outerTexPt1.y); pushVertex(mesh, pt1.x, pt1.y, 1, 0, 0, 1, innerTexPt1.x, innerTexPt1.y); pushVertex(mesh, center.x, center.y, 1, 0, 0, 1, centerTexPt.x, centerTexPt.y); pushVertex(mesh, pt2.x, pt2.y, 1, 0, 0, 1, innerTexPt2.x, innerTexPt2.y); pushVertex(mesh, pt2.x + NETWORK_OFFSET * normal2.x, pt2.y + NETWORK_OFFSET * normal2.y, 0, normal2.x, normal2.y, 0, outerTexPt2.x, outerTexPt2.y); if(i > 0) { int offset = (5 * idx * halfSamples) + 5 * i; for(int j=0; j<4; ++j) { mesh.addTriangle(offset + j, offset - 5 + j, offset - 4 + j); mesh.addTriangle(offset + j, offset + 1 + j, offset - 4 + j); } if(i == halfSamples - 1) { sumCenterPosition += pt1; for(int j=0; j<3; ++j) { centerIndices[3 * idx + j] = offset + 1 + j; } } } } } //add center point: ofVec2f avgCenter = sumCenterPosition / 3.0; ofVec2f centerTriangleTexPt = calculateInternalTexOffset(0.5, true, true, -1); pushVertex(mesh, avgCenter.x, avgCenter.y, 1, 0, 0, 1, centerTriangleTexPt.x, centerTriangleTexPt.y); //stitch to bounds: int centerOffset = mesh.getVertices().size() - 1; for(int i=0; i<9; ++i) mesh.addTriangle(centerOffset, centerIndices[i], centerIndices[(i + 1) % 9]); //centerTriangleMesh.setVertex(0, ofVec3f(avgCenter.x, avgCenter.y, 1)); /* ofVec2f avgCenter = sumCenterPosition / 3.0; centerTriangleMesh.setVertex(0, ofVec3f(avgCenter.x, avgCenter.y, 1)); //stitch up center triangle fan: centerTriangleMesh.addVertex(centerTriangleMesh.getVertex(1)); centerTriangleMesh.addTexCoord(centerTriangleMesh.getTexCoord(1)); centerTriangleMesh.addNormal(centerTriangleMesh.getNormal(1)); centerTriangleMesh.addColor(centerTriangleMesh.getColor(1)); drawMesh(centerTriangleMesh, depth); */ }
bool Loader::loadFromModel(const char *fileName) { printf("load %s begin\n",fileName); printf("parsing..\n"); const aiScene* pScene = m_Importer.ReadFile(fileName,aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals |aiProcess_CalcTangentSpace); this->m_pScene = (aiScene*)pScene; if(!m_pScene) { printf("parsing failure!\n"); return false; } else { printf("parsing succes!\n"); printf("extracting data to memory...\n"); m_model = new CMC_ModelData(); auto inverseTransform = pScene->mRootNode->mTransformation; inverseTransform = inverseTransform.Inverse(); m_model->setGlobalInverseTransform (toQMatrix(inverseTransform)); LoadMaterial(pScene,fileName); const aiVector3D Zero3D(0.0f, 0.0f, 0.0f); for(int i =0 ;i< pScene->mNumMeshes ;i++) { const aiMesh* the_mesh = pScene->mMeshes[i]; auto mesh = new CMC_MeshData; m_model->addMesh(mesh); //set material mesh->setMaterialIndex (the_mesh->mMaterialIndex); for(int j =0; j<the_mesh->mNumVertices;j++) { const aiVector3D* pPos = &(the_mesh->mVertices[j]); const aiVector3D* pNormal = &(the_mesh->mNormals[j]); const aiVector3D* pTexCoord = the_mesh->HasTextureCoords(0) ? &(the_mesh->mTextureCoords[0][j]) : &Zero3D; const aiVector3D* pTangent = &(the_mesh->mTangents[i]); CMC_Vertex vec; vec.setPos (QVector3D(pPos->x,pPos->y,pPos->z)); vec.setNormal (QVector3D(pNormal->x,pNormal->y,pNormal->z)); vec.setUV (QVector2D(pTexCoord->x,pTexCoord->y)); if(pTangent) { vec.setTangent (QVector3D(pTangent->x,pTangent->y,pTangent->z)); } mesh->pushVertex (vec); } for (unsigned int k = 0 ; k < the_mesh->mNumFaces ; k++) { const aiFace& Face = the_mesh->mFaces[k]; assert(Face.mNumIndices == 3); mesh->pushIndex (Face.mIndices[0]); mesh->pushIndex(Face.mIndices[1]); mesh->pushIndex(Face.mIndices[2]); } //load bones loadBoneList(the_mesh,mesh); //mesh->finish(); } loadNodeHeirarchy(nullptr,m_pScene->mRootNode); loadAnimations (); printf("extracting finish..\n"); return true; } }
void BGGraphics::pushSingleConnectedNode(ofMesh& mesh, ofVec2f position, float nodeRadius, ofVec2f edgePoint, bool isRoot) { float innerRadius = nodeRadius - NETWORK_OFFSET; ofVec2f to = edgePoint - position; float toDist = to.length(); to /= toDist; ofVec2f perp = ofVec2f(-to.y, to.x); float depthFactor = isRoot ? .5 : -.5; float proj = sqrtf(.5 * innerRadius * innerRadius); if(toDist > innerRadius + NETWORK_OFFSET) { float offset = min(innerRadius + .5f * (toDist - innerRadius), 2 * proj); //perform spline traversal... ofVec2f controlPoint = position + offset * to;// .5 * (position + innerRadius * to) + .5 * edgePoint; float angle = acosf(innerRadius / offset); pushCirclePart(mesh, position, nodeRadius, atan2f(to.y, to.x) + angle, 2 * (M_PI - angle)); int splineOffset = mesh.getVertices().size(); /* ofVec2f anchorLeft = position + proj * to + proj * perp; ofVec2f anchorRight = position + proj * to - proj * perp; ofVec2f toA1 = (anchorLeft - position).normalize(); ofVec2f toA2 = (anchorRight - position).normalize(); */ float toAng = atan2f(to.y, to.x); ofVec2f toA1(cosf(toAng + angle), sinf(toAng + angle)); ofVec2f toA2(cosf(toAng - angle), sinf(toAng - angle)); float facU = innerRadius * cosf(angle); float facV = innerRadius * sinf(angle); float anchorProj = sqrtf(.5 * innerRadius * innerRadius); ofVec2f anchorLeft = position + innerRadius * toA1; ofVec2f anchorRight = position + innerRadius * toA2; float innerRadiusFactor = .5;// innerRadius / nodeRadius; //add first point: pushVertex(mesh, anchorLeft.x + NETWORK_OFFSET * toA1.x, anchorLeft.y + NETWORK_OFFSET * toA1.y, 0, toA1.x, toA1.y, 0, 0, 1); pushVertex(mesh, anchorLeft.x, anchorLeft.y, 1, 0, 0, 1, 0, innerRadiusFactor); pushVertex(mesh, position.x, position.y, 1, 0, 0, 1, 0, 0); pushVertex(mesh, anchorRight.x, anchorRight.y, 1, 0, 0, 1, 0, innerRadiusFactor); pushVertex(mesh, anchorRight.x + NETWORK_OFFSET * toA2.x, anchorRight.y + NETWORK_OFFSET * toA2.y, 0, toA2.x, toA2.y, 0, 0, 1); int samples = 8; for(int i=1; i<samples; ++i) { float t = i / (float)(samples - 1); float localDepth = depthFactor * t; ofVec2f pt, normal; sampleSpline(anchorLeft, controlPoint, edgePoint, t, pt, normal); normal = -normal; /* //project point on skeleton: //float projDistance = dot(pt - position, to); float innerSampleOffset = dot(pt - position, to);//(pt - centerSample).length(); ofVec2f centerSample = position + innerSampleOffset * to; float centerSampleDepth = depth + depthFactor * (innerSampleOffset / toDist); centerSampleDepth = (centerSampleDepth + localDepth) * .5; */ ofVec2f centerSample; getIntersection(position, to, pt, normal, centerSample); //float innerSampleOffset = (pt - centerSample).length(); float innerSampleOffsetFactor = (1 - t) * .5;// innerSampleOffset / (innerSampleOffset + NETWORK_OFFSET); ofVec2f otherPt = position + reflect(pt - position, to); ofVec2f otherNormal = reflect(normal, to); pushVertex(mesh, pt.x + NETWORK_OFFSET * normal.x, pt.y + NETWORK_OFFSET * normal.y, 0, normal.x, normal.y, 0, localDepth, 1); pushVertex(mesh, pt.x, pt.y, 1, 0, 0, 1, localDepth, innerSampleOffsetFactor); pushVertex(mesh, centerSample.x, centerSample.y, 1, 0, 0, 1, localDepth, 0); pushVertex(mesh, otherPt.x, otherPt.y, 1, 0, 0, 1, localDepth, innerSampleOffsetFactor); pushVertex(mesh, otherPt.x + NETWORK_OFFSET * otherNormal.x, otherPt.y + NETWORK_OFFSET * otherNormal.y, 0, otherNormal.x, otherNormal.y, 0, localDepth, 1); if(i > 0) { int offset = splineOffset + 5 * i; for(int j=0; j<4; ++j) { mesh.addTriangle(offset + j, offset - 5 + j, offset - 4 + j); mesh.addTriangle(offset + j, offset + 1 + j, offset - 4 + j); } } } } else pushSeparateNode(mesh, position, nodeRadius); }