Browse Source

Updated Blender exporter to be able to export scenes.

Work-in-progress.

So close yet so far. Test scene almost works, just two things are not rotated properly (which means maybe everything will need to be reworked :(
alteredq 14 years ago
parent
commit
1859fe4057

+ 47 - 0
examples/obj/blenderscene/scene.Cube.js

@@ -0,0 +1,47 @@
+/*
+ * File generated with Blender 2.56 Exporter
+ * https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/
+ *
+ * vertices: 8
+ * faces: 6
+ * normals: 0
+ * uvs: 0
+ * colors: 0
+ * materials: 1
+ *
+ */
+
+var model = {
+
+    'version' : 2,
+    
+    'materials': [	{
+	"DbgColor" : 0xeeeeee,
+	"DbgIndex" : 0,
+	"DbgName" : "Material",
+	"colorAmbient" : [0.0, 0.0, 0.0],
+	"colorDiffuse" : [0.6400000190734865, 0.10179081114814892, 0.126246120426746],
+	"colorSpecular" : [0.5, 0.5, 0.5],
+	"shading" : "Phong",
+	"specularCoef" : 50,
+	"transparency" : 1.0,
+	"vertexColors" : false
+	}],
+
+    'vertices': [1.000000,-1.000000,-1.000000,1.000000,-1.000000,1.000000,-1.000000,-1.000000,1.000000,-1.000000,-1.000000,-1.000000,1.000000,1.000000,-1.000000,0.999999,1.000000,1.000001,-1.000000,1.000000,1.000000,-1.000000,1.000000,-1.000000],
+
+    'morphTargets': [],
+
+    'normals': [],
+
+    'colors': [],
+
+    'uvs': [[]],
+
+    'faces': [3,0,1,2,3,0,3,4,7,6,5,0,3,0,4,5,1,0,3,1,5,6,2,0,3,2,6,7,3,0,3,4,0,3,7,0],
+
+    'end': (new Date).getTime()
+
+}
+
+postMessage( model );

File diff suppressed because it is too large
+ 30 - 0
examples/obj/blenderscene/scene.Monkey.js


+ 47 - 0
examples/obj/blenderscene/scene.Plane.js

@@ -0,0 +1,47 @@
+/*
+ * File generated with Blender 2.56 Exporter
+ * https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/
+ *
+ * vertices: 4
+ * faces: 1
+ * normals: 0
+ * uvs: 0
+ * colors: 0
+ * materials: 1
+ *
+ */
+
+var model = {
+
+    'version' : 2,
+    
+    'materials': [	{
+	"DbgColor" : 0xeeeeee,
+	"DbgIndex" : 0,
+	"DbgName" : "Material.001",
+	"colorAmbient" : [0.0, 0.0, 0.0],
+	"colorDiffuse" : [0.14462547517754842, 0.6400000190734865, 0.24541190036254967],
+	"colorSpecular" : [0.5, 0.5, 0.5],
+	"shading" : "Phong",
+	"specularCoef" : 50,
+	"transparency" : 1.0,
+	"vertexColors" : false
+	}],
+
+    'vertices': [1.000000,-0.000000,-1.000000,1.000000,0.000000,1.000000,-1.000000,0.000000,1.000000,-1.000000,-0.000000,-1.000000],
+
+    'morphTargets': [],
+
+    'normals': [],
+
+    'colors': [],
+
+    'uvs': [[]],
+
+    'faces': [3,0,3,2,1,0],
+
+    'end': (new Date).getTime()
+
+}
+
+postMessage( model );

BIN
examples/obj/blenderscene/scene.blend


+ 359 - 0
examples/obj/blenderscene/scene.js

@@ -0,0 +1,359 @@
+// Converted from: scene.blend
+//  File generated with Blender 2.56 Exporter
+//  https://github.com/alteredq/three.js/tree/master/utils/exporters/blender/
+
+
+var scene = {
+
+"type" : "scene",
+"urlBaseType" : "relativeToScene",
+
+
+"objects" : 
+{
+    "Cube.006" : {
+        "geometry"  : "geo_Cube",
+        "materials" : [ "Material" ],
+        "position"  : [ 10.623673, 3.370784, -0.321692 ],
+        "rotation"  : [ 0.005265, -0.056306, 4.717181 ],
+        "quaternion": [ 1.000000, 0.000000, 0.000000, 0.000000 ],
+        "scale"	    : [ 8.310000, 4.930000, 0.120000 ],
+        "visible"   : true
+    },
+
+    "Monkey.018" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ 1.702659, 0.680278, 5.860421 ],
+        "rotation"  : [ 1.413516, 0.081378, -3.204182 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 0.435837, 0.435837, 0.435837 ],
+        "visible"   : true
+    },
+
+    "Monkey.017" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ 0.081295, 0.639505, 5.808783 ],
+        "rotation"  : [ 1.413516, 0.081378, -3.204182 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 0.435837, 0.435837, 0.435837 ],
+        "visible"   : true
+    },
+
+    "Monkey.016" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -1.569030, 0.619385, 5.747240 ],
+        "rotation"  : [ 1.413516, 0.081378, -3.204182 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 0.435837, 0.435837, 0.435837 ],
+        "visible"   : true
+    },
+
+    "Monkey.015" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -3.129120, 0.552267, 5.709269 ],
+        "rotation"  : [ 1.413516, 0.081378, -3.204182 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 0.435837, 0.435837, 0.435837 ],
+        "visible"   : true
+    },
+
+    "Monkey.014" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -6.386331, 0.382167, 3.004400 ],
+        "rotation"  : [ 1.646237, -0.058425, -1.670593 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 0.435837, 0.435837, 0.435837 ],
+        "visible"   : true
+    },
+
+    "Monkey.013" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -6.499331, 0.471640, 1.593073 ],
+        "rotation"  : [ 1.646237, -0.058425, -1.670593 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 0.435837, 0.435837, 0.435837 ],
+        "visible"   : true
+    },
+
+    "Monkey.012" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -6.629794, 0.533840, 0.234131 ],
+        "rotation"  : [ 1.646237, -0.058425, -1.670593 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 0.435837, 0.435837, 0.435837 ],
+        "visible"   : true
+    },
+
+    "Monkey.011" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -6.713673, 0.629835, -1.008146 ],
+        "rotation"  : [ 1.646237, -0.058425, -1.670593 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 0.435837, 0.435837, 0.435837 ],
+        "visible"   : true
+    },
+
+    "Monkey.010" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -2.010442, 1.387332, 24.343616 ],
+        "rotation"  : [ 1.520470, 0.191726, -3.004622 ],
+        "quaternion": [ -0.587711, 0.550951, 0.566613, 0.173203 ],
+        "scale"	    : [ 9.160007, 9.160007, 9.160008 ],
+        "visible"   : true
+    },
+
+    "Monkey.009" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -4.292194, 1.826282, -7.975398 ],
+        "rotation"  : [ 1.594819, 0.080713, -0.213986 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Monkey.008" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ 2.151757, 1.891882, -8.065320 ],
+        "rotation"  : [ 1.594819, 0.080713, -0.213986 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Monkey.007" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -0.712512, 2.115002, -8.097841 ],
+        "rotation"  : [ 1.594819, 0.080713, -0.213986 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Cube.005" : {
+        "geometry"  : "geo_Cube",
+        "materials" : [ "Material" ],
+        "position"  : [ -1.000975, 1.319482, -8.755547 ],
+        "rotation"  : [ 0.000000, 0.000000, -0.000000 ],
+        "quaternion": [ 1.000000, 0.000000, 0.000000, 0.000000 ],
+        "scale"	    : [ 6.130000, 1.690000, 0.070000 ],
+        "visible"   : true
+    },
+
+    "Cube.004" : {
+        "geometry"  : "geo_Cube",
+        "materials" : [ "Material" ],
+        "position"  : [ 2.484517, 2.724846, 7.486932 ],
+        "rotation"  : [ 0.220417, -0.075224, 0.181029 ],
+        "quaternion": [ 0.988791, 0.112836, 0.027288, -0.093898 ],
+        "scale"	    : [ 0.350000, 3.310000, 0.890000 ],
+        "visible"   : true
+    },
+
+    "Monkey.006" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ 7.724935, 1.694883, -7.123103 ],
+        "rotation"  : [ 1.835590, 0.083161, -2.048913 ],
+        "quaternion": [ -0.587711, 0.550951, 0.566613, 0.173203 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Monkey.005" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -6.334642, 0.566791, -6.636147 ],
+        "rotation"  : [ 1.327136, -0.032561, -4.135900 ],
+        "quaternion": [ -0.587711, 0.550951, 0.566613, 0.173203 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Monkey.004" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -5.384042, 0.444915, 6.194087 ],
+        "rotation"  : [ 0.991213, 0.181430, -5.246078 ],
+        "quaternion": [ -0.587711, 0.550951, 0.566613, 0.173203 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Monkey.003" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ 3.147747, 1.014840, 4.230884 ],
+        "rotation"  : [ 1.719311, -0.307044, -3.355401 ],
+        "quaternion": [ -0.587711, 0.550951, 0.566613, 0.173203 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Monkey.002" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -2.668043, 3.008879, 2.153389 ],
+        "rotation"  : [ 1.881970, 0.457870, 4.066133 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Cube.003" : {
+        "geometry"  : "geo_Cube",
+        "materials" : [ "Material" ],
+        "position"  : [ -3.031251, 0.702044, 1.943665 ],
+        "rotation"  : [ -1.300741, -1.330343, 3.282723 ],
+        "quaternion": [ 1.000000, 0.000000, 0.000000, 0.000000 ],
+        "scale"	    : [ 1.781142, 0.231142, 0.361142 ],
+        "visible"   : true
+    },
+
+    "Monkey.001" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ 1.245307, 0.620196, -0.137285 ],
+        "rotation"  : [ 2.339869, -0.286025, -1.394760 ],
+        "quaternion": [ -0.587711, 0.550951, 0.566613, 0.173203 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Monkey" : {
+        "geometry"  : "geo_Monkey",
+        "materials" : [ "Material.002" ],
+        "position"  : [ -0.282500, 1.813606, -4.272932 ],
+        "rotation"  : [ 0.646062, -0.219349, -0.010569 ],
+        "quaternion": [ 0.942751, 0.314982, 0.105460, -0.029764 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Cube.002" : {
+        "geometry"  : "geo_Cube",
+        "materials" : [ "Material" ],
+        "position"  : [ 0.042212, 5.536832, -0.199037 ],
+        "rotation"  : [ 0.000000, 0.000000, -0.000000 ],
+        "quaternion": [ 1.000000, 0.000000, 0.000000, 0.000000 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Cube.001" : {
+        "geometry"  : "geo_Cube",
+        "materials" : [ "Material" ],
+        "position"  : [ -0.395497, 1.009696, -3.944532 ],
+        "rotation"  : [ 0.000000, 0.000000, -0.000000 ],
+        "quaternion": [ 1.000000, 0.000000, 0.000000, 0.000000 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    },
+
+    "Plane" : {
+        "geometry"  : "geo_Plane",
+        "materials" : [ "Material.001" ],
+        "position"  : [ 0.000000, 0.000000, 0.118260 ],
+        "rotation"  : [ 0.000000, 0.000000, -0.000000 ],
+        "quaternion": [ 1.000000, 0.000000, 0.000000, 0.000000 ],
+        "scale"	    : [ 7.922787, 7.922787, 7.922787 ],
+        "visible"   : true
+    },
+
+    "Cube" : {
+        "geometry"  : "geo_Cube",
+        "materials" : [ "Material" ],
+        "position"  : [ 3.651978, 1.071144, 0.000000 ],
+        "rotation"  : [ 0.220417, -0.075224, 0.181029 ],
+        "quaternion": [ 0.988791, 0.112836, 0.027288, -0.093898 ],
+        "scale"	    : [ 1.000000, 1.000000, 1.000000 ],
+        "visible"   : true
+    }
+},
+
+
+"geometries" : 
+{
+    "geo_Cube" : {
+        "type" : "ascii_mesh",
+        "url"  : "scene.Cube.js"
+    },
+
+    "geo_Monkey" : {
+        "type" : "ascii_mesh",
+        "url"  : "scene.Monkey.js"
+    },
+
+    "geo_Plane" : {
+        "type" : "ascii_mesh",
+        "url"  : "scene.Plane.js"
+    }
+},
+
+
+"materials" : 
+{
+    "Material" : {
+        "type": "MeshPhongMaterial",
+        "parameters": { color: 0xa31920, opacity: 1.00, ambient: 0x000000, specular: 0x7f7f7f, shininess: 50.0 } 
+    },
+
+    "Material.001" : {
+        "type": "MeshPhongMaterial",
+        "parameters": { color: 0x24a33e, opacity: 1.00, ambient: 0x000000, specular: 0x7f7f7f, shininess: 50.0 } 
+    },
+
+    "Material.002" : {
+        "type": "MeshPhongMaterial",
+        "parameters": { color: 0xa37024, opacity: 1.00, ambient: 0x000000, specular: 0x7f7f7f, shininess: 50.0 } 
+    }
+},
+
+
+"cameras" : 
+{
+    "default_camera" : {
+        "type"  : "perspective",
+        "fov"   : 60.000000,
+        "aspect": 1.333000,
+        "near"  : 1.000000,
+        "far"   : 10000.000000,
+        "position": [ 0.000000, 0.000000, 10.000000 ],
+        "target"  : [ 0.000000, 0.000000, 0.000000 ]
+    }
+},
+
+
+"lights" : 
+{
+	"default_light": {
+		"type"		 : "directional",
+		"direction"	 : [ 0.000000, 1.000000, 1.000000 ],
+		"color" 	 : 0xffffff,
+		"intensity"	 : 0.80
+	}
+},
+
+
+"defaults" : 
+{
+    "bgcolor" : [ 0.000000, 0.000000, 0.000000 ],
+    "bgalpha" : 1.000000,
+    "camera"  : "default_camera"
+}
+
+}
+
+postMessage( scene );
+

+ 561 - 0
examples/webgl_scene_test_blender.html

@@ -0,0 +1,561 @@
+<!DOCTYPE HTML>
+<html lang="en">
+	<head>
+		<title>three.js webgl - io - scene loader [blender]</title>
+		<meta charset="utf-8">
+		<style type="text/css">
+			body {
+				background:#000;
+				color:#fff;
+				padding:0;
+				margin:0;
+				overflow:hidden;
+				font-family:georgia;
+				text-align:center;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
+				font-family: Monospace;
+				font-size: 13px;
+				text-align: center;
+				z-index:100;
+			}
+
+			#progress {
+				color:red;
+				top:7em;
+				width: 100%;
+				font-size:3em;
+				font-variant:small-caps;
+				font-weight:bold;
+				position:absolute;
+				z-index:100;
+				text-align: center;
+				text-shadow: #000 0px 0px 10px;
+				display:none;
+			}
+
+			#start {
+				color:#fff;
+				text-shadow: #000 0px 0px 2px;
+				padding:0.1em 0.3em;
+				width:3em;
+				text-align: center;
+				display:none;
+			}
+
+			.shadow {
+				-moz-box-shadow: 0px 0px 5px #000;
+				-webkit-box-shadow: 0px 0px 5px #000;
+				box-shadow: 0px 0px 5px #000;
+			}
+
+			#progressbar {
+				text-align: center;
+				background: white;
+				width: 250px;
+				height: 10px;
+			}
+
+			#bar {
+				background:#d00;
+				width:50px;
+				height:10px;
+			}
+
+			.enabled {
+				color: lime!important;
+				cursor:pointer;
+			}
+
+			.enabled:hover {
+				text-shadow: #0f0 0px 0px 5px !important;
+			}
+
+			.disabled {
+				background:gray;
+				cursor:default;
+			}
+
+			a { color:red }
+			canvas { pointer-events:none; z-index:10; }
+			#log { position:absolute; top:0; display:block; text-align:left; z-index:1000; pointer-events:none; }
+
+			#scene_explorer {
+				background:transparent;
+				color:#fff;
+				width:200px;
+				position:absolute;
+				text-align:left;
+				top:0px;
+				z-index:200;
+				overflow:auto;
+			}
+
+			#section_exp {
+				background:rgba(0,0,50,0.5);
+				padding:0.5em 0;
+				display:none;
+			}
+
+			#scene_explorer h3 {
+				font-size:1em;
+				padding:0;
+				margin:0;
+				color:orange;
+			}
+
+			#scene_explorer a {
+				color:#555;
+				font-weight:bold;
+				text-decoration:none;
+				font-size:1.2em;
+				font-family:Monospace;
+			}
+			#scene_explorer a:hover {
+				background:#555;
+				color:rgba(0,0,50,1);
+			}
+
+			.part {
+				display:none;
+				padding:0 0 0.5em 2em;
+			}
+
+		</style>
+	</head>
+
+	<body>
+		<div id="info">
+			<a href="http://github.com/mrdoob/three.js">three.js</a> - scene loader test [blender]
+		</div>
+
+		<div id="scene_explorer">
+			<a id="plus_exp" href="#">[+]</a>
+			<div id="section_exp"></div>
+		</div>
+
+		<div id="progress">
+			<span id="message">Loading ...</span>
+
+			<center>
+				<div id="progressbar" class="shadow"><div id="bar" class="shadow"></div></div>
+				<div id="start" class="disabled">Start</div>
+			</center>
+		</div>
+
+		<pre id="log"></pre>
+<!--
+		<script type="text/javascript" src="../build/Three.js"></script>
+-->
+
+		<script type="text/javascript" src="../src/Three.js"></script>
+		<script type="text/javascript" src="../src/core/Color.js"></script>
+		<script type="text/javascript" src="../src/core/Vector2.js"></script>
+		<script type="text/javascript" src="../src/core/Vector3.js"></script>
+		<script type="text/javascript" src="../src/core/Vector4.js"></script>
+		<script type="text/javascript" src="../src/core/Ray.js"></script>
+		<script type="text/javascript" src="../src/core/Rectangle.js"></script>
+		<script type="text/javascript" src="../src/core/Matrix3.js"></script>
+		<script type="text/javascript" src="../src/core/Matrix4.js"></script>
+		<script type="text/javascript" src="../src/core/Object3D.js"></script>
+		<script type="text/javascript" src="../src/core/Quaternion.js"></script>
+		<script type="text/javascript" src="../src/core/Vertex.js"></script>
+		<script type="text/javascript" src="../src/core/Face3.js"></script>
+		<script type="text/javascript" src="../src/core/Face4.js"></script>
+		<script type="text/javascript" src="../src/core/UV.js"></script>
+		<script type="text/javascript" src="../src/core/Geometry.js"></script>
+		<script type="text/javascript" src="../src/core/Spline.js"></script>
+		<script type="text/javascript" src="../src/animation/AnimationHandler.js"></script>
+		<script type="text/javascript" src="../src/animation/Animation.js"></script>
+		<script type="text/javascript" src="../src/cameras/Camera.js"></script>
+		<script type="text/javascript" src="../src/lights/Light.js"></script>
+		<script type="text/javascript" src="../src/lights/AmbientLight.js"></script>
+		<script type="text/javascript" src="../src/lights/DirectionalLight.js"></script>
+		<script type="text/javascript" src="../src/lights/PointLight.js"></script>
+		<script type="text/javascript" src="../src/materials/Material.js"></script>
+		<script type="text/javascript" src="../src/materials/Mappings.js"></script>
+		<script type="text/javascript" src="../src/materials/LineBasicMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshBasicMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshLambertMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshPhongMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshDepthMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshNormalMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshFaceMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/MeshShaderMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/ParticleBasicMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/ParticleCanvasMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/ParticleDOMMaterial.js"></script>
+		<script type="text/javascript" src="../src/materials/Texture.js"></script>
+		<script type="text/javascript" src="../src/materials/RenderTarget.js"></script>
+		<script type="text/javascript" src="../src/materials/Uniforms.js"></script>
+		<script type="text/javascript" src="../src/objects/Particle.js"></script>
+		<script type="text/javascript" src="../src/objects/ParticleSystem.js"></script>
+		<script type="text/javascript" src="../src/objects/Line.js"></script>
+		<script type="text/javascript" src="../src/objects/Mesh.js"></script>
+		<script type="text/javascript" src="../src/objects/Bone.js"></script>
+		<script type="text/javascript" src="../src/objects/SkinnedMesh.js"></script>
+		<script type="text/javascript" src="../src/objects/Ribbon.js"></script>
+		<script type="text/javascript" src="../src/objects/Sound.js"></script>
+		<script type="text/javascript" src="../src/objects/LOD.js"></script>
+		<script type="text/javascript" src="../src/scenes/Scene.js"></script>
+		<script type="text/javascript" src="../src/scenes/Fog.js"></script>
+		<script type="text/javascript" src="../src/scenes/FogExp2.js"></script>
+		<script type="text/javascript" src="../src/renderers/Projector.js"></script>
+		<script type="text/javascript" src="../src/renderers/DOMRenderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/CanvasRenderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/SVGRenderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/WebGLShaders.js"></script>
+		<script type="text/javascript" src="../src/renderers/WebGLRenderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/SoundRenderer.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableVertex.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableFace3.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableFace4.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableObject.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableParticle.js"></script>
+		<script type="text/javascript" src="../src/renderers/renderables/RenderableLine.js"></script>
+		<script type="text/javascript" src="../src/extras/GeometryUtils.js"></script>
+		<script type="text/javascript" src="../src/extras/ImageUtils.js"></script>
+		<script type="text/javascript" src="../src/extras/SceneUtils.js"></script>
+		<script type="text/javascript" src="../src/extras/ShaderUtils.js"></script>
+		<script type="text/javascript" src="../src/extras/cameras/QuakeCamera.js"></script>
+		<script type="text/javascript" src="../src/extras/cameras/PathCamera.js"></script>
+		<script type="text/javascript" src="../src/extras/geometries/Cube.js"></script>
+		<script type="text/javascript" src="../src/extras/geometries/Cylinder.js"></script>
+		<script type="text/javascript" src="../src/extras/geometries/Icosahedron.js"></script>
+		<script type="text/javascript" src="../src/extras/geometries/Lathe.js"></script>
+		<script type="text/javascript" src="../src/extras/geometries/Plane.js"></script>
+		<script type="text/javascript" src="../src/extras/geometries/Sphere.js"></script>
+		<script type="text/javascript" src="../src/extras/geometries/Torus.js"></script>
+		<script type="text/javascript" src="../src/extras/geometries/TorusKnot.js"></script>
+		<script type="text/javascript" src="../src/extras/io/Loader.js"></script>
+		<script type="text/javascript" src="../src/extras/io/JSONLoader.js"></script>
+		<script type="text/javascript" src="../src/extras/io/BinaryLoader.js"></script>
+		<script type="text/javascript" src="../src/extras/objects/MarchingCubes.js"></script>
+		
+		<script type="text/javascript" src="js/Detector.js"></script>
+		<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
+		<script type="text/javascript" src="js/Stats.js"></script>
+
+		<script type="text/javascript">
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var SCREEN_WIDTH = window.innerWidth;
+			var SCREEN_HEIGHT = window.innerHeight;
+
+			var container,stats;
+
+			var camera, scene, loaded;
+			var renderer;
+
+			var mesh, zmesh, geometry;
+
+			var mouseX = 0, mouseY = 0;
+
+			var windowHalfX = window.innerWidth / 2;
+			var windowHalfY = window.innerHeight / 2;
+
+			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+
+			init();
+			animate();
+
+			function $( id ) {
+
+				return document.getElementById( id );
+
+			}
+
+			function handle_update( result, pieces ) {
+
+				refreshSceneView( result );
+				renderer.initWebGLObjects( result.scene );
+
+				var m, material, count = 0;
+
+				for ( m in result.materials ) {
+
+					material = result.materials[ m ];
+					if ( ! ( material instanceof THREE.MeshFaceMaterial ) ) {
+
+						if( !material.program ) {
+
+							console.log(m);
+							renderer.initMaterial( material, result.scene.lights, result.scene.fog );
+
+							count += 1;
+							if( count > pieces ) {
+
+								//console.log("xxxxxxxxx");
+								break;
+
+							}
+
+						}
+
+					}
+
+				}
+
+			}
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				var loadScene = createLoadScene();
+				scene  = loadScene.scene;
+				camera = loadScene.camera;
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
+				renderer.domElement.style.position = "relative";
+				container.appendChild( renderer.domElement );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				stats.domElement.style.right = '0px';
+				stats.domElement.style.zIndex = 100;
+				container.appendChild( stats.domElement );
+
+				$( "start" ).addEventListener( 'click', onStartClick, false );
+
+				var callback_progress = function( progress, result ) {
+
+					var bar = 250,
+						total = progress.total_models + progress.total_textures,
+						loaded = progress.loaded_models + progress.loaded_textures;
+
+					if ( total )
+						bar = Math.floor( bar * loaded / total );
+
+					$( "bar" ).style.width = bar + "px";
+
+					count = 0;
+					for ( var m in result.materials ) count++;
+
+					handle_update( result, Math.floor( count/total ) );
+
+				}
+
+				var callback_sync = function( result ) {
+
+					/*
+
+					// uncomment to see progressive scene loading
+
+					scene = result.scene;
+					camera = result.currentCamera;
+
+					camera.aspect = window.innerWidth / window.innerHeight;
+					camera.updateProjectionMatrix();
+
+					renderer.setClearColor( result.bgColor, result.bgAlpha );
+
+					*/
+
+					//handle_update( result, 1 );
+
+				}
+
+				var callback_async = function( result ) {
+
+					loaded = result;
+
+					$( "message" ).style.display = "none";
+					$( "progressbar" ).style.display = "none";
+					$( "start" ).style.display = "block";
+					$( "start" ).className = "enabled";
+
+					handle_update( result, 1 );
+
+				}
+
+				$( "progress" ).style.display = "block";
+				SceneUtils.loadScene( "obj/blenderscene/scene.js", callback_sync, callback_async, callback_progress );
+
+				$( "plus_exp" ).addEventListener( 'click', createToggle( "exp" ), false );
+
+			}
+
+			function setButtonActive( id ) {
+
+				$( "start" ).style.backgroundColor = "green";
+
+			}
+
+			function onStartClick() {
+
+				$( "progress" ).style.display = "none";
+
+				scene = loaded.scene;
+				camera = loaded.currentCamera;
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setClearColor( loaded.bgColor, loaded.bgAlpha );
+
+			}
+
+			function onDocumentMouseMove(event) {
+
+				mouseX = ( event.clientX - windowHalfX );
+				mouseY = ( event.clientY - windowHalfY );
+
+			}
+
+			function createLoadScene() {
+
+				var result = {
+
+					scene:  new THREE.Scene(),
+					camera: new THREE.Camera( 65, window.innerWidth / window.innerHeight, 1, 1000 )
+
+				};
+
+				result.camera.position.z = 100;
+
+				var object, geometry, material, light, count = 500, range = 200;
+
+				material = new THREE.MeshLambertMaterial( { color:0xffffff } );
+				geometry = new Cube( 5, 5, 5 );
+
+				for( var i = 0; i < count; i++ ) {
+
+					object = new THREE.Mesh( geometry, material );
+					object.position.x = ( Math.random() - 0.5 ) * range;
+					object.position.y = ( Math.random() - 0.5 ) * range;
+					object.position.z = ( Math.random() - 0.5 ) * range;
+					object.rotation.x = Math.random() * 6;
+					object.rotation.y = Math.random() * 6;
+					object.rotation.z = Math.random() * 6;
+					object.matrixAutoUpdate = false;
+					object.updateMatrix();
+					result.scene.addObject( object );
+
+				}
+
+				result.scene.matrixAutoUpdate = false;
+
+				light = new THREE.PointLight( 0xffffff );
+				result.scene.addLight( light );
+
+				light = new THREE.DirectionalLight( 0x111111 );
+				light.position.x = 1;
+				result.scene.addLight( light );
+
+				return result;
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				camera.position.x += ( mouseX - camera.position.x ) * .001;
+				camera.position.y += ( - mouseY - camera.position.y ) * .001;
+
+				renderer.render( scene, camera );
+
+			}
+
+			function log( text ) {
+
+				var e = $("log");
+				e.innerHTML = text + "<br/>" + e.innerHTML;
+
+			}
+
+			// Scene explorer user interface
+
+			function toggle( id ) {
+
+				var scn = $( "section_" + id ).style,
+					btn = $( "plus_" + id );
+
+				if ( scn.display == "block" ) {
+
+					scn.display = "none";
+					btn.innerHTML = "[+]";
+
+				}
+				else {
+
+					scn.display = "block";
+					btn.innerHTML = "[-]";
+
+				}
+
+			}
+
+			function createToggle( label ) { return function() { toggle( label ) } };
+
+			function refreshSceneView( result ) {
+
+				$( "section_exp" ).innerHTML = generateSceneView( result );
+
+				var config = [ "obj", "geo", "mat", "tex", "lit", "cam" ];
+
+				for ( var i = 0; i < config.length; i++ )
+					$( "plus_" + config[i] ).addEventListener( 'click', createToggle( config[i] ), false );
+
+			}
+
+			function generateSection( label, id, objects ) {
+
+				var html = "";
+
+				html += "<h3><a id='plus_" + id + "' href='#'>[+]</a> " + label + "</h3>";
+				html += "<div id='section_" + id + "' class='part'>";
+
+				for( var o in objects ) {
+
+					html += o + "<br/>";
+
+				}
+				html += "</div>";
+
+				return html;
+
+			}
+
+			function generateSceneView( result ) {
+
+				var config = [
+				[ "Objects",    "obj", result.objects ],
+				[ "Geometries", "geo", result.geometries ],
+				[ "Materials",  "mat", result.materials ],
+				[ "Textures",   "tex", result.textures ],
+				[ "Lights",     "lit", result.lights ],
+				[ "Cameras",    "cam", result.cameras ]
+				];
+
+				var html = "";
+
+				for ( var i = 0; i < config.length; i++ )
+					html += generateSection( config[i][0], config[i][1], config[i][2] );
+
+				return html;
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 15 - 5
utils/exporters/blender/2.56/scripts/op/io_mesh_threejs/__init__.py

@@ -35,13 +35,14 @@ class ExportTHREEJS(bpy.types.Operator, ExportHelper):
 
     filename_ext = ".js"
 
-    use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply modifiers to the exported mesh", default=True)
+    option_flip_yz = BoolProperty(name="Flip YZ", description="Flip YZ", default=True)
     use_normals = BoolProperty(name="Normals", description="Export normals", default=True)
     use_colors = BoolProperty(name="Colors", description="Export vertex colors", default=True)
     use_uv_coords = BoolProperty(name="UVs", description="Export texture coordinates", default=True)
+    option_export_scene = BoolProperty(name="Scene", description="Export scene", default=True)
 
     align_types = [("None","None","None"), ("Center","Center","Center"), ("Bottom","Bottom","Bottom"), ("Top","Top","Top")]
-    align_model = EnumProperty(name="Align model", description="Align model", items=align_types, default="Center")
+    align_model = EnumProperty(name="Align model", description="Align model", items=align_types, default="None")
 
     @classmethod
     def poll(cls, context):
@@ -61,15 +62,24 @@ class ExportTHREEJS(bpy.types.Operator, ExportHelper):
         layout = self.layout
 
         row = layout.row()
-        row.prop(self.properties, "use_modifiers")
+        row.prop(self.properties, "option_export_scene")
+        layout.separator()
+
+        row = layout.row()
+        row.prop(self.properties, "option_flip_yz")
+        layout.separator()
+
+        row = layout.row()
+        row.prop(self.properties, "align_model")
+        layout.separator()
+
         row = layout.row()
         row.prop(self.properties, "use_normals")
         row = layout.row()
         row.prop(self.properties, "use_colors")
         row = layout.row()
         row.prop(self.properties, "use_uv_coords")
-        row = layout.row()
-        row.prop(self.properties, "align_model")
+        
 
 
 def menu_func(self, context):

+ 617 - 46
utils/exporters/blender/2.56/scripts/op/io_mesh_threejs/export_threejs.py

@@ -23,9 +23,8 @@
 Blender exporter for Three.js (ASCII JSON format).
 
 TODO
-    - model alignment
+    - export scene
     - copy used images to folder where exported file goes
-    - export all selected meshes
     - binary format
 """
 
@@ -42,13 +41,149 @@ import random
 # Configuration
 # #####################################################
 
-# default colors for debugging (each material gets one distinct color):
+DEFAULTS = {
+"bgcolor" : [0, 0, 0],
+"bgalpha" : 1.0,
+
+"camera"  : 
+    {
+        "name" : "default_camera",
+        "type" : "perspective",
+        "near" : 1,
+        "far"  : 10000,
+        "fov"  : 60,
+        "aspect": 1.333,
+        "position" : [0, 0, 10],
+        "target"   : [0, 0, 0]
+    },
+
+"light" :
+ {
+    "name"       : "default_light",
+    "type"       : "directional",
+    "direction"	 : [0,1,1],
+    "color" 	 : [1,1,1],
+    "intensity"	 : 0.8
+ }
+}
+
+# default colors for debugging (each material gets one distinct color): 
 # white, red, green, blue, yellow, cyan, magenta
 COLORS = [0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, 0xeeee00, 0x00eeee, 0xee00ee]
 
 
 # #####################################################
-# Templates
+# Templates - scene
+# #####################################################
+TEMPLATE_SCENE_ASCII = """\
+// Converted from: %(fname)s
+//  File generated with Blender 2.56 Exporter
+//  https://github.com/alteredq/three.js/tree/master/utils/exporters/blender/
+
+
+var scene = {
+
+"type" : "scene",
+"urlBaseType" : "relativeToScene",
+
+%(sections)s
+
+"defaults" : 
+{
+    "bgcolor" : %(bgcolor)s,
+    "bgalpha" : %(bgalpha)f,
+    "camera"  : %(defcamera)s
+}
+
+}
+
+postMessage( scene );
+
+"""
+
+TEMPLATE_SECTION = """
+"%s" : 
+{
+%s
+},
+"""
+
+TEMPLATE_OBJECT = """\
+    %(object_id)s : {
+        "geometry"  : %(geometry_id)s,
+        "materials" : [ %(material_id)s ],
+        "position"  : %(position)s,
+        "rotation"  : %(rotation)s,
+        "quaternion": %(quaternion)s,
+        "scale"	    : %(scale)s,
+        "visible"   : true
+    }"""
+
+TEMPLATE_GEOMETRY = """\
+    %(geometry_id)s : {
+        "type" : "ascii_mesh",
+        "url"  : %(model_file)s
+    }"""
+
+TEMPLATE_TEXTURE = """\
+    %(texture_id)s : {
+        "url": %(texture_file)s
+    }"""
+
+TEMPLATE_MATERIAL_SCENE = """\
+    %(material_id)s : {
+        "type": %(type)s,
+        "parameters": { %(parameters)s } 
+    }"""
+
+TEMPLATE_CAMERA_PERSPECTIVE = """\
+    %(camera_id)s : {
+        "type"  : "perspective",
+        "fov"   : %(fov)f,
+        "aspect": %(aspect)f,
+        "near"  : %(near)f,
+        "far"   : %(far)f,
+        "position": %(position)s,
+        "target"  : %(target)s
+    }"""
+
+TEMPLATE_CAMERA_ORTHO = """\
+    %(camera_id)s: {
+        "type"  : "ortho",
+        "left"  : %(left)f,
+        "right" : %(right)f,
+        "top"   : %(top)f,
+        "bottom": %(bottom)f,
+        "near"  : %(near)f,
+        "far"   : %(far)f,
+        "position": %(position)s,
+        "target"  : %(target)s
+    }"""
+
+TEMPLATE_LIGHT_DIRECTIONAL = """\
+	%(light_id)s: {
+		"type"		 : "directional",
+		"direction"	 : %(direction)s,
+		"color" 	 : %(color)s,
+		"intensity"	 : %(intensity).2f
+	}"""
+
+TEMPLATE_LIGHT_POINT = """\
+	%(light_id)s: {
+		"type"	     : "point",
+		"position"   : %(position)s,
+		"color"      : %(color)s
+		"intensity"	 : %(intensity).3f
+	}"""
+
+TEMPLATE_VEC4 = '[ %f, %f, %f, %f ]'
+TEMPLATE_VEC3 = '[ %f, %f, %f ]'
+TEMPLATE_VEC2 = '[ %f, %f ]'
+TEMPLATE_STRING = '"%s"'
+TEMPLATE_HEX = "0x%06x"
+
+# #####################################################
+# Templates - model
 # #####################################################
 TEMPLATE_FILE_ASCII = """\
 /*
@@ -98,8 +233,11 @@ TEMPLATE_C = "0x%06x"
 # #####################################################
 # Utils
 # #####################################################
+def veckey3(x,y,z):
+    return round(x, 6), round(y, 6), round(z, 6)
+
 def veckey3d(v):
-    return round(v.x, 6), round(v.y, 6), round(v.z, 6)
+    return veckey3(v.x, v.y, v.z)
 
 def veckey2d(v):
     return round(v[0], 6), round(v[1], 6)
@@ -107,8 +245,13 @@ def veckey2d(v):
 def get_normal_indices(v, normals, mesh):
     n = []
     mv = mesh.vertices
+
     for i in v:
-        n.append( normals[veckey3d(mv[i].normal)] )
+        normal = mv[i].normal        
+        key = veckey3d(normal)
+        
+        n.append( normals[key] )
+
     return n
 
 def get_uv_indices(face_index, uvs, mesh):
@@ -127,6 +270,24 @@ def get_color_indices(face_index, colors, mesh):
         c.append( colors[hexcolor(i)] )
     return c
 
+def rgb2int(rgb):
+    color = (int(rgb[0]*255) << 16) + (int(rgb[1]*255) << 8) + int(rgb[2]*255);
+    return color
+
+# #####################################################
+# Utils - files
+# #####################################################
+def write_file(fname, content):
+    out = open(fname, "w")
+    out.write(content)
+    out.close()
+
+def ensure_folder_exist(foldername):
+    """Create folder (with whole path) if it doesn't exist yet."""
+    
+    if not os.access(foldername, os.R_OK|os.W_OK|os.X_OK):
+        os.makedirs(foldername)
+
 # #####################################################
 # Alignment
 # #####################################################
@@ -231,7 +392,7 @@ def setBit(value, position, on):
         mask = ~(1 << position)
         return (value & mask)    
     
-def generate_face(f, faceIndex, normals, uvs, colors, mesh, use_normals, use_colors, use_uv_coords):
+def generate_face(f, faceIndex, normals, uvs, colors, mesh, use_normals, use_colors, use_uv_coords, flipyz):
     isTriangle = ( len(f.vertices) == 3 )
     
     if isTriangle:
@@ -315,7 +476,10 @@ def extract_vertex_normals(mesh, use_normals):
 
     for f in mesh.faces:
         for v in f.vertices:
-            key = veckey3d(mesh.vertices[v].normal)
+            
+            normal = mesh.vertices[v].normal            
+            key = veckey3d(normal)
+                
             if key not in normals:
                 normals[key] = count
                 count += 1
@@ -327,7 +491,7 @@ def generate_normals(normals, use_normals):
         return ""
 
     chunks = []
-    for key, index in sorted(normals.items(), key=operator.itemgetter(1)):
+    for key, index in sorted(normals.items(), key = operator.itemgetter(1)):
         chunks.append(key)
 
     return ",".join(generate_normal(n) for n in chunks)
@@ -441,7 +605,7 @@ def value2string(v):
         return str(v).lower()
     return str(v)
 
-def generate_materials(mtl, materials, use_colors):
+def generate_materials(mtl, materials, use_colors, draw_type):
     """Generate JS array of materials objects
     """
 
@@ -458,6 +622,10 @@ def generate_materials(mtl, materials, use_colors):
         mtl[m]['DbgColor'] = generate_color(index)
         mtl[m]['vertexColors'] = use_colors
 
+        if draw_type in [ "BOUNDS", "WIRE" ]:
+            mtl[m]['wireframe'] = True
+            mtl[m]['DbgColor'] = 0xff0000
+            
         mtl_raw = ",\n".join(['\t"%s" : %s' % (n, value2string(v)) for n,v in sorted(mtl[m].items())])
         mtl_string = "\t{\n%s\n\t}" % mtl_raw
         mtl_array.append([index, mtl_string])
@@ -505,7 +673,7 @@ def extract_materials(mesh, scene):
 
     return materials
 
-def generate_materials_string(mesh, scene, use_colors):
+def generate_materials_string(mesh, scene, use_colors, draw_type):
 
     random.seed(42) # to get well defined color order for debug materials
 
@@ -522,19 +690,21 @@ def generate_materials_string(mesh, scene, use_colors):
         materials = { 'default':0 }
 
     # default dummy materials
+    
     mtl = generate_mtl(materials)
 
     # extract real materials from the mesh
+    
     mtl.update(extract_materials(mesh, scene))
 
-    return generate_materials(mtl, materials, use_colors)
+    return generate_materials(mtl, materials, use_colors, draw_type)
 
 # #####################################################
 # ASCII exporter
 # #####################################################
-def generate_ascii_model(mesh, scene, use_normals, use_colors, use_uv_coords, align_model):
+def generate_ascii_model(mesh, scene, use_normals, use_colors, use_uv_coords, align_model, flipyz, draw_type):
 
-    vertices = mesh.vertices[:]
+    vertices = mesh.vertices[:]    
 
     if align_model == 1:
         center(vertices)
@@ -547,7 +717,7 @@ def generate_ascii_model(mesh, scene, use_normals, use_colors, use_uv_coords, al
     colors, ncolor = extract_vertex_colors(mesh, use_colors)
     uvs, nuv = extract_uvs(mesh, use_uv_coords)
 
-    mstring, nmaterial = generate_materials_string(mesh, scene, use_colors)
+    mstring, nmaterial = generate_materials_string(mesh, scene, use_colors, draw_type)
     
     text = TEMPLATE_FILE_ASCII % {
     "nvertex"   : len(mesh.vertices),
@@ -565,46 +735,49 @@ def generate_ascii_model(mesh, scene, use_normals, use_colors, use_uv_coords, al
 
     "vertices"      : ",".join(generate_vertex(v) for v in vertices),
 
-    "faces"     : ",".join(generate_face(f, i, normals, uvs, colors, mesh, use_normals, use_colors, use_uv_coords) for i, f in enumerate(mesh.faces))
+    "faces"     : ",".join(generate_face(f, i, normals, uvs, colors, mesh, use_normals, use_colors, use_uv_coords, flipyz) for i, f in enumerate(mesh.faces))
 
     }
 
     return text
 
 # #####################################################
-# Main
+# Utils
 # #####################################################
-def save(operator, context, filepath="", use_modifiers=True, use_normals=True, use_colors=True, use_uv_coords=True, align_model=1):
-
-    def rvec3d(v):
-        return round(v[0], 6), round(v[1], 6), round(v[2], 6)
+def ensure_extension(filepath, extension):
+    if not filepath.lower().endswith(extension):
+        filepath += extension
+    return filepath
+    
+def generate_mesh_filename(meshname, filepath):
+    normpath = os.path.normpath(filepath)
+    path, ext = os.path.splitext(normpath)
+    return "%s.%s%s" % (path, meshname, ext)
+    
+# #####################################################
+# Export single mesh
+# #####################################################
+def export_mesh(obj, scene, filepath, use_normals, use_colors, use_uv_coords, align_model, flipyz, export_single_model):
+    """Export single mesh"""
 
-    def rvec2d(v):
-        return round(v[0], 6), round(v[1], 6)
 
-    scene = context.scene
-    obj = context.object
+    # collapse modifiers into mesh
+    
+    mesh = obj.create_mesh(scene, True, 'RENDER')        
 
-    if not filepath.lower().endswith('.js'):
-        filepath += '.js'
+    if not mesh:
+        raise Exception("Error, could not get mesh data from object [%s]" % obj.name)
 
-    if not obj:
-        raise Exception("Error, Select 1 active object")
+    # that's what Blender's native export_obj.py does
+    # to flip YZ
 
-    if scene.objects.active:
-        bpy.ops.object.mode_set(mode='OBJECT')
+    X_ROT = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
 
-    if use_modifiers:
-        mesh = obj.create_mesh(scene, True, 'PREVIEW')
+    if export_single_model:
+        mesh.transform(X_ROT * obj.matrix_world)
     else:
-        mesh = obj.data
+        mesh.transform(X_ROT)
 
-    if not mesh:
-        raise Exception("Error, could not get mesh data from active object")
-
-    # that's what Blender's native export_obj.py does
-    x_rot = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
-    mesh.transform(x_rot * obj.matrix_world)
     mesh.calc_normals()
 
     faceUV = (len(mesh.uv_textures) > 0)
@@ -627,14 +800,412 @@ def save(operator, context, filepath="", use_modifiers=True, use_normals=True, u
         if not active_col_layer:
             use_colors = False
 
-    text = generate_ascii_model(mesh, scene, use_normals, use_colors, use_uv_coords, align_model)
-    file = open(filepath, 'w')
-    file.write(text)
-    file.close()
+    text = generate_ascii_model(mesh, scene, use_normals, use_colors, use_uv_coords, align_model, flipyz, obj.draw_type)    
+    write_file(filepath, text)
+
+    # remove temp mesh
+
+    bpy.data.meshes.remove(mesh)
 
     print("writing", filepath, "done")
+    
+    
+# #####################################################
+# Export scene
+# #####################################################
+def generate_vec4(vec):
+    return TEMPLATE_VEC4 % (vec[0], vec[1], vec[2], vec[3])
+
+def generate_vec3(vec):
+    return TEMPLATE_VEC3 % (vec[0], vec[1], vec[2])
+
+def generate_vec2(vec):
+    return TEMPLATE_VEC2 % (vec[0], vec[1])
+
+def generate_hex(number):
+    return TEMPLATE_HEX % number
+    
+def generate_string(s):
+    return TEMPLATE_STRING % s
+    
+def generate_section(label, content):
+    return TEMPLATE_SECTION % (label, content)
+    
+def get_mesh_filename(mesh):
+    object_id = mesh["data"]["name"]
+    filename = "%s.js" % sanitize(object_id)
+    return filename
+    
+def generate_material_id_list(materials):
+    chunks = []
+    for material in materials:
+        chunks.append(material.name)
+    
+    return ",".join(chunks)
+    
+def generate_objects(data):
+    chunks = []
+    
+    for obj in data["objects"]:
+        if obj.type == "MESH":
+            object_id = obj.name
+            
+            if len(obj.modifiers) > 0:
+                geo_name = obj.name
+            else:
+                geo_name = obj.data.name
+
+            geometry_id = "geo_%s" % geo_name
+            
+            material_id = generate_material_id_list(obj.material_slots)
+
+            #position = obj.location
+            #rotation = obj.rotation_euler
+            scale = obj.scale
+            quaternion = obj.rotation_quaternion
+            
+            position = [obj.location.x, obj.location.z, -obj.location.y]
+            rotation = [obj.rotation_euler.x, -obj.rotation_euler.y, -obj.rotation_euler.z]
+            #quaternion = obj.rotation_euler.to_quat()
+            scale = [obj.scale.x, obj.scale.z, obj.scale.y]
+            
+            material_string = ""
+            if material_id:
+                material_string = generate_string(material_id)
+                
+            object_string = TEMPLATE_OBJECT % {
+            "object_id"   : generate_string(object_id),
+            "geometry_id" : generate_string(geometry_id),
+            "material_id" : material_string,
+            "position"    : generate_vec3(position),
+            "rotation"    : generate_vec3(rotation),
+            "quaternion"  : generate_vec4(quaternion),
+            "scale"       : generate_vec3(scale)
+            }
+            chunks.append(object_string)
+        
+    return ",\n\n".join(chunks)
+    
+def generate_geometries(data):
+    chunks = []
+    
+    geo_set = set()
+    
+    for obj in data["objects"]:
+        if obj.type == "MESH":
+            
+            if len(obj.modifiers) > 0:
+                name = obj.name
+            else:
+                name = obj.data.name
+            
+            if name not in geo_set:
 
-    if use_modifiers:
-        bpy.data.meshes.remove(mesh)
+                geometry_id = "geo_%s" % name
+                model_filename = os.path.basename(generate_mesh_filename(name, data["filepath"]))
+                
+                geometry_string = TEMPLATE_GEOMETRY % {
+                "geometry_id" : generate_string(geometry_id),
+                "model_file"  : generate_string(model_filename)
+                }
+                chunks.append(geometry_string)
+                
+                geo_set.add(name)
+        
+    return ",\n\n".join(chunks)
+    
+def generate_textures_scene(data):
+    chunks = []
+    
+    # TODO: extract just textures actually used by some objects in the scene
+    
+    for img in bpy.data.images:
+        
+        texture_id = img.name
+        texture_file = extract_texture_filename(img)
+    
+        texture_string = TEMPLATE_TEXTURE % {
+        "texture_id"   : generate_string(texture_id),
+        "texture_file" : generate_string(texture_file)
+        }
+        chunks.append(texture_string)
+
+    return ",\n\n".join(chunks)
+
+def extract_texture_filename(image):
+    fn = bpy.path.abspath(image.filepath)
+    fn = os.path.normpath(fn)
+    fn_strip = os.path.basename(fn)
+    return fn_strip
+    
+def extract_material_data(m):
+    world = bpy.context.scene.world
+    
+    material = { 'name': m.name }
+    
+    material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
+                                m.diffuse_intensity * m.diffuse_color[1],
+                                m.diffuse_intensity * m.diffuse_color[2]]
+
+    material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
+                                 m.specular_intensity * m.specular_color[1],
+                                 m.specular_intensity * m.specular_color[2]]
+
+    material['colorAmbient'] = [m.ambient * world.ambient_color[0],
+                                m.ambient * world.ambient_color[1],
+                                m.ambient * world.ambient_color[2]]
+
+    material['transparency'] = m.alpha
+
+    # not sure about mapping values to Blinn-Phong shader
+    # Blender uses INT from [1,511] with default 0
+    # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
+
+    material["specularCoef"] = m.specular_hardness
+
+    material['mapDiffuse'] = ""
+    material['mapLight'] = ""
+    material['mapNormal'] = ""    
+        
+    # just take first textures of each, for the moment three.js materials can't handle more
+
+    for i in range(len(m.texture_slots)):
+        ts = m.texture_slots[i]
+        if ts:
+            t = ts.texture
+            if ts.use and t.type == 'IMAGE':
+                name = t.image.name
+
+                if t.use_normal_map:
+                    material['mapNormal'] = name
+                else:
+                    if not material['mapDiffuse']:
+                        material['mapDiffuse'] = name
+                    else:
+                        material['mapLight'] = name
+                
+                if material['mapDiffuse'] and material['mapNormal'] and material['mapLight']:
+                    break
+        
+    if m.specular_intensity > 0.0 and (m.specular_color[0] > 0 or m.specular_color[1] > 0 or m.specular_color[2] > 0):
+        material['shading'] = "Phong"
+    else:
+        material['shading'] = "Lambert"
+        
+    return material
+    
+def generate_material_string(material):
+    type_map = {
+    "Lambert"   : "MeshLambertMaterial",
+    "Phong"     : "MeshPhongMaterial"
+    }
+    
+    material_id = material["name"]
+    shading = material["shading"]
+    material_type = type_map.get(shading, "MeshBasicMaterial")
+
+    parameters = "color: %s" % generate_hex(rgb2int(material["colorDiffuse"]))
+    parameters += ", opacity: %.2f" % material["transparency"]
+
+    if shading == "Phong":
+        parameters += ", ambient: %s" % generate_hex(rgb2int(material["colorAmbient"]))
+        parameters += ", specular: %s" % generate_hex(rgb2int(material["colorSpecular"]))
+        parameters += ", shininess: %.1f" % material["specularCoef"]
+
+    colorMap = material['mapDiffuse']
+    lightMap = material['mapLight']
+    normalMap  = material['mapNormal']
+
+    if colorMap:
+        parameters += ", map: %s" % generate_string(colorMap)
+    if lightMap:
+        parameters += ", lightMap: %s" % generate_string(lightMap)
+    if normalMap:
+        parameters += ", normalMap: %s" % generate_string(normalMap)
+
+    material_string = TEMPLATE_MATERIAL_SCENE % {
+    "material_id" : generate_string(material_id),
+    "type"        : generate_string(material_type),
+    "parameters"  : parameters
+    }
+    
+    return material_string
+    
+def generate_materials_scene(data):
+    chunks = []
+
+    # TODO: extract just materials actually used by some objects in the scene
+    
+    for m in bpy.data.materials:
+        material = extract_material_data(m)
+        material_string = generate_material_string(material)
+        chunks.append(material_string)
+
+    return ",\n\n".join(chunks)
+
+def generate_cameras(data):
+    cameras = data.get("cameras", [])
+    if not cameras:
+        cameras.append(DEFAULTS["camera"])
+        
+    chunks = []
+    for camera in cameras:
+
+        if camera["type"] == "perspective":
+            camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
+            "camera_id" : generate_string(camera["name"]),
+            "fov"       : camera["fov"],
+            "aspect"    : camera["aspect"],
+            "near"      : camera["near"],
+            "far"       : camera["far"],
+            "position"  : generate_vec3(camera["position"]),
+            "target"    : generate_vec3(camera["target"])
+            }
+
+        elif camera["type"] == "ortho":
+            camera_string = TEMPLATE_CAMERA_ORTHO % {
+            "camera_id" : generate_string(camera["name"]),
+            "left"      : camera["left"],
+            "right"     : camera["right"],
+            "top"       : camera["top"],
+            "bottom"    : camera["bottom"],
+            "near"      : camera["near"],
+            "far"       : camera["far"],
+            "position"  : generate_vec3(camera["position"]),
+            "target"    : generate_vec3(camera["target"])
+            }
+            
+        chunks.append(camera_string)
+        
+    return ",\n\n".join(chunks)
+
+def generate_lights(data):
+    lights = data.get("lights", [])
+    if not lights:
+        lights.append(DEFAULTS["light"])
+        
+    chunks = []
+    for light in lights:
+
+        if light["type"] == "directional":
+            light_string = TEMPLATE_LIGHT_DIRECTIONAL % {
+            "light_id"      : generate_string(light["name"]),
+            "direction"     : generate_vec3(light["direction"]),
+            "color"         : generate_hex(rgb2int(light["color"])),
+            "intensity"     : light["intensity"]
+            }
+
+        elif light["type"] == "point":
+            light_string = TEMPLATE_LIGHT_POINT % {
+            "light_id"      : generate_string(light["name"]),
+            "position"      : generate_vec3(light["position"]),
+            "color"         : generate_hex(rgb2int(light["color"])),
+            "intensity"     : light["intensity"]
+            }
+            
+        chunks.append(light_string)
+            
+    return ",\n\n".join(chunks)
+
+def generate_ascii_scene(data):
+    objects = generate_objects(data)
+    geometries = generate_geometries(data)
+    textures = generate_textures_scene(data)
+    materials = generate_materials_scene(data)
+    cameras = generate_cameras(data)
+    lights = generate_lights(data)
+    
+    sections = [
+    ["objects",    objects],
+    ["geometries", geometries],
+    ["textures",   textures],
+    ["materials",  materials],
+    ["cameras",    cameras],
+    ["lights",     lights]
+    ]
+    
+    chunks = []
+    for label, content in sections:
+        if content:
+            chunks.append(generate_section(label, content))
+
+    sections_string = "\n".join(chunks)
+    
+    default_camera = "default_camera"
+    
+    parameters = {
+    "fname"     : data["source_file"],
+    "sections"  : sections_string,
+    "bgcolor"   : generate_vec3(DEFAULTS["bgcolor"]),
+    "bgalpha"   : DEFAULTS["bgalpha"],
+    "defcamera" : generate_string(default_camera)
+    }
+
+    text = TEMPLATE_SCENE_ASCII % parameters
+    
+    return text
+    
+def export_scene(scene, filepath, flipyz):
+
+    source_file = os.path.basename(bpy.data.filepath)
+
+    scene_text = ""
+    data = {
+    "scene"       : scene,
+    "objects"     : scene.objects,
+    "source_file" : source_file,
+    "filepath"    : filepath,
+    "flipyz"      : flipyz
+    }
+    scene_text += generate_ascii_scene(data)
+    
+    write_file(filepath, scene_text)
+
+# #####################################################
+# Main
+# #####################################################
+def save(operator, context, filepath = "", option_flip_yz = True, use_normals = True, use_colors = True, use_uv_coords = True, align_model = 0, option_export_scene = True):
+
+    filepath = ensure_extension(filepath, '.js')
 
+    scene = context.scene
+
+    if scene.objects.active:
+        bpy.ops.object.mode_set(mode='OBJECT')
+
+    if option_export_scene:
+
+        export_scene(scene, filepath, option_flip_yz)
+
+        geo_set = set()
+        
+        for obj in scene.objects:
+            if obj.type == "MESH":
+                
+                # create extra copy of geometry with applied modifiers
+                # (if they exist)
+                
+                if len(obj.modifiers) > 0:
+                    name = obj.name
+                    
+                # otherwise can share geometry
+
+                else:
+                    name = obj.data.name
+
+                if name not in geo_set:
+                    fname = generate_mesh_filename(name, filepath)
+                    export_mesh(obj, scene, fname, use_normals, use_colors, use_uv_coords, 0, option_flip_yz, False)
+                    
+                    geo_set.add(name)
+
+    else:
+
+        obj = context.object
+        if not obj:
+            raise Exception("Error, Select 1 active object or select 'export scene'")
+
+        export_mesh(obj, scene, filepath, use_normals, use_colors, use_uv_coords, align_model, option_flip_yz, True)
+
+    
     return {'FINISHED'}

Some files were not shown because too many files changed in this diff