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