diff --git a/types/libtess/.npmignore b/types/libtess/.npmignore new file mode 100644 index 00000000000000..77b77d4729142f --- /dev/null +++ b/types/libtess/.npmignore @@ -0,0 +1,6 @@ +* +!**/*.d.ts +!**/*.d.cts +!**/*.d.mts +!**/*.d.*.ts + diff --git a/types/libtess/index.d.ts b/types/libtess/index.d.ts new file mode 100644 index 00000000000000..877bf3d32780be --- /dev/null +++ b/types/libtess/index.d.ts @@ -0,0 +1,184 @@ +/** + * Polygon tessellation library, ported from SGI's GLU implementation + * written by Eric Veach in 1994 + */ + +/** + * GLU tessellation property and callback type enums + */ +export enum gluEnum { + /** Winding rule property */ + GLU_TESS_WINDING_RULE = 100140, + /** Boundary only property - if true, only outputs boundary contours instead of triangulated polygons */ + GLU_TESS_BOUNDARY_ONLY = 100141, + /** Tolerance property for vertex merging */ + GLU_TESS_TOLERANCE = 100142, + + /** Begin callback - called when beginning a new primitive */ + GLU_TESS_BEGIN = 100100, + /** Vertex callback - called for each vertex */ + GLU_TESS_VERTEX = 100101, + /** End callback - called when ending a primitive */ + GLU_TESS_END = 100102, + /** Error callback - called when an error occurs */ + GLU_TESS_ERROR = 100103, + /** Edge flag callback - called to indicate whether edges are on the polygon boundary */ + GLU_TESS_EDGE_FLAG = 100104, + /** Combine callback - called when vertices need to be merged or interpolated */ + GLU_TESS_COMBINE = 100105, + + /** Begin callback with client data */ + GLU_TESS_BEGIN_DATA = 100106, + /** Vertex callback with client data */ + GLU_TESS_VERTEX_DATA = 100107, + /** End callback with client data */ + GLU_TESS_END_DATA = 100108, + /** Error callback with client data */ + GLU_TESS_ERROR_DATA = 100109, + /** Edge flag callback with client data */ + GLU_TESS_EDGE_FLAG_DATA = 100110, + /** Combine callback with client data */ + GLU_TESS_COMBINE_DATA = 100111, +} + +/** + * Winding rules determine which regions are considered "inside" the polygon + */ +export enum windingRule { + /** Odd-even winding rule - alternating regions are inside/outside */ + GLU_TESS_WINDING_ODD = 100130, + /** Non-zero winding rule - regions with non-zero winding number are inside */ + GLU_TESS_WINDING_NONZERO = 100131, + /** Positive winding rule - regions with positive winding number are inside */ + GLU_TESS_WINDING_POSITIVE = 100132, + /** Negative winding rule - regions with negative winding number are inside */ + GLU_TESS_WINDING_NEGATIVE = 100133, + /** Absolute value >= 2 winding rule - regions where |winding| >= 2 are inside */ + GLU_TESS_WINDING_ABS_GEQ_TWO = 100134, +} + +/** + * Primitive types that can be output by the tessellator + */ +export enum primitiveType { + /** Line loop primitive */ + GL_LINE_LOOP = 2, + /** Triangle list primitive */ + GL_TRIANGLES = 4, + /** Triangle strip primitive */ + GL_TRIANGLE_STRIP = 5, + /** Triangle fan primitive */ + GL_TRIANGLE_FAN = 6, +} + +/** + * Error codes that can be returned by the tessellator + */ +export enum errorType { + GLU_TESS_MISSING_BEGIN_POLYGON = 100151, + GLU_TESS_MISSING_END_POLYGON = 100153, + GLU_TESS_MISSING_BEGIN_CONTOUR = 100152, + GLU_TESS_MISSING_END_CONTOUR = 100154, + GLU_TESS_COORD_TOO_LARGE = 100155, + GLU_TESS_NEED_COMBINE_CALLBACK = 100156, +} + +/** + * The main GLU tessellator class. Used to tessellate complex polygons with holes into simpler primitives + */ +export class GluTesselator { + /** + * Create a new tessellator object + */ + constructor(); + + /** + * Delete the tessellator object. Note: In JavaScript this is largely a no-op as garbage collection handles cleanup + */ + gluDeleteTess(): void; + + /** + * Set a tessellation property + * @param which - The property to set (from gluEnum) + * @param value - The value to set + */ + gluTessProperty(which: gluEnum, value: number | boolean): void; + + /** + * Get a tessellation property + * @param which - The property to get (from gluEnum) + * @returns The current value of the property + */ + gluGetTessProperty(which: gluEnum): number | boolean; + + /** + * Specify the normal vector for the polygon. This helps the tessellator determine the polygon orientation. For 2D tessellation, typically use (0, 0, 1) + * @param x - X component of normal + * @param y - Y component of normal + * @param z - Z component of normal + */ + gluTessNormal(x: number, y: number, z: number): void; + + /** + * Register a callback function for tessellation events. Different callback types have different signatures + */ + gluTessCallback( + which: gluEnum.GLU_TESS_BEGIN | gluEnum.GLU_TESS_BEGIN_DATA, + callback: ((type: primitiveType, polygonData?: any) => void) | null, + ): void; + gluTessCallback( + which: gluEnum.GLU_TESS_EDGE_FLAG | gluEnum.GLU_TESS_EDGE_FLAG_DATA, + callback: ((flag: boolean, polygonData?: any) => void) | null, + ): void; + gluTessCallback( + which: gluEnum.GLU_TESS_VERTEX | gluEnum.GLU_TESS_VERTEX_DATA, + callback: ((vertexData: any, polygonData?: any) => void) | null, + ): void; + gluTessCallback( + which: gluEnum.GLU_TESS_END | gluEnum.GLU_TESS_END_DATA, + callback: ((polygonData?: any) => void) | null, + ): void; + gluTessCallback( + which: gluEnum.GLU_TESS_ERROR | gluEnum.GLU_TESS_ERROR_DATA, + callback: ((errno: errorType | gluEnum, polygonData?: any) => void) | null, + ): void; + gluTessCallback( + which: gluEnum.GLU_TESS_COMBINE | gluEnum.GLU_TESS_COMBINE_DATA, + callback: + | (( + coords: number[], + vertexData: any[], + weight: number[], + polygonData?: any, + ) => any) + | null, + ): void; + + /** + * Add a vertex to the current contour. Must be called between gluTessBeginContour and gluTessEndContour + * @param coords - Vertex coordinates [x, y, z] + * @param data - Client data associated with this vertex (will be passed to callbacks) + */ + gluTessVertex(coords: number[], data: any): void; + + /** + * Begin a new polygon. Must be called before adding any contours + * @param data - Client data for this polygon (will be passed to callbacks) + */ + gluTessBeginPolygon(data: any): void; + + /** + * Begin a new contour within the current polygon. Must be called after gluTessBeginPolygon and before adding vertices + */ + gluTessBeginContour(): void; + + /** + * End the current contour. Must be called after adding vertices to a contour + */ + gluTessEndContour(): void; + + /** + * End the current polygon and perform tessellation. This triggers the tessellation and fires the registered callbacks + */ + gluTessEndPolygon(): void; +} diff --git a/types/libtess/libtess-tests.ts b/types/libtess/libtess-tests.ts new file mode 100644 index 00000000000000..505699da2a998b --- /dev/null +++ b/types/libtess/libtess-tests.ts @@ -0,0 +1,125 @@ +import { errorType, gluEnum, GluTesselator, primitiveType, windingRule } from "libtess"; + +// Create a tessellator +const tess = new GluTesselator(); + +// Set properties +tess.gluTessProperty(gluEnum.GLU_TESS_WINDING_RULE, windingRule.GLU_TESS_WINDING_ODD); +tess.gluTessProperty(gluEnum.GLU_TESS_BOUNDARY_ONLY, false); +tess.gluTessProperty(gluEnum.GLU_TESS_TOLERANCE, 0.0); + +// Get properties +const windingRuleValue: number | boolean = tess.gluGetTessProperty(gluEnum.GLU_TESS_WINDING_RULE); +const boundaryOnly: number | boolean = tess.gluGetTessProperty(gluEnum.GLU_TESS_BOUNDARY_ONLY); + +// Set normal (for 2D tessellation) +tess.gluTessNormal(0, 0, 1); + +// Register callbacks +tess.gluTessCallback(gluEnum.GLU_TESS_BEGIN, (type: primitiveType) => { + if (type === primitiveType.GL_TRIANGLES) { + // handle triangles + } +}); + +tess.gluTessCallback(gluEnum.GLU_TESS_VERTEX, (vertexData: any) => { + // handle vertex +}); + +tess.gluTessCallback(gluEnum.GLU_TESS_END, () => { + // handle end +}); + +tess.gluTessCallback(gluEnum.GLU_TESS_ERROR, (errno: errorType | gluEnum) => { + if (errno === errorType.GLU_TESS_NEED_COMBINE_CALLBACK) { + // handle error + } +}); + +tess.gluTessCallback(gluEnum.GLU_TESS_EDGE_FLAG, (flag: boolean) => { + // handle edge flag +}); + +tess.gluTessCallback( + gluEnum.GLU_TESS_COMBINE, + (coords: number[], vertexData: any[], weight: number[]) => { + return { coords }; + }, +); + +// Callbacks with polygon data +const polygonData = { id: 1 }; + +tess.gluTessCallback(gluEnum.GLU_TESS_BEGIN_DATA, (type: primitiveType, data?: any) => { + if (data) { + // handle with data + } +}); + +tess.gluTessCallback(gluEnum.GLU_TESS_VERTEX_DATA, (vertexData: any, data?: any) => { + if (data) { + // handle with data + } +}); + +tess.gluTessCallback(gluEnum.GLU_TESS_END_DATA, (data?: any) => { + if (data) { + // handle with data + } +}); + +tess.gluTessCallback(gluEnum.GLU_TESS_ERROR_DATA, (errno: errorType | gluEnum, data?: any) => { + if (data) { + // handle with data + } +}); + +tess.gluTessCallback(gluEnum.GLU_TESS_EDGE_FLAG_DATA, (flag: boolean, data?: any) => { + if (data) { + // handle with data + } +}); + +tess.gluTessCallback( + gluEnum.GLU_TESS_COMBINE_DATA, + (coords: number[], vertexData: any[], weight: number[], data?: any) => { + return { coords, data }; + }, +); + +// Clear a callback +tess.gluTessCallback(gluEnum.GLU_TESS_BEGIN, null); + +// Tessellate a simple square +tess.gluTessBeginPolygon(polygonData); +tess.gluTessBeginContour(); +tess.gluTessVertex([0, 0, 0], { id: 0 }); +tess.gluTessVertex([1, 0, 0], { id: 1 }); +tess.gluTessVertex([1, 1, 0], { id: 2 }); +tess.gluTessVertex([0, 1, 0], { id: 3 }); +tess.gluTessEndContour(); +tess.gluTessEndPolygon(); + +// Tessellate a polygon with a hole +tess.gluTessBeginPolygon(null); + +// Outer contour +tess.gluTessBeginContour(); +tess.gluTessVertex([0, 0, 0], 0); +tess.gluTessVertex([2, 0, 0], 1); +tess.gluTessVertex([2, 2, 0], 2); +tess.gluTessVertex([0, 2, 0], 3); +tess.gluTessEndContour(); + +// Inner contour (hole) +tess.gluTessBeginContour(); +tess.gluTessVertex([0.5, 0.5, 0], 4); +tess.gluTessVertex([1.5, 0.5, 0], 5); +tess.gluTessVertex([1.5, 1.5, 0], 6); +tess.gluTessVertex([0.5, 1.5, 0], 7); +tess.gluTessEndContour(); + +tess.gluTessEndPolygon(); + +// Clean up +tess.gluDeleteTess(); diff --git a/types/libtess/package.json b/types/libtess/package.json new file mode 100644 index 00000000000000..7fd88f5a582b55 --- /dev/null +++ b/types/libtess/package.json @@ -0,0 +1,17 @@ +{ + "private": true, + "name": "@types/libtess", + "version": "1.2.9999", + "projects": [ + "https://github.com/brendankenny/libtess.js" + ], + "devDependencies": { + "@types/libtess": "workspace:." + }, + "owners": [ + { + "name": "Jeremy Tribby", + "githubUsername": "jpt" + } + ] +} diff --git a/types/libtess/tsconfig.json b/types/libtess/tsconfig.json new file mode 100644 index 00000000000000..d4d40e3f790c17 --- /dev/null +++ b/types/libtess/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "node16", + "lib": ["es6"], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "libtess-tests.ts" + ] +}