/**
 * Represents a specific point in a {@link VertexData} instance. This can be very useful when we need
 * to work with specific point data from a {@link VertexData} instance.
 */
export class VertexDataTrianglePoint {
    vertexData;
    /**
     * Offset for X value in {@link vertexData.positions} and {@link vertexData.normals} arrays.
     */
    xOffset = 0;
    /**
     * Offset for Y value in {@link vertexData.positions} and {@link vertexData.normals} arrays.
     */
    yOffset = 0;
    /**
     * Offset for Z value in {@link vertexData.positions} and {@link vertexData.normals} arrays.
     */
    zOffset = 0;
    /**
     * Offset for U value in {@link vertexData.uvs}'s arrays
     */
    uOffset = 0;
    /**
     * Offset for V value in {@link vertexData.uvs}'s arrays
     */
    vOffset = 0;
    /**
     *
     * @param vertexData {@link VertexData} instance.
     */
    constructor(vertexData) {
        this.vertexData = vertexData;
    }
    /**
     * Rebuild `x|y|z|u|vOffsets` from specified offset in {@link vertexData.indices} buffer. This is useful
     * in high peformance loops where we might want to reuse {@link VertexDataTrianglePoint} for performance
     * reasons (in very compute heavy scenarios the time to "new" a new object actually matters, not to mention GC contraints).
     * @param indicesOffset Indice in {@link vertexData.indices} (represents a point in a triangle).
     * @return Reference to `this`.
     */
    rebuild(indicesOffset) {
        const self = this;
        self.xOffset = this.vertexData.indices[indicesOffset] * 3;
        self.yOffset = self.xOffset + 1;
        self.zOffset = self.xOffset + 2;
        self.uOffset = this.vertexData.indices[indicesOffset] * 2;
        self.vOffset = self.uOffset + 1;
        return this;
    }
    /**
     * Copy X,Y,Z coordianate from {@link vertexData}, this instance represents, into {@link dst}
     * @param p Property to get X,Y,Z data from in {@link vertexData}.
     * @param dst Where X,Y,Z coordinate shall be written.
     * @returns Reference to `dst`.
     */
    xyzToRef(p, dst) {
        dst.x = this.vertexData[p][this.xOffset];
        dst.y = this.vertexData[p][this.yOffset];
        dst.z = this.vertexData[p][this.zOffset];
        return dst;
    }
    /**
     * Copy U,V coordianate from {@link vertexData}, this instance represents, into {@link dst}
     * @param p Property to get U,V data from in {@link vertexData}.
     * @param dst Where U,V coordinate shall be written.
     * @returns Reference to `dst`.
     */
    uvToRef(p, dst) {
        dst.u = this.vertexData[p][this.uOffset];
        dst.v = this.vertexData[p][this.vOffset];
        return dst;
    }
}
/**
 * Utility methods for {@link VertexData}.
 */
export class VertexDataUtils {
    /**
     * Visit each triangle (and their corners) defined by `vertexData.indices` and `vertexData.positions`. Also makes it
     * possible to get normals and uvs from the triangle corners.
     * @param vertexData {@link VertexData}.
     * @param action Callback where parameters represents the three corners of the triangle. Do NOT store references to these parameters (or anything in them)
     * as they point to objects which are reused for every invocation of the callback.
     * @param indiceStartOffset Offset in `vertexData.indice` where iteration shall start. Defaults to 0. Will be forced to >= 0 and a multiple of 3.
     */
    static forEachTriangle(vertexData, action, indiceStartOffset = 0) {
        const iLen = vertexData.indices?.length ?? 0;
        const vLen = vertexData.indices?.length ?? 0;
        if (iLen === 0 || vLen === 0) {
            return;
        }
        // Ensure start offset is >= 0 and a multiple of 3
        indiceStartOffset = Math.max(0, indiceStartOffset);
        indiceStartOffset = Math.floor(indiceStartOffset / 3) * 3;
        // TODO If we really need to cut down on allocations then we can put
        // these in a static temp variable instead.
        const p1 = new VertexDataTrianglePoint(vertexData);
        const p2 = new VertexDataTrianglePoint(vertexData);
        const p3 = new VertexDataTrianglePoint(vertexData);
        for (let i = indiceStartOffset; i < iLen; i += 3) {
            p1.rebuild(i);
            p2.rebuild(i + 1);
            p3.rebuild(i + 2);
            if (action(p1, p2, p3) === false) {
                return; // abort if callback returns false.
            }
        }
    }
}
//# sourceMappingURL=VertexDataUtil.js.map