| 247 | } |
| 248 | |
| 249 | scene::INodePtr constructCap(const IPatch& sourcePatch, CapType capType, bool front, const std::string& material) |
| 250 | { |
| 251 | auto cap = GlobalPatchModule().createPatch(PatchDefType::Def2); |
| 252 | |
| 253 | auto& capPatch = *Node_getPatch(cap); |
| 254 | |
| 255 | auto width = sourcePatch.getWidth(); |
| 256 | auto height = sourcePatch.getHeight(); |
| 257 | |
| 258 | std::vector<Vector3> points(sourcePatch.getWidth()); |
| 259 | |
| 260 | auto row = front ? 0 : height - 1; |
| 261 | |
| 262 | for (auto i = 0; i < width; i++) |
| 263 | { |
| 264 | const auto& ctrl = sourcePatch.ctrlAt(row, i); |
| 265 | points[front ? i : width - 1 - i] = ctrl.vertex; |
| 266 | } |
| 267 | |
| 268 | // Inherit the same fixed tesselation as the source patch |
| 269 | if (sourcePatch.subdivisionsFixed()) |
| 270 | { |
| 271 | const auto& subdivisions = sourcePatch.getSubdivisions(); |
| 272 | |
| 273 | if (capType == CapType::InvertedEndCap) |
| 274 | { |
| 275 | capPatch.setFixedSubdivisions(true, subdivisions); |
| 276 | } |
| 277 | else |
| 278 | { |
| 279 | // Flip the subdivision X/Y values for all other cap types |
| 280 | capPatch.setFixedSubdivisions(true, { subdivisions.y(), subdivisions.x() }); |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | capPatch.constructSeam(capType, points, width); |
| 285 | |
| 286 | // greebo: Avoid creating "degenerate" patches (all vertices merged in one 3D point) |
| 287 | if (capPatch.isDegenerate()) |
| 288 | { |
| 289 | return {}; |
| 290 | } |
| 291 | |
| 292 | // greebo: Apply natural texture to that patch, to fix the texcoord==1.#INF bug. |
| 293 | capPatch.setShader(material); |
| 294 | capPatch.scaleTextureNaturally(); |
| 295 | |
| 296 | return cap; |
| 297 | } |
| 298 | |
| 299 | void createCaps(const IPatch& patch, const scene::INodePtr& parent, CapType type, const std::string& shader) |
| 300 | { |
no test coverage detected