diff --git a/include/Helpers/Networking/NetClient.cpp b/include/Helpers/Networking/NetClient.cpp index dfa99e6..a15d35c 100644 --- a/include/Helpers/Networking/NetClient.cpp +++ b/include/Helpers/Networking/NetClient.cpp @@ -67,12 +67,9 @@ void NetClient::update() { isDisconnected = true; return; } -#ifdef NDEBUG try { -#endif parse_received_messages(); send_queued_messages(); -#ifdef NDEBUG } catch(const std::exception& e) { Logger::get().log(Logger::LogType::INFO, "[NetClient::update] Exception thrown while parsing and sending messages: " + std::string(e.what())); @@ -82,7 +79,6 @@ void NetClient::update() { Logger::get().log(Logger::LogType::INFO, "[NetClient::update] Unknown exception thrown while parsing and sending messages."); isDisconnected = true; } -#endif } void NetClient::parse_received_messages() { diff --git a/include/Helpers/Networking/NetServer.cpp b/include/Helpers/Networking/NetServer.cpp index 4df9de2..b9087b7 100644 --- a/include/Helpers/Networking/NetServer.cpp +++ b/include/Helpers/Networking/NetServer.cpp @@ -44,12 +44,9 @@ void NetServer::update() { if(client->setToDisconnect) disconnectCallback(client); else { - #ifdef NDEBUG try { - #endif client->parse_received_messages(*this); client->send_queued_messages(*this); - #ifdef NDEBUG } catch(const std::exception& e) { Logger::get().log(Logger::LogType::INFO, "[NetServer::update] Exception thrown while parsing and sending messages for a client: " + std::string(e.what())); @@ -61,7 +58,6 @@ void NetServer::update() { client->setToDisconnect = true; disconnectCallback(client); } - #endif } } } diff --git a/src/CanvasComponents/MeshCanvasComponent.cpp b/src/CanvasComponents/MeshCanvasComponent.cpp index f04934d..e3e9a49 100644 --- a/src/CanvasComponents/MeshCanvasComponent.cpp +++ b/src/CanvasComponents/MeshCanvasComponent.cpp @@ -19,6 +19,7 @@ #include "MeshCanvasComponent.hpp" #include #include +#include #include #include #include @@ -37,48 +38,50 @@ #include "../World.hpp" #include #include +#include template void skpath_write(const SkPath& p, Archive& a) { - std::vector contourSizes; - uint32_t contourSize = 0; - auto verbs = p.verbs(); - auto points = p.points(); - for(size_t verbIndex = 0; verbIndex < verbs.size(); verbIndex++) { - switch(verbs[verbIndex]) { + std::vector> contours; + + SkPath::Iter iter(p, true); + for(;;) { + std::optional rec = iter.next(); + if(!rec.has_value()) + break; + + switch(rec->fVerb) { case SkPathVerb::kClose: - contourSizes.emplace_back(contourSize); - contourSize = 0; + if(!contours.back().empty()) + contours.back().pop_back(); + break; + case SkPathVerb::kLine: + contours.back().emplace_back(rec->fPoints[1]); break; case SkPathVerb::kMove: - case SkPathVerb::kLine: - contourSize++; + contours.emplace_back(); + contours.back().emplace_back(rec->fPoints[0]); break; default: - throw std::runtime_error("[skpath_write] Illegal verb " + std::to_string(static_cast(verbs[verbIndex]))); + throw std::runtime_error("[get_predraw_data_accurate] Illegal verb " + std::to_string(static_cast(rec->fVerb))); break; } } - a(p.getFillType() == SkPathFillType::kEvenOdd, contourSizes); - for(const SkPoint& p : points) - a(p); + + a(p.getFillType() == SkPathFillType::kEvenOdd, contours); } template SkPath skpath_read(Archive& a) { bool isEvenOdd; - SkPathBuilder builder; - std::vector contourSizes; - a(isEvenOdd, contourSizes); - builder.setFillType(isEvenOdd ? SkPathFillType::kEvenOdd : SkPathFillType::kWinding); - for(uint32_t contourSize : contourSizes) { - SkPoint p; - if(contourSize == 0) + std::vector> contours; + a(isEvenOdd, contours); + // NOTE: setFillType doesn't properly set the fill type for the path IN DEBUG BUILDS. Setting fill type in builder constructor meanwhile works for both debug and release builds + SkPathBuilder builder(isEvenOdd ? SkPathFillType::kEvenOdd : SkPathFillType::kWinding); + for(const std::vector& contour : contours) { + if(contour.size() == 0) continue; - a(p); - builder.moveTo(p); - for(uint32_t i = 1; i < contourSize; i++) { - a(p); - builder.lineTo(p); - } + builder.moveTo(contour[0]); + for(uint32_t i = 1; i < contour.size(); i++) + builder.lineTo(contour[i]); builder.close(); } return builder.detach(); @@ -141,98 +144,128 @@ void MeshCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData, const } std::shared_ptr MeshCanvasComponent::get_predraw_data_accurate(const DrawData& drawData, const CoordSpaceHelper& coords) const { - SCollision::AABB viewGenerousColliderInObjSpace = coords.world_collider_to_coords>(drawData.cam.viewingAreaGenerousCollider); - viewGenerousColliderInObjSpace.min -= Vector2f{1.0f, 1.0f}; - viewGenerousColliderInObjSpace.max += Vector2f{1.0f, 1.0f}; + try { + SCollision::AABB viewGenerousColliderInObjSpace = coords.world_collider_to_coords>(drawData.cam.viewingAreaGenerousCollider); + viewGenerousColliderInObjSpace.min -= Vector2f{1.0f, 1.0f}; + viewGenerousColliderInObjSpace.max += Vector2f{1.0f, 1.0f}; - SkPath::Iter iter(d.meshPath, true); - std::vector> points; - std::vector edges; + // GrTriangulator is faster, but isn't as robust + //GrCpuVertexAllocator cpuAlloc; + //bool isLinear; + //GrTriangulator::PathToTriangles(d.meshPath, 0.0001f, viewGenerousColliderInObjSpace.get_sk_rect(), &cpuAlloc, &isLinear); + //sk_sp detachedVertexData = cpuAlloc.detachVertexData(); + //if(!detachedVertexData) + // return nullptr; + //if(detachedVertexData->vertexSize() != 8) + // throw std::runtime_error("[MeshCanvasComponent::get_predraw_data_accurate] Vertex data vertex size not equal to 8"); - for(;;) { - std::optional rec = iter.next(); - if(!rec.has_value()) - break; + // Triangulation implementation using CDT + SkPath::Iter iter(d.meshPath, true); + std::vector> points; + std::vector edges; - switch(rec->fVerb) { - case SkPathVerb::kClose: + // Makes duplicate vertices by default, but duplicates are impossible to completely remove, so just rely on RemoveDuplicatesAndRemapEdges + for(;;) { + std::optional rec = iter.next(); + if(!rec.has_value()) break; - case SkPathVerb::kLine: - points.emplace_back(rec->fPoints[1].x(), rec->fPoints[1].y()); - edges.emplace_back(points.size() - 2, points.size() - 1); - break; - case SkPathVerb::kMove: - points.emplace_back(rec->fPoints[0].x(), rec->fPoints[0].y()); - break; - default: - throw std::runtime_error("[get_predraw_data_accurate] Illegal verb " + std::to_string(static_cast(rec->fVerb))); - break; - } - } - CDT::RemoveDuplicatesAndRemapEdges( - points, - edges - ); - - CDT::Triangulation cdt(CDT::VertexInsertionOrder::Auto, CDT::IntersectingConstraintEdges::TryResolve, 0.001f); - cdt.insertVertices(points); - cdt.insertEdges(edges); - cdt.eraseOuterTrianglesAndHoles(); - - std::vector> finalTrianglePoints; - - auto clipListFunc = [](const std::vector>& clipList, const std::array& axisLineSegment, const std::function& isInClippingAreaFunc) { - std::vector> resultList; - for(auto& t : clipList) - clip_triangle_against_axis(resultList, t, axisLineSegment, isInClippingAreaFunc); - return resultList; - }; - - for(auto& tri : cdt.triangles) { - SCollision::Triangle triCollider(Vector2f{points[tri.vertices[0]].x, points[tri.vertices[0]].y}, Vector2f{points[tri.vertices[1]].x, points[tri.vertices[1]].y}, Vector2f{points[tri.vertices[2]].x, points[tri.vertices[2]].y}); - if(SCollision::collide(triCollider.bounds, viewGenerousColliderInObjSpace)) { - std::vector> clipList; - clipList.emplace_back(std::array{coords.from_space(triCollider.p[0]), coords.from_space(triCollider.p[1]), coords.from_space(triCollider.p[2])}); - clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.min, drawData.cam.viewingAreaGenerousCollider.top_right()}, [&](const WorldVec& p) { - return p.y() > drawData.cam.viewingAreaGenerousCollider.min.y(); - }); - clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.max, drawData.cam.viewingAreaGenerousCollider.bottom_left()}, [&](const WorldVec& p) { - return p.y() < drawData.cam.viewingAreaGenerousCollider.max.y(); - }); - clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.min, drawData.cam.viewingAreaGenerousCollider.bottom_left()}, [&](const WorldVec& p) { - return p.x() > drawData.cam.viewingAreaGenerousCollider.min.x(); - }); - clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.max, drawData.cam.viewingAreaGenerousCollider.top_right()}, [&](const WorldVec& p) { - return p.x() < drawData.cam.viewingAreaGenerousCollider.max.x(); - }); - for(auto& tri : clipList) { - auto& c = drawData.cam.c; - finalTrianglePoints.emplace_back(std::array{convert_vec2(c.to_space(tri[0])), convert_vec2(c.to_space(tri[1])), convert_vec2(c.to_space(tri[2]))}); + switch(rec->fVerb) { + case SkPathVerb::kClose: + break; + case SkPathVerb::kLine: { + CDT::V2d newPoint{rec->fPoints[1].x(), rec->fPoints[1].y()}; + points.emplace_back(newPoint); + edges.emplace_back(points.size() - 2, points.size() - 1); + break; + } + case SkPathVerb::kMove: + points.emplace_back(rec->fPoints[0].x(), rec->fPoints[0].y()); + break; + default: + throw std::runtime_error("[get_predraw_data_accurate] Illegal verb " + std::to_string(static_cast(rec->fVerb))); + break; } } + + CDT::RemoveDuplicatesAndRemapEdges( + points, + edges + ); + + CDT::Triangulation cdt(CDT::VertexInsertionOrder::Auto, CDT::IntersectingConstraintEdges::TryResolve, 0.001f); + cdt.insertVertices(points); + cdt.insertEdges(edges); + cdt.eraseOuterTrianglesAndHoles(); + + std::vector> finalTrianglePoints; + + auto clipListFunc = [](const std::vector>& clipList, const std::array& axisLineSegment, const std::function& isInClippingAreaFunc) { + std::vector> resultList; + for(auto& t : clipList) + clip_triangle_against_axis(resultList, t, axisLineSegment, isInClippingAreaFunc); + return resultList; + }; + + // GrTriangulator + //for(int i = 0; i < detachedVertexData->numVertices(); i += 3) { + // Vector2f v1 = {static_cast(detachedVertexData->vertices())[i], static_cast(detachedVertexData->vertices())[i + 1]}; + // Vector2f v2 = {static_cast(detachedVertexData->vertices())[i + 2], static_cast(detachedVertexData->vertices())[i + 3]}; + // Vector2f v3 = {static_cast(detachedVertexData->vertices())[i + 4], static_cast(detachedVertexData->vertices())[i + 5]}; + // CDT + for(size_t i = 0; i < cdt.triangles.size(); i++) { + auto& tri = cdt.triangles[i].vertices; + Vector2f v1{cdt.vertices[tri[0]].x, cdt.vertices[tri[0]].y}; + Vector2f v2{cdt.vertices[tri[1]].x, cdt.vertices[tri[1]].y}; + Vector2f v3{cdt.vertices[tri[2]].x, cdt.vertices[tri[2]].y}; + SCollision::Triangle triCollider(v1, v2, v3); + if(SCollision::collide(triCollider.bounds, viewGenerousColliderInObjSpace)) { + std::vector> clipList; + clipList.emplace_back(std::array{coords.from_space(triCollider.p[0]), coords.from_space(triCollider.p[1]), coords.from_space(triCollider.p[2])}); + clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.min, drawData.cam.viewingAreaGenerousCollider.top_right()}, [&](const WorldVec& p) { + return p.y() > drawData.cam.viewingAreaGenerousCollider.min.y(); + }); + clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.max, drawData.cam.viewingAreaGenerousCollider.bottom_left()}, [&](const WorldVec& p) { + return p.y() < drawData.cam.viewingAreaGenerousCollider.max.y(); + }); + clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.min, drawData.cam.viewingAreaGenerousCollider.bottom_left()}, [&](const WorldVec& p) { + return p.x() > drawData.cam.viewingAreaGenerousCollider.min.x(); + }); + clipList = clipListFunc(clipList, {drawData.cam.viewingAreaGenerousCollider.max, drawData.cam.viewingAreaGenerousCollider.top_right()}, [&](const WorldVec& p) { + return p.x() < drawData.cam.viewingAreaGenerousCollider.max.x(); + }); + for(auto& tri : clipList) { + auto& c = drawData.cam.c; + finalTrianglePoints.emplace_back(std::array{convert_vec2(c.to_space(tri[0])), convert_vec2(c.to_space(tri[1])), convert_vec2(c.to_space(tri[2]))}); + } + } + } + + // Match points that are close enough. I don't think this is required. + //if(!finalTrianglePoints.empty()) { + // for(size_t i = 0; i < finalTrianglePoints.size() - 1; i++) { + // for(size_t j = 0; j < 3; j++) { + // for(size_t k = i + 1; k < finalTrianglePoints.size(); k++) { + // for(size_t l = 0; l < 3; l++) { + // if(std::fabs(finalTrianglePoints[i][j].fX - finalTrianglePoints[k][l].fX) < 0.0001f && std::fabs(finalTrianglePoints[i][j].fY - finalTrianglePoints[k][l].fY) < 0.0001f && finalTrianglePoints[k][l] != finalTrianglePoints[i][j]) + // finalTrianglePoints[k][l] = finalTrianglePoints[i][j]; + // } + // } + // } + // } + //} + + if(finalTrianglePoints.empty()) + return nullptr; + SkPathBuilder pathBuilder; + for(auto& finalTriangle : finalTrianglePoints) + pathBuilder.addPolygon({finalTriangle.data(), finalTriangle.size()}, true); + return std::make_shared(pathBuilder.detach()); } - - // Match points that are close enough. I don't think this is required. - //if(!finalTrianglePoints.empty()) { - // for(size_t i = 0; i < finalTrianglePoints.size() - 1; i++) { - // for(size_t j = 0; j < 3; j++) { - // for(size_t k = i + 1; k < finalTrianglePoints.size(); k++) { - // for(size_t l = 0; l < 3; l++) { - // if(std::fabs(finalTrianglePoints[i][j].fX - finalTrianglePoints[k][l].fX) < 0.0001f && std::fabs(finalTrianglePoints[i][j].fY - finalTrianglePoints[k][l].fY) < 0.0001f && finalTrianglePoints[k][l] != finalTrianglePoints[i][j]) - // finalTrianglePoints[k][l] = finalTrianglePoints[i][j]; - // } - // } - // } - // } - //} - - if(finalTrianglePoints.empty()) + catch(...) { return nullptr; - SkPathBuilder pathBuilder; - for(auto& finalTriangle : finalTrianglePoints) - pathBuilder.addPolygon({finalTriangle.data(), finalTriangle.size()}, true); - return std::make_shared(pathBuilder.detach()); + } + return nullptr; } bool MeshCanvasComponent::accurate_draw(SkCanvas* canvas, const DrawData& drawData, const CoordSpaceHelper& coords, const std::shared_ptr& predrawData) const {