ThreeJSExporter.ms 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. -------------------------------------------------------------------------------------
  2. -- ThreeJSExporter.ms
  3. -- Exports geometry from 3ds max to Three.js models in ASCII JSON format v3
  4. -- By alteredq / http://alteredqualia.com
  5. -------------------------------------------------------------------------------------
  6. rollout ThreeJSExporter "ThreeJSExporter"
  7. (
  8. -- Variables
  9. local ostream,
  10. headerFormat = "\"metadata\":
  11. {
  12. \"sourceFile\": \"%\",
  13. \"generatedBy\": \"3ds max ThreeJSExporter\",
  14. \"formatVersion\": 3.1,
  15. \"vertices\": %,
  16. \"normals\": %,
  17. \"colors\": %,
  18. \"uvs\": %,
  19. \"triangles\": %,
  20. \"materials\": %
  21. },
  22. ",
  23. vertexFormat = "%,%,%",
  24. vertexNormalFormat = "%,%,%",
  25. UVFormat = "%,%",
  26. triFormat = "%,%,%,%",
  27. triUVFormat = "%,%,%,%,%,%,%",
  28. triNFormat = "%,%,%,%,%,%,%",
  29. triUVNFormat = "%,%,%,%,%,%,%,%,%,%",
  30. footerFormat = "}"
  31. -------------------------------------------------------------------------------------
  32. -- User interface
  33. group "ThreeJSExporter v0.8"
  34. (
  35. label msg "Exports selected meshes in Three.js ascii JSON format" align:#left
  36. hyperLink lab1 "Original source at GitHub" address:"https://github.com/alteredq/three.js/blob/master/utils/exporters/max/ThreeJSExporter.ms" color:(color 255 120 0) align:#left
  37. label dummy1 "--------------------------------------------------------" align:#left
  38. checkbox exportColor "Export vertex colors" checked:false enabled:true
  39. checkbox exportUv "Export uvs" checked:true enabled:true
  40. checkbox exportNormal "Export normals" checked:true enabled:true
  41. checkbox smoothNormal "Use vertex normals" checked:false enabled:true
  42. label dummy2 "--------------------------------------------------------" align:#left
  43. checkbox flipYZ "Flip YZ" checked:true enabled:true
  44. checkbox flipUV "Flip UV" checked:false enabled:true
  45. checkbox flipFace "Flip all faces" checked:false enabled:true
  46. checkbox autoflipFace "Try fixing flipped faces" checked:false enabled:true
  47. label dummy3 "--------------------------------------------------------" align:#left
  48. button btn_export "Export selected objects"
  49. )
  50. -------------------------------------------------------------------------------------
  51. -- Dump vertices
  52. function DumpVertices src =
  53. (
  54. Format "\"vertices\": [" to:ostream
  55. num = src.count
  56. if num > 0 then
  57. (
  58. for i = 1 to num do
  59. (
  60. vert = src[i]
  61. if flipYZ.checked then
  62. (
  63. x = vert.x
  64. y = vert.z
  65. z = vert.y
  66. z *= -1
  67. )
  68. else
  69. (
  70. x = vert.x
  71. y = vert.y
  72. z = vert.z
  73. )
  74. Format vertexFormat x y z to:ostream
  75. if i < num then Format "," to:ostream
  76. )
  77. )
  78. Format "],\n\n" to:ostream
  79. )
  80. -------------------------------------------------------------------------------------
  81. -- Dump colors
  82. function DumpColors src useColors =
  83. (
  84. Format "\"colors\": [" to:ostream
  85. num = src.count
  86. if num > 0 and useColors then
  87. (
  88. for i = 1 to num do
  89. (
  90. col = src[i]
  91. r = col.r as Integer
  92. g = col.g as Integer
  93. b = col.b as Integer
  94. hexNum = ( bit.shift r 16 ) + ( bit.shift g 8 ) + b
  95. -- hexColor = formattedPrint hexNum format:"#x"
  96. -- Format "%" hexColor to:ostream
  97. decColor = formattedPrint hexNum format:"#d"
  98. Format "%" decColor to:ostream
  99. if i < num then Format "," to:ostream
  100. )
  101. )
  102. Format "],\n\n" to:ostream
  103. )
  104. -------------------------------------------------------------------------------------
  105. -- Dump normals
  106. function DumpNormals src =
  107. (
  108. Format "\"normals\": [" to:ostream
  109. num = src.count
  110. if num > 0 and exportNormal.checked then
  111. (
  112. for i = 1 to num do
  113. (
  114. normal = src[i]
  115. normal = normalize normal as point3
  116. if flipYZ.checked then
  117. (
  118. x = normal.x
  119. y = normal.z
  120. z = normal.y
  121. z *= -1
  122. )
  123. else
  124. (
  125. x = normal.x
  126. y = normal.y
  127. z = normal.z
  128. )
  129. Format vertexNormalFormat x y z to:ostream
  130. if i < num then Format "," to:ostream
  131. )
  132. )
  133. Format "],\n\n" to:ostream
  134. )
  135. -------------------------------------------------------------------------------------
  136. -- Dump uvs
  137. function DumpUvs src =
  138. (
  139. Format "\"uvs\": [[" to:ostream
  140. num = src.count
  141. if num > 0 and exportUv.checked then
  142. (
  143. for i = 1 to num do
  144. (
  145. uvw = src[i]
  146. u = uvw.x
  147. if flipUV.checked then
  148. (
  149. v = 1 - uvw.y
  150. )
  151. else
  152. (
  153. v = uvw.y
  154. )
  155. Format UVFormat u v to:ostream
  156. if i < num then Format "," to:ostream
  157. )
  158. )
  159. Format "]],\n\n" to:ostream
  160. )
  161. -------------------------------------------------------------------------------------
  162. -- Dump faces
  163. function DumpFaces src useColors =
  164. (
  165. Format "\"faces\": [" to:ostream
  166. num = src.count
  167. if num > 0 then
  168. (
  169. for i = 1 to num do
  170. (
  171. zface = src[i]
  172. fv = zface[1]
  173. fuv = zface[2]
  174. m = zface[3] - 1
  175. fc = zface[4]
  176. needsFlip = zface[5]
  177. isTriangle = true
  178. hasMaterial = true
  179. hasFaceUvs = false
  180. hasFaceVertexUvs = ((classof fuv == Point3) and exportUv.checked)
  181. hasFaceNormals = false
  182. hasFaceVertexNormals = (exportNormal.checked)
  183. hasFaceColors = false
  184. hasFaceVertexColors = ((classof fc == Point3) and useColors)
  185. faceType = 0
  186. faceType = bit.set faceType 1 (not isTriangle)
  187. faceType = bit.set faceType 2 hasMaterial
  188. faceType = bit.set faceType 3 hasFaceUvs
  189. faceType = bit.set faceType 4 hasFaceVertexUvs
  190. faceType = bit.set faceType 5 hasFaceNormals
  191. faceType = bit.set faceType 6 hasFaceVertexNormals
  192. faceType = bit.set faceType 7 hasFaceColors
  193. faceType = bit.set faceType 8 hasFaceVertexColors
  194. if i > 1 then
  195. (
  196. Format "," faceType to:ostream
  197. )
  198. Format "%" faceType to:ostream
  199. if isTriangle then
  200. (
  201. va = (fv.x - 1) as Integer
  202. vb = (fv.y - 1) as Integer
  203. vc = (fv.z - 1) as Integer
  204. if flipFace.checked or needsFlip then
  205. (
  206. tmp = vb
  207. vb = vc
  208. vc = tmp
  209. )
  210. Format ",%,%,%" va vb vc to:ostream
  211. if hasMaterial then
  212. (
  213. Format ",%" m to:ostream
  214. )
  215. if hasFaceVertexUvs then
  216. (
  217. ua = (fuv.x - 1) as Integer
  218. ub = (fuv.y - 1) as Integer
  219. uc = (fuv.z - 1) as Integer
  220. if flipFace.checked or needsFlip then
  221. (
  222. tmp = ub
  223. ub = uc
  224. uc = tmp
  225. )
  226. Format ",%,%,%" ua ub uc to:ostream
  227. )
  228. if hasFaceVertexNormals then
  229. (
  230. if smoothNormal.checked then
  231. (
  232. -- normals have the same indices as vertices
  233. na = va
  234. nb = vb
  235. nc = vc
  236. )
  237. else
  238. (
  239. -- normals have the same indices as face
  240. na = i - 1
  241. nb = na
  242. nc = na
  243. )
  244. if flipFace.checked or needsFlip then
  245. (
  246. tmp = nb
  247. nb = nc
  248. nc = tmp
  249. )
  250. Format ",%,%,%" na nb nc to:ostream
  251. )
  252. if hasFaceVertexColors then
  253. (
  254. ca = (fc.x - 1) as Integer
  255. cb = (fc.y - 1) as Integer
  256. cc = (fc.z - 1) as Integer
  257. if flipFace.checked or needsFlip then
  258. (
  259. tmp = cb
  260. cb = cc
  261. cc = tmp
  262. )
  263. Format ",%,%,%" ca cb cc to:ostream
  264. )
  265. )
  266. )
  267. )
  268. Format "]\n\n" to:ostream
  269. )
  270. -------------------------------------------------------------------------------------
  271. -- Dump color
  272. function DumpColor pcolor label =
  273. (
  274. r = pcolor.r / 255
  275. g = pcolor.g / 255
  276. b = pcolor.b / 255
  277. fr = formattedPrint r format:".4f"
  278. fg = formattedPrint g format:".4f"
  279. fb = formattedPrint b format:".4f"
  280. Format "\"%\" : [%, %, %],\n" label fr fg fb to:ostream
  281. )
  282. -------------------------------------------------------------------------------------
  283. -- Dump map
  284. function DumpMap pmap label =
  285. (
  286. if classof pmap == BitmapTexture then
  287. (
  288. bm = pmap.bitmap
  289. if bm != undefined then
  290. (
  291. fname = filenameFromPath bm.filename
  292. Format "\"%\" : \"%\",\n" label fname to:ostream
  293. )
  294. )
  295. )
  296. -------------------------------------------------------------------------------------
  297. -- Export materials
  298. function ExportMaterials zmaterials zcolors =
  299. (
  300. Format "\"materials\": [\n" to:ostream
  301. totalMaterials = zmaterials.count
  302. for i = 1 to totalMaterials do
  303. (
  304. mat = zmaterials[i]
  305. Format "{\n" to:ostream
  306. -- debug
  307. Format "\"DbgIndex\" : %,\n" (i-1) to:ostream
  308. if classof mat != BooleanClass then
  309. (
  310. useVertexColors = zcolors[i]
  311. Format "\"DbgName\" : \"%\",\n" mat.name to:ostream
  312. -- colors
  313. DumpColor mat.diffuse "colorDiffuse"
  314. DumpColor mat.ambient "colorAmbient"
  315. DumpColor mat.specular "colorSpecular"
  316. t = mat.opacity / 100
  317. s = mat.glossiness
  318. Format "\"transparency\" : %,\n" t to:ostream
  319. Format "\"specularCoef\" : %,\n" s to:ostream
  320. -- maps
  321. DumpMap mat.diffuseMap "mapDiffuse"
  322. DumpMap mat.ambientMap "mapAmbient"
  323. DumpMap mat.specularMap "mapSpecular"
  324. DumpMap mat.bumpMap "mapBump"
  325. DumpMap mat.opacityMap "mapAlpha"
  326. )
  327. else
  328. (
  329. useVertexColors = false
  330. Format "\"DbgName\" : \"%\",\n" "dummy" to:ostream
  331. DumpColor red "colorDiffuse"
  332. )
  333. Format "\"vertexColors\" : %\n" useVertexColors to:ostream
  334. Format "}" to:ostream
  335. if ( i < totalMaterials ) then Format "," to:ostream
  336. Format "\n\n" to:ostream
  337. )
  338. Format "],\n\n" to:ostream
  339. )
  340. -------------------------------------------------------------------------------------
  341. -- Extract vertices from mesh
  342. function ExtractVertices obj whereto =
  343. (
  344. n = obj.numVerts
  345. for i = 1 to n do
  346. (
  347. v = GetVert obj i
  348. append whereto v
  349. )
  350. )
  351. -------------------------------------------------------------------------------------
  352. -- Extract vertex colors from mesh
  353. function ExtractColors obj whereto =
  354. (
  355. nColors = GetNumCPVVerts obj
  356. if nColors > 0 then
  357. (
  358. for i = 1 to nColors do
  359. (
  360. c = GetVertColor obj i
  361. append whereto c
  362. )
  363. )
  364. )
  365. -------------------------------------------------------------------------------------
  366. -- Extract normals from mesh
  367. function ExtractNormals obj whereto needsFlip =
  368. (
  369. if smoothNormal.checked then
  370. (
  371. num = obj.numVerts
  372. for i = 1 to num do
  373. (
  374. n = GetNormal obj i
  375. if flipFace.checked or needsFlip then
  376. (
  377. n.x *= -1
  378. n.y *= -1
  379. n.z *= -1
  380. )
  381. append whereto n
  382. )
  383. )
  384. else
  385. (
  386. num = obj.numFaces
  387. for i = 1 to num do
  388. (
  389. n = GetFaceNormal obj i
  390. if flipFace.checked or needsFlip then
  391. (
  392. n.x *= -1
  393. n.y *= -1
  394. n.z *= -1
  395. )
  396. append whereto n
  397. )
  398. )
  399. )
  400. -------------------------------------------------------------------------------------
  401. -- Extract uvs from mesh
  402. function ExtractUvs obj whereto =
  403. (
  404. n = obj.numTVerts
  405. for i = 1 to n do
  406. (
  407. v = GetTVert obj i
  408. append whereto v
  409. )
  410. )
  411. -------------------------------------------------------------------------------------
  412. -- Extract faces from mesh
  413. function ExtractFaces objMesh objMaterial whereto allMaterials needsFlip hasVColors offsetVert offsetUv offsetColor =
  414. (
  415. n = objMesh.numFaces
  416. hasUVs = objMesh.numTVerts > 0
  417. useMultiMaterial = false
  418. materialIDList = #()
  419. materialClass = classof objMaterial
  420. if materialClass == StandardMaterial then
  421. (
  422. fm = findItem allMaterials objMaterial
  423. )
  424. else if materialClass == MultiMaterial then
  425. (
  426. useMultiMaterial = true
  427. for i = 1 to n do
  428. (
  429. mID = GetFaceMatID objMesh i
  430. materialIndex = findItem objMaterial.materialIDList mID
  431. if materialIndex > 0 then
  432. (
  433. subMaterial = objMaterial.materialList[materialIndex]
  434. mMergedIndex = findItem allMaterials subMaterial
  435. if mMergedIndex > 0 then
  436. (
  437. materialIDList[mID] = mMergedIndex
  438. )
  439. else
  440. (
  441. materialIDList[mID] = findItem allMaterials false
  442. )
  443. )
  444. else
  445. (
  446. materialIDList[mID] = findItem allMaterials false
  447. )
  448. )
  449. )
  450. else
  451. (
  452. -- undefined material
  453. fm = findItem allMaterials false
  454. )
  455. for i = 1 to n do
  456. (
  457. zface = #()
  458. fv = GetFace objMesh i
  459. fv.x += offsetVert
  460. fv.y += offsetVert
  461. fv.z += offsetVert
  462. if useMultiMaterial then
  463. (
  464. mID = GetFaceMatID objMesh i
  465. fm = materialIDList[mID]
  466. )
  467. if hasUVs then
  468. (
  469. fuv = GetTVFace objMesh i
  470. fuv.x += offsetUv
  471. fuv.y += offsetUv
  472. fuv.z += offsetUv
  473. )
  474. else
  475. (
  476. fuv = false
  477. )
  478. if hasVColors then
  479. (
  480. fc = GetVCFace objMesh i
  481. fc.x += offsetColor
  482. fc.y += offsetColor
  483. fc.z += offsetColor
  484. )
  485. else
  486. (
  487. fc = false
  488. )
  489. append zface fv
  490. append zface fuv
  491. append zface fm
  492. append zface fc
  493. append zface needsFlip
  494. append whereto zface
  495. )
  496. )
  497. -------------------------------------------------------------------------------------
  498. -- Extract materials from eventual multi-material
  499. function ExtractMaterials objMesh objMaterial whereto wheretoColors zname hasVColors =
  500. (
  501. materialClass = classof objMaterial
  502. if materialClass == StandardMaterial then
  503. (
  504. if ( findItem whereto objMaterial ) == 0 then
  505. (
  506. append whereto objMaterial
  507. append wheretoColors hasVColors
  508. )
  509. )
  510. else if materialClass == MultiMaterial then
  511. (
  512. n = objMesh.numFaces
  513. for i = 1 to n do
  514. (
  515. mID = getFaceMatId objMesh i
  516. materialIndex = findItem objMaterial.materialIDList mID
  517. if materialIndex > 0 then
  518. (
  519. subMaterial = objMaterial.materialList[materialIndex]
  520. if ( findItem whereto subMaterial ) == 0 then
  521. (
  522. append whereto subMaterial
  523. append wheretoColors hasVColors
  524. )
  525. )
  526. )
  527. )
  528. else
  529. (
  530. -- unknown or undefined material
  531. append whereto false
  532. append wheretoColors false
  533. )
  534. )
  535. -------------------------------------------------------------------------------------
  536. -- Hack to figure out if normals are messed up
  537. function NeedsFaceFlip node =
  538. (
  539. needsFlip = false
  540. local tmp = Snapshot node
  541. face_normal = normalize ( getfacenormal tmp 1 )
  542. face = getface tmp 1
  543. va = getvert tmp face[1]
  544. vb = getvert tmp face[2]
  545. vc = getvert tmp face[3]
  546. computed_normal = normalize ( cross (vc - vb) (va - vb) )
  547. if distance computed_normal face_normal > 0.1 then needsFlip = true
  548. delete tmp
  549. return needsFlip
  550. )
  551. -------------------------------------------------------------------------------------
  552. -- Extract only things that either already are or can be converted to meshes
  553. function ExtractMesh node =
  554. (
  555. if SuperClassOf node == GeometryClass then
  556. (
  557. needsFlip = false
  558. hasVColors = false
  559. zmesh = SnapshotAsMesh node
  560. if autoflipFace.checked then
  561. (
  562. needsFlip = NeedsFaceFlip node
  563. )
  564. if exportColor.checked and ( getNumCPVVerts zmesh ) > 0 then
  565. (
  566. hasVColors = true
  567. )
  568. return #( zmesh, node.name, node.material, needsFlip, hasVColors )
  569. )
  570. -- Not geometry ... could be a camera, light, etc.
  571. return #( false, node.name, 0, false, false )
  572. )
  573. -------------------------------------------------------------------------------------
  574. -- Export scene
  575. function ExportScene =
  576. (
  577. -- Extract meshes
  578. meshObjects = #()
  579. mergedVertices = #()
  580. mergedNormals = #()
  581. mergedColors = #()
  582. mergedUvs = #()
  583. mergedFaces = #()
  584. mergedMaterials = #()
  585. mergedMaterialsColors = #()
  586. sceneHasVColors = false
  587. for obj in selection do
  588. (
  589. result = ExtractMesh obj
  590. meshObj = result[1]
  591. if ClassOf meshObj == TriMesh then
  592. (
  593. meshName = result[2]
  594. meshMaterial = result[3]
  595. needsFlip = result[4]
  596. hasVColors = result[5]
  597. sceneHasVColors = sceneHasVColors or hasVColors
  598. append meshObjects result
  599. vertexOffset = mergedVertices.count
  600. uvOffset = mergedUvs.count
  601. colorOffset = mergedColors.count
  602. ExtractMaterials meshObj meshMaterial mergedMaterials mergedMaterialsColors meshName hasVColors
  603. ExtractVertices meshObj mergedVertices
  604. ExtractNormals meshObj mergedNormals needsFlip
  605. ExtractColors meshObj mergedColors
  606. ExtractUvs meshObj mergedUvs
  607. ExtractFaces meshObj meshMaterial mergedFaces mergedMaterials needsFlip hasVColors vertexOffset uvOffset colorOffset
  608. )
  609. )
  610. totalVertices = mergedVertices.count
  611. totalFaces = mergedFaces.count
  612. totalMaterials = mergedMaterials.count
  613. totalColors = 0
  614. totalNormals = 0
  615. totalUvs = 0
  616. useColors = false
  617. if sceneHasVColors and exportColor.checked then
  618. (
  619. totalColors = mergedColors.count
  620. useColors = true
  621. )
  622. if exportNormal.checked then
  623. (
  624. totalNormals = mergedNormals.count
  625. )
  626. if exportUv.checked then
  627. (
  628. totalUvs = mergedUvs.count
  629. )
  630. -- Dump objects (debug)
  631. -- Format "// Source objects:\n\n" to:ostream
  632. -- i = 0
  633. -- for obj in meshObjects do
  634. -- (
  635. -- meshName = obj[2]
  636. -- Format "// %: %\n" i meshName to:ostream
  637. -- i += 1
  638. -- )
  639. -- Dump model
  640. Format "{\n\n" to:ostream
  641. -- Dump header
  642. Format headerFormat maxFileName totalVertices totalNormals totalColors totalUvs totalFaces totalMaterials to:ostream
  643. -- Dump all materials in the scene
  644. ExportMaterials mergedMaterials mergedMaterialsColors
  645. -- Dump merged data from all selected geometries
  646. DumpVertices mergedVertices
  647. DumpNormals mergedNormals
  648. DumpColors mergedColors useColors
  649. DumpUvs mergedUvs
  650. DumpFaces mergedFaces useColors
  651. -- Dump footer
  652. Format footerFormat to:ostream
  653. )
  654. -------------------------------------------------------------------------------------
  655. -- Open and prepare a file handle for writing
  656. function GetSaveFileStream =
  657. (
  658. zname = getFilenameFile maxFileName
  659. zname += ".js"
  660. fname = GetSaveFileName filename:zname types:"JavaScript file (*.js)|*.js|All Files(*.*)|*.*|"
  661. if fname == undefined then
  662. (
  663. return undefined
  664. )
  665. ostream = CreateFile fname
  666. if ostream == undefined then
  667. (
  668. MessageBox "Couldn't open file for writing !"
  669. return undefined
  670. )
  671. return ostream
  672. )
  673. -------------------------------------------------------------------------------------
  674. -- Export button click handler
  675. on btn_export pressed do
  676. (
  677. ostream = GetSaveFileStream()
  678. if ostream != undefined then
  679. (
  680. ExportScene()
  681. close ostream
  682. )
  683. )
  684. )
  685. createDialog ThreeJSExporter width:300