void PaintLayer::fillLineEndPointAt(CCPoint center, CCPoint aLineDir, float radius, ccColor4F color) { int numberOfSegments = 32; LineVertex *vertices = (LineVertex *)malloc(sizeof(LineVertex) * numberOfSegments * 9); float anglePerSegment = (float)(M_PI / (numberOfSegments - 1)); //! we need to cover M_PI from this, dot product of normalized vectors is equal to cos angle between them... and if you include rightVec dot you get to know the correct direction :) CCPoint perpendicular = ccpPerp(aLineDir); float angle = acosf(ccpDot(perpendicular, CCPointMake(0, 1))); float rightDot = ccpDot(perpendicular, CCPointMake(1, 0)); if (rightDot < 0.0f) { angle *= -1; } CCPoint prevPoint = center; CCPoint prevDir = ccp(sinf(0), cosf(0)); for (unsigned int i = 0; i < numberOfSegments; ++i) { CCPoint dir = ccp(sinf(angle), cosf(angle)); CCPoint curPoint = ccp(center.x + radius * dir.x, center.y + radius * dir.y); vertices[i * 9 + 0].pos = center; vertices[i * 9 + 1].pos = prevPoint; vertices[i * 9 + 2].pos = curPoint; //! fill rest of vertex data for (unsigned int j = 0; j < 9; ++j) { vertices[i * 9 + j].z = j < 3 ? 1.0f : 2.0f; vertices[i * 9 + j].color = color; } //! add overdraw vertices[i * 9 + 3].pos = ccpAdd(prevPoint, ccpMult(prevDir, overdraw)); vertices[i * 9 + 3].color.a = 0; vertices[i * 9 + 4].pos = prevPoint; vertices[i * 9 + 5].pos = ccpAdd(curPoint, ccpMult(dir, overdraw)); vertices[i * 9 + 5].color.a = 0; vertices[i * 9 + 6].pos = prevPoint; vertices[i * 9 + 7].pos = curPoint; vertices[i * 9 + 8].pos = ccpAdd(curPoint, ccpMult(dir, overdraw)); vertices[i * 9 + 8].color.a = 0; prevPoint = curPoint; prevDir = dir; angle += anglePerSegment; } glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, sizeof(LineVertex), &vertices[0].pos); glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_FLOAT, GL_FALSE, sizeof(LineVertex), &vertices[0].color); glDrawArrays(GL_TRIANGLES, 0, numberOfSegments * 9); free(vertices); }
NS_CC_BEGIN void ccVertexLineToPolygon(DPoint *points, float stroke, ccVertex2F *vertices, unsigned int offset, unsigned int nuPoints) { nuPoints += offset; if(nuPoints<=1) return; stroke *= 0.5f; unsigned int idx; unsigned int nuPointsMinus = nuPoints-1; for(unsigned int i = offset; i<nuPoints; i++) { idx = i*2; DPoint p1 = points[i]; DPoint perpVector; if(i == 0) perpVector = ccpPerp(ccpNormalize(ccpSub(p1, points[i+1]))); else if(i == nuPointsMinus) perpVector = ccpPerp(ccpNormalize(ccpSub(points[i-1], p1))); else { DPoint p2 = points[i+1]; DPoint p0 = points[i-1]; DPoint p2p1 = ccpNormalize(ccpSub(p2, p1)); DPoint p0p1 = ccpNormalize(ccpSub(p0, p1)); // Calculate angle between vectors float angle = acosf(ccpDot(p2p1, p0p1)); if(angle < CC_DEGREES_TO_RADIANS(70)) perpVector = ccpPerp(ccpNormalize(ccpMidpoint(p2p1, p0p1))); else if(angle < CC_DEGREES_TO_RADIANS(170)) perpVector = ccpNormalize(ccpMidpoint(p2p1, p0p1)); else perpVector = ccpPerp(ccpNormalize(ccpSub(p2, p0))); } perpVector = ccpMult(perpVector, stroke); vertices[idx] = vertex2(p1.x+perpVector.x, p1.y+perpVector.y); vertices[idx+1] = vertex2(p1.x-perpVector.x, p1.y-perpVector.y); } // Validate vertexes offset = (offset==0) ? 0 : offset-1; for(unsigned int i = offset; i<nuPointsMinus; i++) { idx = i*2; const unsigned int idx1 = idx+2; ccVertex2F p1 = vertices[idx]; ccVertex2F p2 = vertices[idx+1]; ccVertex2F p3 = vertices[idx1]; ccVertex2F p4 = vertices[idx1+1]; float s; //BOOL fixVertex = !ccpLineIntersect(DPoint(p1.x, p1.y), DPoint(p4.x, p4.y), DPoint(p2.x, p2.y), DPoint(p3.x, p3.y), &s, &t); bool fixVertex = !ccVertexLineIntersect(p1.x, p1.y, p4.x, p4.y, p2.x, p2.y, p3.x, p3.y, &s); if(!fixVertex) if (s<0.0f || s>1.0f) fixVertex = true; if(fixVertex) { vertices[idx1] = p4; vertices[idx1+1] = p3; } } }
void PaintLayer::drawLines(CCArray *linePoints, ccColor4F color) { unsigned int numberOfVertices = (linePoints->count() - 1) * 18; LineVertex *vertices = (LineVertex *)calloc(sizeof(LineVertex), numberOfVertices); CCPoint prevPoint = ((LinePoint *)linePoints->objectAtIndex(0))->pos; float prevValue = ((LinePoint *)linePoints->objectAtIndex(0))->width; float curValue; int index = 0; for (int i = 1; i < linePoints->count(); ++i) { LinePoint *pointValue = (LinePoint *)linePoints->objectAtIndex(i); CCPoint curPoint = pointValue->pos; curValue = pointValue->width; //! equal points, skip them if (ccpFuzzyEqual(curPoint, prevPoint, 0.0001f)) { continue; } CCPoint dir = ccpSub(curPoint, prevPoint); CCPoint perpendicular = ccpNormalize(ccpPerp(dir)); CCPoint A = ccpAdd(prevPoint, ccpMult(perpendicular, prevValue / 2)); CCPoint B = ccpSub(prevPoint, ccpMult(perpendicular, prevValue / 2)); CCPoint C = ccpAdd(curPoint, ccpMult(perpendicular, curValue / 2)); CCPoint D = ccpSub(curPoint, ccpMult(perpendicular, curValue / 2)); //! continuing line if (connectingLine || index > 0) { A = prevC; B = prevD; } else if (index == 0) { //! circle at start of line, revert direction circlesPoints->addObject(pointValue); circlesPoints->addObject(linePoints->objectAtIndex(i-1)); } ADD_TRIANGLE(A, B, C, 1.0f); ADD_TRIANGLE(B, C, D, 1.0f); prevD = D; prevC = C; if (finishingLine && (i == linePoints->count() - 1)) { circlesPoints->addObject(linePoints->objectAtIndex(i-1)); circlesPoints->addObject(pointValue); finishingLine = false; } prevPoint = curPoint; prevValue = curValue; //! Add overdraw CCPoint F = ccpAdd(A, ccpMult(perpendicular, overdraw)); CCPoint G = ccpAdd(C, ccpMult(perpendicular, overdraw)); CCPoint H = ccpSub(B, ccpMult(perpendicular, overdraw)); CCPoint I = ccpSub(D, ccpMult(perpendicular, overdraw)); //! end vertices of last line are the start of this one, also for the overdraw if (connectingLine || index > 6) { F = prevG; H = prevI; } prevG = G; prevI = I; ADD_TRIANGLE(F, A, G, 2.0f); ADD_TRIANGLE(A, G, C, 2.0f); ADD_TRIANGLE(B, H, D, 2.0f); ADD_TRIANGLE(H, D, I, 2.0f); } this->fillLineTriangles(vertices, index, color); if (index > 0) { connectingLine = true; } free(vertices); }
float CCRibbon::sideOfLine(CCPoint p, CCPoint l1, CCPoint l2) { CCPoint vp = ccpPerp(ccpSub(l1, l2)); CCPoint vx = ccpSub(p, l1); return ccpDot(vx, vp); }