From a8548c200593bb3ed15f77a60a2a8ab3e4e844fa Mon Sep 17 00:00:00 2001 From: Samuel Freilich Date: Fri, 25 Apr 2025 11:11:54 -0400 Subject: [PATCH] Replace tess->outOfMemory with a tess->status enum Add declaration for that and tessGetStatus accessor to public header. Change the failure value for "input is out of range" to something other than "out of memory". --- Include/tesselator.h | 15 ++++++++++++++- Source/tess.c | 39 +++++++++++++++++++++------------------ Source/tess.h | 4 +--- Tests/libtess2_test.cc | 16 ++++++++++++++++ 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/Include/tesselator.h b/Include/tesselator.h index 8993daa..667da41 100755 --- a/Include/tesselator.h +++ b/Include/tesselator.h @@ -222,7 +222,8 @@ void tessSetOption( TESStesselator *tess, int option, int value ); // vertexSize - defines the number of coordinates in tesselation result vertex, must be 2 or 3. // normal - defines the normal of the input contours, of null the normal is calculated automatically. // Returns: -// 1 if succeed, 0 if failed. +// 1 if succeed, 0 if failed (tessGetStatus can be used after to get a more +// specific failure status) int tessTesselate( TESStesselator *tess, int windingRule, int elementType, int polySize, int vertexSize, const TESSreal* normal ); // tessGetVertexCount() - Returns number of vertices in the tesselated output. @@ -243,6 +244,18 @@ int tessGetElementCount( TESStesselator *tess ); // tessGetElements() - Returns pointer to the first element. const TESSindex* tessGetElements( TESStesselator *tess ); +typedef enum TESSstatus { + TESS_STATUS_OK, + TESS_STATUS_OUT_OF_MEMORY, + TESS_STATUS_INVALID_INPUT +} TESSstatus; + +// Return the success or failure status. If tessTesselate fails (or will fail, +// e.g. after invalid data is passed to tessAddContour), this can indicate +// more specifically why. It can also be checked after tessAddContour to +// see whether to bail out early. +TESSstatus tessGetStatus( TESStesselator *tess ); + #ifdef __cplusplus }; #endif diff --git a/Source/tess.c b/Source/tess.c index 9312791..0b47921 100755 --- a/Source/tess.c +++ b/Source/tess.c @@ -650,7 +650,7 @@ TESStesselator* tessNewTess( TESSalloc* alloc ) // Initialize to begin polygon. tess->mesh = NULL; - tess->outOfMemory = 0; + tess->status = TESS_STATUS_OK; tess->vertexIndexCounter = 0; tess->vertices = 0; @@ -716,7 +716,7 @@ void OutputPolymesh( TESStesselator *tess, TESSmesh *mesh, int elementType, int { if (!tessMeshMergeConvexFaces( mesh, polySize )) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } } @@ -759,7 +759,7 @@ void OutputPolymesh( TESStesselator *tess, TESSmesh *mesh, int elementType, int sizeof(TESSindex) * maxFaceCount * polySize ); if (!tess->elements) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -768,7 +768,7 @@ void OutputPolymesh( TESStesselator *tess, TESSmesh *mesh, int elementType, int sizeof(TESSreal) * tess->vertexCount * vertexSize ); if (!tess->vertices) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -776,7 +776,7 @@ void OutputPolymesh( TESStesselator *tess, TESSmesh *mesh, int elementType, int sizeof(TESSindex) * tess->vertexCount ); if (!tess->vertexIndices) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -867,7 +867,7 @@ void OutputContours( TESStesselator *tess, TESSmesh *mesh, int vertexSize ) sizeof(TESSindex) * tess->elementCount * 2 ); if (!tess->elements) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -875,7 +875,7 @@ void OutputContours( TESStesselator *tess, TESSmesh *mesh, int vertexSize ) sizeof(TESSreal) * tess->vertexCount * vertexSize ); if (!tess->vertices) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -883,7 +883,7 @@ void OutputContours( TESStesselator *tess, TESSmesh *mesh, int vertexSize ) sizeof(TESSindex) * tess->vertexCount ); if (!tess->vertexIndices) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -934,7 +934,7 @@ void tessAddContour( TESStesselator *tess, int size, const void* vertices, if ( tess->mesh == NULL ) tess->mesh = tessMeshNewMesh( &tess->alloc ); if ( tess->mesh == NULL ) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } @@ -951,19 +951,18 @@ void tessAddContour( TESStesselator *tess, int size, const void* vertices, if (!IsValidCoord(coords[0]) || !IsValidCoord(coords[1]) || (size > 2 && !IsValidCoord(coords[2]))) { - // "Out of memory" isn't quite right, but give up and bail out - tess->outOfMemory = 1; + tess->status = TESS_STATUS_INVALID_INPUT; return; } if( e == NULL ) { /* Make a self-loop (one vertex, one edge). */ e = tessMeshMakeEdge( tess->mesh ); if ( e == NULL ) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } if ( !tessMeshSplice( tess->mesh, e, e->Sym ) ) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } } else { @@ -971,7 +970,7 @@ void tessAddContour( TESStesselator *tess, int size, const void* vertices, * in the ordering around the left face. */ if ( tessMeshSplitEdge( tess->mesh, e ) == NULL ) { - tess->outOfMemory = 1; + tess->status = TESS_STATUS_OUT_OF_MEMORY; return; } e = e->Lnext; @@ -1051,7 +1050,7 @@ int tessTesselate( TESStesselator *tess, int windingRule, int elementType, return 0; } - if (tess->outOfMemory || !tess->mesh) + if (tess->status != TESS_STATUS_OK || !tess->mesh) { return 0; } @@ -1099,9 +1098,7 @@ int tessTesselate( TESStesselator *tess, int windingRule, int elementType, tessMeshDeleteMesh( &tess->alloc, mesh ); tess->mesh = NULL; - if (tess->outOfMemory) - return 0; - return 1; + return tess->status == TESS_STATUS_OK; } int tessGetVertexCount( TESStesselator *tess ) @@ -1128,3 +1125,9 @@ const int* tessGetElements( TESStesselator *tess ) { return tess->elements; } + +TESSstatus tessGetStatus( TESStesselator *tess ) +{ + return tess->status; +} + diff --git a/Source/tess.h b/Source/tess.h index 30fda27..c754af0 100755 --- a/Source/tess.h +++ b/Source/tess.h @@ -43,14 +43,12 @@ extern "C" { #endif -//typedef struct TESStesselator TESStesselator; - struct TESStesselator { /*** state needed for collecting the input data ***/ TESSmesh *mesh; /* stores the input contours, and eventually the tessellation itself */ - int outOfMemory; + TESSstatus status; /*** state needed for projecting onto the sweep plane ***/ diff --git a/Tests/libtess2_test.cc b/Tests/libtess2_test.cc index 6d40934..d3f9850 100644 --- a/Tests/libtess2_test.cc +++ b/Tests/libtess2_test.cc @@ -158,6 +158,22 @@ TEST_F(Libtess2Test, UnitQuad) { EXPECT_EQ(tessGetElementCount(tess), 2); } +TEST_F(Libtess2Test, GetStatusInvalidInput) { + AddPolyline(tess, {{-2e+37f, 0.f}, {0, 5}, {1e37f, -5}}); + EXPECT_EQ(tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, + kNumTriangleVertices, kComponentCount, nullptr), + 0); + EXPECT_EQ(tessGetStatus(tess), TESS_STATUS_INVALID_INPUT); +} + +TEST_F(Libtess2Test, GetStatusOk) { + AddPolyline(tess, {{0, 0}, {0, 1}, {1, 1}, {1, 0}}); + EXPECT_NE(tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, + kNumTriangleVertices, kComponentCount, nullptr), + 0); + EXPECT_EQ(tessGetStatus(tess), TESS_STATUS_OK); +} + TEST_F(Libtess2Test, FloatOverflowQuad) { constexpr float kFloatMin = std::numeric_limits::min(); constexpr float kFloatMax = std::numeric_limits::max();