void PolygonalSkin::setPoints(const std::vector<FloatPoint>& _points) { if (_points.size() < 2) { mVertexCount = 0; mResultVerticiesPos.clear(); mResultVerticiesUV.clear(); mLinePoints = _points; return; } VectorFloatPoint finalPoints; finalPoints.reserve(_points.size()); mLineLength = 0.0f; FloatPoint point = _points[0]; finalPoints.push_back(point); // ignore repeating points for (std::vector<FloatPoint>::const_iterator iter = _points.begin() + 1; iter != _points.end(); ++iter) { if (point != *iter) { finalPoints.push_back(*iter); mLineLength += len(iter->left - point.left, iter->top - point.top); point = *iter; } } mLinePoints = finalPoints; #ifdef MYGUI_NO_POLYGONAL_SKIN_CROPPING size_t count = (mLinePoints.size() - 1) * VertexQuad::VertexCount * 2; #else // it's too hard to calculate maximum possible verticies count and worst // approximation gives 7 times more verticies than in not cropped geometry // so we multiply count by 2, because this looks enough size_t count = (mLinePoints.size() - 1) * VertexQuad::VertexCount * 2 * 2; #endif if (count > mVertexCount) { mVertexCount = count; if (nullptr != mRenderItem) mRenderItem->reallockDrawItem(this, mVertexCount); } _updateView(); }
void PolygonalSkin::_rebuildGeometry() { if (mLinePoints.size() < 2) return; if (!mRenderItem || !mRenderItem->getRenderTarget()) return; mGeometryOutdated = false; // using mCurrentCoord as rectangle where we draw polygons // base texture coordinates FloatPoint baseVerticiesUV[4] = { FloatPoint(mCurrentTexture.left, mCurrentTexture.top), FloatPoint(mCurrentTexture.right, mCurrentTexture.top), FloatPoint(mCurrentTexture.right, mCurrentTexture.bottom), FloatPoint(mCurrentTexture.left, mCurrentTexture.bottom) }; // UV vectors FloatPoint vectorU = baseVerticiesUV[1] - baseVerticiesUV[0]; FloatPoint vectorV = baseVerticiesUV[3] - baseVerticiesUV[0]; FloatPoint vertex1; FloatPoint vertex2; mResultVerticiesPos.clear(); mResultVerticiesUV.clear(); // add first two verticies FloatPoint normal = _getPerpendicular(mLinePoints[0], mLinePoints[1]); FloatPoint points[2] = {mLinePoints[0] + normal, mLinePoints[0] - normal}; FloatPoint pointsUV[2] = {baseVerticiesUV[0], baseVerticiesUV[3]}; // add other verticies float currentLength = 0.0f; for (size_t i = 1; i < mLinePoints.size(); ++i) { currentLength += len(mLinePoints[i - 1].left - mLinePoints[i].left, mLinePoints[i - 1].top - mLinePoints[i].top); // getting normal between previous and next point if (i != mLinePoints.size() - 1) normal = _getMiddleLine(mLinePoints[i - 1], mLinePoints[i + 1], mLinePoints[i]); else normal = _getPerpendicular(mLinePoints[i - 1], mLinePoints[i]); bool edge = false; bool sharp = false; if (normal == FloatPoint() /*|| len(normal.left, normal.top) > mLineWidth * 2*/) { edge = true; normal = _getPerpendicular(mLinePoints[i - 1], mLinePoints[i]); } else if (len(normal.left, normal.top) > mLineWidth * 1.5) { sharp = true; normal = _getPerpendicular(mLinePoints[i - 1], mLinePoints[i]); } // check orientation FloatPoint lineDir = mLinePoints[i] - mLinePoints[i - 1]; if (lineDir.left * normal.top - lineDir.top * normal.left < 0) { normal.left = -normal.left; normal.top = -normal.top; } FloatPoint UVoffset(currentLength / mLineLength * vectorU.left, currentLength / mLineLength * vectorU.top); mResultVerticiesPos.push_back(points[0]); mResultVerticiesPos.push_back(points[1]); mResultVerticiesPos.push_back(mLinePoints[i] + normal); mResultVerticiesUV.push_back(pointsUV[0]); mResultVerticiesUV.push_back(pointsUV[1]); mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset); mResultVerticiesPos.push_back(points[1]); mResultVerticiesPos.push_back(mLinePoints[i] - normal); mResultVerticiesPos.push_back(mLinePoints[i] + normal); mResultVerticiesUV.push_back(pointsUV[1]); mResultVerticiesUV.push_back(baseVerticiesUV[3] + UVoffset); mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset); points[edge ? 1 : 0] = mLinePoints[i] + normal; points[edge ? 0 : 1] = mLinePoints[i] - normal; pointsUV[0] = baseVerticiesUV[0] + UVoffset; pointsUV[1] = baseVerticiesUV[3] + UVoffset; if (sharp) { normal = _getMiddleLine(mLinePoints[i - 1], mLinePoints[i + 1], mLinePoints[i]); float sharpness = len(normal.left, normal.top) / mLineWidth; float length = len(normal.left, normal.top); normal.left *= 2 * mLineWidth / length / (sharpness - 0.5f); normal.top *= 2 * mLineWidth / length / (sharpness - 0.5f); // check orientation lineDir = mLinePoints[i] - mLinePoints[i - 1]; if (lineDir.left * normal.top - lineDir.top * normal.left < 0) { normal.left = -normal.left; normal.top = -normal.top; } FloatPoint lineDir1 = mLinePoints[i] - mLinePoints[i - 1]; FloatPoint lineDir2 = mLinePoints[i + 1] - mLinePoints[i]; if (lineDir1.left * lineDir2.top - lineDir1.top * lineDir2.left > 0) { normal.left = -normal.left; normal.top = -normal.top; } // check orientation FloatPoint normal2 = _getPerpendicular(mLinePoints[i], mLinePoints[i + 1]); lineDir = mLinePoints[i - 1] - mLinePoints[i]; if ((lineDir.left * normal2.top - lineDir.top * normal2.left < 0)) { normal2.left = -normal2.left; normal2.top = -normal2.top; } FloatPoint UVcenter((baseVerticiesUV[0].left + baseVerticiesUV[3].left) / 2, (baseVerticiesUV[0].top + baseVerticiesUV[3].top) / 2); mResultVerticiesPos.push_back(points[0]); mResultVerticiesPos.push_back(mLinePoints[i] + normal); mResultVerticiesPos.push_back(mLinePoints[i]); mResultVerticiesUV.push_back(pointsUV[0]); mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset); mResultVerticiesUV.push_back(UVcenter + UVoffset); mResultVerticiesPos.push_back(mLinePoints[i] + normal); mResultVerticiesPos.push_back(mLinePoints[i] + normal2); mResultVerticiesPos.push_back(mLinePoints[i]); mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset); mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset); mResultVerticiesUV.push_back(UVcenter + UVoffset); points[0] = mLinePoints[i] + normal2; points[1] = mLinePoints[i] - normal2; pointsUV[0] = baseVerticiesUV[0] + UVoffset; pointsUV[1] = baseVerticiesUV[3] + UVoffset; } } #ifndef MYGUI_NO_POLYGONAL_SKIN_CROPPING // crop triangles IntCoord cropRectangle( mCurrentCoord.left, mCurrentCoord.top, mCurrentCoord.width, mCurrentCoord.height ); VectorFloatPoint newResultVerticiesPos; VectorFloatPoint newResultVerticiesUV; newResultVerticiesPos.reserve(mResultVerticiesPos.size()); newResultVerticiesUV.reserve(mResultVerticiesPos.size()); for (size_t i = 0; i < mResultVerticiesPos.size(); i += 3) { VectorFloatPoint croppedTriangle = geometry_utility::cropPolygon(&mResultVerticiesPos[i], 3, cropRectangle); if (!croppedTriangle.empty()) { FloatPoint v0 = mResultVerticiesUV[i + 2] - mResultVerticiesUV[i]; FloatPoint v1 = mResultVerticiesUV[i + 1] - mResultVerticiesUV[i]; for (size_t j = 1; j < croppedTriangle.size() - 1; ++j) { newResultVerticiesPos.push_back(croppedTriangle[0]); newResultVerticiesPos.push_back(croppedTriangle[j]); newResultVerticiesPos.push_back(croppedTriangle[j + 1]); // calculate UV FloatPoint point; point = geometry_utility::getPositionInsideRect(croppedTriangle[0], mResultVerticiesPos[i], mResultVerticiesPos[i + 1], mResultVerticiesPos[i + 2]); newResultVerticiesUV.push_back(geometry_utility::getUVFromPositionInsideRect(point, v0, v1, mResultVerticiesUV[i])); point = geometry_utility::getPositionInsideRect(croppedTriangle[j], mResultVerticiesPos[i], mResultVerticiesPos[i + 1], mResultVerticiesPos[i + 2]); newResultVerticiesUV.push_back(geometry_utility::getUVFromPositionInsideRect(point, v0, v1, mResultVerticiesUV[i])); point = geometry_utility::getPositionInsideRect(croppedTriangle[j + 1], mResultVerticiesPos[i], mResultVerticiesPos[i + 1], mResultVerticiesPos[i + 2]); newResultVerticiesUV.push_back(geometry_utility::getUVFromPositionInsideRect(point, v0, v1, mResultVerticiesUV[i])); } } } std::swap(mResultVerticiesPos, newResultVerticiesPos); std::swap(mResultVerticiesUV, newResultVerticiesUV); #endif // now calculate widget base offset and then resulting position in screen coordinates const RenderTargetInfo& info = mRenderItem->getRenderTarget()->getInfo(); float vertex_left_base = ((info.pixScaleX * (float)(mCroppedParent->getAbsoluteLeft()) + info.hOffset) * 2) - 1; float vertex_top_base = -(((info.pixScaleY * (float)(mCroppedParent->getAbsoluteTop()) + info.vOffset) * 2) - 1); for (size_t i = 0; i < mResultVerticiesPos.size(); ++i) { mResultVerticiesPos[i].left = vertex_left_base + mResultVerticiesPos[i].left * info.pixScaleX * 2; mResultVerticiesPos[i].top = vertex_top_base + mResultVerticiesPos[i].top * info.pixScaleY * -2; } }