Skip to content

Commit 90a5df5

Browse files
author
Andrew Adamson
committed
Adding Wavefront file loader for episode 19
1 parent 4d3e144 commit 90a5df5

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

19.wavefrontparser1.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* Loads a text file (for loading the Wavefront OBJ file)
3+
* @param {string} filename
4+
* @returns {string} contents of text file
5+
*/
6+
const getFileContents = async (filename) => {
7+
const file = await fetch(filename);
8+
const body = await file.text();
9+
return body;
10+
};
11+
12+
/**
13+
* Converts an array of string numbers to an array of floating point numbers
14+
* @param {string[]} strings array of strings containing numeric values
15+
* @returns {number[]} a regular JS array of floating point numbers
16+
*/
17+
const stringsToNumbers = (strings) => {
18+
const numbers = [];
19+
for (const str of strings) {
20+
numbers.push(parseFloat(str));
21+
}
22+
return numbers;
23+
};
24+
25+
/**
26+
* Parses a Wavefront OBJ, returning an array buffer
27+
* @param {string} fileContents the text contents of a Wavefront OBJ file
28+
* @returns {ArrayBuffer} the array buffer of a Float32Array
29+
*/
30+
const parseFile = (fileContents) => {
31+
const positions = [];
32+
const texCoords = [];
33+
const normals = [];
34+
35+
const arrayBufferSource = [];
36+
37+
const lines = fileContents.split('\n');
38+
for (const line of lines) {
39+
const [ command, ...values ] = line.split(' ', 4);
40+
41+
if (command === 'v') {
42+
positions.push(stringsToNumbers(values));
43+
} else if (command === 'vt') {
44+
texCoords.push(stringsToNumbers(values));
45+
} else if (command === 'vn') {
46+
normals.push(stringsToNumbers(values));
47+
}
48+
49+
else if (command === 'f') {
50+
for (const group of values) {
51+
const [ positionIndex, texCoordIndex, normalIndex ] = stringsToNumbers(group.split('/'));
52+
53+
arrayBufferSource.push(...positions[positionIndex - 1]);
54+
arrayBufferSource.push(...normals[normalIndex - 1]);
55+
arrayBufferSource.push(...texCoords[texCoordIndex - 1]);
56+
}
57+
}
58+
}
59+
60+
// Note: if you want to use JSON, the regular JS array, you can stop here.
61+
// arrayBufferSource contains all the numeric data you want. Use these numbers
62+
// in your JSON output.
63+
// e.g.:
64+
// return JSON.stringify({ vertices: arrayBufferSource });
65+
66+
// Because we're writing a binary file, we return a Float32Array buffer containing the vertex data.
67+
return new Float32Array(arrayBufferSource).buffer;
68+
};
69+
70+
/**
71+
* Saves a binary file of the contents of arrayBuffer to the browser's Downloads folder
72+
* @param {string} fileName name of file to be saved
73+
* @param {ArrayBuffer} arrayBuffer array buffer to be stored
74+
*/
75+
const saveBinaryFile = (fileName, arrayBuffer) => {
76+
const blob = new Blob([arrayBuffer], { type: 'application/octet-stream'});
77+
const url = URL.createObjectURL(blob);
78+
79+
const anchor = document.createElement('a');
80+
document.body.appendChild(anchor);
81+
82+
anchor.type = 'application/octet-stream';
83+
anchor.download = fileName;
84+
anchor.href = url;
85+
86+
anchor.click();
87+
};
88+
89+
const main = async () => {
90+
// 1. Load the Wavefront OBJ file
91+
// If using Node, use `fs.readFile(path, callback)`
92+
const fileContents = await getFileContents('burger.obj');
93+
94+
// 2. Parse the file and create an array buffer from its contents
95+
const arrayBuffer = parseFile(fileContents);
96+
97+
// 3. Save the binary file
98+
// If using Node, use `fs.writeFile(path, arrayBuffer, "binary", callback)`
99+
saveBinaryFile('burger.bin', arrayBuffer);
100+
};
101+
102+
main();

0 commit comments

Comments
 (0)