Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions src/core/InternalMeshAttributeBuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,11 @@ export class InternalMeshAttributeBuffer {
}

/**
* @template {import("./Mesh.js").GetVertexDataOptionsTemplate} T
* @param {import("./Mesh.js").AttributeType} attributeType
* @param {import("./Mesh.js").GetVertexDataOptions<T>} [options]
*/
*getVertexData(attributeType) {
*getVertexData(attributeType, { vec } = {}) {
const attributeSettings = this.getAttributeSettings(attributeType);
if (!attributeSettings) {
throw new Error("The attribute does not contain the specified attribute type.");
Expand Down Expand Up @@ -362,7 +364,11 @@ export class InternalMeshAttributeBuffer {
while (i <= this.buffer.byteLength - this.arrayStride) {
const x = getFunction(i + attributeSettings.offset + valueByteSize * 0, true);
const y = getFunction(i + attributeSettings.offset + valueByteSize * 1, true);
yield new Vec2(x, y);
if (!vec) {
yield new Vec2(x, y);
} else {
yield vec.set(x, y);
}
i += this.arrayStride;
}
} else if (attributeSettings.componentCount == 3) {
Expand All @@ -371,7 +377,12 @@ export class InternalMeshAttributeBuffer {
const x = getFunction(i + attributeSettings.offset + valueByteSize * 0, true);
const y = getFunction(i + attributeSettings.offset + valueByteSize * 1, true);
const z = getFunction(i + attributeSettings.offset + valueByteSize * 2, true);
yield new Vec3(x, y, z);
if (!vec) {
yield new Vec3(x, y, z);
} else {
const castVec = /** @type {Vec3} */ (vec);
yield castVec.set(x, y, z);
}
i += this.arrayStride;
}
} else if (attributeSettings.componentCount == 4) {
Expand All @@ -381,7 +392,12 @@ export class InternalMeshAttributeBuffer {
const y = getFunction(i + attributeSettings.offset + valueByteSize * 1, true);
const z = getFunction(i + attributeSettings.offset + valueByteSize * 2, true);
const w = getFunction(i + attributeSettings.offset + valueByteSize * 3, true);
yield new Vec4(x, y, z, w);
if (!vec) {
yield new Vec4(x, y, z, w);
} else {
const castVec = /** @type {Vec4} */ (vec);
yield castVec.set(x, y, z, w);
}
i += this.arrayStride;
}
}
Expand Down
14 changes: 12 additions & 2 deletions src/core/Mesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ import { InternalMeshAttributeBuffer } from "./InternalMeshAttributeBuffer.js";

/** @typedef {() => void} OnIndexBufferChangeCallback */

/** @typedef {import("../mod.js").Vec2 | import("../mod.js").Vec3 | import("../mod.js").Vec4} GetVertexDataOptionsTemplate */

/**
* @template {GetVertexDataOptionsTemplate} T
* @typedef GetVertexDataOptions
* @property {T} [vec]
*/

export class Mesh {
/** @type {InternalMeshAttributeBuffer[]} */
#buffers = [];
Expand Down Expand Up @@ -311,14 +319,16 @@ export class Mesh {

/**
* Iterates over the vertex data of the specified attribute.
* @template {GetVertexDataOptionsTemplate} T
* @param {AttributeType} attributeType
* @param {GetVertexDataOptions<T>} [options]
*/
getVertexData(attributeType) {
getVertexData(attributeType, options) {
const buffer = this.#getInternalAttributeBuffer(attributeType);
if (!buffer) {
throw new Error("This mesh does not contain an attribute with the specified type. Either add a vertex state that includes this attribute or add vertex data using setVertexData().");
}
return buffer.getVertexData(attributeType);
return buffer.getVertexData(attributeType, options);
}

// TODO: change the signature so that you can only provide an ArrayBuffer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { assertEquals, assertExists, assertThrows } from "std/testing/asserts.ts";
import { assertEquals, assertExists, assertStrictEquals, assertThrows } from "std/testing/asserts.ts";
import { Mesh, Vec2, Vec3, Vec4 } from "../../../../../src/mod.js";
import { assertVecAlmostEquals } from "../../../../../src/util/asserts.js";
import { InternalMeshAttributeBuffer } from "../../../../../src/core/InternalMeshAttributeBuffer.js";
Expand Down Expand Up @@ -930,6 +930,50 @@ Deno.test({
},
});

/**
* @param {number} componentCount
* @param {new () => Vec2 | Vec3 | Vec4} VecConstructor
* @param {(Vec2 | Vec3 | Vec4)[]} vectors
*/
function runProvidedTest(componentCount, VecConstructor, vectors) {
const buffer = new InternalMeshAttributeBuffer({
attributeSettings: [{ offset: 0, format: Mesh.AttributeFormat.FLOAT32, componentCount, attributeType: Mesh.AttributeType.POSITION }],
});
buffer.setVertexCount(2);
buffer.setVertexData(Mesh.AttributeType.POSITION, vectors, false);

const vec = new VecConstructor();
let i = 0;
for (const pos of buffer.getVertexData(Mesh.AttributeType.POSITION, { vec })) {
assertStrictEquals(pos, vec);
assertVecAlmostEquals(pos, vectors[i]);
i++;
}

assertEquals(i, vectors.length);
}

Deno.test({
name: "getVertexData() yielding provided Vec2",
fn() {
runProvidedTest(2, Vec2, [new Vec2(1, 2), new Vec2(4, 5)]);
},
});

Deno.test({
name: "getVertexData() yielding provided Vec3",
fn() {
runProvidedTest(3, Vec3, [new Vec3(1, 2, 3), new Vec3(4, 5, 6)]);
},
});

Deno.test({
name: "getVertexData() yielding provided Vec4",
fn() {
runProvidedTest(4, Vec4, [new Vec4(1, 2, 3, 4), new Vec4(5, 6, 7, 8)]);
},
});

Deno.test({
name: "getVertexData() yielding different AttributeFormats",
fn() {
Expand Down
Loading