ThreeJSExporter.ms 18 KB

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