mirror of
				https://github.com/MapMakersAndProgrammers/alternativa3d-archive.git
				synced 2025-10-31 09:16:14 -07:00 
			
		
		
		
	Remove .svn folders
This commit is contained in:
		| @@ -1,11 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 76 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src | ||||
| END | ||||
| manifest.xml | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 89 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/manifest.xml | ||||
| END | ||||
| @@ -1,43 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-10-20T15:36:49.086084Z | ||||
| 22341 | ||||
| int | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| manifest.xml | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 2e2b1aa9d128d192e5f544209f610433 | ||||
| 2009-06-25T13:27:32.420515Z | ||||
| 15144 | ||||
| int | ||||
|  | ||||
| alternativa | ||||
| dir | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 8 | ||||
| @@ -1,4 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <componentPackage> | ||||
| 	<component id="Alternativa3D" class="alternativa.Alternativa3D"/> | ||||
| </componentPackage> | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 88 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa | ||||
| END | ||||
| Alternativa3D.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 105 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/Alternativa3D.as | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 648 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,43 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-10-20T15:36:49.086084Z | ||||
| 22341 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| Alternativa3D.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 1500acb71dc17d3fd581f2398575f25e | ||||
| 2009-06-25T13:27:32.420515Z | ||||
| 15144 | ||||
| int | ||||
|  | ||||
| engine3d | ||||
| dir | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 8 | ||||
| @@ -1,14 +0,0 @@ | ||||
| package alternativa { | ||||
|  | ||||
| 	/** | ||||
| 	 * Класс содержит информацию о версии библиотеки. | ||||
| 	 * Также используется для интеграции библиотеки в среду разработки Adobe Flash. | ||||
| 	 */ | ||||
| 	public class Alternativa3D { | ||||
|  | ||||
| 		/** | ||||
| 		 * Версия библиотеки в формате: поколение.feature-версия.fix-версия | ||||
| 		 */ | ||||
| 		public static const version:String = "7.0.0"; | ||||
| 	} | ||||
| } | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 97 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d | ||||
| END | ||||
| alternativa3d.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 114 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/alternativa3d.as | ||||
| END | ||||
| @@ -1,58 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-10-20T15:36:49.086084Z | ||||
| 22341 | ||||
| int | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| alternativa3d.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 64183f832985e252cc4bc98977484bc9 | ||||
| 2009-02-11T11:56:39.925226Z | ||||
| 7238 | ||||
| wolf | ||||
|  | ||||
| containers | ||||
| dir | ||||
|  | ||||
| controllers | ||||
| dir | ||||
|  | ||||
| core | ||||
| dir | ||||
|  | ||||
| loaders | ||||
| dir | ||||
|  | ||||
| objects | ||||
| dir | ||||
|  | ||||
| primitives | ||||
| dir | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 8 | ||||
| @@ -1,3 +0,0 @@ | ||||
| package alternativa.engine3d { | ||||
| 	public namespace alternativa3d = "http://alternativaplatform.com/en/alternativa3d"; | ||||
| } | ||||
| @@ -1,47 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 108 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers | ||||
| END | ||||
| KDTree.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 118 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers/KDTree.as | ||||
| END | ||||
| SplitContainer.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 126 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers/SplitContainer.as | ||||
| END | ||||
| SkyBox.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 118 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers/SkyBox.as | ||||
| END | ||||
| DirectionContainer.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 130 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers/DirectionContainer.as | ||||
| END | ||||
| BSPTree.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 119 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers/BSPTree.as | ||||
| END | ||||
| ConflictContainer.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 129 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers/ConflictContainer.as | ||||
| END | ||||
| AverageZContainer.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 129 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers/AverageZContainer.as | ||||
| END | ||||
| @@ -1,113 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/containers | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-10-20T15:36:49.086084Z | ||||
| 22341 | ||||
| int | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| KDTree.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 7b8bf5f7391901c409b1efd39b1b8495 | ||||
| 2009-10-19T11:39:18.186364Z | ||||
| 22296 | ||||
| int | ||||
|  | ||||
| SplitContainer.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 64e1b96019ddcb6251c485edf7743afc | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
|  | ||||
| SkyBox.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| d5637774608e1a7c6c303f83e55afeb9 | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
| DirectionContainer.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 9e2cc7ec294ef915a6c85fa2564e6214 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
|  | ||||
| BSPTree.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| b1334a64f09aa52c172b20df7fa66f5a | ||||
| 2009-10-19T11:39:18.186364Z | ||||
| 22296 | ||||
| int | ||||
|  | ||||
| ConflictContainer.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 795ebff90c493f5d194a202a73f0fa0e | ||||
| 2009-10-20T15:36:49.086084Z | ||||
| 22341 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| AverageZContainer.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 2869f9a450deef9ccb26b0bd328dabd7 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
|  | ||||
| @@ -1,5 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 0 | ||||
|  | ||||
| END | ||||
| @@ -1,77 +0,0 @@ | ||||
| package alternativa.engine3d.containers { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	import alternativa.engine3d.core.Object3DContainer; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Контейнер, дочерние объекты которого отрисовываются по удалённости от камеры  | ||||
| 	 */ | ||||
| 	public class AverageZContainer extends Object3DContainer { | ||||
| 		 | ||||
| 		static private const averageZ:Vector.<Number> = new Vector.<Number>(); | ||||
| 		static private const center:Vector.<Number> = Vector.<Number>([0, 0, 0]); | ||||
| 		static private const cameraCenter:Vector.<Number> = new Vector.<Number>(3, true); | ||||
| 		static private const sortingStack:Vector.<int> = new Vector.<int>(); | ||||
| 		 | ||||
| 		override protected function drawVisibleChildren(camera:Camera3D, object:Object3D, canvas:Canvas):void { | ||||
| 			var i:int; | ||||
| 			var j:int; | ||||
| 			var l:int = 0; | ||||
| 			var r:int = numVisibleChildren - 1; | ||||
| 			var child:Object3D; | ||||
| 			var sortingStackIndex:int; | ||||
| 			var sortingLeft:Number; | ||||
| 			var sortingMedian:Number; | ||||
| 			var sortingRight:Number; | ||||
| 			var sortingChild:Object3D; | ||||
| 			// Сортировка | ||||
| 			for (i = 0; i < numVisibleChildren; i++) { | ||||
| 				child = visibleChildren[i]; | ||||
| 				child.cameraMatrix.transformVectors(center, cameraCenter); | ||||
| 				averageZ[i] = cameraCenter[0]*cameraCenter[0] + cameraCenter[1]*cameraCenter[1] + cameraCenter[2]*cameraCenter[2]; | ||||
| 			} | ||||
| 			sortingStack[0] = l; | ||||
| 			sortingStack[1] = r; | ||||
| 			sortingStackIndex = 2; | ||||
| 			while (sortingStackIndex > 0) { | ||||
| 				j = r = sortingStack[--sortingStackIndex]; | ||||
| 				i = l = sortingStack[--sortingStackIndex]; | ||||
| 				sortingMedian = averageZ[(r + l) >> 1]; | ||||
| 				do { | ||||
| 	 				while ((sortingLeft = averageZ[i]) > sortingMedian) i++; | ||||
| 	 				while ((sortingRight = averageZ[j]) < sortingMedian) j--; | ||||
| 	 				if (i <= j) { | ||||
| 	 					sortingChild = visibleChildren[i]; | ||||
| 						visibleChildren[i] = visibleChildren[j]; | ||||
| 						visibleChildren[j] = sortingChild; | ||||
| 						averageZ[i++] = sortingRight; | ||||
| 						averageZ[j--] = sortingLeft; | ||||
| 	 				} | ||||
| 				} while (i <= j); | ||||
| 				if (l < j) { | ||||
| 					sortingStack[sortingStackIndex++] = l; | ||||
| 					sortingStack[sortingStackIndex++] = j; | ||||
| 				} | ||||
| 				if (i < r) { | ||||
| 					sortingStack[sortingStackIndex++] = i; | ||||
| 					sortingStack[sortingStackIndex++] = r; | ||||
| 				} | ||||
| 			} | ||||
| 			// Отрисовка | ||||
| 			for (i = numVisibleChildren - 1; i >= 0; i--) { | ||||
| 				child = visibleChildren[i]; | ||||
| 				if (camera.debugMode) child.debug(camera, child, canvas); | ||||
| 				child.draw(camera, child, canvas); | ||||
| 				visibleChildren[i] = null; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| package alternativa.engine3d.containers { | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
|  | ||||
| 	public class BSPTree extends ConflictContainer { | ||||
| 		 | ||||
| 		 | ||||
| 		 | ||||
| 		 | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,38 +0,0 @@ | ||||
| package alternativa.engine3d.containers { | ||||
|  | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	import alternativa.engine3d.core.Object3DContainer; | ||||
| 	 | ||||
| 	import flash.geom.Vector3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class DirectionContainer extends Object3DContainer { | ||||
| 		 | ||||
| 		public var direction:Vector3D = new Vector3D(0, 0, -1); | ||||
| 		 | ||||
| 		override protected function drawVisibleChildren(camera:Camera3D, object:Object3D, canvas:Canvas):void { | ||||
| 			var i:int; | ||||
| 			var child:Object3D; | ||||
| 			if (Vector3D.Z_AXIS.dotProduct(object.cameraMatrix.deltaTransformVector(direction)) < 0) { | ||||
| 				for (i = 0; i < numVisibleChildren; i++) { | ||||
| 					child = visibleChildren[i]; | ||||
| 					if (camera.debugMode) child.debug(camera, child, canvas); | ||||
| 					child.draw(camera, child, canvas); | ||||
| 					visibleChildren[i] = null; | ||||
| 				} | ||||
| 			} else { | ||||
| 				for (i = numVisibleChildren - 1; i >= 0; i--) { | ||||
| 					child = visibleChildren[i]; | ||||
| 					if (camera.debugMode) child.debug(camera, child, canvas); | ||||
| 					child.draw(camera, child, canvas); | ||||
| 					visibleChildren[i] = null; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,826 +0,0 @@ | ||||
| package alternativa.engine3d.containers { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Debug; | ||||
| 	import alternativa.engine3d.core.Geometry; | ||||
| 	import alternativa.engine3d.core.Node; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	import alternativa.engine3d.objects.Occluder; | ||||
| 	import alternativa.engine3d.objects.Reference; | ||||
| 	 | ||||
| 	import flash.geom.Utils3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Контейнер, дочерние объекты которого помещены в бинарную древовидную структуру. | ||||
| 	 * Для построения дерева нужно добавить статические дочерние объекты  | ||||
| 	 * с помощью addStaticChild(), затем вызвать createTree(). По баундам статических объектов | ||||
| 	 * построится ориентированная по осям бинарная древовидная структура (KD - частный случай BSP). | ||||
| 	 * Динамические объекты, можно в любое время добавлять addDynamicChild() и удалять removeDynamicChild(). | ||||
| 	 * Объекты, добавленные с помощью addChild() будут отрисовываться поверх всего в порядке добавления. | ||||
| 	 */ | ||||
| 	public class KDTree extends ConflictContainer { | ||||
| 		 | ||||
| 		public var debugAlphaFade:Number = 0.8; | ||||
| 		 | ||||
| 		private var rootNode:Node; | ||||
| 		 | ||||
| 		override alternativa3d function get canDraw():Boolean { | ||||
| 			return _numChildren > 0 || rootNode != null; | ||||
| 		} | ||||
|  | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			// Если есть корневая нода | ||||
| 			if (rootNode != null) { | ||||
| 				// Расчёт инверсной матрицы камеры и позицци камеры в контейнере | ||||
| 				calculateInverseCameraMatrix(object.cameraMatrix); | ||||
| 				// Расчёт плоскостей камеры в контейнере | ||||
| 				calculateCameraPlanes(camera); | ||||
| 				// Проверка на видимость рутовой ноды | ||||
| 				var culling:int = cullingInContainer(camera, rootNode.boundBox, object.culling); | ||||
| 				if (culling >= 0) { | ||||
| 					// Подготовка канваса | ||||
| 					var canvas:Canvas = parentCanvas.getChildCanvas(false, true, object.alpha, object.blendMode, object.colorTransform, object.filters); | ||||
| 					canvas.numDraws = 0; | ||||
| 					// Окклюдеры | ||||
| 					numOccluders = 0; | ||||
| 					if (camera.numOccluders > 0) { | ||||
| 						updateOccluders(camera); | ||||
| 					} | ||||
| 					// Сбор видимой геометрии | ||||
| 					var geometry:Geometry = getGeometry(camera, object); | ||||
| 					var current:Geometry = geometry; | ||||
| 					while (current != null) { | ||||
| 						current.vertices.length = current.verticesLength; | ||||
| 						inverseCameraMatrix.transformVectors(current.vertices, current.vertices); | ||||
| 						current.calculateAABB(); | ||||
| 						current = current.next; | ||||
| 					} | ||||
| 					// Отрисовка дерева | ||||
| 					drawNode(rootNode, culling, camera, object, canvas, geometry); | ||||
| 					// Если была отрисовка | ||||
| 					if (canvas.numDraws > 0) { | ||||
| 						canvas.removeChildren(canvas.numDraws); | ||||
| 					} else { | ||||
| 						parentCanvas.numDraws--; | ||||
| 					} | ||||
| 				} else { | ||||
| 					super.draw(camera, object, parentCanvas); | ||||
| 				} | ||||
| 			} else { | ||||
| 				super.draw(camera, object, parentCanvas); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function debug(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			var debugResult:int = camera.checkInDebug(this); | ||||
| 			if (debugResult == 0) return; | ||||
| 			var canvas:Canvas = parentCanvas.getChildCanvas(true, false); | ||||
| 			// Ноды | ||||
| 			if (debugResult & Debug.NODES) { | ||||
| 				if (rootNode != null) { | ||||
| 					var culling:int = cullingInContainer(camera, rootNode.boundBox, object.culling); | ||||
| 					if (culling >= 0) { | ||||
| 						debugNode(rootNode, culling, camera, object, canvas, 1); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			// Оси, центры, имена, баунды | ||||
| 			if (debugResult & Debug.AXES) object.drawAxes(camera, canvas); | ||||
| 			if (debugResult & Debug.CENTERS) object.drawCenter(camera, canvas); | ||||
| 			if (debugResult & Debug.NAMES) object.drawName(camera, canvas); | ||||
| 			if (debugResult & Debug.BOUNDS) object.drawBoundBox(camera, canvas); | ||||
| 		} | ||||
| 		 | ||||
| 		// Отрисовка ноды | ||||
| 		private function drawNode(node:Node, culling:int, camera:Camera3D, object:Object3D, canvas:Canvas, geometry:Geometry):void { | ||||
| 			var i:int; | ||||
| 			var next:Geometry; | ||||
| 			var negative:Geometry; | ||||
| 			var middle:Geometry; | ||||
| 			var positive:Geometry; | ||||
| 			var negativePart:Geometry; | ||||
| 			var positivePart:Geometry; | ||||
| 			if (camera.occludedAll) { | ||||
| 				while (geometry != null) { | ||||
| 					next = geometry.next; | ||||
| 					geometry.destroy(); | ||||
| 					geometry = next; | ||||
| 				} | ||||
| 				return; | ||||
| 			} | ||||
| 			var nodeObjects:Vector.<Object3D> = node.objects; | ||||
| 			var nodeNumObjects:int = node.numObjects; | ||||
| 			var nodeNumNonOccluders:int = node.numNonOccluders; | ||||
| 			var staticChild:Object3D; | ||||
| 			// Узловая нода | ||||
| 			if (node.negative != null) { | ||||
| 				var negativeCulling:int = (culling > 0 || numOccluders > 0) ? cullingInContainer(camera, node.negative.boundBox, culling) : 0; | ||||
| 				var positiveCulling:int = (culling > 0 || numOccluders > 0) ? cullingInContainer(camera, node.positive.boundBox, culling) : 0; | ||||
| 				var axisX:Boolean = node.normalX != 0; | ||||
| 				var axisY:Boolean = node.normalY != 0; | ||||
| 				var min:Number; | ||||
| 				var max:Number; | ||||
| 				// Если видны обе дочерние ноды | ||||
| 				if (negativeCulling >= 0 && positiveCulling >= 0) { | ||||
| 					// Перебор динамиков | ||||
| 					while (geometry != null) { | ||||
| 						next = geometry.next; | ||||
| 						// Проверка с окклюдерами | ||||
| 						if (geometry.numOccluders < numOccluders && occludeGeometry(camera, geometry)) { | ||||
| 							geometry.destroy(); | ||||
| 						} else { | ||||
| 							min = axisX ? geometry.minX : (axisY ? geometry.minY : geometry.minZ); | ||||
| 							max = axisX ? geometry.maxX : (axisY ? geometry.maxY : geometry.maxZ); | ||||
| 							if (max <= node.offsetMax) { | ||||
| 								if (min < node.offsetMin) { | ||||
| 									geometry.next = negative; | ||||
| 									negative = geometry; | ||||
| 								} else { | ||||
| 									geometry.next = middle; | ||||
| 									middle = geometry; | ||||
| 								} | ||||
| 							} else { | ||||
| 								if (min >= node.offsetMin) { | ||||
| 									geometry.next = positive; | ||||
| 									positive = geometry; | ||||
| 								} else { | ||||
| 									negativePart = geometry.create(); | ||||
| 									positivePart = geometry.create(); | ||||
| 									geometry.split(axisX, axisY, node.offset, threshold, negativePart, positivePart); | ||||
| 									geometry.destroy(); | ||||
| 									// Если негативный не пустой | ||||
| 									if (negativePart.fragment != null) { | ||||
| 										negativePart.next = negative; | ||||
| 										negative = negativePart; | ||||
| 									} else { | ||||
| 										negativePart.destroy(); | ||||
| 									} | ||||
| 									// Если позитивный не пустой | ||||
| 									if (positivePart.fragment != null) { | ||||
| 										positivePart.next = positive; | ||||
| 										positive = positivePart; | ||||
| 									} else { | ||||
| 										positivePart.destroy(); | ||||
| 									} | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						geometry = next; | ||||
| 					} | ||||
| 					// Отрисовка дочерних нод и объектов в плоскости | ||||
| 					if (axisX && cameraX > node.offset || axisY && cameraY > node.offset || !axisX && !axisY && cameraZ > node.offset) { | ||||
| 						// Отрисовка позитивной ноды | ||||
| 						drawNode(node.positive, positiveCulling, camera, object, canvas, positive); | ||||
| 						// Отрисовка динамических объектов в ноде | ||||
| 						while (middle != null) { | ||||
| 							next = middle.next; | ||||
| 							// Проверка с окклюдерами и отрисовка | ||||
| 							if (middle.numOccluders >= numOccluders || !occludeGeometry(camera, middle)) { | ||||
| 								if (camera.debugMode) middle.debug(camera, object, canvas, threshold, 1, object.cameraMatrix); | ||||
| 								middle.draw(camera, canvas, threshold, object.cameraMatrix); | ||||
| 							} | ||||
| 							middle.destroy(); | ||||
| 							middle = next; | ||||
| 						} | ||||
| 						// Отрисовка плоских статических объектов в ноде | ||||
| 						for (i = 0; i < nodeNumObjects; i++) { | ||||
| 							staticChild = nodeObjects[i];  | ||||
| 							if (staticChild.visible && staticChild.canDraw && ((staticChild.culling = culling) == 0 && numOccluders == 0 || (staticChild.culling = cullingInContainer(camera, node.bounds[i], culling)) >= 0)) { | ||||
| 								staticChild.cameraMatrix.identity(); | ||||
| 								staticChild.cameraMatrix.prepend(object.cameraMatrix); | ||||
| 								staticChild.cameraMatrix.prepend(staticChild.matrix); | ||||
| 								if (camera.debugMode) staticChild.debug(camera, staticChild, canvas); | ||||
| 								staticChild.draw(camera, staticChild, canvas); | ||||
| 							} | ||||
| 						} | ||||
| 						// Обновление окклюдеров | ||||
| 						if (nodeNumObjects > nodeNumNonOccluders) { | ||||
| 							updateOccluders(camera); | ||||
| 						} | ||||
| 						// Отрисовка негативной ноды | ||||
| 						drawNode(node.negative, negativeCulling, camera, object, canvas, negative);  | ||||
| 					} else { | ||||
| 						// Отрисовка негативной ноды | ||||
| 						drawNode(node.negative, negativeCulling, camera, object, canvas, negative); | ||||
| 						// Отрисовка динамических объектов в ноде | ||||
| 						while (middle != null) { | ||||
| 							next = middle.next; | ||||
| 							// Проверка с окклюдерами и отрисовка | ||||
| 							if (middle.numOccluders >= numOccluders || !occludeGeometry(camera, middle)) { | ||||
| 								if (camera.debugMode) middle.debug(camera, object, canvas, threshold, 1, object.cameraMatrix); | ||||
| 								middle.draw(camera, canvas, threshold, object.cameraMatrix); | ||||
| 							} | ||||
| 							middle.destroy(); | ||||
| 							middle = next; | ||||
| 						} | ||||
| 						// Отрисовка статических объектов в ноде | ||||
| 						for (i = 0; i < nodeNumObjects; i++) { | ||||
| 							staticChild = nodeObjects[i];  | ||||
| 							if (staticChild.visible && staticChild.canDraw && ((staticChild.culling = culling) == 0 && numOccluders == 0 || (staticChild.culling = cullingInContainer(camera, node.bounds[i], culling)) >= 0)) { | ||||
| 								staticChild.cameraMatrix.identity(); | ||||
| 								staticChild.cameraMatrix.prepend(object.cameraMatrix); | ||||
| 								staticChild.cameraMatrix.prepend(staticChild.matrix); | ||||
| 								if (camera.debugMode) staticChild.debug(camera, staticChild, canvas); | ||||
| 								staticChild.draw(camera, staticChild, canvas); | ||||
| 							} | ||||
| 						} | ||||
| 						// Обновление окклюдеров | ||||
| 						if (nodeNumObjects > nodeNumNonOccluders) { | ||||
| 							updateOccluders(camera); | ||||
| 						} | ||||
| 						// Отрисовка позитивной ноды | ||||
| 						drawNode(node.positive, positiveCulling, camera, object, canvas, positive); | ||||
| 					} | ||||
| 				// Если видна только негативная | ||||
| 				} else if (negativeCulling >= 0) { | ||||
| 					// Перебор динамиков | ||||
| 					while (geometry != null) { | ||||
| 						next = geometry.next; | ||||
| 						// Проверка с окклюдерами | ||||
| 						if (geometry.numOccluders < numOccluders && occludeGeometry(camera, geometry)) { | ||||
| 							geometry.destroy(); | ||||
| 						} else { | ||||
| 							min = axisX ? geometry.minX : (axisY ? geometry.minY : geometry.minZ); | ||||
| 							max = axisX ? geometry.maxX : (axisY ? geometry.maxY : geometry.maxZ); | ||||
| 							if (max <= node.offsetMax) { | ||||
| 								geometry.next = negative; | ||||
| 								negative = geometry; | ||||
| 							} else if (min < node.offsetMin) { | ||||
| 								negativePart = geometry.create(); | ||||
| 								geometry.split(axisX, axisY, node.offset, threshold, negativePart, null); | ||||
| 								geometry.destroy(); | ||||
| 								// Если негативный не пустой | ||||
| 								if (negativePart.fragment != null) { | ||||
| 									negativePart.next = negative; | ||||
| 									negative = negativePart; | ||||
| 								} else { | ||||
| 									negativePart.destroy(); | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						geometry = next; | ||||
| 					} | ||||
| 					// Отрисовка негативной ноды | ||||
| 					drawNode(node.negative, negativeCulling, camera, object, canvas, negative); | ||||
| 				// Если видна только позитивная | ||||
| 				} else if (positiveCulling >= 0) { | ||||
| 					// Перебор динамиков | ||||
| 					while (geometry != null) { | ||||
| 						next = geometry.next; | ||||
| 						// Проверка с окклюдерами | ||||
| 						if (geometry.numOccluders < numOccluders && occludeGeometry(camera, geometry)) { | ||||
| 							geometry.destroy(); | ||||
| 						} else { | ||||
| 							min = axisX ? geometry.minX : (axisY ? geometry.minY : geometry.minZ); | ||||
| 							max = axisX ? geometry.maxX : (axisY ? geometry.maxY : geometry.maxZ); | ||||
| 							if (min >= node.offsetMin) { | ||||
| 								geometry.next = positive; | ||||
| 								positive = geometry; | ||||
| 							} else if (max > node.offsetMax) { | ||||
| 								positivePart = geometry.create(); | ||||
| 								geometry.split(axisX, axisY, node.offset, threshold, null, positivePart); | ||||
| 								geometry.destroy(); | ||||
| 								// Если позитивный не пустой | ||||
| 								if (positivePart.fragment != null) { | ||||
| 									positivePart.next = positive; | ||||
| 									positive = positivePart; | ||||
| 								} else { | ||||
| 									positivePart.destroy(); | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						geometry = next; | ||||
| 					} | ||||
| 					// Отрисовка позитивной ноды | ||||
| 					drawNode(node.positive, positiveCulling, camera, object, canvas, positive); | ||||
| 				} | ||||
| 			// Конечная нода | ||||
| 			} else { | ||||
| 				// Если есть статические объекты, не считая окклюдеры | ||||
| 				if (nodeNumNonOccluders > 0) { | ||||
| 					// Если есть конфликт | ||||
| 					if (nodeNumNonOccluders > 1 || geometry != null) { | ||||
| 						// Перебор динамиков | ||||
| 						while (geometry != null) { | ||||
| 							next = geometry.next; | ||||
| 							// Проверка с окклюдерами | ||||
| 							if (geometry.numOccluders < numOccluders && occludeGeometry(camera, geometry)) { | ||||
| 								geometry.destroy(); | ||||
| 							} else { | ||||
| 								geometry.vertices.length = geometry.verticesLength; | ||||
| 								object.cameraMatrix.transformVectors(geometry.vertices, geometry.vertices); | ||||
| 								geometry.next = middle; | ||||
| 								middle = geometry; | ||||
| 							} | ||||
| 							geometry = next; | ||||
| 						} | ||||
| 						// Превращение статиков в геометрию | ||||
| 						for (i = 0; i < nodeNumNonOccluders; i++) { | ||||
| 							staticChild = nodeObjects[i]; | ||||
| 							if (staticChild.visible && staticChild.canDraw && ((staticChild.culling = culling) == 0 && numOccluders == 0 || (staticChild.culling = cullingInContainer(camera, node.bounds[i], culling)) >= 0)) { | ||||
| 								staticChild.cameraMatrix.identity(); | ||||
| 								staticChild.cameraMatrix.prepend(object.cameraMatrix); | ||||
| 								staticChild.cameraMatrix.prepend(staticChild.matrix); | ||||
| 								geometry = staticChild.getGeometry(camera, staticChild); | ||||
| 								while (geometry != null) { | ||||
| 									next = geometry.next; | ||||
| 									geometry.next = middle; | ||||
| 									middle = geometry; | ||||
| 									geometry = next; | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						// Разруливаем конфликт | ||||
| 						if (middle != null) { | ||||
| 							if (middle.next != null) { | ||||
| 								drawConflictGeometry(camera, object, canvas, middle); | ||||
| 							} else { | ||||
| 								if (camera.debugMode) middle.debug(camera, object, canvas, threshold, 1); | ||||
| 								middle.draw(camera, canvas, threshold); | ||||
| 								middle.destroy(); | ||||
| 							} | ||||
| 						} | ||||
| 					} else { | ||||
| 						// Если только один статик | ||||
| 						staticChild = nodeObjects[i]; | ||||
| 						if (staticChild.visible && staticChild.canDraw) { | ||||
| 							staticChild.cameraMatrix.identity(); | ||||
| 							staticChild.cameraMatrix.prepend(object.cameraMatrix); | ||||
| 							staticChild.cameraMatrix.prepend(staticChild.matrix); | ||||
| 							staticChild.culling = culling; | ||||
| 							if (camera.debugMode) staticChild.debug(camera, staticChild, canvas); | ||||
| 							staticChild.draw(camera, staticChild, canvas); | ||||
| 						} | ||||
| 					} | ||||
| 				// Если нет статических объектов | ||||
| 				} else { | ||||
| 					// Если есть динамические объекты | ||||
| 					if (geometry != null) { | ||||
| 						// Если динамических объектов несколько | ||||
| 						if (geometry.next != null) { | ||||
| 							// Если есть окклюдеры | ||||
| 							if (numOccluders > 0) { | ||||
| 								// Перебор динамиков | ||||
| 								while (geometry != null) { | ||||
| 									next = geometry.next; | ||||
| 									// Проверка с окклюдерами | ||||
| 									if (geometry.numOccluders < numOccluders && occludeGeometry(camera, geometry)) { | ||||
| 										geometry.destroy(); | ||||
| 									} else { | ||||
| 										geometry.next = middle; | ||||
| 										middle = geometry; | ||||
| 									} | ||||
| 									geometry = next; | ||||
| 								} | ||||
| 								// Если остались объекты | ||||
| 								if (middle != null) { | ||||
| 									if (middle.next != null) { | ||||
| 										// Разруливание | ||||
| 										if (resolveByAABB) { | ||||
| 											drawAABBGeometry(camera, object, canvas, middle); | ||||
| 										} else if (resolveByOOBB) { | ||||
| 											geometry = middle; | ||||
| 											while (geometry != null) { | ||||
| 												geometry.vertices.length = geometry.verticesLength; | ||||
| 												object.cameraMatrix.transformVectors(geometry.vertices, geometry.vertices); | ||||
| 												if (!geometry.viewAligned) { | ||||
| 													geometry.calculateOOBB(); | ||||
| 												} | ||||
| 												geometry = geometry.next; | ||||
| 											} | ||||
| 											drawOOBBGeometry(camera, object, canvas, middle); | ||||
| 										} else { | ||||
| 											geometry = middle; | ||||
| 											while (geometry != null) { | ||||
| 												geometry.vertices.length = geometry.verticesLength; | ||||
| 												object.cameraMatrix.transformVectors(geometry.vertices, geometry.vertices); | ||||
| 												geometry = geometry.next; | ||||
| 											} | ||||
| 											drawConflictGeometry(camera, object, canvas, middle); | ||||
| 										} | ||||
| 									} else { | ||||
| 										if (camera.debugMode) middle.debug(camera, object, canvas, threshold, 1, object.cameraMatrix); | ||||
| 										middle.draw(camera, canvas, threshold, object.cameraMatrix); | ||||
| 										middle.destroy(); | ||||
| 									} | ||||
| 								} | ||||
| 							} else { | ||||
| 								// Разруливание | ||||
| 								middle = geometry; | ||||
| 								if (resolveByAABB) { | ||||
| 									drawAABBGeometry(camera, object, canvas, middle); | ||||
| 								} else if (resolveByOOBB) { | ||||
| 									geometry = middle; | ||||
| 									while (geometry != null) { | ||||
| 										geometry.vertices.length = geometry.verticesLength; | ||||
| 										object.cameraMatrix.transformVectors(geometry.vertices, geometry.vertices); | ||||
| 										if (!geometry.viewAligned) { | ||||
| 											geometry.calculateOOBB(); | ||||
| 										} | ||||
| 										geometry = geometry.next; | ||||
| 									} | ||||
| 									drawOOBBGeometry(camera, object, canvas, middle); | ||||
| 								} else { | ||||
| 									geometry = middle; | ||||
| 									while (geometry != null) { | ||||
| 										geometry.vertices.length = geometry.verticesLength; | ||||
| 										object.cameraMatrix.transformVectors(geometry.vertices, geometry.vertices); | ||||
| 										geometry = geometry.next; | ||||
| 									} | ||||
| 									drawConflictGeometry(camera, object, canvas, middle); | ||||
| 								} | ||||
| 							} | ||||
| 						} else { | ||||
| 							// Проверка с окклюдерами и отрисовка | ||||
| 							if (geometry.numOccluders >= numOccluders || !occludeGeometry(camera, geometry)) { | ||||
| 								if (camera.debugMode) geometry.debug(camera, object, canvas, threshold, 1, object.cameraMatrix); | ||||
| 								geometry.draw(camera, canvas, threshold, object.cameraMatrix); | ||||
| 							} | ||||
| 							geometry.destroy(); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				// Если в ноде есть окклюдеры | ||||
| 				if (nodeNumObjects > nodeNumNonOccluders) { | ||||
| 					for (i = nodeNumNonOccluders; i < nodeNumObjects; i++) { | ||||
| 						staticChild = nodeObjects[i]; | ||||
| 						if (staticChild.visible && staticChild.canDraw && ((staticChild.culling = culling) == 0 && numOccluders == 0 || (staticChild.culling = cullingInContainer(camera, node.bounds[i], culling)) >= 0)) { | ||||
| 							staticChild.cameraMatrix.identity(); | ||||
| 							staticChild.cameraMatrix.prepend(object.cameraMatrix); | ||||
| 							staticChild.cameraMatrix.prepend(staticChild.matrix); | ||||
| 							if (camera.debugMode) staticChild.debug(camera, staticChild, canvas); | ||||
| 							staticChild.draw(camera, staticChild, canvas); | ||||
| 						} | ||||
| 					} | ||||
| 					// Обновление окклюдеров | ||||
| 					updateOccluders(camera); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		static private const nodeVertices:Vector.<Number> = new Vector.<Number>(12, true); | ||||
| 		static private const nodeProjectedVertices:Vector.<Number> = new Vector.<Number>(8, true); | ||||
| 		static private const nodeUVTs:Vector.<Number> = new Vector.<Number>(12, true); | ||||
|  | ||||
| 		private function debugNode(node:Node, culling:int, camera:Camera3D, object:Object3D, canvas:Canvas, alpha:Number):void { | ||||
| 			if (node.negative != null) { | ||||
| 				var negativeCulling:int = (culling > 0) ? cullingInContainer(camera, node.negative.boundBox, culling) : 0; | ||||
| 				var positiveCulling:int = (culling > 0) ? cullingInContainer(camera, node.positive.boundBox, culling) : 0; | ||||
| 				if (negativeCulling >= 0) { | ||||
| 					debugNode(node.negative, negativeCulling, camera, object, canvas, alpha*debugAlphaFade); | ||||
| 				} | ||||
| 				if (positiveCulling >= 0) { | ||||
| 					debugNode(node.positive, positiveCulling, camera, object, canvas, alpha*debugAlphaFade); | ||||
| 				} | ||||
| 				 | ||||
| 				if (node.normalX) { | ||||
| 					nodeVertices[0] = node.offset; | ||||
| 					nodeVertices[1] = node.boundBox.minY; | ||||
| 					nodeVertices[2] = node.boundBox.maxZ; | ||||
| 					 | ||||
| 					nodeVertices[3] = node.offset; | ||||
| 					nodeVertices[4] = node.boundBox.maxY; | ||||
| 					nodeVertices[5] = node.boundBox.maxZ; | ||||
| 					 | ||||
| 					nodeVertices[6] = node.offset; | ||||
| 					nodeVertices[7] = node.boundBox.maxY; | ||||
| 					nodeVertices[8] = node.boundBox.minZ; | ||||
| 					 | ||||
| 					nodeVertices[9] = node.offset; | ||||
| 					nodeVertices[10] = node.boundBox.minY; | ||||
| 					nodeVertices[11] = node.boundBox.minZ; | ||||
| 				} else if (node.normalY) { | ||||
| 					nodeVertices[0] = node.boundBox.maxX; | ||||
| 					nodeVertices[1] = node.offset; | ||||
| 					nodeVertices[2] = node.boundBox.maxZ; | ||||
| 					 | ||||
| 					nodeVertices[3] = node.boundBox.minX; | ||||
| 					nodeVertices[4] = node.offset; | ||||
| 					nodeVertices[5] = node.boundBox.maxZ; | ||||
| 					 | ||||
| 					nodeVertices[6] = node.boundBox.minX; | ||||
| 					nodeVertices[7] = node.offset; | ||||
| 					nodeVertices[8] = node.boundBox.minZ; | ||||
| 					 | ||||
| 					nodeVertices[9] = node.boundBox.maxX; | ||||
| 					nodeVertices[10] = node.offset; | ||||
| 					nodeVertices[11] = node.boundBox.minZ; | ||||
| 				} else { | ||||
| 					nodeVertices[0] = node.boundBox.minX; | ||||
| 					nodeVertices[1] = node.boundBox.minY; | ||||
| 					nodeVertices[2] = node.offset; | ||||
| 					 | ||||
| 					nodeVertices[3] = node.boundBox.maxX; | ||||
| 					nodeVertices[4] = node.boundBox.minY; | ||||
| 					nodeVertices[5] = node.offset; | ||||
| 					 | ||||
| 					nodeVertices[6] = node.boundBox.maxX; | ||||
| 					nodeVertices[7] = node.boundBox.maxY; | ||||
| 					nodeVertices[8] = node.offset; | ||||
| 					 | ||||
| 					nodeVertices[9] = node.boundBox.minX; | ||||
| 					nodeVertices[10] = node.boundBox.maxY; | ||||
| 					nodeVertices[11] = node.offset; | ||||
| 				} | ||||
| 				object.cameraMatrix.transformVectors(nodeVertices, nodeVertices); | ||||
| 				var i:int; | ||||
| 				for (i = 0; i < 12; i += 3) { | ||||
| 					if (nodeVertices[int(i + 2)] <= 0) break; | ||||
| 				} | ||||
| 				if (i == 12) { | ||||
| 					Utils3D.projectVectors(camera.projectionMatrix, nodeVertices, nodeProjectedVertices, nodeUVTs); | ||||
| 					canvas.gfx.lineStyle(0, node.normalX ? 0xFF0000 : (node.normalY ? 0x00FF00 : 0x0000FF)); | ||||
| 					canvas.gfx.moveTo(nodeProjectedVertices[0], nodeProjectedVertices[1]); | ||||
| 					canvas.gfx.lineTo(nodeProjectedVertices[2], nodeProjectedVertices[3]); | ||||
| 					canvas.gfx.lineTo(nodeProjectedVertices[4], nodeProjectedVertices[5]); | ||||
| 					canvas.gfx.lineTo(nodeProjectedVertices[6], nodeProjectedVertices[7]); | ||||
| 					canvas.gfx.lineTo(nodeProjectedVertices[0], nodeProjectedVertices[1]); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		public function createTree(staticObjects:Vector.<Object3D>, boundBox:BoundBox = null):void { | ||||
| 			var numStaticChildren:int = staticObjects.length; | ||||
| 			if (numStaticChildren > 0) { | ||||
| 				// Создаём корневую ноду | ||||
| 				rootNode = new Node(); | ||||
| 				rootNode.objects = new Vector.<Object3D>(); | ||||
| 				rootNode.bounds = new Vector.<BoundBox>(); | ||||
| 				rootNode.numObjects = 0; | ||||
| 				// Расчитываем баунды объектов и рутовой ноды | ||||
| 				rootNode.boundBox = (boundBox != null) ? boundBox : new BoundBox(); | ||||
| 				// Сначала добавляем не окклюдеры | ||||
| 				var staticOccluders:Vector.<Object3D> = new Vector.<Object3D>(); | ||||
| 				var staticOccludersLength:int = 0; | ||||
| 				var object:Object3D; | ||||
| 				var objectBoundBox:BoundBox; | ||||
| 				for (var i:int = 0; i < numStaticChildren; i++) { | ||||
| 					object = staticObjects[i]; | ||||
| 					// Поиск оригинального объекта | ||||
| 					var source:Object3D = object; | ||||
| 					while (source is Reference) { | ||||
| 						source = (source as Reference).referenceObject; | ||||
| 					} | ||||
| 					// Если окклюдер | ||||
| 					if (source is Occluder) { | ||||
| 						staticOccluders[staticOccludersLength++] = object; | ||||
| 					} else { | ||||
| 						objectBoundBox = object.calculateBoundBox(object.matrix); | ||||
| 						rootNode.objects[rootNode.numObjects] = object; | ||||
| 						rootNode.bounds[rootNode.numObjects++] = objectBoundBox; | ||||
| 						rootNode.boundBox.addBoundBox(objectBoundBox); | ||||
| 					} | ||||
| 				} | ||||
| 				// Добавляем окклюдеры | ||||
| 				for (i = 0; i < staticOccludersLength; i++) { | ||||
| 					object = staticOccluders[i]; | ||||
| 					objectBoundBox = object.calculateBoundBox(object.matrix); | ||||
| 					rootNode.objects[rootNode.numObjects] = object; | ||||
| 					rootNode.bounds[rootNode.numObjects++] = objectBoundBox; | ||||
| 					rootNode.boundBox.addBoundBox(objectBoundBox); | ||||
| 				} | ||||
| 				// Разделяем рутовую ноду | ||||
| 				splitNode(rootNode); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private var splitAxis:int; | ||||
| 		private var splitCoord:Number; | ||||
| 		private var splitCost:Number; | ||||
| 		static private const nodeBoundBoxThreshold:BoundBox = new BoundBox(); | ||||
| 		static private const splitCoordsX:Vector.<Number> = new Vector.<Number>(); | ||||
| 		static private const splitCoordsY:Vector.<Number> = new Vector.<Number>(); | ||||
| 		static private const splitCoordsZ:Vector.<Number> = new Vector.<Number>(); | ||||
| 		private function splitNode(node:Node):void { | ||||
|  | ||||
| 			var object:Object3D, boundBox:BoundBox, i:int, j:int, k:int, c1:Number, c2:Number, coordMin:Number, coordMax:Number, area:Number, areaNegative:Number, areaPositive:Number, numNegative:int, numPositive:int, conflict:Boolean, cost:Number; | ||||
| 			var nodeBoundBox:BoundBox = node.boundBox; | ||||
|  | ||||
| 			// Подготовка баунда с погрешностями | ||||
| 			nodeBoundBoxThreshold.minX = nodeBoundBox.minX + threshold; | ||||
| 			nodeBoundBoxThreshold.minY = nodeBoundBox.minY + threshold; | ||||
| 			nodeBoundBoxThreshold.minZ = nodeBoundBox.minZ + threshold; | ||||
| 			nodeBoundBoxThreshold.maxX = nodeBoundBox.maxX - threshold; | ||||
| 			nodeBoundBoxThreshold.maxY = nodeBoundBox.maxY - threshold; | ||||
| 			nodeBoundBoxThreshold.maxZ = nodeBoundBox.maxZ - threshold; | ||||
| 			var doubleThreshold:Number = threshold + threshold; | ||||
|  | ||||
| 			// Собираем опорные координаты | ||||
| 			var numSplitCoordsX:int = 0, numSplitCoordsY:int = 0, numSplitCoordsZ:int = 0; | ||||
| 			for (i = 0; i < node.numObjects; i++) { | ||||
| 				boundBox = node.bounds[i]; | ||||
| 				if (boundBox.maxX - boundBox.minX <= doubleThreshold) { | ||||
| 					if (boundBox.minX <= nodeBoundBoxThreshold.minX) splitCoordsX[numSplitCoordsX++] = nodeBoundBox.minX; | ||||
| 					else if (boundBox.maxX >= nodeBoundBoxThreshold.maxX) splitCoordsX[numSplitCoordsX++] = nodeBoundBox.maxX; | ||||
| 					else splitCoordsX[numSplitCoordsX++] = (boundBox.minX + boundBox.maxX)*0.5; | ||||
| 				} else { | ||||
| 					if (boundBox.minX > nodeBoundBoxThreshold.minX) splitCoordsX[numSplitCoordsX++] = boundBox.minX; | ||||
| 					if (boundBox.maxX < nodeBoundBoxThreshold.maxX) splitCoordsX[numSplitCoordsX++] = boundBox.maxX; | ||||
| 				} | ||||
| 				if (boundBox.maxY - boundBox.minY <= doubleThreshold) { | ||||
| 					if (boundBox.minY <= nodeBoundBoxThreshold.minY) splitCoordsY[numSplitCoordsY++] = nodeBoundBox.minY; | ||||
| 					else if (boundBox.maxY >= nodeBoundBoxThreshold.maxY) splitCoordsY[numSplitCoordsY++] = nodeBoundBox.maxY; | ||||
| 					else splitCoordsY[numSplitCoordsY++] = (boundBox.minY + boundBox.maxY)*0.5; | ||||
| 				} else { | ||||
| 					if (boundBox.minY > nodeBoundBoxThreshold.minY) splitCoordsY[numSplitCoordsY++] = boundBox.minY; | ||||
| 					if (boundBox.maxY < nodeBoundBoxThreshold.maxY) splitCoordsY[numSplitCoordsY++] = boundBox.maxY; | ||||
| 				} | ||||
| 				if (boundBox.maxZ - boundBox.minZ <= doubleThreshold) { | ||||
| 					if (boundBox.minZ <= nodeBoundBoxThreshold.minZ) splitCoordsZ[numSplitCoordsZ++] = nodeBoundBox.minZ; | ||||
| 					else if (boundBox.maxZ >= nodeBoundBoxThreshold.maxZ) splitCoordsZ[numSplitCoordsZ++] = nodeBoundBox.maxZ; | ||||
| 					else splitCoordsZ[numSplitCoordsZ++] = (boundBox.minZ + boundBox.maxZ)*0.5; | ||||
| 				} else { | ||||
| 					if (boundBox.minZ > nodeBoundBoxThreshold.minZ) splitCoordsZ[numSplitCoordsZ++] = boundBox.minZ; | ||||
| 					if (boundBox.maxZ < nodeBoundBoxThreshold.maxZ) splitCoordsZ[numSplitCoordsZ++] = boundBox.maxZ; | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			// Убираем дубликаты координат, ищем наилучший сплит | ||||
| 			splitAxis = -1; splitCost = Number.MAX_VALUE; | ||||
| 			i = 0; area = (nodeBoundBox.maxY - nodeBoundBox.minY)*(nodeBoundBox.maxZ - nodeBoundBox.minZ); | ||||
| 			while (i < numSplitCoordsX) { | ||||
| 				if (!isNaN(c1 = splitCoordsX[i++])) { | ||||
| 					coordMin = c1 - threshold; | ||||
| 					coordMax = c1 + threshold; | ||||
| 					areaNegative = area*(c1 - nodeBoundBox.minX); | ||||
| 					areaPositive = area*(nodeBoundBox.maxX - c1); | ||||
| 					numNegative = numPositive = 0; | ||||
| 					conflict = false; | ||||
| 					// Проверяем объекты | ||||
| 					for (j = 0; j < node.numObjects; j++) { | ||||
| 						boundBox = node.bounds[j]; | ||||
| 						if (boundBox.maxX <= coordMax) { | ||||
| 							if (boundBox.minX < coordMin) numNegative++; | ||||
| 						} else { | ||||
| 							if (boundBox.minX >= coordMin) numPositive++; else {conflict = true; break;} | ||||
| 						} | ||||
| 					} | ||||
| 					// Если хороший сплит, сохраняем | ||||
| 					if (!conflict && (cost = areaNegative*numNegative + areaPositive*numPositive) < splitCost) { | ||||
| 						splitCost = cost; | ||||
| 						splitAxis = 0; | ||||
| 						splitCoord = c1; | ||||
| 					} | ||||
| 					j = i; | ||||
| 					while (++j < numSplitCoordsX) if ((c2 = splitCoordsX[j]) >= c1 - threshold && c2 <= c1 + threshold) splitCoordsX[j] = NaN; | ||||
| 				}  | ||||
| 			} | ||||
| 			i = 0; area = (nodeBoundBox.maxX - nodeBoundBox.minX)*(nodeBoundBox.maxZ - nodeBoundBox.minZ); | ||||
| 			while (i < numSplitCoordsY) { | ||||
| 				if (!isNaN(c1 = splitCoordsY[i++])) { | ||||
| 					coordMin = c1 - threshold; | ||||
| 					coordMax = c1 + threshold; | ||||
| 					areaNegative = area*(c1 - nodeBoundBox.minY); | ||||
| 					areaPositive = area*(nodeBoundBox.maxY - c1); | ||||
| 					numNegative = numPositive = 0; | ||||
| 					conflict = false; | ||||
| 					// Проверяем объекты | ||||
| 					for (j = 0; j < node.numObjects; j++) { | ||||
| 						boundBox = node.bounds[j]; | ||||
| 						if (boundBox.maxY <= coordMax) { | ||||
| 							if (boundBox.minY < coordMin) numNegative++; | ||||
| 						} else { | ||||
| 							if (boundBox.minY >= coordMin) numPositive++; else {conflict = true; break;} | ||||
| 						} | ||||
| 					} | ||||
| 					// Если хороший сплит, сохраняем | ||||
| 					if (!conflict && (cost = areaNegative*numNegative + areaPositive*numPositive) < splitCost) { | ||||
| 						splitCost = cost; | ||||
| 						splitAxis = 1; | ||||
| 						splitCoord = c1; | ||||
| 					} | ||||
| 					j = i; | ||||
| 					while (++j < numSplitCoordsY) if ((c2 = splitCoordsY[j]) >= c1 - threshold && c2 <= c1 + threshold) splitCoordsY[j] = NaN; | ||||
| 				}  | ||||
| 			} | ||||
| 			i = 0; area = (nodeBoundBox.maxX - nodeBoundBox.minX)*(nodeBoundBox.maxY - nodeBoundBox.minY); | ||||
| 			while (i < numSplitCoordsZ) { | ||||
| 				if (!isNaN(c1 = splitCoordsZ[i++])) { | ||||
| 					coordMin = c1 - threshold; | ||||
| 					coordMax = c1 + threshold; | ||||
| 					areaNegative = area*(c1 - nodeBoundBox.minZ); | ||||
| 					areaPositive = area*(nodeBoundBox.maxZ - c1); | ||||
| 					numNegative = numPositive = 0; | ||||
| 					conflict = false; | ||||
| 					// Проверяем объекты | ||||
| 					for (j = 0; j < node.numObjects; j++) { | ||||
| 						boundBox = node.bounds[j]; | ||||
| 						if (boundBox.maxZ <= coordMax) { | ||||
| 							if (boundBox.minZ < coordMin) numNegative++; | ||||
| 						} else { | ||||
| 							if (boundBox.minZ >= coordMin) numPositive++; else {conflict = true; break;} | ||||
| 						} | ||||
| 					} | ||||
| 					// Если хороший сплит, сохраняем | ||||
| 					if (!conflict && (cost = areaNegative*numNegative + areaPositive*numPositive) < splitCost) { | ||||
| 						splitCost = cost; | ||||
| 						splitAxis = 2; | ||||
| 						splitCoord = c1; | ||||
| 					} | ||||
| 					j = i; | ||||
| 					while (++j < numSplitCoordsZ) if ((c2 = splitCoordsZ[j]) >= c1 - threshold && c2 <= c1 + threshold) splitCoordsZ[j] = NaN; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			// Если сплит не найден, выходим | ||||
| 			if (splitAxis < 0) { | ||||
| 				// Находим, откуда начинаются окклюдеры | ||||
| 				for (i = 0; i < node.numObjects; i++) { | ||||
| 					object = node.objects[i]; | ||||
| 					// Поиск оригинального объекта | ||||
| 					while (object is Reference) object = (object as Reference).referenceObject; | ||||
| 					if (object is Occluder) break; | ||||
| 				} | ||||
| 				node.numNonOccluders = i; | ||||
| 				return; | ||||
| 			} | ||||
| 			 | ||||
| 			// Разделяем ноду | ||||
| 			if (splitAxis == 0) { | ||||
| 				node.normalX = 1; | ||||
| 				node.normalY = 0; | ||||
| 				node.normalZ = 0; | ||||
| 			} else if (splitAxis == 1) { | ||||
| 				node.normalX = 0; | ||||
| 				node.normalY = 1; | ||||
| 				node.normalZ = 0; | ||||
| 			} else { | ||||
| 				node.normalX = 0; | ||||
| 				node.normalY = 0; | ||||
| 				node.normalZ = 1; | ||||
| 			} | ||||
| 			node.offset = splitCoord; | ||||
| 			node.offsetMin = splitCoord - threshold; | ||||
| 			node.offsetMax = splitCoord + threshold; | ||||
| 			 | ||||
| 			// Создаём дочерние ноды | ||||
| 			node.negative = new Node(); | ||||
| 			node.positive = new Node(); | ||||
| 			node.negative.boundBox = nodeBoundBox.clone(); | ||||
| 			node.positive.boundBox = nodeBoundBox.clone(); | ||||
| 			node.negative.numObjects = 0; | ||||
| 			node.positive.numObjects = 0; | ||||
| 			if (node.normalX) { | ||||
| 				node.negative.boundBox.maxX = node.positive.boundBox.minX = splitCoord; | ||||
| 			} else if (node.normalY) { | ||||
| 				node.negative.boundBox.maxY = node.positive.boundBox.minY = splitCoord; | ||||
| 			} else { | ||||
| 				node.negative.boundBox.maxZ = node.positive.boundBox.minZ = splitCoord; | ||||
| 			} | ||||
| 			// Распределяем объекты по дочерним нодам | ||||
| 			for (i = 0; i < node.numObjects; i++) { | ||||
| 				object = node.objects[i]; | ||||
| 				boundBox = node.bounds[i]; | ||||
| 				var min:Number = node.normalX ? boundBox.minX : (node.normalY ? boundBox.minY : boundBox.minZ); | ||||
| 				var max:Number = node.normalX ? boundBox.maxX : (node.normalY ? boundBox.maxY : boundBox.maxZ); | ||||
| 				if (max <= node.offsetMax) { | ||||
| 					if (min < node.offsetMin) { | ||||
| 						// Объект в негативной стороне | ||||
| 						if (node.negative.objects == null) node.negative.objects = new Vector.<Object3D>(), node.negative.bounds = new Vector.<BoundBox>(); | ||||
| 						node.negative.objects[node.negative.numObjects] = object, node.negative.bounds[node.negative.numObjects++] = boundBox; | ||||
| 						node.objects[i] = null, node.bounds[i] = null; | ||||
| 					} else { | ||||
| 						// Остаётся в ноде | ||||
| 					} | ||||
| 				} else { | ||||
| 					if (min >= node.offsetMin) { | ||||
| 						// Объект в положительной стороне | ||||
| 						if (node.positive.objects == null) node.positive.objects = new Vector.<Object3D>(), node.positive.bounds = new Vector.<BoundBox>(); | ||||
| 						node.positive.objects[node.positive.numObjects] = object, node.positive.bounds[node.positive.numObjects++] = boundBox; | ||||
| 						node.objects[i] = null, node.bounds[i] = null; | ||||
| 					} else { | ||||
| 						// Распилился | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			// Очистка списка объектов | ||||
| 			for (i = 0, j = 0; i < node.numObjects; i++) if (node.objects[i] != null) node.objects[j] = node.objects[i], node.bounds[j++] = node.bounds[i]; | ||||
| 			if (j > 0) { | ||||
| 				node.numObjects = node.objects.length = node.bounds.length = j; | ||||
| 				// Находим, откуда начинаются окклюдеры | ||||
| 				for (i = 0; i < node.numObjects; i++) { | ||||
| 					object = node.objects[i]; | ||||
| 					// Поиск оригинального объекта | ||||
| 					while (object is Reference) object = (object as Reference).referenceObject; | ||||
| 					if (object is Occluder) break; | ||||
| 				} | ||||
| 				node.numNonOccluders = i; | ||||
| 			} else { | ||||
| 				node.numObjects = node.numNonOccluders = 0, node.objects = null, node.bounds = null; | ||||
| 			} | ||||
| 			 | ||||
| 			// Разделение дочерних нод | ||||
| 			if (node.negative.objects != null) splitNode(node.negative); | ||||
| 			if (node.positive.objects != null) splitNode(node.positive); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,141 +0,0 @@ | ||||
| package alternativa.engine3d.containers { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.core.Object3DContainer; | ||||
| 	import alternativa.engine3d.objects.Mesh; | ||||
| 	 | ||||
| 	import flash.display.BitmapData; | ||||
| 	 | ||||
| 	public class SkyBox extends Object3DContainer { | ||||
| 		 | ||||
| 		private var backPlane:Mesh; | ||||
| 		private var frontPlane:Mesh; | ||||
| 		private var topPlane:Mesh; | ||||
| 		private var bottomPlane:Mesh; | ||||
| 		private var leftPlane:Mesh; | ||||
| 		private var rightPlane:Mesh; | ||||
| 		 | ||||
| 		public function SkyBox(size:Number = 1000):void { | ||||
| 			backPlane = new Mesh(); | ||||
| 			frontPlane = new Mesh(); | ||||
| 			topPlane = new Mesh(); | ||||
| 			bottomPlane = new Mesh(); | ||||
| 			leftPlane = new Mesh(); | ||||
| 			rightPlane = new Mesh(); | ||||
| 			 | ||||
| 			backPlane.clipping = 2; | ||||
| 			frontPlane.clipping = 2; | ||||
| 			topPlane.clipping = 2; | ||||
| 			bottomPlane.clipping = 2; | ||||
| 			leftPlane.clipping = 2; | ||||
| 			rightPlane.clipping = 2; | ||||
| 			 | ||||
| 			backPlane.vertices = Vector.<Number>([ | ||||
| 				-size, -size, -size, | ||||
| 				-size, -size, size, | ||||
| 				size, -size, size, | ||||
| 				size, -size, -size, | ||||
| 			]); | ||||
| 			frontPlane.vertices = Vector.<Number>([ | ||||
| 				size, size, -size, | ||||
| 				size, size, size, | ||||
| 				-size, size, size, | ||||
| 				-size, size, -size, | ||||
| 			]); | ||||
| 			topPlane.vertices = Vector.<Number>([ | ||||
| 				size, size, size, | ||||
| 				size, -size, size, | ||||
| 				-size, -size, size, | ||||
| 				-size, size, size, | ||||
| 			]); | ||||
| 			bottomPlane.vertices = Vector.<Number>([ | ||||
| 				size, -size, -size, | ||||
| 				size, size, -size, | ||||
| 				-size, size, -size, | ||||
| 				-size, -size, -size, | ||||
| 			]); | ||||
| 			leftPlane.vertices = Vector.<Number>([ | ||||
| 				-size, size, -size, | ||||
| 				-size, size, size, | ||||
| 				-size, -size, size, | ||||
| 				-size, -size, -size, | ||||
| 			]); | ||||
| 			rightPlane.vertices = Vector.<Number>([ | ||||
| 				size, -size, -size, | ||||
| 				size, -size, size, | ||||
| 				size, size, size, | ||||
| 				size, size, -size, | ||||
| 			]); | ||||
| 			 | ||||
| 			var uvts:Vector.<Number> = Vector.<Number>([1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0]);  | ||||
| 			backPlane.uvts = uvts; | ||||
| 			frontPlane.uvts = uvts; | ||||
| 			topPlane.uvts = uvts; | ||||
| 			bottomPlane.uvts = uvts; | ||||
| 			leftPlane.uvts = uvts; | ||||
| 			rightPlane.uvts = uvts; | ||||
|  | ||||
| 			var indices:Vector.<int> = Vector.<int>([4, 0, 1, 2, 3]);  | ||||
| 			backPlane.indices = indices; | ||||
| 			frontPlane.indices = indices; | ||||
| 			topPlane.indices = indices; | ||||
| 			bottomPlane.indices = indices; | ||||
| 			leftPlane.indices = indices; | ||||
| 			rightPlane.indices = indices; | ||||
|  | ||||
| 			backPlane.numVertices = 4; | ||||
| 			frontPlane.numVertices = 4; | ||||
| 			topPlane.numVertices = 4; | ||||
| 			bottomPlane.numVertices = 4; | ||||
| 			leftPlane.numVertices = 4; | ||||
| 			rightPlane.numVertices = 4; | ||||
|  | ||||
| 			backPlane.numFaces = 1; | ||||
| 			frontPlane.numFaces = 1; | ||||
| 			topPlane.numFaces = 1; | ||||
| 			bottomPlane.numFaces = 1; | ||||
| 			leftPlane.numFaces = 1; | ||||
| 			rightPlane.numFaces = 1; | ||||
|  | ||||
| 			backPlane.poly = true; | ||||
| 			frontPlane.poly = true; | ||||
| 			topPlane.poly = true; | ||||
| 			bottomPlane.poly = true; | ||||
| 			leftPlane.poly = true; | ||||
| 			rightPlane.poly = true; | ||||
|  | ||||
| 			addChild(backPlane); | ||||
| 			addChild(frontPlane); | ||||
| 			addChild(topPlane); | ||||
| 			addChild(bottomPlane); | ||||
| 			addChild(leftPlane); | ||||
| 			addChild(rightPlane); | ||||
| 		} | ||||
| 		 | ||||
| 		public function set backTexture(value:BitmapData):void { | ||||
| 			backPlane.texture = value; | ||||
| 		} | ||||
|  | ||||
| 		public function set frontTexture(value:BitmapData):void { | ||||
| 			frontPlane.texture = value; | ||||
| 		} | ||||
|  | ||||
| 		public function set topTexture(value:BitmapData):void { | ||||
| 			topPlane.texture = value; | ||||
| 		} | ||||
|  | ||||
| 		public function set bottomTexture(value:BitmapData):void { | ||||
| 			bottomPlane.texture = value; | ||||
| 		} | ||||
|  | ||||
| 		public function set leftTexture(value:BitmapData):void { | ||||
| 			leftPlane.texture = value; | ||||
| 		} | ||||
|  | ||||
| 		public function set rightTexture(value:BitmapData):void { | ||||
| 			rightPlane.texture = value; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,48 +0,0 @@ | ||||
| package alternativa.engine3d.containers { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	import alternativa.engine3d.core.Object3DContainer; | ||||
| 	 | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Vector3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class SplitContainer extends Object3DContainer { | ||||
| 		 | ||||
| 		public var splitPlane:Vector3D = new Vector3D(0, 0, 1, 0); | ||||
| 		static private const invertCameraMatrix:Matrix3D = new Matrix3D(); | ||||
| 		static private const cameraPosition:Vector.<Number> = Vector.<Number>([0, 0, 0]); | ||||
| 		static private const invertCameraPosition:Vector.<Number> = new Vector.<Number>(3, true);		 | ||||
| 		 | ||||
| 		override protected function drawVisibleChildren(camera:Camera3D, object:Object3D, canvas:Canvas):void { | ||||
| 			var i:int; | ||||
| 			var child:Object3D; | ||||
| 			invertCameraMatrix.identity(); | ||||
| 			invertCameraMatrix.prepend(object.cameraMatrix); | ||||
| 			invertCameraMatrix.invert(); | ||||
| 			invertCameraMatrix.transformVectors(cameraPosition, invertCameraPosition); | ||||
| 			if (invertCameraPosition[0]*splitPlane.x + invertCameraPosition[1]*splitPlane.y + invertCameraPosition[2]*splitPlane.z < splitPlane.w) { | ||||
| 				for (i = 0; i < numVisibleChildren; i++) { | ||||
| 					child = visibleChildren[i]; | ||||
| 					if (camera.debugMode) child.debug(camera, child, canvas); | ||||
| 					child.draw(camera, child, canvas); | ||||
| 					visibleChildren[i] = null; | ||||
| 				} | ||||
| 			} else { | ||||
| 				for (i = numVisibleChildren - 1; i >= 0; i--) { | ||||
| 					child = visibleChildren[i]; | ||||
| 					if (camera.debugMode) child.debug(camera, child, canvas); | ||||
| 					child.draw(camera, child, canvas); | ||||
| 					visibleChildren[i] = null; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 109 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/controllers | ||||
| END | ||||
| SimpleObjectController.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 135 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/controllers/SimpleObjectController.as | ||||
| END | ||||
| @@ -1,40 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/controllers | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-07-09T12:53:17.549217Z | ||||
| 16221 | ||||
| int | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| SimpleObjectController.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 850afc2a3acec3ceff3924b122dabc29 | ||||
| 2009-07-09T12:53:17.549217Z | ||||
| 16221 | ||||
| int | ||||
|  | ||||
| @@ -1,454 +0,0 @@ | ||||
| package alternativa.engine3d.controllers { | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.display.InteractiveObject; | ||||
| 	import flash.events.KeyboardEvent; | ||||
| 	import flash.events.MouseEvent; | ||||
| 	import flash.geom.Point; | ||||
| 	import flash.geom.Vector3D; | ||||
| 	import flash.ui.Keyboard; | ||||
| 	import flash.utils.getTimer; | ||||
| 	 | ||||
| 	/** | ||||
| 	 *  | ||||
| 	 */ | ||||
| 	public class SimpleObjectController { | ||||
|  | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш движения вперёд. | ||||
| 		 */ | ||||
| 		public static const ACTION_FORWARD:String = "ACTION_FORWARD"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш движения назад. | ||||
| 		 */ | ||||
| 		public static const ACTION_BACK:String = "ACTION_BACK"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш движения влево. | ||||
| 		 */ | ||||
| 		public static const ACTION_LEFT:String = "ACTION_LEFT"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш движения вправо. | ||||
| 		 */ | ||||
| 		public static const ACTION_RIGHT:String = "ACTION_RIGHT"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш движения вверх. | ||||
| 		 */ | ||||
| 		public static const ACTION_UP:String = "ACTION_UP"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш движения вниз. | ||||
| 		 */ | ||||
| 		public static const ACTION_DOWN:String = "ACTION_DOWN"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш поворота вверх. | ||||
| 		 */ | ||||
| 		public static const ACTION_PITCH_UP:String = "ACTION_PITCH_UP"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш поворота вниз. | ||||
| 		 */ | ||||
| 		public static const ACTION_PITCH_DOWN:String = "ACTION_PITCH_DOWN"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш поворота налево. | ||||
| 		 */ | ||||
| 		public static const ACTION_YAW_LEFT:String = "ACTION_YAW_LEFT"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш поворота направо. | ||||
| 		 */ | ||||
| 		public static const ACTION_YAW_RIGHT:String = "ACTION_YAW_RIGHT"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш увеличения скорости. | ||||
| 		 */ | ||||
| 		public static const ACTION_ACCELERATE:String = "ACTION_ACCELERATE"; | ||||
| 		/** | ||||
| 		 * Имя действия для привязки клавиш активации обзора мышью. | ||||
| 		 */ | ||||
| 		public static const ACTION_MOUSE_LOOK:String = "ACTION_MOUSE_LOOK"; | ||||
|  | ||||
| 		 | ||||
| 		public var speed:Number; | ||||
| 		public var speedMultiplier:Number; | ||||
| 		public var mouseSensitivity:Number; | ||||
| 		public var maxPitch:Number = Number.MAX_VALUE; | ||||
| 		public var minPitch:Number = -Number.MAX_VALUE; | ||||
| 		 | ||||
| 		private var eventSource:InteractiveObject; | ||||
| 		private var _object:Object3D; | ||||
| 		 | ||||
| 		private var _up:Boolean; | ||||
| 		private var _down:Boolean; | ||||
| 		private var _forward:Boolean; | ||||
| 		private var _back:Boolean; | ||||
| 		private var _left:Boolean; | ||||
| 		private var _right:Boolean; | ||||
| 		private var _accelerate:Boolean; | ||||
|  | ||||
| 		private var displacement:Vector3D = new Vector3D(); | ||||
| 		private var mousePoint:Point = new Point(); | ||||
| 		private var mouseLook:Boolean; | ||||
| 		private var objectTransform:Vector.<Vector3D>; | ||||
| 		 | ||||
| 		private var time:int; | ||||
|  | ||||
| 		/** | ||||
| 		 * Ассоциативный массив, связывающий имена команд с реализующими их функциями. Функции должны иметь вид | ||||
| 		 * function(value:Boolean):void. Значение параметра <code>value</code> указывает, нажата или отпущена соответсвующая команде | ||||
| 		 * клавиша. | ||||
| 		 */ | ||||
| 		private var actionBindings:Object = {}; | ||||
| 		/** | ||||
| 		 * Ассоциативный массив, связывающий коды клавиатурных клавиш с именами команд. | ||||
| 		 */ | ||||
| 		protected var keyBindings:Object = {}; | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param eventSource источник событий для контроллера | ||||
| 		 * @param speed скорость поступательного перемещения объекта | ||||
| 		 * @param mouseSensitivity чувствительность мыши - количество градусов поворота на один пиксель перемещения мыши | ||||
| 		 */ | ||||
| 		public function SimpleObjectController(eventSource:InteractiveObject, object:Object3D, speed:Number, speedMultiplier:Number = 3, mouseSensitivity:Number = 1) { | ||||
| 			this.eventSource = eventSource; | ||||
| 			this.object = object; | ||||
| 			this.speed = speed; | ||||
| 			this.speedMultiplier = speedMultiplier; | ||||
| 			this.mouseSensitivity = mouseSensitivity; | ||||
|  | ||||
| 			actionBindings[ACTION_FORWARD] = moveForward; | ||||
| 			actionBindings[ACTION_BACK] = moveBack; | ||||
| 			actionBindings[ACTION_LEFT] = moveLeft; | ||||
| 			actionBindings[ACTION_RIGHT] = moveRight; | ||||
| 			actionBindings[ACTION_UP] = moveUp; | ||||
| 			actionBindings[ACTION_DOWN] = moveDown; | ||||
| 			actionBindings[ACTION_ACCELERATE] = accelerate; | ||||
| 			 | ||||
| 			setDefaultBindings(); | ||||
|  | ||||
| 			enable(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Активирует контроллер. | ||||
| 		 */ | ||||
| 		public function enable():void { | ||||
| 			eventSource.addEventListener(KeyboardEvent.KEY_DOWN, onKey); | ||||
| 			eventSource.addEventListener(KeyboardEvent.KEY_UP, onKey); | ||||
| 			eventSource.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); | ||||
| 			eventSource.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Дективирует контроллер. | ||||
| 		 */ | ||||
| 		public function disable():void { | ||||
| 			eventSource.removeEventListener(KeyboardEvent.KEY_DOWN, onKey); | ||||
| 			eventSource.removeEventListener(KeyboardEvent.KEY_UP, onKey); | ||||
| 			eventSource.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); | ||||
| 			eventSource.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); | ||||
| 			stopMouseLook(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function onMouseDown(e:MouseEvent):void { | ||||
| 			startMouseLook(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function onMouseUp(e:MouseEvent):void { | ||||
| 			stopMouseLook(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Включает режим взгляда мышью. | ||||
| 		 */ | ||||
| 		public function startMouseLook():void { | ||||
| 			mousePoint.x = eventSource.mouseX; | ||||
| 			mousePoint.y = eventSource.mouseY; | ||||
| 			mouseLook = true; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Отключает режим взгляда мышью. | ||||
| 		 */ | ||||
| 		public function stopMouseLook():void { | ||||
| 			mouseLook = false; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * | ||||
| 		 */ | ||||
| 		private function onKey(e:KeyboardEvent):void { | ||||
| 			var method:Function = keyBindings[e.keyCode]; | ||||
| 			if (method != null) method.call(this, e.type == KeyboardEvent.KEY_DOWN); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Управляемый объект. | ||||
| 		 */ | ||||
| 		public function set object(value:Object3D):void { | ||||
| 			_object = value; | ||||
| 			updateObjectTransform(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		public function get object():Object3D { | ||||
| 			return _object; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Обновляет инофрмацию о трансформации объекта. Метод следует вызывать после изменения матрицы объекта вне контролллера.  | ||||
| 		 */ | ||||
| 		public function updateObjectTransform():void { | ||||
| 			if (_object != null) objectTransform = _object.matrix.decompose(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Вычисляет новое положение объекта, используя внутренний счётчик времени.  | ||||
| 		 */ | ||||
| 		public function update():void { | ||||
| 			if (_object == null) return; | ||||
| 			 | ||||
| 			var frameTime:Number = time; | ||||
| 			time = getTimer(); | ||||
| 			frameTime = 0.001*(time - frameTime); | ||||
| 			if (frameTime > 0.1) frameTime = 0.1; | ||||
| 			 | ||||
| 			var moved:Boolean = false; | ||||
| 			 | ||||
| 			if (mouseLook) { | ||||
| 				var dx:Number = eventSource.mouseX - mousePoint.x; | ||||
| 				var dy:Number = eventSource.mouseY - mousePoint.y; | ||||
| 				mousePoint.x = eventSource.mouseX; | ||||
| 				mousePoint.y = eventSource.mouseY; | ||||
| 				var v:Vector3D = objectTransform[1]; | ||||
| 				v.x -= dy*Math.PI/180*mouseSensitivity; | ||||
| 				if (v.x > maxPitch) v.x = maxPitch; | ||||
| 				if (v.x < minPitch) v.x = minPitch; | ||||
| 				v.z -= dx*Math.PI/180*mouseSensitivity; | ||||
| 				moved = true; | ||||
| 			} | ||||
| 			 | ||||
| 			displacement.x = _right ? 1 : (_left ? -1 : 0); | ||||
| 			displacement.y = _forward ? 1 : (_back ? -1 : 0); | ||||
| 			displacement.z = _up ? 1 : (_down ? -1 : 0); | ||||
| 			if (displacement.lengthSquared > 0) { | ||||
| 				if (_object is Camera3D) { | ||||
| 					var tmp:Number = displacement.z; | ||||
| 					displacement.z = displacement.y; | ||||
| 					displacement.y = -tmp; | ||||
| 				} | ||||
| 				deltaTransformVector(displacement); | ||||
| 				if (_accelerate) displacement.scaleBy(speedMultiplier*speed*frameTime/displacement.length); | ||||
| 				else displacement.scaleBy(speed*frameTime/displacement.length); | ||||
| 				(objectTransform[0] as Vector3D).incrementBy(displacement); | ||||
| 				moved = true; | ||||
| 			} | ||||
| 			 | ||||
| 			if (moved) _object.matrix.recompose(objectTransform); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param pos | ||||
| 		 */ | ||||
| 		public function setObjectPos(pos:Vector3D):void { | ||||
| 			if (_object != null) { | ||||
| 				var v:Vector3D = objectTransform[0]; | ||||
| 				v.x = pos.x; | ||||
| 				v.y = pos.y; | ||||
| 				v.z = pos.z; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param pos | ||||
| 		 */ | ||||
| 		public function setObjectPosXYZ(x:Number, y:Number, z:Number):void { | ||||
| 			if (_object != null) { | ||||
| 				var v:Vector3D = objectTransform[0]; | ||||
| 				v.x = x; | ||||
| 				v.y = y; | ||||
| 				v.z = z; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param point | ||||
| 		 */ | ||||
| 		public function lookAt(point:Vector3D):void { | ||||
| 			lookAtXYZ(point.x, point.y, point.z); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param x | ||||
| 		 * @param y | ||||
| 		 * @param z | ||||
| 		 */ | ||||
| 		public function lookAtXYZ(x:Number, y:Number, z:Number):void { | ||||
| 			if (_object == null) return; | ||||
| 			var v:Vector3D = objectTransform[0]; | ||||
| 			var dx:Number = x - v.x; | ||||
| 			var dy:Number = y - v.y; | ||||
| 			var dz:Number = z - v.z; | ||||
| 			v = objectTransform[1]; | ||||
| 			v.x = Math.atan2(dz, Math.sqrt(dx*dx + dy*dy)); | ||||
| 			if (_object is Camera3D) v.x -= 0.5*Math.PI; | ||||
| 			v.y = 0; | ||||
| 			v.z = -Math.atan2(dx, dy); | ||||
| 			_object.matrix.recompose(objectTransform); | ||||
| 		} | ||||
| 		 | ||||
| 		private var _vin:Vector.<Number> = new Vector.<Number>(3); | ||||
| 		private var _vout:Vector.<Number> = new Vector.<Number>(3); | ||||
| 		 | ||||
| 		private function deltaTransformVector(v:Vector3D):void { | ||||
| 			_vin[0] = v.x; | ||||
| 			_vin[1] = v.y; | ||||
| 			_vin[2] = v.z; | ||||
| 			_object.matrix.transformVectors(_vin, _vout); | ||||
| 			var c:Vector3D = objectTransform[0]; | ||||
| 			v.x = _vout[0] - c.x; | ||||
| 			v.y = _vout[1] - c.y; | ||||
| 			v.z = _vout[2] - c.z; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Активация движения вперёд. | ||||
| 		 *  | ||||
| 		 * @param value <code>true</code> для начала движения, <code>false</code> для окончания | ||||
| 		 */ | ||||
| 		public function moveForward(value:Boolean):void { | ||||
| 			_forward = value; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Активация движения назад. | ||||
| 		 *  | ||||
| 		 * @param value <code>true</code> для начала движения, <code>false</code> для окончания | ||||
| 		 */ | ||||
| 		public function moveBack(value:Boolean):void { | ||||
| 			_back = value; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Активация движения влево. | ||||
| 		 *  | ||||
| 		 * @param value <code>true</code> для начала движения, <code>false</code> для окончания | ||||
| 		 */ | ||||
| 		public function moveLeft(value:Boolean):void { | ||||
| 			_left = value; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Активация движения вправо. | ||||
| 		 *  | ||||
| 		 * @param value <code>true</code> для начала движения, <code>false</code> для окончания | ||||
| 		 */ | ||||
| 		public function moveRight(value:Boolean):void { | ||||
| 			_right = value; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Активация движения вверх. | ||||
| 		 *  | ||||
| 		 * @param value <code>true</code> для начала движения, <code>false</code> для окончания | ||||
| 		 */ | ||||
| 		public function moveUp(value:Boolean):void { | ||||
| 			_up = value; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Активация движения вниз. | ||||
| 		 *  | ||||
| 		 * @param value <code>true</code> для начала движения, <code>false</code> для окончания | ||||
| 		 */ | ||||
| 		public function moveDown(value:Boolean):void { | ||||
| 			_down = value; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Активация режима увеличенной скорости. | ||||
| 		 *  | ||||
| 		 * @param value <code>true</code> для включения ускорения, <code>false</code> для выключения | ||||
| 		 */ | ||||
| 		public function accelerate(value:Boolean):void { | ||||
| 			_accelerate = value; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Метод выполняет привязку клавиши к действию. Одной клавише может быть назначено только одно действие. | ||||
| 		 *  | ||||
| 		 * @param keyCode код клавиши | ||||
| 		 * @param action наименование действия | ||||
| 		 *  | ||||
| 		 * @see #unbindKey() | ||||
| 		 * @see #unbindAll() | ||||
| 		 */ | ||||
| 		public function bindKey(keyCode:uint, action:String):void { | ||||
| 			var method:Function = actionBindings[action]; | ||||
| 			if (method != null) keyBindings[keyCode] = method; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		public function bindKeys(bindings:Array):void { | ||||
| 			for (var i:int = 0; i < bindings.length; i += 2) bindKey(bindings[i], bindings[i + 1]); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Очистка привязки клавиши. | ||||
| 		 *  | ||||
| 		 * @param keyCode код клавиши | ||||
| 		 *  | ||||
| 		 * @see #bindKey() | ||||
| 		 * @see #unbindAll() | ||||
| 		 */ | ||||
| 		public function unbindKey(keyCode:uint):void { | ||||
| 			delete keyBindings[keyCode]; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Очистка привязки всех клавиш. | ||||
| 		 *  | ||||
| 		 * @see #bindKey() | ||||
| 		 * @see #unbindKey() | ||||
| 		 */ | ||||
| 		public function unbindAll():void { | ||||
| 			for (var key:* in keyBindings) delete keyBindings[key]; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Метод устанавливает привязки клавиш по умолчанию. Реализация по умолчанию не делает ничего. | ||||
| 		 *  | ||||
| 		 * @see #bindKey() | ||||
| 		 * @see #unbindKey() | ||||
| 		 * @see #unbindAll() | ||||
| 		 */ | ||||
| 		public function setDefaultBindings():void { | ||||
| 			bindKey(87, ACTION_FORWARD); | ||||
| 			bindKey(83, ACTION_BACK); | ||||
| 			bindKey(65, ACTION_LEFT); | ||||
| 			bindKey(68, ACTION_RIGHT); | ||||
| 			bindKey(69, ACTION_UP); | ||||
| 			bindKey(67, ACTION_DOWN); | ||||
| 			bindKey(Keyboard.SHIFT, ACTION_ACCELERATE); | ||||
|  | ||||
| 			bindKey(Keyboard.UP, ACTION_FORWARD); | ||||
| 			bindKey(Keyboard.DOWN, ACTION_BACK); | ||||
| 			bindKey(Keyboard.LEFT, ACTION_LEFT); | ||||
| 			bindKey(Keyboard.RIGHT, ACTION_RIGHT); | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,89 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 102 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core | ||||
| END | ||||
| BackfaceCulling.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 121 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/BackfaceCulling.as | ||||
| END | ||||
| Object3D.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 114 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Object3D.as | ||||
| END | ||||
| Camera3D.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 114 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Camera3D.as | ||||
| END | ||||
| BoundBox.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 114 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/BoundBox.as | ||||
| END | ||||
| Object3DContainer.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 123 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Object3DContainer.as | ||||
| END | ||||
| MipMapping.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 116 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/MipMapping.as | ||||
| END | ||||
| Fragment.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 114 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Fragment.as | ||||
| END | ||||
| MipMap.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 112 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/MipMap.as | ||||
| END | ||||
| Clipping.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 114 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Clipping.as | ||||
| END | ||||
| Node.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 110 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Node.as | ||||
| END | ||||
| Sorting.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 113 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Sorting.as | ||||
| END | ||||
| Debug.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 111 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Debug.as | ||||
| END | ||||
| Canvas.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 112 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Canvas.as | ||||
| END | ||||
| Geometry.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 114 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core/Geometry.as | ||||
| END | ||||
| @@ -1,200 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/core | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-10-19T11:39:18.186364Z | ||||
| 22296 | ||||
| int | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| BackfaceCulling.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 7bea5cb8c30609d1e38c7511b4bb29f4 | ||||
| 2009-10-16T12:40:21.746295Z | ||||
| 22165 | ||||
| int | ||||
|  | ||||
| Object3D.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 2bdfdaa15f7c223f49895e000158fd7f | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Camera3D.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| d239950295dbf063016f345efb243b2e | ||||
| 2009-10-15T16:06:18.552844Z | ||||
| 22065 | ||||
| int | ||||
|  | ||||
| BoundBox.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 7c4d9b43878d419d034e6d20484b9564 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Object3DContainer.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 7e7d9af7577428ba82dfa9655ce6265f | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
|  | ||||
| MipMapping.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| bc8aa0796ff6fe7bc165e58e3c81f4a7 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
|  | ||||
| Fragment.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 0766b94a07ef7298ece02c2161616871 | ||||
| 2009-10-18T13:22:08.786837Z | ||||
| 22234 | ||||
| int | ||||
|  | ||||
| MipMap.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 257d1c88bd8bf829ecb9c9d1a9349e99 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
|  | ||||
| Clipping.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 9e7c045c894b1c0f59c244baa23319c6 | ||||
| 2009-10-16T11:48:05.744366Z | ||||
| 22160 | ||||
| int | ||||
|  | ||||
| Node.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 0808882f8440b9c9e5e0488afc181bbd | ||||
| 2009-10-19T11:39:18.186364Z | ||||
| 22296 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Sorting.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 72006aa7f32e39a9d7b5693042c1c903 | ||||
| 2009-10-16T11:48:05.744366Z | ||||
| 22160 | ||||
| int | ||||
|  | ||||
| Debug.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 4d8de4fb9b1c0b0683861df1042fcc13 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
|  | ||||
| Canvas.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 0a3bab96a01540f24aea3a9381b37c3a | ||||
| 2009-10-18T09:57:48.052564Z | ||||
| 22208 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Geometry.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 6eed84f0a8ff5f7851c2de69863ea27a | ||||
| 2009-10-18T15:44:36.557045Z | ||||
| 22247 | ||||
| int | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 8 | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 842 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/bounds/BoundBox.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/core/BoundBox.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/bounds/BoundBox.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/bounds/BoundBox.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/bounds/BoundBox.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/bounds/BoundBox.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/bounds/BoundBox.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,5 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 119 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/core/Canvas.as:17447,17456-18883 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 816 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/KDNode.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/core/KDNode.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/KDNode.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/KDNode.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/KDNode.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/KDNode.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/KDNode.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,10 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 718 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/core/Object3D.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/Object3D.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/Object3D.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/Object3D.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/Object3D.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/Object3D.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,15 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	public class BackfaceCulling { | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Отсечение по динамически расчитываемым нормалям.  | ||||
| 		 */ | ||||
| 		static public const DYNAMIC_NORMALS:int = 0; | ||||
| 		/** | ||||
| 		 * Отсечение по предрасчитанным нормалям.  | ||||
| 		 */ | ||||
| 		static public const STATIC_NORMALS:int = 1; | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,67 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	 | ||||
| 	public class BoundBox { | ||||
| 		 | ||||
| 		public var minX:Number = Number.MAX_VALUE; | ||||
| 		public var minY:Number = Number.MAX_VALUE; | ||||
| 		public var minZ:Number = Number.MAX_VALUE; | ||||
| 		public var maxX:Number = -Number.MAX_VALUE; | ||||
| 		public var maxY:Number = -Number.MAX_VALUE; | ||||
| 		public var maxZ:Number = -Number.MAX_VALUE; | ||||
| 		 | ||||
| 		public function setSize(minX:Number, minY:Number, minZ:Number, maxX:Number, maxY:Number, maxZ:Number):void { | ||||
| 			this.minX = minX; | ||||
| 			this.minY = minY; | ||||
| 			this.minZ = minZ; | ||||
| 			this.maxX = maxX; | ||||
| 			this.maxY = maxY; | ||||
| 			this.maxZ = maxZ; | ||||
| 		} | ||||
|  | ||||
| 		public function addBoundBox(boundBox:BoundBox):void { | ||||
| 			minX = (boundBox.minX < minX) ? boundBox.minX : minX; | ||||
| 			minY = (boundBox.minY < minY) ? boundBox.minY : minY; | ||||
| 			minZ = (boundBox.minZ < minZ) ? boundBox.minZ : minZ; | ||||
| 			maxX = (boundBox.maxX > maxX) ? boundBox.maxX : maxX; | ||||
| 			maxY = (boundBox.maxY > maxY) ? boundBox.maxY : maxY; | ||||
| 			maxZ = (boundBox.maxZ > maxZ) ? boundBox.maxZ : maxZ; | ||||
| 		} | ||||
| 		 | ||||
| 		public function addPoint(x:Number, y:Number, z:Number):void { | ||||
| 			if (x < minX) minX = x; | ||||
| 			if (x > maxX) maxX = x; | ||||
| 			if (y < minY) minY = y; | ||||
| 			if (y > maxY) maxY = y; | ||||
| 			if (z < minZ) minZ = z; | ||||
| 			if (z > maxZ) maxZ = z; | ||||
| 		} | ||||
| 		 | ||||
| 		public function infinity():void { | ||||
| 			minX = minY = minZ = Number.MAX_VALUE; | ||||
| 			maxX = maxY = maxZ = -Number.MAX_VALUE; | ||||
| 		} | ||||
| 		 | ||||
| 		public function copyFrom(boundBox:BoundBox):void { | ||||
| 			minX = boundBox.minX; | ||||
| 			minY = boundBox.minY; | ||||
| 			minZ = boundBox.minZ; | ||||
| 			maxX = boundBox.maxX; | ||||
| 			maxY = boundBox.maxY; | ||||
| 			maxZ = boundBox.maxZ; | ||||
| 		} | ||||
| 		 | ||||
| 		public function clone():BoundBox { | ||||
| 			var clone:BoundBox = new BoundBox(); | ||||
| 			clone.copyFrom(this);  | ||||
| 			return clone; | ||||
| 		} | ||||
| 		 | ||||
| 		public function toString():String { | ||||
| 			return "BoundBox [" + minX.toFixed(2) + ", " + minY.toFixed(2) + ", " + minZ.toFixed(2) + " - " + maxX.toFixed(2) + ", " + maxY.toFixed(2) + ", " + maxZ.toFixed(2) + "]"; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,414 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	 | ||||
| 	import flash.display.Bitmap; | ||||
| 	import flash.display.BitmapData; | ||||
| 	import flash.display.Sprite; | ||||
| 	import flash.display.StageAlign; | ||||
| 	import flash.events.Event; | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Point; | ||||
| 	import flash.geom.Rectangle; | ||||
| 	import flash.geom.Vector3D; | ||||
| 	import flash.system.System; | ||||
| 	import flash.text.TextField; | ||||
| 	import flash.text.TextFieldAutoSize; | ||||
| 	import flash.text.TextFormat; | ||||
| 	import flash.utils.Dictionary; | ||||
| 	import flash.utils.getDefinitionByName; | ||||
| 	import flash.utils.getQualifiedClassName; | ||||
| 	import flash.utils.getQualifiedSuperclassName; | ||||
| 	import flash.utils.getTimer; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class Camera3D extends Object3D { | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Вьюпорт камеры.  | ||||
| 		 */ | ||||
| 		public var canvas:Canvas; | ||||
| 		public var fov:Number = Math.PI/2; | ||||
| 		/** | ||||
| 		 * Ширина вьюпорта.  | ||||
| 		 */ | ||||
| 		public var width:Number = 500; | ||||
| 		/** | ||||
| 		 * Высота вьюпорта.  | ||||
| 		 */ | ||||
| 		public var height:Number = 500; | ||||
| 		 | ||||
| 		public var nearClipping:Number = 0; | ||||
| 		public var farClipping:Number = 5000; | ||||
| 		public var farFalloff:Number = 4000; | ||||
|  | ||||
| 		// Матрица проецирования | ||||
| 		alternativa3d var projectionMatrix:Matrix3D; | ||||
| 		alternativa3d var projectionMatrixData:Vector.<Number> = new Vector.<Number>(16, true); | ||||
| 		// Параметры перспективы | ||||
| 		alternativa3d var viewSize:Number; | ||||
| 		alternativa3d var viewSizeX:Number; | ||||
| 		alternativa3d var viewSizeY:Number; | ||||
| 		alternativa3d var perspectiveScaleX:Number; | ||||
| 		alternativa3d var perspectiveScaleY:Number; | ||||
| 		alternativa3d var focalLength:Number; | ||||
| 		// Перекрытия | ||||
| 		alternativa3d var occlusionPlanes:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(); | ||||
| 		alternativa3d var occlusionEdges:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>(); | ||||
| 		alternativa3d var numOccluders:int; | ||||
| 		alternativa3d var occludedAll:Boolean; | ||||
| 		 | ||||
| 		public function Camera3D() { | ||||
| 			updateProjection(); | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function get canDraw():Boolean { | ||||
| 			return false; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Отрисовка иерархии объектов, в которой находится камера. | ||||
| 		 * Перед render(), если менялись параметры камеры, нужно вызвать updateProjection(). | ||||
| 		 */ | ||||
| 		public function render():void { | ||||
| 			// Расчёт матрицы перевода из рута в камеру | ||||
| 			cameraMatrix.identity(); | ||||
| 			var object:Object3D = this; | ||||
| 			while (object._parent != null) { | ||||
| 				cameraMatrix.append(object.matrix); | ||||
| 				object = object._parent; | ||||
| 			} | ||||
| 			cameraMatrix.invert(); | ||||
| 			cameraMatrix.appendScale(perspectiveScaleX, perspectiveScaleY, 1); | ||||
| 			 | ||||
| 			numOccluders = 0; | ||||
| 			occludedAll = false; | ||||
| 			 | ||||
| 			numTriangles = 0; | ||||
| 			 | ||||
| 			// Отрисовка | ||||
| 			if (object.visible && object.canDraw) { | ||||
| 				object.cameraMatrix.identity(); | ||||
| 				object.cameraMatrix.prepend(cameraMatrix); | ||||
| 				object.cameraMatrix.prepend(object.matrix); | ||||
| 				if (object.cullingInCamera(this, 63) >= 0) { | ||||
| 					// Отрисовка объекта | ||||
| 					canvas.numDraws = 0; | ||||
| 					if (debugMode) object.debug(this, object, canvas); | ||||
| 					object.draw(this, object, canvas); | ||||
| 					// Зачистка ненужных канвасов | ||||
| 					canvas.removeChildren(canvas.numDraws); | ||||
| 				} else { | ||||
| 					// Если отсеклось, зачищаем рутовый канвас | ||||
| 					canvas.removeChildren(0); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * После изменения параметров fov, width, height нужно вызвать этот метод. | ||||
| 		 */ | ||||
| 		public function updateProjection():void { | ||||
| 			// Расчёт параметров перспективы | ||||
| 			viewSize = Math.sqrt(width*width + height*height)*0.5; | ||||
| 			focalLength = viewSize/Math.tan(fov*0.5); | ||||
| 			viewSizeX = width*0.5; | ||||
| 			viewSizeY = height*0.5; | ||||
| 			perspectiveScaleX = focalLength/viewSizeX; | ||||
| 			perspectiveScaleY = focalLength/viewSizeY; | ||||
| 			// Подготовка матрицы проецирования | ||||
| 			projectionMatrixData[0] = viewSizeX; | ||||
| 			projectionMatrixData[5] = viewSizeY; | ||||
| 			projectionMatrixData[10] = 1; | ||||
| 			projectionMatrixData[11] = 1; | ||||
| 			projectionMatrix = new Matrix3D(projectionMatrixData); | ||||
| 		} | ||||
| 		 | ||||
| 		private static var _tmpv:Vector.<Number> = new Vector.<Number>(3); | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @param v | ||||
| 		 * @param result | ||||
| 		 */ | ||||
| 		public function projectGlobal(v:Vector3D, result:Vector3D):void { | ||||
| 			_tmpv[0] = v.x; _tmpv[1] = v.y; _tmpv[2] = v.z; | ||||
| 			cameraMatrix.transformVectors(_tmpv, _tmpv); | ||||
| 			projectionMatrix.transformVectors(_tmpv, _tmpv); | ||||
| 			result.z = _tmpv[2]; | ||||
| 			result.x = _tmpv[0]/result.z; | ||||
| 			result.y = _tmpv[1]/result.z; | ||||
| 		} | ||||
| 		 | ||||
| 		// DEBUG | ||||
| 		 | ||||
| 		// Режим отладки | ||||
| 		public var debugMode:Boolean = false; | ||||
| 		 | ||||
| 		// Список объектов дебага | ||||
| 		private var debugSet:Object = new Object(); | ||||
| 		 | ||||
| 		// Добавить в дебаг | ||||
| 		public function addToDebug(debug:int, ... rest):void { | ||||
| 			if (!debugSet[debug]) debugSet[debug] = new Dictionary(); | ||||
| 			for (var i:int = 0; i < rest.length;) debugSet[debug][rest[i++]] = true; | ||||
| 		} | ||||
| 		 | ||||
| 		// Убрать из дебага | ||||
| 		public function removeFromDebug(debug:int, ... rest):void { | ||||
| 			if (debugSet[debug]) { | ||||
| 				for (var i:int = 0; i < rest.length;) delete debugSet[debug][rest[i++]]; | ||||
| 				for (var key:* in debugSet[debug]); | ||||
| 				if (!key) delete debugSet[debug]; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		// Проверка, находится ли объект или один из классов, от которых он нследован, в дебаге | ||||
| 		alternativa3d function checkInDebug(object:Object3D):int { | ||||
| 			var res:int = 0; | ||||
| 			for (var debug:int = 1; debug <= 256; debug = debug << 1) { | ||||
| 				if (debugSet[debug]) { | ||||
| 					if (debugSet[debug][Object3D] || debugSet[debug][object]) { | ||||
| 						res |= debug; | ||||
| 					} else { | ||||
| 						var objectClass:Class = getDefinitionByName(getQualifiedClassName(object)) as Class; | ||||
| 						while (objectClass != Object3D) { | ||||
| 							if (debugSet[debug][objectClass]) { | ||||
| 								res |= debug; | ||||
| 								break; | ||||
| 							} | ||||
| 							objectClass = Class(getDefinitionByName(getQualifiedSuperclassName(objectClass))); | ||||
| 						}			 | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 		public var diagram:Sprite = createDiagram(); | ||||
| 		 | ||||
| 		private var fpsTextField:TextField; | ||||
| 		private var memoryTextField:TextField; | ||||
| 		private var trianglesTextField:TextField; | ||||
| 		private var timerTextField:TextField; | ||||
| 		private var graph:Bitmap; | ||||
| 		private var rect:Rectangle; | ||||
| 		 | ||||
| 		private var _diagramAlign:String = "TR"; | ||||
| 		private var _diagramHorizontalMargin:Number = 2; | ||||
| 		private var _diagramVerticalMargin:Number = 2; | ||||
|  | ||||
| 		public var fpsUpdatePeriod:int = 10; | ||||
| 		private var fpsUpdateCounter:int; | ||||
| 		private var previousFrameTime:int; | ||||
| 		private var previousPeriodTime:int; | ||||
| 	 | ||||
| 		private var maxMemory:int; | ||||
| 		alternativa3d var numTriangles:int; | ||||
|  | ||||
| 		public var timerUpdatePeriod:int = 10; | ||||
| 		private var timerUpdateCounter:int; | ||||
| 		private var timeSum:int; | ||||
| 		private var timeCount:int; | ||||
| 		private var timer:int; | ||||
|  | ||||
| 		private function createDiagram():Sprite { | ||||
| 			var diagram:Sprite = new Sprite(); | ||||
| 			diagram.mouseEnabled = false; | ||||
| 			diagram.mouseChildren = false; | ||||
| 			// Инициализация диаграммы | ||||
| 			diagram.addEventListener(Event.ADDED_TO_STAGE, function():void { | ||||
| 				// FPS | ||||
| 				fpsTextField = new TextField(); | ||||
| 				fpsTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xCCCCCC); | ||||
| 				fpsTextField.autoSize = TextFieldAutoSize.LEFT; | ||||
| 				fpsTextField.text = "FPS: " + Number(diagram.stage.frameRate).toFixed(2); | ||||
| 				fpsTextField.selectable = false; | ||||
| 				fpsTextField.x = -3; | ||||
| 				fpsTextField.y = -5; | ||||
| 				diagram.addChild(fpsTextField); | ||||
| 				// Память | ||||
| 				memoryTextField = new TextField(); | ||||
| 				memoryTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xCCCC00); | ||||
| 				memoryTextField.autoSize = TextFieldAutoSize.LEFT; | ||||
| 				memoryTextField.text = "MEM: " + bytesToString(System.totalMemory); | ||||
| 				memoryTextField.selectable = false; | ||||
| 				memoryTextField.x = -3; | ||||
| 				memoryTextField.y = 4; | ||||
| 				diagram.addChild(memoryTextField); | ||||
| 				// Треугольники | ||||
| 				trianglesTextField = new TextField(); | ||||
| 				trianglesTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xFF6600); | ||||
| 				trianglesTextField.autoSize = TextFieldAutoSize.LEFT; | ||||
| 				trianglesTextField.text = "TRI: " + 0; | ||||
| 				trianglesTextField.selectable = false; | ||||
| 				trianglesTextField.x = -2; | ||||
| 				trianglesTextField.y = 13; | ||||
| 				diagram.addChild(trianglesTextField); | ||||
| 				// Время выполнения метода | ||||
| 				timerTextField = new TextField(); | ||||
| 				timerTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x0066FF); | ||||
| 				timerTextField.autoSize = TextFieldAutoSize.LEFT; | ||||
| 				timerTextField.text = "TMR:"; | ||||
| 				timerTextField.selectable = false; | ||||
| 				timerTextField.x = -2; | ||||
| 				timerTextField.y = 13 + 9; | ||||
| 				diagram.addChild(timerTextField); | ||||
| 				// График | ||||
| 				graph = new Bitmap(new BitmapData(60, 40, true, 0x20FFFFFF)); | ||||
| 				rect = new Rectangle(0, 0, 1, 40) | ||||
| 				graph.x = 0; | ||||
| 				graph.y = 27 + 9; | ||||
| 				diagram.addChild(graph); | ||||
| 				// Сброс параметров | ||||
| 				previousFrameTime = previousPeriodTime = getTimer(); | ||||
| 				fpsUpdateCounter = 0; | ||||
| 				maxMemory = 0; | ||||
| 				timerUpdateCounter = 0; | ||||
| 				timeSum = 0; | ||||
| 				timeCount = 0; | ||||
| 				// Подписка			 | ||||
| 				diagram.stage.addEventListener(Event.ENTER_FRAME, updateDiagram, false, -1000); | ||||
| 				diagram.stage.addEventListener(Event.RESIZE, resizeDiagram, false, -1000); | ||||
| 				resizeDiagram(); | ||||
| 			}); | ||||
| 			// Деинициализация диаграммы | ||||
| 			diagram.addEventListener(Event.REMOVED_FROM_STAGE, function():void { | ||||
| 				// Обнуление | ||||
| 				diagram.removeChild(fpsTextField); | ||||
| 				diagram.removeChild(memoryTextField); | ||||
| 				diagram.removeChild(trianglesTextField); | ||||
| 				diagram.removeChild(graph); | ||||
| 				fpsTextField = null; | ||||
| 				memoryTextField = null; | ||||
| 				trianglesTextField = null; | ||||
| 				timerTextField = null; | ||||
| 				graph.bitmapData.dispose(); | ||||
| 				graph = null; | ||||
| 				rect = null; | ||||
| 				// Отписка | ||||
| 				diagram.stage.removeEventListener(Event.ENTER_FRAME, updateDiagram); | ||||
| 				diagram.stage.removeEventListener(Event.RESIZE, resizeDiagram); | ||||
| 			}); | ||||
| 			return diagram; | ||||
| 		} | ||||
| 				 | ||||
| 		private function resizeDiagram(e:Event = null):void { | ||||
| 			if (diagram.stage != null) { | ||||
| 				var coord:Point = diagram.parent.globalToLocal(new Point()); | ||||
| 				if (_diagramAlign == StageAlign.TOP_LEFT || _diagramAlign == StageAlign.LEFT || _diagramAlign == StageAlign.BOTTOM_LEFT) { | ||||
| 					diagram.x = Math.round(coord.x + _diagramHorizontalMargin); | ||||
| 				} | ||||
| 				if (_diagramAlign == StageAlign.TOP || _diagramAlign == StageAlign.BOTTOM) { | ||||
| 					diagram.x = Math.round(coord.x + diagram.stage.stageWidth/2 - graph.width/2); | ||||
| 				} | ||||
| 				if (_diagramAlign == StageAlign.TOP_RIGHT || _diagramAlign == StageAlign.RIGHT || _diagramAlign == StageAlign.BOTTOM_RIGHT) { | ||||
| 					diagram.x = Math.round(coord.x + diagram.stage.stageWidth - _diagramHorizontalMargin - graph.width); | ||||
| 				} | ||||
| 				if (_diagramAlign == StageAlign.TOP_LEFT || _diagramAlign == StageAlign.TOP || _diagramAlign == StageAlign.TOP_RIGHT) { | ||||
| 					diagram.y = Math.round(coord.y + _diagramVerticalMargin); | ||||
| 				} | ||||
| 				if (_diagramAlign == StageAlign.LEFT || _diagramAlign == StageAlign.RIGHT) { | ||||
| 					diagram.y = Math.round(coord.y + diagram.stage.stageHeight/2 - (graph.y + graph.height)/2); | ||||
| 				} | ||||
| 				if (_diagramAlign == StageAlign.BOTTOM_LEFT || _diagramAlign == StageAlign.BOTTOM || _diagramAlign == StageAlign.BOTTOM_RIGHT) { | ||||
| 					diagram.y = Math.round(coord.y + diagram.stage.stageHeight - _diagramVerticalMargin - graph.y - graph.height); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 				 | ||||
| 		private function updateDiagram(e:Event):void { | ||||
| 			var fps:Number; | ||||
| 			var mod:int; | ||||
| 			var time:int = getTimer(); | ||||
| 			var stageFrameRate:int = diagram.stage.frameRate; | ||||
|  | ||||
| 			// FPS текст | ||||
| 			if (++fpsUpdateCounter == fpsUpdatePeriod) { | ||||
| 				fps = 1000*fpsUpdatePeriod/(time - previousPeriodTime); | ||||
| 				if (fps > stageFrameRate) fps = stageFrameRate; | ||||
| 				mod = fps*100 % 100; | ||||
| 				fpsTextField.text = "FPS: " + int(fps) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00")); | ||||
| 				previousPeriodTime = time; | ||||
| 				fpsUpdateCounter = 0; | ||||
| 			} | ||||
| 			// FPS график | ||||
| 			fps = 1000/(time - previousFrameTime); | ||||
| 			if (fps > stageFrameRate) fps = stageFrameRate; | ||||
| 			graph.bitmapData.scroll(1, 0); | ||||
| 			graph.bitmapData.fillRect(rect, 0x20FFFFFF); | ||||
| 			graph.bitmapData.setPixel32(0, 40*(1 - fps/stageFrameRate), 0xFFCCCCCC); | ||||
| 			previousFrameTime = time; | ||||
| 			 | ||||
| 			// Память текст | ||||
| 			var memory:int = System.totalMemory; | ||||
| 			memoryTextField.text = "MEM: " + bytesToString(memory); | ||||
| 			// Память график | ||||
| 			if (memory > maxMemory) maxMemory = memory; | ||||
| 			graph.bitmapData.setPixel32(0, 40*(1 - memory/maxMemory), 0xFFCCCC00); | ||||
|  | ||||
| 			// Треугольники текст | ||||
| 			trianglesTextField.text = "TRI: " + numTriangles; | ||||
|  | ||||
| 			// Время текст | ||||
| 			if (++timerUpdateCounter == timerUpdatePeriod) { | ||||
| 				if (timeCount > 0) { | ||||
| 					fps = timeSum/timeCount; | ||||
| 					mod = fps*100 % 100; | ||||
| 					timerTextField.text = "TMR: " + int(fps) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00")); | ||||
| 				} else { | ||||
| 					timerTextField.text = "TMR:"; | ||||
| 				} | ||||
| 				timerUpdateCounter = 0; | ||||
| 				timeSum = 0; | ||||
| 				timeCount = 0; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		public function startTimer():void { | ||||
| 			timer = getTimer(); | ||||
| 		} | ||||
| 		 | ||||
| 		public function stopTimer():void { | ||||
| 			timeSum += getTimer() - timer; | ||||
| 			timeCount++; | ||||
| 		} | ||||
| 		 | ||||
| 		public function get diagramAlign():String { | ||||
| 			return _diagramAlign; | ||||
| 		} | ||||
| 		public function set diagramAlign(value:String):void { | ||||
| 			_diagramAlign = value; | ||||
| 			resizeDiagram(); | ||||
| 		}  | ||||
| 		 | ||||
| 		public function get diagramHorizontalMargin():Number { | ||||
| 			return _diagramHorizontalMargin; | ||||
| 		} | ||||
| 		public function set diagramHorizontalMargin(value:Number):void { | ||||
| 			_diagramHorizontalMargin = value; | ||||
| 			resizeDiagram(); | ||||
| 		}  | ||||
| 		 | ||||
| 		public function get diagramVerticalMargin():Number { | ||||
| 			return _diagramVerticalMargin; | ||||
| 		} | ||||
| 		public function set diagramVerticalMargin(value:Number):void { | ||||
| 			_diagramVerticalMargin = value; | ||||
| 			resizeDiagram(); | ||||
| 		}  | ||||
| 		 | ||||
| 		private function bytesToString(bytes:int):String { | ||||
| 			if (bytes < 1024) return bytes + "b"; | ||||
| 			else if (bytes < 10240) return (bytes/1024).toFixed(2) + "kb"; | ||||
| 			else if (bytes < 102400) return (bytes/1024).toFixed(1) + "kb"; | ||||
| 			else if (bytes < 1048576) return (bytes >> 10) + "kb"; | ||||
| 			else if (bytes < 10485760) return (bytes/1048576).toFixed(2) + "mb"; | ||||
| 			else if (bytes < 104857600) return (bytes/1048576).toFixed(1) + "mb"; | ||||
| 			else return (bytes >> 20) + "mb"; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,104 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
|  | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	 | ||||
| 	import flash.display.DisplayObject; | ||||
| 	import flash.display.Graphics; | ||||
| 	import flash.display.Sprite; | ||||
| 	import flash.geom.ColorTransform; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class Canvas extends Sprite { | ||||
| 		 | ||||
| 		static private const defaultColorTransform:ColorTransform = new ColorTransform(); | ||||
| 		static private const collector:Vector.<Canvas> = new Vector.<Canvas>(); | ||||
| 		static private var collectorLength:int = 0; | ||||
| 		 | ||||
| 		alternativa3d var gfx:Graphics = graphics; | ||||
| 		 | ||||
| 		private var modifiedGraphics:Boolean; | ||||
| 		private var modifiedAlpha:Boolean; | ||||
| 		private var modifiedBlendMode:Boolean; | ||||
| 		private var modifiedColorTransform:Boolean; | ||||
| 		private var modifiedFilters:Boolean; | ||||
| 		 | ||||
| 		alternativa3d var _numChildren:int = 0; | ||||
| 		alternativa3d var numDraws:int = 0; | ||||
|  | ||||
| 		public function Canvas() { | ||||
| 			mouseEnabled = false; | ||||
| 			mouseChildren = false; | ||||
| 		} | ||||
|  | ||||
| 		alternativa3d function getChildCanvas(useGraphics:Boolean, useChildren:Boolean, alpha:Number = 1, blendMode:String = "normal", colorTransform:ColorTransform = null, filters:Array = null):Canvas { | ||||
| 			var canvas:Canvas; | ||||
| 			var displayObject:DisplayObject; | ||||
| 			// Зачистка не канвасов | ||||
| 			while (_numChildren > numDraws && !((displayObject = getChildAt(_numChildren - 1 - numDraws)) is Canvas)) { | ||||
| 				removeChild(displayObject); | ||||
| 				_numChildren--; | ||||
| 			} | ||||
| 			// Получение канваса | ||||
| 			if (_numChildren > numDraws++) { | ||||
| 				canvas = displayObject as Canvas; | ||||
| 				// Зачистка | ||||
| 				canvas.gfx.clear(); | ||||
| 				if (canvas._numChildren > 0 && !useChildren) { | ||||
| 					canvas.removeChildren(0); | ||||
| 				} | ||||
| 			} else { | ||||
| 				canvas = (collectorLength > 0) ? collector[--collectorLength] : new Canvas(); | ||||
| 				addChildAt(canvas, 0); | ||||
| 				_numChildren++; | ||||
| 			} | ||||
| 			// Пометка о том, что в graphics будет что-то нарисовано | ||||
| 			canvas.modifiedGraphics = useGraphics; | ||||
| 			// Установка свойств | ||||
| 			if (alpha != 1) { | ||||
| 				canvas.alpha = alpha; | ||||
| 				canvas.modifiedAlpha = true; | ||||
| 			} else if (canvas.modifiedAlpha) { | ||||
| 				canvas.alpha = 1; | ||||
| 				canvas.modifiedAlpha = false; | ||||
| 			} | ||||
| 			if (blendMode != "normal") { | ||||
| 				canvas.blendMode = blendMode; | ||||
| 				canvas.modifiedBlendMode = true; | ||||
| 			} else if (canvas.modifiedBlendMode) { | ||||
| 				canvas.blendMode = "normal"; | ||||
| 				canvas.modifiedBlendMode = false; | ||||
| 			} | ||||
| 			if (colorTransform != null) { | ||||
| 				colorTransform.alphaMultiplier = alpha; | ||||
| 				canvas.transform.colorTransform = colorTransform; | ||||
| 				canvas.modifiedColorTransform = true; | ||||
| 			} else if (canvas.modifiedColorTransform) { | ||||
| 				defaultColorTransform.alphaMultiplier = alpha; | ||||
| 				canvas.transform.colorTransform = defaultColorTransform; | ||||
| 				canvas.modifiedColorTransform = false; | ||||
| 			} | ||||
| 			if (filters != null) { | ||||
| 				canvas.filters = filters; | ||||
| 				canvas.modifiedFilters = true; | ||||
| 			} else if (canvas.modifiedFilters) { | ||||
| 				canvas.filters = null; | ||||
| 				canvas.modifiedFilters = false; | ||||
| 			} | ||||
| 			return canvas; | ||||
| 		} | ||||
| 		 | ||||
| 		alternativa3d function removeChildren(keep:int):void { | ||||
| 			for (var canvas:Canvas; _numChildren > keep; _numChildren--) { | ||||
| 				if ((canvas = removeChildAt(0) as Canvas) != null) { | ||||
| 					if (canvas.modifiedGraphics) canvas.gfx.clear(); | ||||
| 					if (canvas._numChildren > 0) canvas.removeChildren(0); | ||||
| 					collector[collectorLength++] = canvas; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	public class Clipping { | ||||
| 				 | ||||
| 		/** | ||||
| 		 * Объект отсекается целиком, если он полностью вне пирамиды видимости или пересекает nearClipping камеры.  | ||||
| 		 */ | ||||
| 		static public const BOUND_CULLING:int = 0; | ||||
| 		/** | ||||
| 		 * Грань отсекается целиком, если она полностью вне пирамиды видимости или пересекает nearClipping камеры.  | ||||
| 		 */ | ||||
| 		static public const FACE_CULLING:int = 1; | ||||
| 		/** | ||||
| 		 * Грань подрезается пирамидой видимости камеры.  | ||||
| 		 */ | ||||
| 		static public const FACE_CLIPPING:int = 2; | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	public class Debug { | ||||
| 		 | ||||
| 		static public const NAMES:int = 1; | ||||
| 		static public const AXES:int = 2; | ||||
| 		static public const CENTERS:int = 4; | ||||
| 		static public const BOUNDS:int = 8; | ||||
| 		 | ||||
| 		static public const EDGES:int = 16; | ||||
| 		static public const VERTICES:int = 32; | ||||
| 		static public const NORMALS:int = 64; | ||||
| 		 | ||||
| 		static public const NODES:int = 128; | ||||
| 		static public const SPLITS:int = 256; | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,53 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	public class Fragment { | ||||
| 		 | ||||
| 		static private var collector:Fragment; | ||||
| 		 | ||||
| 		public var next:Fragment; | ||||
| 		 | ||||
| 		public var negative:Fragment; | ||||
| 		public var positive:Fragment; | ||||
| 		 | ||||
| 		public var geometry:Geometry; | ||||
| 		 | ||||
| 		public var indices:Vector.<int> = new Vector.<int>(); | ||||
| 		public var num:int = 0; | ||||
| 		 | ||||
| 		public var normalX:Number; | ||||
| 		public var normalY:Number; | ||||
| 		public var normalZ:Number; | ||||
| 		public var offset:Number; | ||||
| 		 | ||||
| 		static public function create():Fragment { | ||||
| 			if (collector != null) { | ||||
| 				var res:Fragment = collector; | ||||
| 				collector = collector.next; | ||||
| 				res.next = null; | ||||
| 				return res; | ||||
| 			} else { | ||||
| 				return new Fragment(); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		public function create():Fragment { | ||||
| 			if (collector != null) { | ||||
| 				var res:Fragment = collector; | ||||
| 				collector = collector.next; | ||||
| 				res.next = null; | ||||
| 				return res; | ||||
| 			} else { | ||||
| 				return new Fragment(); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		public function destroy():void { | ||||
| 			num = 0; | ||||
| 			next = collector; | ||||
| 			collector = this; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,73 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	 | ||||
| 	import flash.display.BitmapData; | ||||
| 	import flash.filters.ConvolutionFilter; | ||||
| 	import flash.geom.Matrix; | ||||
| 	import flash.geom.Point; | ||||
| 	import flash.geom.Rectangle; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 		 | ||||
| 	/** | ||||
| 	 * Объект, представляющий текстуру в виде последовательности её уменьшенных копий. | ||||
| 	 * Каждая следующая в два раза меньше предыдущей. Последняя имеет размер 1х1 пиксел. | ||||
| 	 * Чем дальше от камеры отрисовываемый объект, тем меньшая текстура выбирается. | ||||
| 	 * Это позволяет получить лучший визуальный результат и большую производительность. | ||||
| 	 */ | ||||
| 	public class MipMap { | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Мип-текстуры  | ||||
| 		 */ | ||||
| 		public var textures:Vector.<BitmapData> = new Vector.<BitmapData>(); | ||||
| 		/** | ||||
| 		 * Количество мип-текстур  | ||||
| 		 */ | ||||
| 		public var num:int; | ||||
| 		/** | ||||
| 		 * Отношение размера пиксела текстуры к единице измерения трёхмерного пространства | ||||
| 		 */ | ||||
| 		public var resolution:Number; | ||||
| 		 | ||||
| 		static private const filter:ConvolutionFilter = new ConvolutionFilter(2, 2, [1, 1, 1, 1], 4, 0, false, true); | ||||
| 		static private const point:Point = new Point(); | ||||
| 		static private const matrix:Matrix = new Matrix(); | ||||
| 		static private const rect:Rectangle = new Rectangle(); | ||||
| 		public function MipMap(texture:BitmapData, resolution:Number = 1) { | ||||
| 			var bmp:BitmapData = new BitmapData(texture.width, texture.height, texture.transparent); | ||||
| 			var current:BitmapData = textures[num++] = texture; | ||||
| 			filter.preserveAlpha = !texture.transparent; | ||||
| 			var w:Number = rect.width = texture.width, h:Number = rect.height = texture.height; | ||||
| 			while (w > 1 && h > 1 && rect.width > 1 && rect.height > 1) { | ||||
| 				bmp.applyFilter(current, rect, point, filter); | ||||
| 				rect.width = w >> 1; | ||||
| 				rect.height = h >> 1; | ||||
| 				matrix.a = rect.width/w; | ||||
| 				matrix.d = rect.height/h; | ||||
| 				w *= 0.5; | ||||
| 				h *= 0.5; | ||||
| 				current = new BitmapData(rect.width, rect.height, texture.transparent, 0); | ||||
| 				current.draw(bmp, matrix, null, null, null, false);					 | ||||
| 				textures[num++] = current; | ||||
| 			} | ||||
| 			bmp.dispose(); | ||||
| 			this.resolution = resolution; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Получение мип-уровня в зависимости от удалённости объекта от камеры  | ||||
| 		 * @param distance Z-координата объекта в пространстве камеры  | ||||
| 		 * @param camera Камера | ||||
| 		 * @return Индекс в списке мип-текстур textures | ||||
| 		 */ | ||||
| 		public function getLevel(distance:Number, camera:Camera3D):int { | ||||
| 			var level:int = Math.log(distance/(camera.focalLength*resolution))*1.442695040888963387; | ||||
| 			if (level < 0) return 0; else if (level >= num) return num - 1; | ||||
| 			return level; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	public class MipMapping	{ | ||||
| 				 | ||||
| 		/** | ||||
| 		 * Нет мипмаппинга.  | ||||
| 		 */ | ||||
| 		static public const NONE:int = 0; | ||||
| 		/** | ||||
| 		 * Мипмаппинг по удалённости объекта от камеры.  | ||||
| 		 */ | ||||
| 		static public const PER_OBJECT:int = 1; | ||||
| 		 | ||||
| 		//static public const PER_POLYGON:int = 2; | ||||
| 		//static public const PER_PIXEL:int = 3; | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,27 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	import __AS3__.vec.Vector; | ||||
|  | ||||
| 	public final class Node { | ||||
| 	 | ||||
| 		public var positive:Node; | ||||
| 		public var negative:Node; | ||||
|  | ||||
| 		public var normalX:Number; | ||||
| 		public var normalY:Number; | ||||
| 		public var normalZ:Number; | ||||
|  | ||||
| 		public var offset:Number; | ||||
| 		public var offsetMin:Number; | ||||
| 		public var offsetMax:Number; | ||||
| 		 | ||||
| 		public var boundBox:BoundBox; | ||||
| 	 | ||||
| 		public var objects:Vector.<Object3D>; | ||||
| 		public var bounds:Vector.<BoundBox>; | ||||
| 		 | ||||
| 		public var numObjects:int = 0; | ||||
| 		public var numNonOccluders:int = 0; | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,270 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
|  | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	 | ||||
| 	import flash.geom.ColorTransform; | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Utils3D; | ||||
| 	import flash.utils.getQualifiedClassName; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
|  | ||||
| 	/** | ||||
| 	 * Базовый трёхмерный объект | ||||
| 	 */ | ||||
| 	public class Object3D { | ||||
| 		 | ||||
| 		public var name:String; | ||||
| 		/** | ||||
| 		 * Матрица трансформации. Управлять трансформацией объекта можно только через это свойство | ||||
| 		 * путём назначения новой матрицы или с помощью методов матрицы. | ||||
| 		 */ | ||||
| 		public var matrix:Matrix3D = new Matrix3D(); | ||||
| 		public var visible:Boolean = true; | ||||
| 		 | ||||
| 		public var alpha:Number = 1; | ||||
| 		public var blendMode:String = "normal"; | ||||
| 		public var colorTransform:ColorTransform = null; | ||||
| 		public var filters:Array = null; | ||||
|  | ||||
| 		alternativa3d var _parent:Object3DContainer; | ||||
|  | ||||
| 		alternativa3d var _boundBox:BoundBox; | ||||
| 		 | ||||
| 		alternativa3d var culling:int = 0; | ||||
|  | ||||
| 		alternativa3d var cameraMatrix:Matrix3D = new Matrix3D(); | ||||
|  | ||||
| 		static private const boundBoxVertices:Vector.<Number> = new Vector.<Number>(24, true); | ||||
|  | ||||
| 		alternativa3d function get canDraw():Boolean { | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void {} | ||||
| 		 | ||||
| 		alternativa3d function debug(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			var debugResult:int = camera.checkInDebug(this); | ||||
| 			if (debugResult == 0) return; | ||||
| 			var canvas:Canvas = parentCanvas.getChildCanvas(true, false); | ||||
| 			if (debugResult & Debug.AXES) object.drawAxes(camera, canvas); | ||||
| 			if (debugResult & Debug.CENTERS) object.drawCenter(camera, canvas); | ||||
| 			if (debugResult & Debug.NAMES) object.drawName(camera, canvas); | ||||
| 			if (debugResult & Debug.BOUNDS) object.drawBoundBox(camera, canvas); | ||||
| 		} | ||||
| 		 | ||||
| 		alternativa3d function getGeometry(camera:Camera3D, object:Object3D):Geometry { | ||||
| 			return null; | ||||
| 		} | ||||
| 		 | ||||
| 		public function get boundBox():BoundBox { | ||||
| 			return _boundBox; | ||||
| 		} | ||||
| 		 | ||||
| 		public function set boundBox(value:BoundBox):void { | ||||
| 			_boundBox = value; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Расчёт баунда  | ||||
| 		 * @param matrix Трансформация пространства, в системе которого расчитывается баунд. | ||||
| 		 * Если этот параметр не указан, баунд расчитается в локальных координатах объекта.  | ||||
| 		 * @param boundBox Баунд, в который записывается результат. | ||||
| 		 * Если этот параметр не указан, создаётся новый экземпляр. | ||||
| 		 * @return Расчитанный баунд. | ||||
| 		 */ | ||||
| 		public function calculateBoundBox(matrix:Matrix3D = null, boundBox:BoundBox = null):BoundBox { | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		public function get parent():Object3DContainer { | ||||
| 			return _parent; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		alternativa3d function cullingInCamera(camera:Camera3D, parentCulling:int):int { | ||||
| 			if (camera.occludedAll) return -1; | ||||
| 			culling = parentCulling; | ||||
| 			var i:int, infront:Boolean, behind:Boolean, boundBox:BoundBox = this.boundBox, numOccluders:int = camera.numOccluders, cull:Boolean = culling > 0 && boundBox != null, occlude:Boolean = numOccluders > 0 && boundBox != null; | ||||
| 			// Расчёт точек баунда в координатах камеры  | ||||
| 			if (cull || occlude) boundBoxVertices[0] = boundBoxVertices[3] = boundBoxVertices[6] = boundBoxVertices[9] = boundBox.minX, boundBoxVertices[1] = boundBoxVertices[4] = boundBoxVertices[13] = boundBoxVertices[16] = boundBox.minY, boundBoxVertices[2] = boundBoxVertices[8] = boundBoxVertices[14] = boundBoxVertices[20] = boundBox.minZ, boundBoxVertices[12] = boundBoxVertices[15] = boundBoxVertices[18] = boundBoxVertices[21] = boundBox.maxX, boundBoxVertices[7] = boundBoxVertices[10] = boundBoxVertices[19] = boundBoxVertices[22] = boundBox.maxY, boundBoxVertices[5] = boundBoxVertices[11] = boundBoxVertices[17] = boundBoxVertices[23] = boundBox.maxZ, cameraMatrix.transformVectors(boundBoxVertices, boundBoxVertices); | ||||
| 			// Куллинг | ||||
| 			if (cull) { | ||||
| 				if (culling & 1) { | ||||
| 					for (i = 2, infront = false, behind = false; i <= 23; i += 3) { | ||||
| 						if (boundBoxVertices[i] > camera.nearClipping) { | ||||
| 							infront = true; | ||||
| 							if (behind) break; | ||||
| 						} else { | ||||
| 							behind = true; | ||||
| 							if (infront) break; | ||||
| 						} | ||||
| 					} | ||||
| 					if (behind) { | ||||
| 						if (!infront) return -1; | ||||
| 					} else { | ||||
| 						// TODO: проверка не нужна | ||||
| 						if (infront) culling &= 62; | ||||
| 					} | ||||
| 				} | ||||
| 				if (culling & 2) { | ||||
| 					for (i = 2, infront = false, behind = false; i <= 23; i += 3) { | ||||
| 						if (boundBoxVertices[i] < camera.farClipping) { | ||||
| 							infront = true; | ||||
| 							if (behind) break; | ||||
| 						} else { | ||||
| 							behind = true; | ||||
| 							if (infront) break; | ||||
| 						} | ||||
| 					} | ||||
| 					if (behind) { | ||||
| 						if (!infront) return -1; | ||||
| 					} else { | ||||
| 						if (infront) culling &= 61; | ||||
| 					} | ||||
| 				} | ||||
| 				if (culling & 4) { | ||||
| 					for (i = 0, infront = false, behind = false; i <= 21; i += 3) { | ||||
| 						if (-boundBoxVertices[i] < boundBoxVertices[int(i + 2)]) { | ||||
| 							infront = true; | ||||
| 							if (behind) break; | ||||
| 						} else { | ||||
| 							behind = true; | ||||
| 							if (infront) break; | ||||
| 						} | ||||
| 					} | ||||
| 					if (behind) { | ||||
| 						if (!infront) return -1; | ||||
| 					} else { | ||||
| 						if (infront) culling &= 59; | ||||
| 					} | ||||
| 				} | ||||
| 				if (culling & 8) { | ||||
| 					for (i = 0, infront = false, behind = false; i <= 21; i += 3) { | ||||
| 						if (boundBoxVertices[i] < boundBoxVertices[int(i + 2)]) { | ||||
| 							infront = true; | ||||
| 							if (behind) break; | ||||
| 						} else { | ||||
| 							behind = true; | ||||
| 							if (infront) break; | ||||
| 						} | ||||
| 					} | ||||
| 					if (behind) { | ||||
| 						if (!infront) return -1; | ||||
| 					} else { | ||||
| 						if (infront) culling &= 55; | ||||
| 					} | ||||
| 				} | ||||
| 				if (culling & 16) { | ||||
| 					for (i = 1, infront = false, behind = false; i <= 22; i += 3) { | ||||
| 						if (-boundBoxVertices[i] < boundBoxVertices[int(i + 1)]) { | ||||
| 							infront = true; | ||||
| 							if (behind) break; | ||||
| 						} else { | ||||
| 							behind = true; | ||||
| 							if (infront) break; | ||||
| 						} | ||||
| 					} | ||||
| 					if (behind) { | ||||
| 						if (!infront) return -1; | ||||
| 					} else { | ||||
| 						if (infront) culling &= 47; | ||||
| 					} | ||||
| 				} | ||||
| 				if (culling & 32) { | ||||
| 					for (i = 1, infront = false, behind = false; i <= 22; i += 3) { | ||||
| 						if (boundBoxVertices[i] < boundBoxVertices[int(i + 1)]) { | ||||
| 							infront = true; | ||||
| 							if (behind) break; | ||||
| 						} else { | ||||
| 							behind = true; | ||||
| 							if (infront) break; | ||||
| 						} | ||||
| 					} | ||||
| 					if (behind) { | ||||
| 						if (!infront) return -1; | ||||
| 					} else { | ||||
| 						if (infront) culling &= 31; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			// Окклюдинг | ||||
| 			if (occlude) { | ||||
| 				for (var o:int = 0; o < numOccluders; o++) { | ||||
| 					var planeOccluder:Vector.<Number> = camera.occlusionPlanes[o], planeOccluderLength:int = planeOccluder.length; | ||||
| 					for (var ni:int = 0; ni < planeOccluderLength; ni += 3) { | ||||
| 						var nx:Number = planeOccluder[ni], ny:Number = planeOccluder[int(ni + 1)], nz:Number = planeOccluder[int(ni + 2)]; | ||||
| 						for (i = 0; i < 24; i += 3) if (nx*boundBoxVertices[i] + ny*boundBoxVertices[int(i + 1)] + nz*boundBoxVertices[int(i + 2)] >= 0) break; | ||||
| 						if (i < 24) break; | ||||
| 					} | ||||
| 					if (ni == planeOccluderLength) return -1; | ||||
| 				} | ||||
| 			} | ||||
| 			return culling; | ||||
| 		} | ||||
|  | ||||
| 		alternativa3d function drawAxes(camera:Camera3D, canvas:Canvas):void { | ||||
| 			 | ||||
| 		} | ||||
| 		 | ||||
| 		alternativa3d function drawCenter(camera:Camera3D, canvas:Canvas):void { | ||||
| 			 | ||||
| 		} | ||||
| 		 | ||||
| 		alternativa3d function drawName(camera:Camera3D, canvas:Canvas):void { | ||||
| 			 | ||||
| 		} | ||||
| 		 | ||||
| 		static private const boundBoxProjectedVertices:Vector.<Number> = new Vector.<Number>(16, true); | ||||
| 		static private const boundBoxUVTs:Vector.<Number> = new Vector.<Number>(24, true); | ||||
| 		alternativa3d function drawBoundBox(camera:Camera3D, canvas:Canvas, color:int = -1):void { | ||||
| 			 | ||||
| 			var boundBox:BoundBox = this.boundBox; | ||||
| 			if (boundBox == null) return; | ||||
| 			 | ||||
| 			boundBoxVertices[0] = boundBoxVertices[3] = boundBoxVertices[6] = boundBoxVertices[9] = boundBox.minX; | ||||
| 			boundBoxVertices[1] = boundBoxVertices[4] = boundBoxVertices[13] = boundBoxVertices[16] = boundBox.minY; | ||||
| 			boundBoxVertices[2] = boundBoxVertices[8] = boundBoxVertices[14] = boundBoxVertices[20] = boundBox.minZ; | ||||
| 			 | ||||
| 			boundBoxVertices[12] = boundBoxVertices[15] = boundBoxVertices[18] = boundBoxVertices[21] = boundBox.maxX; | ||||
| 			boundBoxVertices[7] = boundBoxVertices[10] = boundBoxVertices[19] = boundBoxVertices[22] = boundBox.maxY; | ||||
| 			boundBoxVertices[5] = boundBoxVertices[11] = boundBoxVertices[17] = boundBoxVertices[23] = boundBox.maxZ; | ||||
| 			 | ||||
| 			cameraMatrix.transformVectors(boundBoxVertices, boundBoxVertices); | ||||
| 			for (var i:int = 0; i < 8; i++) { | ||||
| 				if (boundBoxVertices[int(i*3 +2)] <= 0) return; | ||||
| 			} | ||||
| 			Utils3D.projectVectors(camera.projectionMatrix, boundBoxVertices, boundBoxProjectedVertices, boundBoxUVTs); | ||||
| 			canvas.gfx.endFill(); | ||||
| 			canvas.gfx.lineStyle(0, (color < 0) ? ((culling > 0) ? 0xFFFF00 : 0x00FF00) : color); | ||||
| 			canvas.gfx.moveTo(boundBoxProjectedVertices[0], boundBoxProjectedVertices[1]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[2], boundBoxProjectedVertices[3]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[6], boundBoxProjectedVertices[7]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[4], boundBoxProjectedVertices[5]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[0], boundBoxProjectedVertices[1]); | ||||
| 			canvas.gfx.moveTo(boundBoxProjectedVertices[8], boundBoxProjectedVertices[9]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[10], boundBoxProjectedVertices[11]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[14], boundBoxProjectedVertices[15]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[12], boundBoxProjectedVertices[13]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[8], boundBoxProjectedVertices[9]); | ||||
| 			canvas.gfx.moveTo(boundBoxProjectedVertices[0], boundBoxProjectedVertices[1]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[8], boundBoxProjectedVertices[9]); | ||||
| 			canvas.gfx.moveTo(boundBoxProjectedVertices[2], boundBoxProjectedVertices[3]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[10], boundBoxProjectedVertices[11]); | ||||
| 			canvas.gfx.moveTo(boundBoxProjectedVertices[4], boundBoxProjectedVertices[5]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[12], boundBoxProjectedVertices[13]); | ||||
| 			canvas.gfx.moveTo(boundBoxProjectedVertices[6], boundBoxProjectedVertices[7]); | ||||
| 			canvas.gfx.lineTo(boundBoxProjectedVertices[14], boundBoxProjectedVertices[15]); | ||||
| 		} | ||||
| 		 | ||||
| 		public function toString():String { | ||||
| 			var className:String = getQualifiedClassName(this); | ||||
| 			return "[" + className.substr(className.indexOf("::") + 2) + " " + name + "]"; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,203 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
|  | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	 | ||||
| 	import flash.geom.ColorTransform; | ||||
| 	import flash.geom.Matrix3D; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Базовый контейнер трёхмерных объектов. | ||||
| 	 * Логика контейнеров и child-parent-отношений идентична логике  | ||||
| 	 * displayObject'ов во Flash. | ||||
| 	 */ | ||||
| 	public class Object3DContainer extends Object3D { | ||||
| 		 | ||||
| 		protected var children:Vector.<Object3D> = new Vector.<Object3D>(); | ||||
| 		protected var _numChildren:int = 0; | ||||
| 		 | ||||
| 		protected var visibleChildren:Vector.<Object3D> = new Vector.<Object3D>(); | ||||
| 		protected var numVisibleChildren:int = 0; | ||||
| 		 | ||||
| 		override alternativa3d function get canDraw():Boolean { | ||||
| 			return _numChildren > 0; | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			// Сбор видимых объектов | ||||
| 			numVisibleChildren = 0; | ||||
| 			for (var i:int = 0; i < _numChildren; i++) { | ||||
| 				var child:Object3D = children[i]; | ||||
| 				if (child.visible && child.canDraw) { | ||||
| 					child.cameraMatrix.identity(); | ||||
| 					child.cameraMatrix.prepend(object.cameraMatrix); | ||||
| 					child.cameraMatrix.prepend(child.matrix); | ||||
| 					if (child.cullingInCamera(camera, object.culling) >= 0) { | ||||
| 						visibleChildren[numVisibleChildren] = child; | ||||
| 						numVisibleChildren++; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			// Если есть видимые объекты | ||||
| 			if (numVisibleChildren > 0) { | ||||
| 				// Подготовка канваса | ||||
| 				var canvas:Canvas = parentCanvas.getChildCanvas(false, true, object.alpha, object.blendMode, object.colorTransform, object.filters); | ||||
| 				canvas.numDraws = 0; | ||||
| 				// Отрисовка видимых объектов | ||||
| 				drawVisibleChildren(camera, object, canvas); | ||||
| 				// Если была отрисовка | ||||
| 				if (canvas.numDraws > 0) { | ||||
| 					canvas.removeChildren(canvas.numDraws); | ||||
| 				} else { | ||||
| 					parentCanvas.numDraws--; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		protected function drawVisibleChildren(camera:Camera3D, object:Object3D, canvas:Canvas):void { | ||||
| 			for (var i:int = numVisibleChildren - 1; i >= 0; i--) { | ||||
| 				var child:Object3D = visibleChildren[i]; | ||||
| 				if (camera.debugMode) child.debug(camera, child, canvas); | ||||
| 				child.draw(camera, child, canvas); | ||||
| 				visibleChildren[i] = null; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function getGeometry(camera:Camera3D, object:Object3D):Geometry { | ||||
| 			var i:int; | ||||
| 			var first:Geometry; | ||||
| 			var last:Geometry; | ||||
| 			var geometry:Geometry; | ||||
| 			for (i = 0; i < _numChildren; i++) { | ||||
| 				var child:Object3D = children[i]; | ||||
| 				if (child.visible && child.canDraw) { | ||||
| 					child.cameraMatrix.identity(); | ||||
| 					child.cameraMatrix.prepend(object.cameraMatrix); | ||||
| 					child.cameraMatrix.prepend(child.matrix); | ||||
| 					if (child.cullingInCamera(camera, object.culling) >= 0) { | ||||
| 						geometry = child.getGeometry(camera, child); | ||||
| 						if (geometry != null) { | ||||
| 							if (first != null) { | ||||
| 								last.next = geometry; | ||||
| 							} else { | ||||
| 								first = geometry; | ||||
| 								last = geometry; | ||||
| 							} | ||||
| 							while (last.next != null) { | ||||
| 								last = last.next; | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if (object.alpha != 1) { | ||||
| 				geometry = first; | ||||
| 				while (geometry != null) { | ||||
| 					geometry.alpha *= object.alpha; | ||||
| 					geometry = geometry.next; | ||||
| 				} | ||||
| 			} | ||||
| 			if (object.blendMode != "normal") { | ||||
| 				geometry = first; | ||||
| 				while (geometry != null) { | ||||
| 					if (geometry.blendMode == "normal") { | ||||
| 						geometry.blendMode = object.blendMode; | ||||
| 					} | ||||
| 					geometry = geometry.next; | ||||
| 				} | ||||
| 			} | ||||
| 			if (object.colorTransform != null) { | ||||
| 				geometry = first; | ||||
| 				while (geometry != null) { | ||||
| 					if (geometry.colorTransform != null) { | ||||
| 						var ct:ColorTransform = new ColorTransform(object.colorTransform.redMultiplier, object.colorTransform.greenMultiplier, object.colorTransform.blueMultiplier, object.colorTransform.alphaMultiplier, object.colorTransform.redOffset, object.colorTransform.greenOffset, object.colorTransform.blueOffset, object.colorTransform.alphaOffset); | ||||
| 						ct.concat(geometry.colorTransform); | ||||
| 						geometry.colorTransform = ct; | ||||
| 					} else { | ||||
| 						geometry.colorTransform = object.colorTransform; | ||||
| 					} | ||||
| 					geometry = geometry.next; | ||||
| 				} | ||||
| 			} | ||||
| 			if (object.filters != null) { | ||||
| 				geometry = first; | ||||
| 				while (geometry != null) { | ||||
| 					if (geometry.filters != null) { | ||||
| 						var fs:Array = new Array(); | ||||
| 						var fsLength:int = 0; | ||||
| 						var num:int = geometry.filters.length; | ||||
| 						for (i = 0; i < num; i++) { | ||||
| 							fs[fsLength] = geometry.filters[i]; fsLength++; | ||||
| 						} | ||||
| 						num = object.filters.length; | ||||
| 						for (i = 0; i < num; i++) { | ||||
| 							fs[fsLength] = object.filters[i]; fsLength++; | ||||
| 						} | ||||
| 						geometry.filters = fs; | ||||
| 					} else { | ||||
| 						geometry.filters = object.filters; | ||||
| 					} | ||||
| 					geometry = geometry.next; | ||||
| 				} | ||||
| 			} | ||||
| 			return first; | ||||
| 		} | ||||
| 		 | ||||
| 		override public function calculateBoundBox(matrix:Matrix3D = null, boundBox:BoundBox = null):BoundBox { | ||||
| 			var m:Matrix3D = matrix != null ? matrix.clone() : new Matrix3D(); | ||||
| 			// Если указан баунд-бокс | ||||
| 			if (boundBox != null) { | ||||
| 				boundBox.infinity(); | ||||
| 			} else { | ||||
| 				boundBox = new BoundBox(); | ||||
| 			}			 | ||||
| 			// Расчитываем баунды объектов | ||||
| 			var childBoundBox:BoundBox = new BoundBox(); | ||||
| 			var childMatrix:Matrix3D = new Matrix3D(); | ||||
| 			for (var i:int = 0; i < _numChildren; i++) { | ||||
| 				var child:Object3D = children[i]; | ||||
| 				childMatrix.identity(); | ||||
| 				childMatrix.prepend(m); | ||||
| 				childMatrix.prepend(child.matrix); | ||||
| 				child.calculateBoundBox(childMatrix, childBoundBox); | ||||
| 				boundBox.minX = (childBoundBox.minX < boundBox.minX) ? childBoundBox.minX : boundBox.minX; | ||||
| 				boundBox.minY = (childBoundBox.minY < boundBox.minY) ? childBoundBox.minY : boundBox.minY; | ||||
| 				boundBox.minZ = (childBoundBox.minZ < boundBox.minZ) ? childBoundBox.minZ : boundBox.minZ; | ||||
| 				boundBox.maxX = (childBoundBox.maxX > boundBox.maxX) ? childBoundBox.maxX : boundBox.maxX; | ||||
| 				boundBox.maxY = (childBoundBox.maxY > boundBox.maxY) ? childBoundBox.maxY : boundBox.maxY; | ||||
| 				boundBox.maxZ = (childBoundBox.maxZ > boundBox.maxZ) ? childBoundBox.maxZ : boundBox.maxZ; | ||||
| 			} | ||||
| 			return boundBox; | ||||
| 		} | ||||
| 		 | ||||
| 		public function addChild(child:Object3D):void { | ||||
| 			children[_numChildren++] = child; | ||||
| 			child._parent = this; | ||||
| 		} | ||||
|  | ||||
| 		public function removeChild(child:Object3D):void { | ||||
| 			var i:int = children.indexOf(child); | ||||
| 			if (i < 0) throw new ArgumentError("Child not found"); | ||||
| 			_numChildren--; | ||||
| 			for (; i < _numChildren; i++) children[i] = children[int(i + 1)]; | ||||
| 			children.length = _numChildren; | ||||
| 			child._parent = null; | ||||
| 		} | ||||
| 		 | ||||
| 		public function hasChild(child:Object3D):Boolean { | ||||
| 			return children.indexOf(child) > -1; | ||||
| 		} | ||||
| 		 | ||||
| 		public function getChildAt(index:uint):Object3D { | ||||
| 			return children[index]; | ||||
| 		} | ||||
|  | ||||
| 		public function get numChildren():uint { | ||||
| 			return _numChildren; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,23 +0,0 @@ | ||||
| package alternativa.engine3d.core { | ||||
| 	 | ||||
| 	public class Sorting { | ||||
| 				 | ||||
| 		/** | ||||
| 		 * Грани не сортируются.  | ||||
| 		 */ | ||||
| 		static public const NONE:int = 0; | ||||
| 		/** | ||||
| 		 * Грани сортируются по средним Z. | ||||
| 		 */ | ||||
| 		static public const AVERAGE_Z:int = 1; | ||||
| 		/** | ||||
| 		 * Грани находятся в BSP-дереве. | ||||
| 		 */ | ||||
| 		static public const STATIC_BSP:int = 2; | ||||
| 		/** | ||||
| 		 * Грани при отрисовке образуют BSP-дерево. | ||||
| 		 */ | ||||
| 		static public const DYNAMIC_BSP:int = 3; | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,59 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 105 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders | ||||
| END | ||||
| TextureFilesData.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 125 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/TextureFilesData.as | ||||
| END | ||||
| Loader3DS.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 118 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/Loader3DS.as | ||||
| END | ||||
| MaterialParams.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 123 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/MaterialParams.as | ||||
| END | ||||
| Parsed3DSData.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 122 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/Parsed3DSData.as | ||||
| END | ||||
| Loader3DSByteArray.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 127 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/Loader3DSByteArray.as | ||||
| END | ||||
| Parser3DS.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 118 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/Parser3DS.as | ||||
| END | ||||
| TextureLoader.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 122 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/TextureLoader.as | ||||
| END | ||||
| BatchTextureLoader.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 127 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/BatchTextureLoader.as | ||||
| END | ||||
| TextureInfo.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 120 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/TextureInfo.as | ||||
| END | ||||
| @@ -1,139 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| TextureFilesData.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 5dab534b47ec603953467a319d0a9757 | ||||
| 2009-03-03T10:45:06.942390Z | ||||
| 8557 | ||||
| mike | ||||
|  | ||||
| Loader3DS.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 65726f9d6bede8e1fedd506d28056fed | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
| events | ||||
| dir | ||||
|  | ||||
| MaterialParams.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 101884503099df0a70e423bd56fcfa4b | ||||
| 2009-03-03T10:45:06.942390Z | ||||
| 8557 | ||||
| mike | ||||
|  | ||||
| Parsed3DSData.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 9c3dbe4c093e301aa3af29bb56a12386 | ||||
| 2009-03-03T10:45:06.942390Z | ||||
| 8557 | ||||
| mike | ||||
|  | ||||
| Loader3DSByteArray.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| ed80c6eb3e24ea03208ce9363846c069 | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
| Parser3DS.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| b48bd1b567b70ed6ae2bf5a19e7937a3 | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
| TextureLoader.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 2fe362bd5849c1f2bced6097745e778e | ||||
| 2009-09-24T13:14:56.450304Z | ||||
| 20448 | ||||
| mike | ||||
|  | ||||
| BatchTextureLoader.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| a200c12bc82bf970605115a4f35be670 | ||||
| 2009-08-27T08:28:22.626310Z | ||||
| 18884 | ||||
| mike | ||||
|  | ||||
| TextureInfo.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 1b2b5a651cb0fb845e977f30ad97b28e | ||||
| 2009-08-27T08:17:26.370911Z | ||||
| 18883 | ||||
| mike | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 8 | ||||
| @@ -1,275 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.loaders.events.BatchTextureLoaderErrorEvent; | ||||
| 	import alternativa.engine3d.loaders.events.LoaderEvent; | ||||
| 	import alternativa.engine3d.loaders.events.LoaderProgressEvent; | ||||
| 	 | ||||
| 	import flash.display.BitmapData; | ||||
| 	import flash.events.ErrorEvent; | ||||
| 	import flash.events.Event; | ||||
| 	import flash.events.EventDispatcher; | ||||
| 	import flash.events.IOErrorEvent; | ||||
| 	import flash.system.LoaderContext; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Событие посылается, когда начинается загрузка пакета. | ||||
| 	 *  | ||||
| 	 * @eventType flash.events.Event.OPEN | ||||
| 	 */ | ||||
| 	[Event (name="open", type="flash.events.Event")] | ||||
| 	/** | ||||
| 	 * Событие посылается, когда загрузка пакета успешно завершена. | ||||
| 	 *  | ||||
| 	 * @eventType flash.events.Event.COMPLETE | ||||
| 	 */ | ||||
| 	[Event (name="complete", type="flash.events.Event")] | ||||
| 	/** | ||||
| 	 * Событие посылается при возникновении ошибки загрузки. | ||||
| 	 *  | ||||
| 	 * @eventType alternativa.engine3d.loaders.events.BatchTextureLoaderErrorEvent.LOADER_ERROR | ||||
| 	 */ | ||||
| 	[Event (name="loaderError", type="alternativa.engine3d.loaders.events.BatchTextureLoaderErrorEvent")] | ||||
| 	/** | ||||
| 	 * Событие посылается, когда начинается загрузка очередной текстуры. | ||||
| 	 *  | ||||
| 	 * @eventType alternativa.engine3d.loaders.events.LoaderEvent.PART_OPEN | ||||
| 	 */ | ||||
| 	[Event (name="partOpen", type="alternativa.engine3d.loaders.events.LoaderEvent")] | ||||
| 	/** | ||||
| 	 * Событие посылается, когда загрузка очередной текстуры успешно завершена. | ||||
| 	 *  | ||||
| 	 * @eventType alternativa.engine3d.loaders.events.LoaderEvent.PART_COMPLETE | ||||
| 	 */ | ||||
| 	[Event (name="partComplete", type="alternativa.engine3d.loaders.events.LoaderEvent")] | ||||
| 	/** | ||||
| 	 * Событие посылается для отображения прогресса загрузки. | ||||
| 	 *  | ||||
| 	 * @eventType alternativa.engine3d.loaders.events.LoaderProgressEvent.LOADER_PROGRESS | ||||
| 	 */ | ||||
| 	[Event (name="loaderProgress", type="alternativa.engine3d.loaders.events.LoaderProgressEvent")] | ||||
| 	 | ||||
| 	/** | ||||
| 	 * @private | ||||
| 	 * Пакетный загрузчик текстур. | ||||
| 	 *  | ||||
| 	 * При возникновении ошибки во время загрузки очередной текстуры, пакетный загрузчик заменяет соответствующую текстуру изображением-заглушкой и | ||||
| 	 * генерирует событие ошибки пакетного загрузчика. Пользователь пакетного загрузчика в обработчике ошибки может решить, прерывать ли процесс | ||||
| 	 * загрузки вызовом метода close() или нет. | ||||
| 	 */ | ||||
| 	public class BatchTextureLoader extends EventDispatcher { | ||||
| 		/** | ||||
| 		 * Текстура-заглушка для замены незагруженных текстур. | ||||
| 		 */ | ||||
| 		private static var stubBitmapData:BitmapData; | ||||
| 		 | ||||
| 		private static const IDLE:int = 0; | ||||
| 		private static const LOADING:int = 1; | ||||
| 		 | ||||
| 		// Состояние загрузчика | ||||
| 		private var state:int = IDLE; | ||||
| 		 | ||||
| 		// Загрузчик текстур | ||||
| 		private var textureLoader:TextureLoader; | ||||
| 		// Контекст безопасности загрузчика | ||||
| 		private var loaderContext:LoaderContext; | ||||
| 		// Базовый URL файлов текстур | ||||
| 		private var baseURL:String; | ||||
| 		// Пакет с описанием текстур материалов (textureName => TextureInfo) | ||||
| 		private var batch:Object; | ||||
| 		// Список имён текстур в пакете | ||||
| 		private var textureNames:Vector.<String>; | ||||
| 		// Индекс текущего материала. | ||||
| 		private var textureIndex:int; | ||||
| 		// Общее количество загружаемых текстур | ||||
| 		private var numTextures:int; | ||||
| 		// Результирующая таблица (textureName => BitmapData) | ||||
| 		private var _textures:Object; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт новый экземпляр загрузчика. | ||||
| 		 */ | ||||
| 		public function BatchTextureLoader() { | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Результирующая таблица битмапов. Ключами являются имена текстур, значениями -- объекты класса BitmapData. | ||||
| 		 */ | ||||
| 		public function get textures():Object { | ||||
| 			return _textures; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Прекращает текущую загрузку. | ||||
| 		 */ | ||||
| 		public function close():void { | ||||
| 			if (state == LOADING) { | ||||
| 				textureLoader.close(); | ||||
| 				cleanup(); | ||||
| 				_textures = null; | ||||
| 				state = IDLE; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Очищает ссылку на загруженный список текстур материалов. | ||||
| 		 */ | ||||
| 		public function unload():void { | ||||
| 			_textures = null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Запускает загрузку. | ||||
| 		 *  | ||||
| 		 * @param baseURL базовый URL файлов текстур | ||||
| 		 * @param batch описание пакета текстур -- таблица textureName => TextureInfo | ||||
| 		 * @param loaderContext LoaderContext для загрузки | ||||
| 		 */ | ||||
| 		public function load(baseURL:String, batch:Object, loaderContext:LoaderContext = null):void { | ||||
| 			if (baseURL == null) { | ||||
| 				throw ArgumentError("Parameter baseURL cannot be null"); | ||||
| 			} | ||||
| 			if (batch == null) { | ||||
| 				throw ArgumentError("Parameter batch cannot be null"); | ||||
| 			} | ||||
| 			 | ||||
| 			this.baseURL = baseURL; | ||||
| 			this.batch = batch; | ||||
| 			this.loaderContext = loaderContext; | ||||
| 			 | ||||
| 			if (textureLoader == null) { | ||||
| 				textureLoader = new TextureLoader(); | ||||
| 			} else { | ||||
| 				close(); | ||||
| 			} | ||||
| 			textureLoader.addEventListener(Event.OPEN, onTextureLoadingStart); | ||||
| 			textureLoader.addEventListener(LoaderProgressEvent.LOADER_PROGRESS, onProgress); | ||||
| 			textureLoader.addEventListener(Event.COMPLETE, onTextureLoadingComplete); | ||||
| 			textureLoader.addEventListener(IOErrorEvent.IO_ERROR, onLoadingError); | ||||
|  | ||||
| 			// Получение массива имён текстур | ||||
| 			textureNames = new Vector.<String>(); | ||||
| 			for (var textureName:String in batch) { | ||||
| 				textureNames.push(textureName); | ||||
| 			} | ||||
| 			numTextures = textureNames.length; | ||||
| 			// Старт загрузки | ||||
| 			textureIndex = 0; | ||||
| 			_textures = {}; | ||||
| 			 | ||||
| 			if (hasEventListener(Event.OPEN)) { | ||||
| 				dispatchEvent(new Event(Event.OPEN)); | ||||
| 			} | ||||
| 			 | ||||
| 			state = LOADING; | ||||
| 			loadNextTexture(); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Запускает загрузку очередной текстуры. | ||||
| 		 */ | ||||
| 		private function loadNextTexture():void { | ||||
| 			var info:TextureInfo = batch[textureNames[textureIndex]]; | ||||
| 			var opacityMapFileUrl:String = info.opacityMapFileName == null || info.opacityMapFileName == "" ? null : baseURL + info.opacityMapFileName; | ||||
| 			textureLoader.load(baseURL + info.diffuseMapFileName, opacityMapFileUrl, loaderContext); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function onTextureLoadingStart(e:Event):void { | ||||
| 			if (hasEventListener(LoaderEvent.PART_OPEN)) { | ||||
| 				dispatchEvent(new LoaderEvent(LoaderEvent.PART_OPEN, numTextures, textureIndex)); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function onProgress(e:LoaderProgressEvent):void { | ||||
| 			if (hasEventListener(LoaderProgressEvent.LOADER_PROGRESS)) { | ||||
| 				var totalProgress:Number = (textureIndex + e.totalProgress)/numTextures; | ||||
| 				dispatchEvent(new LoaderProgressEvent(LoaderProgressEvent.LOADER_PROGRESS, numTextures, textureIndex, totalProgress, e.bytesLoaded, e.bytesTotal)); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Обрабатывает завершение загрузки текстуры. | ||||
| 		 */ | ||||
| 		private function onTextureLoadingComplete(e:Event):void { | ||||
| 			_textures[textureNames[textureIndex]] = textureLoader.bitmapData; | ||||
| 			tryNextTexure(); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Обрабатывает ошибку при загрузке текстуры. Незагруженная текстура заменяется изображением-заглушкой и | ||||
| 		 * генерируется событие ошибки пакетного загрузчика. | ||||
| 		 */ | ||||
| 		private function onLoadingError(e:ErrorEvent):void { | ||||
| 			var textureName:String = textureNames[textureIndex]; | ||||
| 			_textures[textureName] = getStubBitmapData(); | ||||
| 			dispatchEvent(new BatchTextureLoaderErrorEvent(BatchTextureLoaderErrorEvent.LOADER_ERROR, textureName, e.text)); | ||||
| 			tryNextTexure(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function tryNextTexure():void { | ||||
| 			// Проверка состояния необходима, т.к. оно могло измениться в результате вызова метода close() в обработчике события ошибки загрузки | ||||
| 			if (state == IDLE) return; | ||||
| 			 | ||||
| 			if (hasEventListener(LoaderEvent.PART_COMPLETE)) { | ||||
| 				dispatchEvent(new LoaderEvent(LoaderEvent.PART_COMPLETE, numTextures, textureIndex)); | ||||
| 			} | ||||
| 			if (++textureIndex == numTextures) { | ||||
| 				// Загружены все текстуры, отправляется сообщение о завершении | ||||
| 				cleanup(); | ||||
| 				removeEventListeners(); | ||||
| 				state = IDLE; | ||||
| 				if (hasEventListener(Event.COMPLETE)) { | ||||
| 					dispatchEvent(new Event(Event.COMPLETE)); | ||||
| 				} | ||||
| 			} else { | ||||
| 				loadNextTexture(); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function removeEventListeners():void { | ||||
| 			textureLoader.removeEventListener(Event.OPEN, onTextureLoadingStart); | ||||
| 			textureLoader.removeEventListener(LoaderProgressEvent.LOADER_PROGRESS, onProgress); | ||||
| 			textureLoader.removeEventListener(Event.COMPLETE, onTextureLoadingComplete); | ||||
| 			textureLoader.removeEventListener(IOErrorEvent.IO_ERROR, onLoadingError); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Очищает внутренние ссылки на объекты. | ||||
| 		 */ | ||||
| 		private function cleanup():void { | ||||
| 			loaderContext = null; | ||||
| 			textureNames = null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Метод для получения текстуры-заглушки. | ||||
| 		 * 	 | ||||
| 		 * @return текстура-заглушка для замещения незагруженных текстур | ||||
| 		 */ | ||||
| 		private function getStubBitmapData():BitmapData { | ||||
| 			if (stubBitmapData == null) { | ||||
| 				var size:uint = 20; | ||||
| 				stubBitmapData = new BitmapData(size, size, false, 0); | ||||
| 				for (var i:uint = 0; i < size; i++) { | ||||
| 					for (var j:uint = 0; j < size; j += 2) { | ||||
| 						stubBitmapData.setPixel((i%2) ? j : (j + 1), i, 0xFF00FF); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			return stubBitmapData; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,927 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.objects.Mesh; | ||||
| 	 | ||||
| 	import flash.display.BitmapData; | ||||
| 	import flash.display.BlendMode; | ||||
| 	import flash.events.Event; | ||||
| 	import flash.events.EventDispatcher; | ||||
| 	import flash.events.IOErrorEvent; | ||||
| 	import flash.events.SecurityErrorEvent; | ||||
| 	import flash.geom.Matrix; | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Orientation3D; | ||||
| 	import flash.geom.Point; | ||||
| 	import flash.geom.Vector3D; | ||||
| 	import flash.net.URLLoader; | ||||
| 	import flash.net.URLLoaderDataFormat; | ||||
| 	import flash.net.URLRequest; | ||||
| 	import flash.system.LoaderContext; | ||||
| 	import flash.utils.ByteArray; | ||||
| 	import flash.utils.Endian; | ||||
|  | ||||
| 	[Event (name="complete", type="flash.events.Event")]	 | ||||
| 	/** | ||||
| 	 *  | ||||
| 	 */ | ||||
| 	public class Loader3DS extends EventDispatcher { | ||||
|  | ||||
| 		private static const STATE_IDLE:int = -1; | ||||
| 		private static const STATE_LOADING_MODEL:int = 0; | ||||
| 		private static const STATE_LOADING_TEXTURES:int = 1; | ||||
| 		 | ||||
| 		private static var stubBitmapData:BitmapData; | ||||
| 		 | ||||
| 		private var _content:Vector.<Mesh>; | ||||
| 		private var version:uint; | ||||
| 		private var objectDatas:Object; | ||||
| 		private var animationDatas:Array; | ||||
| 		private var materialDatas:Array; | ||||
| 		private var bitmaps:Array; | ||||
| 		 | ||||
| 		private var modelLoader:URLLoader; | ||||
| 		private var textureLoader:TextureLoader; | ||||
| 		private var data:ByteArray; | ||||
| 		 | ||||
| 		private var counter:int; | ||||
| 		private var textureMaterialNames:Array; | ||||
| 		private var context:LoaderContext; | ||||
| 		private var path:String; | ||||
| 		 | ||||
| 		private var loaderState:int = STATE_IDLE; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Повтор текстуры при заливке для создаваемых текстурных материалов. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */ | ||||
| 		public var repeat:Boolean = true; | ||||
| 		/** | ||||
| 		 * Сглаживание текстур при увеличении масштаба. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */		 | ||||
| 		public var smooth:Boolean = false; | ||||
| 		/** | ||||
| 		 * Режим наложения цвета для создаваемых текстурных материалов. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */ | ||||
| 		public var blendMode:String = BlendMode.NORMAL; | ||||
|  | ||||
| 		/** | ||||
| 		 * Коэффициент пересчёта единиц измерения модели. | ||||
| 		 */ | ||||
| 		public var units:Number = 1; | ||||
| 		/** | ||||
| 		 * Устанавливаемый уровень мобильности загруженных объектов. | ||||
| 		 */		 | ||||
| 		public var mobility:int = 0; | ||||
|  | ||||
| 		/** | ||||
| 		 * Прекращение текущей загрузки. | ||||
| 		 */ | ||||
| 		public function close():void { | ||||
| 			if (loaderState == STATE_LOADING_MODEL) { | ||||
| 				modelLoader.close(); | ||||
| 			} | ||||
| 			if (loaderState == STATE_LOADING_TEXTURES) { | ||||
| 				textureLoader.close(); | ||||
| 			} | ||||
| 			loaderState = STATE_IDLE; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Метод очищает внутренние ссылки на загруженные данные чтобы сборщик мусора мог освободить занимаемую ими память. Метод не работает | ||||
| 		 * во время загрузки. | ||||
| 		 */ | ||||
| 		public function unload():void { | ||||
| 			if (loaderState == STATE_IDLE) { | ||||
| 				clean(); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function clean():void { | ||||
| 			_content = null; | ||||
| 			objectDatas = null; | ||||
| 			animationDatas = null; | ||||
| 			materialDatas = null; | ||||
| 			bitmaps = null; | ||||
| 			textureMaterialNames = null; | ||||
| 		} | ||||
| 		 | ||||
| 		public function load(url:String, context:LoaderContext = null):void { | ||||
| 			path = url.substring(0, url.lastIndexOf("/") + 1); | ||||
| 			this.context = context; | ||||
| 			 | ||||
| 			// Очистка | ||||
| 			version = 0; | ||||
| 			clean(); | ||||
| 			 | ||||
| 			if (modelLoader == null) { | ||||
| 				modelLoader = new URLLoader(); | ||||
| 				modelLoader.dataFormat = URLLoaderDataFormat.BINARY; | ||||
| 				modelLoader.addEventListener(Event.COMPLETE, on3DSLoad); | ||||
| 				modelLoader.addEventListener(IOErrorEvent.IO_ERROR, on3DSError); | ||||
| 				modelLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, on3DSError); | ||||
| 			} else { | ||||
| 				close(); | ||||
| 			} | ||||
| 			 | ||||
| 			loaderState = STATE_LOADING_MODEL; | ||||
| 			modelLoader.load(new URLRequest(url)); | ||||
| 		}  | ||||
|  | ||||
| 		private function on3DSLoad(e:Event):void { | ||||
| 			loaderState = STATE_IDLE; | ||||
| 			data = modelLoader.data; | ||||
| 			data.endian = Endian.LITTLE_ENDIAN; | ||||
| 			parse3DSChunk(0, data.bytesAvailable); | ||||
| 		} | ||||
| 		 | ||||
| 		private function on3DSError(e:Event):void { | ||||
| 			loaderState = STATE_IDLE; | ||||
| 			dispatchEvent(e); | ||||
| 		} | ||||
| 		 | ||||
| 		private function loadBitmaps():void { | ||||
| 			if (textureLoader == null) { | ||||
| 				textureLoader = new TextureLoader(); | ||||
| 				textureLoader.addEventListener(Event.COMPLETE, loadNextBitmap); | ||||
| 				textureLoader.addEventListener(IOErrorEvent.IO_ERROR, loadNextBitmap); | ||||
| 			} | ||||
| 			 | ||||
| 			// Имена материалов с диффузными текстурами собираются в массив textureMaterialNames | ||||
| 			bitmaps = new Array(); | ||||
| 			textureMaterialNames = new Array(); | ||||
| 			for each (var materialData:MaterialData in materialDatas) { | ||||
| 				if (materialData.diffuseMap != null) { | ||||
| 					textureMaterialNames.push(materialData.name); | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			loaderState = STATE_LOADING_TEXTURES; | ||||
| 			loadNextBitmap(); | ||||
| 		} | ||||
| 		 | ||||
| 		private function loadNextBitmap(e:Event = null):void { | ||||
| 			if (e != null) { | ||||
| 				if (!(e is IOErrorEvent)) { | ||||
| 					bitmaps[textureMaterialNames[counter]] = textureLoader.bitmapData; | ||||
| 				} else { | ||||
| 					if (stubBitmapData == null) { | ||||
| 						var size:uint = 20; | ||||
| 						stubBitmapData = new BitmapData(size, size, false, 0); | ||||
| 						for (var i:uint = 0; i < size; i++) { | ||||
| 							for (var j:uint = 0; j < size; j+=2) { | ||||
| 								stubBitmapData.setPixel((i % 2) ? j : (j+1), i, 0xFF00FF); | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 					bitmaps[textureMaterialNames[counter]] = stubBitmapData; | ||||
| 				} | ||||
| 			} else { | ||||
| 				counter = -1; | ||||
| 			} | ||||
| 			counter++; | ||||
| 			if (counter < textureMaterialNames.length) { | ||||
| 				var materialData:MaterialData = materialDatas[textureMaterialNames[counter]]; | ||||
| 				textureLoader.load(path + materialData.diffuseMap.filename, materialData.opacityMap == null ? null : path + materialData.opacityMap.filename, context); | ||||
| 			} else { | ||||
| 				loaderState = STATE_IDLE; | ||||
| 				buildContent(); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function buildContent():void { | ||||
| 			var i:uint; | ||||
| 			var length:uint; | ||||
| 			 | ||||
| 			// Формируем связи объектов | ||||
| 			_content = new Vector.<Mesh>(); | ||||
| 			 | ||||
| 			// Создаём материалы | ||||
| 			var materialData:MaterialData; | ||||
| 			for (var materialName:String in materialDatas) { | ||||
| 				materialData = materialDatas[materialName]; | ||||
| 				var mapData:MapData = materialData.diffuseMap; | ||||
| 				var materialMatrix:Matrix = new Matrix(); | ||||
| 				if (mapData != null) { | ||||
| 					var rot:Number = mapData.rotation*Math.PI/180; | ||||
| 					var rotSin:Number = Math.sin(rot); | ||||
| 					var rotCos:Number = Math.cos(rot); | ||||
| 					materialMatrix.translate(-mapData.offsetU, mapData.offsetV); | ||||
| 					materialMatrix.translate(-0.5, -0.5); | ||||
| 					materialMatrix.rotate(-rot); | ||||
| 					materialMatrix.scale(mapData.scaleU, mapData.scaleV); | ||||
| 					materialMatrix.translate(0.5, 0.5); | ||||
| 				} | ||||
| 				materialData.matrix = materialMatrix; | ||||
| 			} | ||||
| 			 | ||||
| 			// Если есть данные об анимации и иерархии объектов | ||||
| 			var objectName:String; | ||||
| 			var objectData:ObjectData; | ||||
| 			var mesh:Mesh; | ||||
| 			if (animationDatas != null) { | ||||
| 				if (objectDatas != null) { | ||||
| 					 | ||||
| 					length = animationDatas.length; | ||||
| 					for (i = 0; i < length; i++) { | ||||
| 						var animationData:AnimationData = animationDatas[i]; | ||||
| 						objectName = animationData.objectName; | ||||
| 						objectData = objectDatas[objectName]; | ||||
| 						 | ||||
| 						// Если на один объект приходится несколько данных об анимации | ||||
| 						if (objectData != null) { | ||||
| 							var nameCounter:uint = 2; | ||||
| 							for (var j:uint = i + 1; j < length; j++) { | ||||
| 								var animationData2:AnimationData = animationDatas[j]; | ||||
| 								if (objectName == animationData2.objectName) { | ||||
| 									var newName:String = objectName + nameCounter; | ||||
| 									var newObjectData:ObjectData = new ObjectData(); | ||||
| 									animationData2.objectName = newName; | ||||
| 									newObjectData.name = newName; | ||||
| 									if (objectData.vertices != null) { | ||||
| 										newObjectData.vertices = new Vector.<Vector3D>().concat(objectData.vertices); | ||||
| 									} | ||||
| 									if (objectData.uvs != null) { | ||||
| 										newObjectData.uvs = new new Vector.<Point>().concat(objectData.uvs); | ||||
| 									} | ||||
| 									if (objectData.matrix != null) { | ||||
| 										newObjectData.matrix = objectData.matrix.clone(); | ||||
| 									} | ||||
| 									if (objectData.faces != null) { | ||||
| 										newObjectData.faces = new Array().concat(objectData.faces); | ||||
| 									} | ||||
| 									if (objectData.surfaces != null) { | ||||
| 										newObjectData.surfaces = objectData.surfaces.clone(); | ||||
| 									} | ||||
| 									objectDatas[newName] = newObjectData; | ||||
| 									nameCounter++; | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						 | ||||
| 						if (objectData != null && objectData.vertices != null) { | ||||
| 							// Меш | ||||
| 							mesh = new Mesh(); | ||||
| 							mesh.createEmptyGeometry(objectData.vertices.length, objectData.faces.length); | ||||
| 							animationData.object = mesh; | ||||
| 							buildObject(animationData); | ||||
| 							buildMesh(mesh, objectData, animationData); | ||||
| 							_content.push(mesh); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				for (objectName in objectDatas) { | ||||
| 					objectData = objectDatas[objectName]; | ||||
| 					if (objectData.vertices != null) { | ||||
| 						// Меш | ||||
| 						mesh = new Mesh(); | ||||
| 						mesh.createEmptyGeometry(objectData.vertices.length, objectData.faces.length); | ||||
| 						buildMesh(mesh, objectData, null); | ||||
| 						_content.push(mesh); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			// Рассылаем событие о завершении | ||||
| 			dispatchEvent(new Event(Event.COMPLETE)); | ||||
| 		} | ||||
| 		 | ||||
| 		private function buildObject(animationData:AnimationData):void { | ||||
| 			var object:Mesh = animationData.object; | ||||
| 			object.name = animationData.objectName; | ||||
| 			var transform:Vector.<Vector3D> = new Vector.<Vector3D>(3, true); | ||||
| 			transform[0] = (animationData.position == null) ? new Vector3D() : new Vector3D(animationData.position.x * units, animationData.position.y * units, animationData.position.z * units); | ||||
| 			transform[1] = (animationData.rotation == null) ? new Vector3D() : animationData.rotation.clone(); | ||||
| 			transform[2] = (animationData.scale == null) ? new Vector3D(1, 1, 1) : animationData.scale.clone(); | ||||
| 			object.matrix.recompose(transform, Orientation3D.AXIS_ANGLE); | ||||
| 		} | ||||
| 		 | ||||
| 		private function buildMesh(mesh:Mesh, objectData:ObjectData, animationData:AnimationData):void { | ||||
| 			// Добавляем вершины | ||||
| 			var i:uint; | ||||
| 			var j:uint; | ||||
| 			var key:*; | ||||
| 			var length:uint = objectData.vertices.length; | ||||
| 			for (i = 0; i < length; i++) { | ||||
| 				var vertexData:Vector3D = objectData.vertices[i]; | ||||
| 				var uv:Point = objectData.uvs[i]; | ||||
| 				j = i*3; | ||||
| 				mesh.vertices[j] = vertexData.x; | ||||
| 				mesh.vertices[j + 1] = vertexData.y; | ||||
| 				mesh.vertices[j + 2] = vertexData.z; | ||||
| 				mesh.uvts[j] = uv.x; | ||||
| 				mesh.uvts[j + 1] = 1 - uv.y; | ||||
| 			} | ||||
| 			 | ||||
| 			// Коррекция вершин | ||||
| 			if (animationData != null) { | ||||
| 				// Инвертируем матрицу | ||||
| 				objectData.matrix.invert(); | ||||
| 				 | ||||
| 				// Вычитаем точку привязки из смещения матрицы | ||||
| 				if (animationData.pivot != null) { | ||||
| 					objectData.matrix.appendTranslation(-animationData.pivot.x, -animationData.pivot.y, -animationData.pivot.z);  | ||||
| 				} | ||||
| 				 | ||||
| 				// Трансформируем вершины | ||||
| 				objectData.matrix.transformVectors(mesh.vertices, mesh.vertices); | ||||
| 			} | ||||
| 			for (i = 0; i < mesh.numVertices*3; i++) { | ||||
| 				mesh.vertices[i] *= units; | ||||
| 			} | ||||
| 			 | ||||
| 			// Добавляем грани | ||||
| 			length = objectData.faces.length; | ||||
| 			for (i = 0; i < length; i++) { | ||||
| 				var faceData:FaceData = objectData.faces[i]; | ||||
| 				j = i*3; | ||||
| 				mesh.indices[j] = faceData.a; | ||||
| 				mesh.indices[j + 1] = faceData.b; | ||||
| 				mesh.indices[j + 2] = faceData.c; | ||||
| 			} | ||||
| 			 | ||||
| 			// Добавляем поверхности | ||||
| 			if (objectData.surfaces != null) { | ||||
| 				for (var surfaceId:String in objectData.surfaces) { | ||||
| 					var materialData:MaterialData = materialDatas[surfaceId]; | ||||
| 					if (materialData.diffuseMap != null) { | ||||
| 						mesh.texture = bitmaps[materialData.name]; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		private function parse3DSChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Главный | ||||
| 					case 0x4D4D: | ||||
| 						parseMainChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parse3DSChunk(index + chunkLength, length - chunkLength); | ||||
| 			} else { | ||||
| 				// Загрузка битмап | ||||
| 				loadBitmaps(); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMainChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Версия | ||||
| 					case 0x0002: | ||||
| 						parseVersion(dataIndex); | ||||
| 						break; | ||||
| 					// 3D-сцена | ||||
| 					case 0x3D3D: | ||||
| 						parse3DChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Анимация | ||||
| 					case 0xB000: | ||||
| 						parseAnimationChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMainChunk(index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseVersion(index:uint):void { | ||||
| 			data.position = index; | ||||
| 			version = data.readUnsignedInt(); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parse3DChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Материал | ||||
| 					case 0xAFFF: | ||||
| 						// Парсим материал | ||||
| 						var material:MaterialData = new MaterialData(); | ||||
| 						parseMaterialChunk(material, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Объект | ||||
| 					case 0x4000: | ||||
| 						// Создаём данные объекта | ||||
| 						var object:ObjectData = new ObjectData(); | ||||
| 						var objectLength:uint = parseObject(object, dataIndex); | ||||
| 						// Парсим объект | ||||
| 						parseObjectChunk(object, dataIndex + objectLength, dataLength - objectLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parse3DChunk(index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMaterialChunk(material:MaterialData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Имя материала | ||||
| 					case 0xA000: | ||||
| 						parseMaterialName(material, dataIndex); | ||||
| 						break; | ||||
| 					// Ambient color | ||||
| 					case 0xA010: | ||||
| 						break; | ||||
| 					// Diffuse color | ||||
| 					case 0xA020: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.color = (data.readUnsignedByte() << 16) + (data.readUnsignedByte() << 8) + data.readUnsignedByte(); | ||||
| 						break; | ||||
| 					// Specular color | ||||
| 					case 0xA030: | ||||
| 						break; | ||||
| 					// Shininess percent | ||||
| 					case 0xA040: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.glossiness = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Shininess strength percent | ||||
| 					case 0xA041: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.specular = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Transperensy | ||||
| 					case 0xA050: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.transparency = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Texture map 1 | ||||
| 					case 0xA200: | ||||
| 						material.diffuseMap = new MapData(); | ||||
| 						parseMapChunk(material.name, material.diffuseMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Texture map 2 | ||||
| 					case 0xA33A: | ||||
| 						break; | ||||
| 					// Opacity map | ||||
| 					case 0xA210: | ||||
| 						material.opacityMap = new MapData(); | ||||
| 						parseMapChunk(material.name, material.opacityMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Bump map | ||||
| 					case 0xA230: | ||||
| 						//material.normalMap = new MapData(); | ||||
| 						//parseMapChunk(material.normalMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Shininess map | ||||
| 					case 0xA33C: | ||||
| 						break; | ||||
| 					// Specular map | ||||
| 					case 0xA204: | ||||
| 						break; | ||||
| 					// Self-illumination map | ||||
| 					case 0xA33D: | ||||
| 						break; | ||||
| 					// Reflection map | ||||
| 					case 0xA220: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMaterialChunk(material, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMaterialName(material:MaterialData, index:uint):void { | ||||
| 			// Создаём список материалов, если надо | ||||
| 			if (materialDatas == null) { | ||||
| 				materialDatas = new Array(); | ||||
| 			} | ||||
| 			// Получаем название материала | ||||
| 			material.name = getString(index); | ||||
| 			// Помещаем данные материала в список | ||||
| 			materialDatas[material.name] = material; | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMapChunk(materialName:String, map:MapData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Имя файла | ||||
| 					case 0xA300: | ||||
| 						map.filename = getString(dataIndex).toLowerCase(); | ||||
| 						break; | ||||
| 					// Масштаб по U | ||||
| 					case 0xA354: | ||||
| 						data.position = dataIndex; | ||||
| 						map.scaleU = data.readFloat(); | ||||
| 						break; | ||||
| 					// Масштаб по V | ||||
| 					case 0xA356: | ||||
| 						data.position = dataIndex; | ||||
| 						map.scaleV = data.readFloat(); | ||||
| 						break; | ||||
| 					// Смещение по U | ||||
| 					case 0xA358: | ||||
| 						data.position = dataIndex; | ||||
| 						map.offsetU = data.readFloat(); | ||||
| 						break; | ||||
| 					// Смещение по V | ||||
| 					case 0xA35A: | ||||
| 						data.position = dataIndex; | ||||
| 						map.offsetV = data.readFloat(); | ||||
| 						break; | ||||
| 					// Угол поворота | ||||
| 					case 0xA35C: | ||||
| 						data.position = dataIndex; | ||||
| 						map.rotation = data.readFloat(); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMapChunk(materialName, map, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObject(object:ObjectData, index:uint):uint { | ||||
| 			// Создаём список объектов, если надо | ||||
| 			if (objectDatas == null) { | ||||
| 				objectDatas = new Object(); | ||||
| 			} | ||||
| 			// Получаем название объекта | ||||
| 			object.name = getString(index); | ||||
| 			// Помещаем данные объекта в список | ||||
| 			objectDatas[object.name] = object; | ||||
| 			return object.name.length + 1; | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Меш | ||||
| 					case 0x4100: | ||||
| 						parseMeshChunk(object, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Источник света | ||||
| 					case 0x4600: | ||||
| 						break; | ||||
| 					// Камера | ||||
| 					case 0x4700: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseObjectChunk(object, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMeshChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Вершины | ||||
| 					case 0x4110: | ||||
| 						parseVertices(object, dataIndex); | ||||
| 						break; | ||||
| 					// UV | ||||
| 					case 0x4140: | ||||
| 						parseUVs(object, dataIndex); | ||||
| 						break; | ||||
| 					// Трансформация | ||||
| 					case 0x4160: | ||||
| 						parseMatrix(object, dataIndex); | ||||
| 						break; | ||||
| 					// Грани | ||||
| 					case 0x4120: | ||||
| 						var facesLength:uint = parseFaces(object, dataIndex); | ||||
| 						parseFacesChunk(object, dataIndex + facesLength, dataLength - facesLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMeshChunk(object, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseVertices(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.vertices = new Vector.<Vector3D>(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				object.vertices.push(new Vector3D(data.readFloat(), data.readFloat(), data.readFloat())); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseUVs(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.uvs = new Vector.<Point>(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				object.uvs.push(new Point(data.readFloat(), data.readFloat())); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMatrix(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			object.matrix = new Matrix3D(Vector.<Number>([ | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 1 | ||||
| 			])); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseFaces(object:ObjectData, index:uint):uint { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.faces = new Array(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				var face:FaceData = new FaceData(); | ||||
| 				face.a = data.readUnsignedShort(); | ||||
| 				face.b = data.readUnsignedShort(); | ||||
| 				face.c = data.readUnsignedShort(); | ||||
| 				object.faces.push(face); | ||||
| 				data.position += 2; // Пропускаем флаг | ||||
| 			} | ||||
| 			return 2 + num*8; | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseFacesChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Поверхности | ||||
| 					case 0x4130: | ||||
| 						parseSurface(object, dataIndex); | ||||
| 						break; | ||||
| 					// Группы сглаживания | ||||
| 					case 0x4150: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseFacesChunk(object, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseSurface(object:ObjectData, index:uint):void { | ||||
| 			// Создаём данные поверхности | ||||
| 			var surface:SurfaceData = new SurfaceData(); | ||||
| 			// Создаём список поверхностей, если надо | ||||
| 			if (object.surfaces == null) { | ||||
| 				object.surfaces = new Object(); | ||||
| 			} | ||||
| 			// Получаем название материала | ||||
| 			surface.materialName = getString(index); | ||||
| 			// Помещаем данные поверхности в список | ||||
| 			object.surfaces[surface.materialName] = surface; | ||||
| 			 | ||||
| 			// Получаем грани поверхности | ||||
| 			data.position = index + surface.materialName.length + 1; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			surface.faces = new Array(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				surface.faces.push(data.readUnsignedShort()); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseAnimationChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Анимация объекта | ||||
| 					case 0xB001: | ||||
| 					case 0xB002: | ||||
| 					case 0xB003: | ||||
| 					case 0xB004: | ||||
| 					case 0xB005: | ||||
| 					case 0xB006: | ||||
| 					case 0xB007: | ||||
| 						var animation:AnimationData = new AnimationData(); | ||||
| 						if (animationDatas == null) { | ||||
| 							animationDatas = new Array(); | ||||
| 						} | ||||
| 						animationDatas.push(animation); | ||||
| 						parseObjectAnimationChunk(animation, dataIndex, dataLength); | ||||
| 						break; | ||||
| 						 | ||||
| 					// Таймлайн | ||||
| 					case 0xB008: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseAnimationChunk(index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
|  | ||||
| 		private function parseObjectAnimationChunk(animation:AnimationData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Идентификация объекта и его связь | ||||
| 					case 0xB010: | ||||
| 						parseObjectAnimationInfo(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Точка привязки объекта (pivot) | ||||
| 					case 0xB013: | ||||
| 						parseObjectAnimationPivot(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Смещение объекта относительно родителя | ||||
| 					case 0xB020: | ||||
| 						parseObjectAnimationPosition(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Поворот объекта относительно родителя (angle-axis) | ||||
| 					case 0xB021: | ||||
| 						parseObjectAnimationRotation(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Масштабирование объекта относительно родителя | ||||
| 					case 0xB022: | ||||
| 						parseObjectAnimationScale(animation, dataIndex); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseObjectAnimationChunk(animation, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
|  | ||||
| 		private function parseObjectAnimationInfo(animation:AnimationData, index:uint):void { | ||||
| 			var name:String = getString(index); | ||||
| 			data.position = index + name.length + 1 + 4; | ||||
| 			animation.objectName = name; | ||||
| 			animation.parentIndex = data.readUnsignedShort(); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectAnimationPivot(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			animation.pivot = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectAnimationPosition(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			animation.position = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectAnimationRotation(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			var angle:Number = data.readFloat(); | ||||
| 			animation.rotation = new Vector3D(-data.readFloat(), -data.readFloat(), -data.readFloat(), angle); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectAnimationScale(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			animation.scale = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Объект-контейнер, содержащий все загруженные объекты.  | ||||
| 		 */ | ||||
| 		public function get content():Vector.<Mesh> { | ||||
| 			return _content; | ||||
| 		} | ||||
| 		 | ||||
| 		// Считываем строку заканчивающуюся на нулевой байт | ||||
| 		private function getString(index:uint):String { | ||||
| 			data.position = index; | ||||
| 			var charCode:uint = data.readByte(); | ||||
| 			var res:String = ""; | ||||
| 			while (charCode != 0) { | ||||
| 				res += String.fromCharCode(charCode); | ||||
| 				charCode = data.readByte(); | ||||
| 			} | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 		private function getRotationFrom3DSAngleAxis(angle:Number, x:Number, z:Number, y:Number):Vector3D { | ||||
| 			var res:Vector3D = new Vector3D(); | ||||
| 			var s:Number = Math.sin(angle); | ||||
| 			var c:Number = Math.cos(angle); | ||||
| 			var t:Number = 1 - c; | ||||
| 			var k:Number = x*y*t + z*s; | ||||
| 			var half:Number; | ||||
| 			if (k > 0.998) { | ||||
| 				half = angle/2; | ||||
| 				res.z = -2*Math.atan2(x*Math.sin(half), Math.cos(half)); | ||||
| 				res.y = -Math.PI/2; | ||||
| 				res.x = 0; | ||||
| 				return res; | ||||
| 			} | ||||
| 			if (k < -0.998) { | ||||
| 				half = angle/2; | ||||
| 				res.z = 2*Math.atan2(x*Math.sin(half), Math.cos(half)); | ||||
| 				res.y = Math.PI/2; | ||||
| 				res.x = 0; | ||||
| 				return res; | ||||
| 			} | ||||
| 			res.z = -Math.atan2(y*s - x*z*t, 1 - (y*y + z*z)*t); | ||||
| 			res.y = -Math.asin(x*y*t + z*s); | ||||
| 			res.x = -Math.atan2(x*s - y*z*t, 1 - (x*x + z*z)*t);			 | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| import flash.geom.Matrix; | ||||
| import flash.geom.Matrix3D; | ||||
| import flash.geom.Vector3D; | ||||
| import __AS3__.vec.Vector; | ||||
| import flash.geom.Point; | ||||
| import alternativa.engine3d.objects.Mesh; | ||||
|  | ||||
| class MaterialData { | ||||
| 	public var name:String; | ||||
| 	public var color:uint; | ||||
| 	public var specular:uint; | ||||
| 	public var glossiness:uint; | ||||
| 	public var transparency:uint; | ||||
| 	public var diffuseMap:MapData; | ||||
| 	public var opacityMap:MapData; | ||||
| 	//public var normalMap:MapData; | ||||
| 	public var matrix:Matrix; | ||||
| } | ||||
|  | ||||
| class MapData { | ||||
| 	public var filename:String; | ||||
| 	public var scaleU:Number = 1; | ||||
| 	public var scaleV:Number = 1; | ||||
| 	public var offsetU:Number = 0; | ||||
| 	public var offsetV:Number = 0; | ||||
| 	public var rotation:Number = 0; | ||||
| } | ||||
|  | ||||
| class ObjectData { | ||||
| 	public var name:String; | ||||
| 	public var vertices:Vector.<Vector3D>; | ||||
| 	public var uvs:Vector.<Point>; | ||||
| 	public var matrix:Matrix3D; | ||||
| 	public var faces:Array;  | ||||
| 	public var surfaces:Object; | ||||
| } | ||||
|  | ||||
| class FaceData { | ||||
| 	public var a:uint; | ||||
| 	public var b:uint; | ||||
| 	public var c:uint; | ||||
| } | ||||
|  | ||||
| class SurfaceData { | ||||
| 	public var materialName:String; | ||||
| 	public var faces:Array; | ||||
| } | ||||
|  | ||||
| class AnimationData { | ||||
| 	public var objectName:String; | ||||
| 	public var object:Mesh; | ||||
| 	public var parentIndex:uint; | ||||
| 	public var pivot:Vector3D; | ||||
| 	public var position:Vector3D; | ||||
| 	public var rotation:Vector3D; | ||||
| 	public var scale:Vector3D; | ||||
| } | ||||
| @@ -1,815 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.objects.Mesh; | ||||
| 	 | ||||
| 	import flash.display.BlendMode; | ||||
| 	import flash.events.Event; | ||||
| 	import flash.events.EventDispatcher; | ||||
| 	import flash.geom.Matrix; | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Orientation3D; | ||||
| 	import flash.geom.Point; | ||||
| 	import flash.geom.Vector3D; | ||||
| 	import flash.net.URLLoader; | ||||
| 	import flash.system.LoaderContext; | ||||
| 	import flash.utils.ByteArray; | ||||
| 	import flash.utils.Endian; | ||||
| 	 | ||||
| 	use namespace alternativa3d;	 | ||||
|  | ||||
| 	public class Loader3DSByteArray extends EventDispatcher { | ||||
|  | ||||
| 		private var _content:Vector.<Mesh>; | ||||
| 		private var version:uint; | ||||
| 		private var objectDatas:Object; | ||||
| 		private var animationDatas:Array; | ||||
| 		private var materialDatas:Array; | ||||
| 		private var bitmaps:Array; | ||||
| 		 | ||||
| 		private var modelLoader:URLLoader; | ||||
| 		private var textureLoader:TextureLoader; | ||||
| 		alternativa3d var data:ByteArray; | ||||
| 		 | ||||
| 		private var counter:int; | ||||
| 		private var textureMaterialNames:Array; | ||||
| 		private var context:LoaderContext; | ||||
| 		private var path:String; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Повтор текстуры при заливке для создаваемых текстурных материалов. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */ | ||||
| 		public var repeat:Boolean = true; | ||||
| 		/** | ||||
| 		 * Сглаживание текстур при увеличении масштаба. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */		 | ||||
| 		public var smooth:Boolean = false; | ||||
| 		/** | ||||
| 		 * Режим наложения цвета для создаваемых текстурных материалов. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */ | ||||
| 		public var blendMode:String = BlendMode.NORMAL; | ||||
|  | ||||
| 		/** | ||||
| 		 * Коэффициент пересчёта единиц измерения модели. | ||||
| 		 */ | ||||
| 		public var units:Number = 1; | ||||
| 		/** | ||||
| 		 * Устанавливаемый уровень мобильности загруженных объектов. | ||||
| 		 */		 | ||||
| 		public var mobility:int = 0; | ||||
| 		 | ||||
| 		private function clean():void { | ||||
| 			_content = null; | ||||
| 			objectDatas = null; | ||||
| 			animationDatas = null; | ||||
| 			materialDatas = null; | ||||
| 			bitmaps = null; | ||||
| 			textureMaterialNames = null; | ||||
| 		} | ||||
|  | ||||
| 		public function parseByteArray(data:ByteArray):void { | ||||
| 			this.data = data; | ||||
| 			this.data.endian = Endian.LITTLE_ENDIAN; | ||||
| 			parse3DSChunk(0, this.data.bytesAvailable); | ||||
| 		} | ||||
|  | ||||
| 		private function buildContent():void { | ||||
| 			var i:uint; | ||||
| 			var length:uint; | ||||
| 			 | ||||
| 			// Формируем связи объектов | ||||
| 			_content = new Vector.<Mesh>(); | ||||
| 			 | ||||
| 			// Создаём материалы | ||||
| 			var materialData:MaterialData; | ||||
| 			for (var materialName:String in materialDatas) { | ||||
| 				materialData = materialDatas[materialName]; | ||||
| 				var mapData:MapData = materialData.diffuseMap; | ||||
| 				var materialMatrix:Matrix = new Matrix(); | ||||
| 				if (mapData != null) { | ||||
| 					var rot:Number = mapData.rotation*Math.PI/180; | ||||
| 					var rotSin:Number = Math.sin(rot); | ||||
| 					var rotCos:Number = Math.cos(rot); | ||||
| 					materialMatrix.translate(-mapData.offsetU, mapData.offsetV); | ||||
| 					materialMatrix.translate(-0.5, -0.5); | ||||
| 					materialMatrix.rotate(-rot); | ||||
| 					materialMatrix.scale(mapData.scaleU, mapData.scaleV); | ||||
| 					materialMatrix.translate(0.5, 0.5); | ||||
| 				} | ||||
| 				materialData.matrix = materialMatrix; | ||||
| 			} | ||||
| 			 | ||||
| 			// Если есть данные об анимации и иерархии объектов | ||||
| 			var objectName:String; | ||||
| 			var objectData:ObjectData; | ||||
| 			var mesh:Mesh; | ||||
| 			if (animationDatas != null) { | ||||
| 				if (objectDatas != null) { | ||||
| 					 | ||||
| 					length = animationDatas.length; | ||||
| 					for (i = 0; i < length; i++) { | ||||
| 						var animationData:AnimationData = animationDatas[i]; | ||||
| 						objectName = animationData.objectName; | ||||
| 						objectData = objectDatas[objectName]; | ||||
| 						 | ||||
| 						// Если на один объект приходится несколько данных об анимации | ||||
| 						if (objectData != null) { | ||||
| 							var nameCounter:uint = 2; | ||||
| 							for (var j:uint = i + 1; j < length; j++) { | ||||
| 								var animationData2:AnimationData = animationDatas[j]; | ||||
| 								if (objectName == animationData2.objectName) { | ||||
| 									var newName:String = objectName + nameCounter; | ||||
| 									var newObjectData:ObjectData = new ObjectData(); | ||||
| 									animationData2.objectName = newName; | ||||
| 									newObjectData.name = newName; | ||||
| 									if (objectData.vertices != null) { | ||||
| 										newObjectData.vertices = new Vector.<Vector3D>().concat(objectData.vertices); | ||||
| 									} | ||||
| 									if (objectData.uvs != null) { | ||||
| 										newObjectData.uvs = new new Vector.<Point>().concat(objectData.uvs); | ||||
| 									} | ||||
| 									if (objectData.matrix != null) { | ||||
| 										newObjectData.matrix = objectData.matrix.clone(); | ||||
| 									} | ||||
| 									if (objectData.faces != null) { | ||||
| 										newObjectData.faces = new Array().concat(objectData.faces); | ||||
| 									} | ||||
| 									if (objectData.surfaces != null) { | ||||
| 										newObjectData.surfaces = objectData.surfaces.clone(); | ||||
| 									} | ||||
| 									objectDatas[newName] = newObjectData; | ||||
| 									nameCounter++; | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						 | ||||
| 						if (objectData != null && objectData.vertices != null) { | ||||
| 							// Меш | ||||
| 							mesh = new Mesh(); | ||||
| 							mesh.createEmptyGeometry(objectData.vertices.length, objectData.faces.length); | ||||
| 							animationData.object = mesh; | ||||
| 							buildObject(animationData); | ||||
| 							buildMesh(mesh, objectData, animationData); | ||||
| 							_content.push(mesh); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				for (objectName in objectDatas) { | ||||
| 					objectData = objectDatas[objectName]; | ||||
| 					if (objectData.vertices != null) { | ||||
| 						// Меш | ||||
| 						mesh = new Mesh(); | ||||
| 						mesh.createEmptyGeometry(objectData.vertices.length, objectData.faces.length); | ||||
| 						buildMesh(mesh, objectData, null); | ||||
| 						_content.push(mesh); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			// Рассылаем событие о завершении | ||||
| 			dispatchEvent(new Event(Event.COMPLETE)); | ||||
| 		} | ||||
| 		 | ||||
| 		private function buildObject(animationData:AnimationData):void { | ||||
| 			var object:Mesh = animationData.object; | ||||
| 			var transform:Vector.<Vector3D> = new Vector.<Vector3D>(3, true); | ||||
| 			transform[0] = (animationData.position == null) ? new Vector3D() : new Vector3D(animationData.position.x * units, animationData.position.y * units, animationData.position.z * units); | ||||
| 			transform[1] = (animationData.rotation == null) ? new Vector3D() : animationData.rotation.clone(); | ||||
| 			transform[2] = (animationData.scale == null) ? new Vector3D(1, 1, 1) : animationData.scale.clone(); | ||||
| 			object.matrix.recompose(transform, Orientation3D.AXIS_ANGLE); | ||||
| 		} | ||||
| 		 | ||||
| 		private function buildMesh(mesh:Mesh, objectData:ObjectData, animationData:AnimationData):void { | ||||
| 			 | ||||
| 			// Добавляем вершины | ||||
| 			var i:uint; | ||||
| 			var j:uint; | ||||
| 			var key:*; | ||||
| 			var length:uint = objectData.vertices.length; | ||||
| 			for (i = 0; i < length; i++) { | ||||
| 				var vertexData:Vector3D = objectData.vertices[i]; | ||||
| 				var uv:Point = objectData.uvs[i]; | ||||
| 				j = i*3; | ||||
| 				mesh.vertices[j] = vertexData.x; | ||||
| 				mesh.vertices[j + 1] = vertexData.y; | ||||
| 				mesh.vertices[j + 2] = vertexData.z; | ||||
| 				mesh.uvts[j] = uv.x; | ||||
| 				mesh.uvts[j + 1] = 1 - uv.y; | ||||
| 			} | ||||
| 			 | ||||
| 			// Коррекция вершин | ||||
| 			if (animationData != null) { | ||||
| 				// Инвертируем матрицу | ||||
| 				objectData.matrix.invert(); | ||||
| 				 | ||||
| 				// Вычитаем точку привязки из смещения матрицы | ||||
| 				if (animationData.pivot != null) { | ||||
| 					objectData.matrix.appendTranslation(-animationData.pivot.x, -animationData.pivot.y, -animationData.pivot.z);  | ||||
| 				} | ||||
| 				 | ||||
| 				// Трансформируем вершины | ||||
| 				objectData.matrix.transformVectors(mesh.vertices, mesh.vertices); | ||||
| 			} | ||||
| 			for (i = 0; i < mesh.numVertices*3; i++) { | ||||
| 				mesh.vertices[i] *= units; | ||||
| 			} | ||||
| 			 | ||||
| 			// Добавляем грани | ||||
| 			length = objectData.faces.length; | ||||
| 			for (i = 0; i < length; i++) { | ||||
| 				var faceData:FaceData = objectData.faces[i]; | ||||
| 				j = i*3; | ||||
| 				mesh.indices[j] = faceData.a; | ||||
| 				mesh.indices[j + 1] = faceData.b; | ||||
| 				mesh.indices[j + 2] = faceData.c; | ||||
| 			} | ||||
| 			 | ||||
| 			// Добавляем поверхности | ||||
| 			/*if (objectData.surfaces != null) { | ||||
| 				for (var surfaceId:String in objectData.surfaces) { | ||||
| 					var materialData:MaterialData = materialDatas[surfaceId]; | ||||
| 					if (materialData.diffuseMap != null) { | ||||
| 						mesh.texture = bitmaps[materialData.name]; | ||||
| 					} | ||||
| 				} | ||||
| 			}*/ | ||||
| 		} | ||||
| 		 | ||||
| 		alternativa3d function parse3DSChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Главный | ||||
| 					case 0x4D4D: | ||||
| 						parseMainChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parse3DSChunk(index + chunkLength, length - chunkLength); | ||||
| 			} else { | ||||
| 				// Загрузка битмап | ||||
| 				//loadBitmaps(); | ||||
| 				buildContent(); // Без подгрузки битмап | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMainChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Версия | ||||
| 					case 0x0002: | ||||
| 						parseVersion(dataIndex); | ||||
| 						break; | ||||
| 					// 3D-сцена | ||||
| 					case 0x3D3D: | ||||
| 						parse3DChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Анимация | ||||
| 					case 0xB000: | ||||
| 						parseAnimationChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMainChunk(index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseVersion(index:uint):void { | ||||
| 			data.position = index; | ||||
| 			version = data.readUnsignedInt(); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parse3DChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Материал | ||||
| 					case 0xAFFF: | ||||
| 						// Парсим материал | ||||
| 						var material:MaterialData = new MaterialData(); | ||||
| 						parseMaterialChunk(material, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Объект | ||||
| 					case 0x4000: | ||||
| 						// Создаём данные объекта | ||||
| 						var object:ObjectData = new ObjectData(); | ||||
| 						var objectLength:uint = parseObject(object, dataIndex); | ||||
| 						// Парсим объект | ||||
| 						parseObjectChunk(object, dataIndex + objectLength, dataLength - objectLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parse3DChunk(index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMaterialChunk(material:MaterialData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Имя материала | ||||
| 					case 0xA000: | ||||
| 						parseMaterialName(material, dataIndex); | ||||
| 						break; | ||||
| 					// Ambient color | ||||
| 					case 0xA010: | ||||
| 						break; | ||||
| 					// Diffuse color | ||||
| 					case 0xA020: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.color = (data.readUnsignedByte() << 16) + (data.readUnsignedByte() << 8) + data.readUnsignedByte(); | ||||
| 						break; | ||||
| 					// Specular color | ||||
| 					case 0xA030: | ||||
| 						break; | ||||
| 					// Shininess percent | ||||
| 					case 0xA040: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.glossiness = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Shininess strength percent | ||||
| 					case 0xA041: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.specular = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Transperensy | ||||
| 					case 0xA050: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.transparency = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Texture map 1 | ||||
| 					case 0xA200: | ||||
| 						material.diffuseMap = new MapData(); | ||||
| 						parseMapChunk(material.name, material.diffuseMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Texture map 2 | ||||
| 					case 0xA33A: | ||||
| 						break; | ||||
| 					// Opacity map | ||||
| 					case 0xA210: | ||||
| 						material.opacityMap = new MapData(); | ||||
| 						parseMapChunk(material.name, material.opacityMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Bump map | ||||
| 					case 0xA230: | ||||
| 						//material.normalMap = new MapData(); | ||||
| 						//parseMapChunk(material.normalMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Shininess map | ||||
| 					case 0xA33C: | ||||
| 						break; | ||||
| 					// Specular map | ||||
| 					case 0xA204: | ||||
| 						break; | ||||
| 					// Self-illumination map | ||||
| 					case 0xA33D: | ||||
| 						break; | ||||
| 					// Reflection map | ||||
| 					case 0xA220: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMaterialChunk(material, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMaterialName(material:MaterialData, index:uint):void { | ||||
| 			// Создаём список материалов, если надо | ||||
| 			if (materialDatas == null) { | ||||
| 				materialDatas = new Array(); | ||||
| 			} | ||||
| 			// Получаем название материала | ||||
| 			material.name = getString(index); | ||||
| 			// Помещаем данные материала в список | ||||
| 			materialDatas[material.name] = material; | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMapChunk(materialName:String, map:MapData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Имя файла | ||||
| 					case 0xA300: | ||||
| 						map.filename = getString(dataIndex).toLowerCase(); | ||||
| 						break; | ||||
| 					// Масштаб по U | ||||
| 					case 0xA354: | ||||
| 						data.position = dataIndex; | ||||
| 						map.scaleU = data.readFloat(); | ||||
| 						break; | ||||
| 					// Масштаб по V | ||||
| 					case 0xA356: | ||||
| 						data.position = dataIndex; | ||||
| 						map.scaleV = data.readFloat(); | ||||
| 						break; | ||||
| 					// Смещение по U | ||||
| 					case 0xA358: | ||||
| 						data.position = dataIndex; | ||||
| 						map.offsetU = data.readFloat(); | ||||
| 						break; | ||||
| 					// Смещение по V | ||||
| 					case 0xA35A: | ||||
| 						data.position = dataIndex; | ||||
| 						map.offsetV = data.readFloat(); | ||||
| 						break; | ||||
| 					// Угол поворота | ||||
| 					case 0xA35C: | ||||
| 						data.position = dataIndex; | ||||
| 						map.rotation = data.readFloat(); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMapChunk(materialName, map, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObject(object:ObjectData, index:uint):uint { | ||||
| 			// Создаём список объектов, если надо | ||||
| 			if (objectDatas == null) { | ||||
| 				objectDatas = new Object(); | ||||
| 			} | ||||
| 			// Получаем название объекта | ||||
| 			object.name = getString(index); | ||||
| 			// Помещаем данные объекта в список | ||||
| 			objectDatas[object.name] = object; | ||||
| 			return object.name.length + 1; | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Меш | ||||
| 					case 0x4100: | ||||
| 						parseMeshChunk(object, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Источник света | ||||
| 					case 0x4600: | ||||
| 						break; | ||||
| 					// Камера | ||||
| 					case 0x4700: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseObjectChunk(object, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMeshChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Вершины | ||||
| 					case 0x4110: | ||||
| 						parseVertices(object, dataIndex); | ||||
| 						break; | ||||
| 					// UV | ||||
| 					case 0x4140: | ||||
| 						parseUVs(object, dataIndex); | ||||
| 						break; | ||||
| 					// Трансформация | ||||
| 					case 0x4160: | ||||
| 						parseMatrix(object, dataIndex); | ||||
| 						break; | ||||
| 					// Грани | ||||
| 					case 0x4120: | ||||
| 						var facesLength:uint = parseFaces(object, dataIndex); | ||||
| 						parseFacesChunk(object, dataIndex + facesLength, dataLength - facesLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMeshChunk(object, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseVertices(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.vertices = new Vector.<Vector3D>(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				object.vertices.push(new Vector3D(data.readFloat(), data.readFloat(), data.readFloat())); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseUVs(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.uvs = new Vector.<Point>(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				object.uvs.push(new Point(data.readFloat(), data.readFloat())); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseMatrix(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			object.matrix = new Matrix3D(Vector.<Number>([ | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 1 | ||||
| 			])); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseFaces(object:ObjectData, index:uint):uint { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.faces = new Array(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				var face:FaceData = new FaceData(); | ||||
| 				face.a = data.readUnsignedShort(); | ||||
| 				face.b = data.readUnsignedShort(); | ||||
| 				face.c = data.readUnsignedShort(); | ||||
| 				object.faces.push(face); | ||||
| 				data.position += 2; // Пропускаем флаг | ||||
| 			} | ||||
| 			return 2 + num*8; | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseFacesChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Поверхности | ||||
| 					case 0x4130: | ||||
| 						parseSurface(object, dataIndex); | ||||
| 						break; | ||||
| 					// Группы сглаживания | ||||
| 					case 0x4150: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseFacesChunk(object, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseSurface(object:ObjectData, index:uint):void { | ||||
| 			// Создаём данные поверхности | ||||
| 			var surface:SurfaceData = new SurfaceData(); | ||||
| 			// Создаём список поверхностей, если надо | ||||
| 			if (object.surfaces == null) { | ||||
| 				object.surfaces = new Object(); | ||||
| 			} | ||||
| 			// Получаем название материала | ||||
| 			surface.materialName = getString(index); | ||||
| 			// Помещаем данные поверхности в список | ||||
| 			object.surfaces[surface.materialName] = surface; | ||||
| 			 | ||||
| 			// Получаем грани поверхности | ||||
| 			data.position = index + surface.materialName.length + 1; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			surface.faces = new Array(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				surface.faces.push(data.readUnsignedShort()); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseAnimationChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Анимация объекта | ||||
| 					case 0xB001: | ||||
| 					case 0xB002: | ||||
| 					case 0xB003: | ||||
| 					case 0xB004: | ||||
| 					case 0xB005: | ||||
| 					case 0xB006: | ||||
| 					case 0xB007: | ||||
| 						var animation:AnimationData = new AnimationData(); | ||||
| 						if (animationDatas == null) { | ||||
| 							animationDatas = new Array(); | ||||
| 						} | ||||
| 						animationDatas.push(animation); | ||||
| 						parseObjectAnimationChunk(animation, dataIndex, dataLength); | ||||
| 						break; | ||||
| 						 | ||||
| 					// Таймлайн | ||||
| 					case 0xB008: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseAnimationChunk(index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
|  | ||||
| 		private function parseObjectAnimationChunk(animation:AnimationData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Идентификация объекта и его связь | ||||
| 					case 0xB010: | ||||
| 						parseObjectAnimationInfo(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Точка привязки объекта (pivot) | ||||
| 					case 0xB013: | ||||
| 						parseObjectAnimationPivot(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Смещение объекта относительно родителя | ||||
| 					case 0xB020: | ||||
| 						parseObjectAnimationPosition(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Поворот объекта относительно родителя (angle-axis) | ||||
| 					case 0xB021: | ||||
| 						parseObjectAnimationRotation(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Масштабирование объекта относительно родителя | ||||
| 					case 0xB022: | ||||
| 						parseObjectAnimationScale(animation, dataIndex); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseObjectAnimationChunk(animation, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
|  | ||||
| 		private function parseObjectAnimationInfo(animation:AnimationData, index:uint):void { | ||||
| 			var name:String = getString(index); | ||||
| 			data.position = index + name.length + 1 + 4; | ||||
| 			animation.objectName = name; | ||||
| 			animation.parentIndex = data.readUnsignedShort(); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectAnimationPivot(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			animation.pivot = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectAnimationPosition(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			animation.position = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectAnimationRotation(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			var angle:Number = data.readFloat(); | ||||
| 			animation.rotation = new Vector3D(data.readFloat(), -data.readFloat(), data.readFloat(), angle); | ||||
| 		} | ||||
| 		 | ||||
| 		private function parseObjectAnimationScale(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			animation.scale = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Объект-контейнер, содержащий все загруженные объекты.  | ||||
| 		 */ | ||||
| 		public function get content():Vector.<Mesh> { | ||||
| 			return _content; | ||||
| 		} | ||||
| 		 | ||||
| 		// Считываем строку заканчивающуюся на нулевой байт | ||||
| 		private function getString(index:uint):String { | ||||
| 			data.position = index; | ||||
| 			var charCode:uint = data.readByte(); | ||||
| 			var res:String = ""; | ||||
| 			while (charCode != 0) { | ||||
| 				res += String.fromCharCode(charCode); | ||||
| 				charCode = data.readByte(); | ||||
| 			} | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 		private function getRotationFrom3DSAngleAxis(angle:Number, x:Number, z:Number, y:Number):Vector3D { | ||||
| 			var res:Vector3D = new Vector3D(); | ||||
| 			var s:Number = Math.sin(angle); | ||||
| 			var c:Number = Math.cos(angle); | ||||
| 			var t:Number = 1 - c; | ||||
| 			var k:Number = x*y*t + z*s; | ||||
| 			var half:Number; | ||||
| 			if (k > 0.998) { | ||||
| 				half = angle/2; | ||||
| 				res.z = -2*Math.atan2(x*Math.sin(half), Math.cos(half)); | ||||
| 				res.y = -Math.PI/2; | ||||
| 				res.x = 0; | ||||
| 				return res; | ||||
| 			} | ||||
| 			if (k < -0.998) { | ||||
| 				half = angle/2; | ||||
| 				res.z = 2*Math.atan2(x*Math.sin(half), Math.cos(half)); | ||||
| 				res.y = Math.PI/2; | ||||
| 				res.x = 0; | ||||
| 				return res; | ||||
| 			} | ||||
| 			res.z = -Math.atan2(y*s - x*z*t, 1 - (y*y + z*z)*t); | ||||
| 			res.y = -Math.asin(x*y*t + z*s); | ||||
| 			res.x = -Math.atan2(x*s - y*z*t, 1 - (x*x + z*z)*t);			 | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| import flash.geom.Matrix; | ||||
| import flash.geom.Matrix3D; | ||||
| import flash.geom.Vector3D; | ||||
| import __AS3__.vec.Vector; | ||||
| import flash.geom.Point; | ||||
| import alternativa.engine3d.objects.Mesh; | ||||
|  | ||||
| class MaterialData { | ||||
| 	public var name:String; | ||||
| 	public var color:uint; | ||||
| 	public var specular:uint; | ||||
| 	public var glossiness:uint; | ||||
| 	public var transparency:uint; | ||||
| 	public var diffuseMap:MapData; | ||||
| 	public var opacityMap:MapData; | ||||
| 	//public var normalMap:MapData; | ||||
| 	public var matrix:Matrix; | ||||
| } | ||||
|  | ||||
| class MapData { | ||||
| 	public var filename:String; | ||||
| 	public var scaleU:Number = 1; | ||||
| 	public var scaleV:Number = 1; | ||||
| 	public var offsetU:Number = 0; | ||||
| 	public var offsetV:Number = 0; | ||||
| 	public var rotation:Number = 0; | ||||
| } | ||||
|  | ||||
| class ObjectData { | ||||
| 	public var name:String; | ||||
| 	public var vertices:Vector.<Vector3D>; | ||||
| 	public var uvs:Vector.<Point>; | ||||
| 	public var matrix:Matrix3D; | ||||
| 	public var faces:Array;  | ||||
| 	public var surfaces:Object; | ||||
| } | ||||
|  | ||||
| class FaceData { | ||||
| 	public var a:uint; | ||||
| 	public var b:uint; | ||||
| 	public var c:uint; | ||||
| } | ||||
|  | ||||
| class SurfaceData { | ||||
| 	public var materialName:String; | ||||
| 	public var faces:Array; | ||||
| } | ||||
|  | ||||
| class AnimationData { | ||||
| 	public var objectName:String; | ||||
| 	public var object:Mesh; | ||||
| 	public var parentIndex:uint; | ||||
| 	public var pivot:Vector3D; | ||||
| 	public var position:Vector3D; | ||||
| 	public var rotation:Vector3D; | ||||
| 	public var scale:Vector3D; | ||||
| } | ||||
| @@ -1,15 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
| 	 | ||||
| 	public class MaterialParams { | ||||
| 		 | ||||
| 		public var color:uint; | ||||
| 		public var opacity:Number; | ||||
| 		public var diffuseMap:String; | ||||
| 		public var opacityMap:String; | ||||
| 		 | ||||
| 		public function toString():String { | ||||
| 			return "[MaterialParams color=" + color + ", opacity=" + opacity + ", diffuseMap=" + diffuseMap + ", opacityMap=" + opacityMap + "]"; | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,22 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	public class Parsed3DSData { | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Список объектов в порядке их появления в 3DS-данных. | ||||
| 		 **/		  | ||||
| 		public var objects:Vector.<Object3D>; | ||||
| 		/** | ||||
| 		 * Список материалов каждого объекта. Если для объекта нет назначенных материалов, соответствующий элемент списка равен null. | ||||
| 		 **/ | ||||
| 		public var objectMaterials:Vector.<Vector.<String>>; | ||||
| 		/** | ||||
| 		 * Список материалов 3DS-файла (materialName => MaterialParams). | ||||
| 		 */		 | ||||
| 		public var materials:Object; | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,973 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	import alternativa.engine3d.objects.Mesh; | ||||
| 	 | ||||
| 	import flash.display.BlendMode; | ||||
| 	import flash.events.EventDispatcher; | ||||
| 	import flash.geom.Matrix; | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Orientation3D; | ||||
| 	import flash.geom.Point; | ||||
| 	import flash.geom.Vector3D; | ||||
| 	import flash.net.URLLoader; | ||||
| 	import flash.utils.ByteArray; | ||||
| 	import flash.utils.Endian; | ||||
|  | ||||
| 	/** | ||||
| 	 *  | ||||
| 	 */ | ||||
| 	public class Parser3DS extends EventDispatcher { | ||||
|  | ||||
| 		private var version:uint; | ||||
| 		private var objectDatas:Object; | ||||
| 		private var animationDatas:Vector.<AnimationData>; | ||||
| 		private var materialDatas:Object; | ||||
| 		 | ||||
| 		private var modelLoader:URLLoader; | ||||
| 		private var data:ByteArray; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Повтор текстуры при заливке для создаваемых текстурных материалов. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */ | ||||
| 		public var repeat:Boolean = true; | ||||
| 		/** | ||||
| 		 * Сглаживание текстур при увеличении масштаба. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */		 | ||||
| 		public var smooth:Boolean = false; | ||||
| 		/** | ||||
| 		 * Режим наложения цвета для создаваемых текстурных материалов. | ||||
| 		 *  | ||||
| 		 * @see alternativa.engine3d.materials.TextureMaterial | ||||
| 		 */ | ||||
| 		public var blendMode:String = BlendMode.NORMAL; | ||||
|  | ||||
| 		/** | ||||
| 		 * Коэффициент пересчёта единиц измерения модели. | ||||
| 		 */ | ||||
| 		public var units:Number = 1; | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param data | ||||
| 		 */ | ||||
| 		public function Parser3DS() { | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param data | ||||
| 		 */ | ||||
| 		public function parse(data:ByteArray):Parsed3DSData { | ||||
| 			this.data = data; | ||||
| 			data.endian = Endian.LITTLE_ENDIAN; | ||||
| 			parse3DSChunk(0, data.bytesAvailable); | ||||
| 			return buildContent(); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function clean():void { | ||||
| 			objectDatas = null; | ||||
| 			animationDatas = null; | ||||
| 			materialDatas = null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function buildContent():Parsed3DSData { | ||||
| 			var result:Parsed3DSData = new Parsed3DSData(); | ||||
| 			var i:uint; | ||||
| 			var length:uint; | ||||
| 			 | ||||
| 			// Формируем связи объектов | ||||
| 			result.objects = new Vector.<Object3D>(); | ||||
| 			result.objectMaterials = new Vector.<Vector.<String>>(); | ||||
| 			result.materials = {}; | ||||
| 			 | ||||
| 			// Создаём материалы | ||||
| 			var materialData:MaterialData; | ||||
| 			for (var materialName:String in materialDatas) { | ||||
| 				materialData = materialDatas[materialName]; | ||||
| 				var mapData:MapData = materialData.diffuseMap; | ||||
| 				var materialMatrix:Matrix = new Matrix(); | ||||
| 				if (mapData != null) { | ||||
| 					var rot:Number = mapData.rotation*Math.PI/180; | ||||
| 					var rotSin:Number = Math.sin(rot); | ||||
| 					var rotCos:Number = Math.cos(rot); | ||||
| 					materialMatrix.translate(-mapData.offsetU, mapData.offsetV); | ||||
| 					materialMatrix.translate(-0.5, -0.5); | ||||
| 					materialMatrix.rotate(-rot); | ||||
| 					materialMatrix.scale(mapData.scaleU, mapData.scaleV); | ||||
| 					materialMatrix.translate(0.5, 0.5); | ||||
| 				} | ||||
| 				materialData.matrix = materialMatrix; | ||||
| 				 | ||||
| 				var mat:MaterialParams = new MaterialParams(); | ||||
| 				mat.color = materialData.color; | ||||
| 				mat.opacity = 1 - 0.01*materialData.transparency; | ||||
| 				if (materialData.diffuseMap != null) { | ||||
| 					mat.diffuseMap = materialData.diffuseMap.filename; | ||||
| 				} | ||||
| 				if (materialData.opacityMap != null) { | ||||
| 					mat.opacityMap = materialData.opacityMap.filename; | ||||
| 				} | ||||
| 				result.materials[materialName] = mat; | ||||
| 			} | ||||
| 			 | ||||
| 			// Если есть данные об анимации и иерархии объектов | ||||
| 			var objectName:String; | ||||
| 			var objectData:ObjectData; | ||||
| 			var mesh:Mesh; | ||||
| 			if (animationDatas != null) { | ||||
| 				if (objectDatas != null) { | ||||
| 					 | ||||
| 					length = animationDatas.length; | ||||
| 					for (i = 0; i < length; i++) { | ||||
| 						var animationData:AnimationData = animationDatas[i]; | ||||
| 						objectName = animationData.objectName; | ||||
| 						objectData = objectDatas[objectName]; | ||||
| 						 | ||||
| 						// Если на один объект приходится несколько данных об анимации | ||||
| 						if (objectData != null) { | ||||
| 							var nameCounter:uint = 2; | ||||
| 							for (var j:uint = i + 1; j < length; j++) { | ||||
| 								var animationData2:AnimationData = animationDatas[j]; | ||||
| 								if (objectName == animationData2.objectName) { | ||||
| 									var newName:String = objectName + nameCounter; | ||||
| 									var newObjectData:ObjectData = new ObjectData(); | ||||
| 									animationData2.objectName = newName; | ||||
| 									newObjectData.name = newName; | ||||
| 									if (objectData.vertices != null) { | ||||
| 										newObjectData.vertices = new Vector.<Vector3D>().concat(objectData.vertices); | ||||
| 									} | ||||
| 									if (objectData.uvs != null) { | ||||
| 										newObjectData.uvs = new Vector.<Point>().concat(objectData.uvs); | ||||
| 									} | ||||
| 									if (objectData.matrix != null) { | ||||
| 										newObjectData.matrix = objectData.matrix.clone(); | ||||
| 									} | ||||
| 									if (objectData.faces != null) { | ||||
| 										newObjectData.faces = new Array().concat(objectData.faces); | ||||
| 									} | ||||
| 									if (objectData.surfaces != null) { | ||||
| 										newObjectData.surfaces = objectData.surfaces.clone(); | ||||
| 									} | ||||
| 									objectDatas[newName] = newObjectData; | ||||
| 									nameCounter++; | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 						 | ||||
| 						if (objectData != null && objectData.vertices != null) { | ||||
| 							// Меш | ||||
| 							mesh = new Mesh(); | ||||
| 							mesh.createEmptyGeometry(objectData.vertices.length, objectData.faces.length); | ||||
| 							animationData.object = mesh; | ||||
| 							buildObject(animationData); | ||||
| 							buildMesh(mesh, objectData, animationData, result); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				for (objectName in objectDatas) { | ||||
| 					objectData = objectDatas[objectName]; | ||||
| 					if (objectData.vertices != null) { | ||||
| 						// Меш | ||||
| 						mesh = new Mesh(); | ||||
| 						mesh.createEmptyGeometry(objectData.vertices.length, objectData.faces.length); | ||||
| 						buildMesh(mesh, objectData, null, result); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 			clean(); | ||||
| 			return result; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param animationData | ||||
| 		 */ | ||||
| 		private function buildObject(animationData:AnimationData):void { | ||||
| 			var object:Mesh = animationData.object; | ||||
| 			var transform:Vector.<Vector3D> = new Vector.<Vector3D>(3, true); | ||||
| 			transform[0] = (animationData.position == null) ? new Vector3D() : new Vector3D(animationData.position.x*units, animationData.position.y*units, animationData.position.z*units); | ||||
| 			transform[1] = (animationData.rotation == null) ? new Vector3D() : animationData.rotation.clone(); | ||||
| 			transform[2] = (animationData.scale == null) ? new Vector3D(1, 1, 1) : animationData.scale.clone(); | ||||
| //			trace("transform[2]", transform[2]); | ||||
| 			object.matrix.recompose(transform, Orientation3D.AXIS_ANGLE); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param mesh | ||||
| 		 * @param objectData | ||||
| 		 * @param animationData | ||||
| 		 */ | ||||
| 		private function buildMesh(mesh:Mesh, objectData:ObjectData, animationData:AnimationData, parsedData:Parsed3DSData):void { | ||||
| 			mesh.name = objectData.name; | ||||
| 			// Добавляем вершины | ||||
| 			var i:uint; | ||||
| 			var j:uint; | ||||
| 			var key:*; | ||||
| 			var length:uint = objectData.vertices.length; | ||||
| 			for (i = 0; i < length; i++) { | ||||
| 				var vertexData:Vector3D = objectData.vertices[i]; | ||||
| 				var uv:Point = objectData.uvs[i]; | ||||
| 				j = i*3; | ||||
| 				mesh.vertices[j] = vertexData.x; | ||||
| 				mesh.vertices[j + 1] = vertexData.y; | ||||
| 				mesh.vertices[j + 2] = vertexData.z; | ||||
| 				mesh.uvts[j] = uv.x; | ||||
| 				mesh.uvts[j + 1] = 1 - uv.y; | ||||
| 			} | ||||
| 			 | ||||
| 			// Коррекция вершин | ||||
| 			if (animationData != null) { | ||||
| 				// Инвертируем матрицу | ||||
| 				objectData.matrix.invert(); | ||||
| 				 | ||||
| 				// Вычитаем точку привязки из смещения матрицы | ||||
| 				if (animationData.pivot != null) { | ||||
| 					objectData.matrix.appendTranslation(-animationData.pivot.x, -animationData.pivot.y, -animationData.pivot.z);  | ||||
| 				} | ||||
| 				 | ||||
| 				// Трансформируем вершины | ||||
| 				objectData.matrix.transformVectors(mesh.vertices, mesh.vertices); | ||||
| 			} | ||||
| 			for (i = 0; i < mesh.numVertices*3; i++) { | ||||
| 				mesh.vertices[i] *= units; | ||||
| 			} | ||||
| 			 | ||||
| 			// Добавляем грани | ||||
| 			length = objectData.faces.length; | ||||
| 			for (i = 0; i < length; i++) { | ||||
| 				var faceData:FaceData = objectData.faces[i]; | ||||
| 				j = i*3; | ||||
| 				mesh.indices[j] = faceData.a; | ||||
| 				mesh.indices[j + 1] = faceData.b; | ||||
| 				mesh.indices[j + 2] = faceData.c; | ||||
| 			} | ||||
| 			 | ||||
| 			parsedData.objects.push(mesh); | ||||
| 			 | ||||
| 			// Добавляем поверхности | ||||
| 			if (objectData.surfaces != null) { | ||||
| 				var meshMaterials:Vector.<String> = new Vector.<String>(); | ||||
| 				for (var surfaceId:String in objectData.surfaces) { | ||||
| 					meshMaterials.push(surfaceId); | ||||
| //					var materialData:MaterialData = materialDatas[surfaceId]; | ||||
| //					if (materialData.diffuseMap != null) { | ||||
| //						mesh.texture = bitmaps[materialData.name]; | ||||
| //					} | ||||
| 				} | ||||
| 				parsedData.objectMaterials.push(meshMaterials); | ||||
| 			} else { | ||||
| 				parsedData.objectMaterials.push(null); | ||||
| 			} | ||||
| //			trace("mesh.matrix.decompose()", mesh.matrix.decompose()); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */		 | ||||
| 		private function parse3DSChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Главный | ||||
| 					case 0x4D4D: | ||||
| 						parseMainChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parse3DSChunk(index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parseMainChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Версия | ||||
| 					case 0x0002: | ||||
| 						parseVersion(dataIndex); | ||||
| 						break; | ||||
| 					// 3D-сцена | ||||
| 					case 0x3D3D: | ||||
| 						parse3DChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Анимация | ||||
| 					case 0xB000: | ||||
| 						parseAnimationChunk(dataIndex, dataLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMainChunk(index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseVersion(index:uint):void { | ||||
| 			data.position = index; | ||||
| 			version = data.readUnsignedInt(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parse3DChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Материал | ||||
| 					case 0xAFFF: | ||||
| 						// Парсим материал | ||||
| 						var material:MaterialData = new MaterialData(); | ||||
| 						parseMaterialChunk(material, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Объект | ||||
| 					case 0x4000: | ||||
| 						// Создаём данные объекта | ||||
| 						var object:ObjectData = new ObjectData(); | ||||
| 						var objectLength:uint = parseObject(object, dataIndex); | ||||
| 						// Парсим объект | ||||
| 						parseObjectChunk(object, dataIndex + objectLength, dataLength - objectLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parse3DChunk(index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param material | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parseMaterialChunk(material:MaterialData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Имя материала | ||||
| 					case 0xA000: | ||||
| 						parseMaterialName(material, dataIndex); | ||||
| 						break; | ||||
| 					// Ambient color | ||||
| 					case 0xA010: | ||||
| 						break; | ||||
| 					// Diffuse color | ||||
| 					case 0xA020: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.color = (data.readUnsignedByte() << 16) + (data.readUnsignedByte() << 8) + data.readUnsignedByte(); | ||||
| 						break; | ||||
| 					// Specular color | ||||
| 					case 0xA030: | ||||
| 						break; | ||||
| 					// Shininess percent | ||||
| 					case 0xA040: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.glossiness = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Shininess strength percent | ||||
| 					case 0xA041: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.specular = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Transperensy | ||||
| 					case 0xA050: | ||||
| 						data.position = dataIndex + 6; | ||||
| 						material.transparency = data.readUnsignedShort(); | ||||
| 						break; | ||||
| 					// Texture map 1 | ||||
| 					case 0xA200: | ||||
| 						material.diffuseMap = new MapData(); | ||||
| 						parseMapChunk(material.name, material.diffuseMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Texture map 2 | ||||
| 					case 0xA33A: | ||||
| 						break; | ||||
| 					// Opacity map | ||||
| 					case 0xA210: | ||||
| 						material.opacityMap = new MapData(); | ||||
| 						parseMapChunk(material.name, material.opacityMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Bump map | ||||
| 					case 0xA230: | ||||
| 						//material.normalMap = new MapData(); | ||||
| 						//parseMapChunk(material.normalMap, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Shininess map | ||||
| 					case 0xA33C: | ||||
| 						break; | ||||
| 					// Specular map | ||||
| 					case 0xA204: | ||||
| 						break; | ||||
| 					// Self-illumination map | ||||
| 					case 0xA33D: | ||||
| 						break; | ||||
| 					// Reflection map | ||||
| 					case 0xA220: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMaterialChunk(material, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param material | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseMaterialName(material:MaterialData, index:uint):void { | ||||
| 			// Создаём список материалов, если надо | ||||
| 			if (materialDatas == null) { | ||||
| 				materialDatas = {}; | ||||
| 			} | ||||
| 			// Получаем название материала | ||||
| 			material.name = getString(index); | ||||
| 			// Помещаем данные материала в список | ||||
| 			materialDatas[material.name] = material; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param materialName | ||||
| 		 * @param map | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parseMapChunk(materialName:String, map:MapData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Имя файла | ||||
| 					case 0xA300: | ||||
| 						map.filename = getString(dataIndex).toLowerCase(); | ||||
| 						break; | ||||
| 					// Масштаб по U | ||||
| 					case 0xA354: | ||||
| 						data.position = dataIndex; | ||||
| 						map.scaleU = data.readFloat(); | ||||
| 						break; | ||||
| 					// Масштаб по V | ||||
| 					case 0xA356: | ||||
| 						data.position = dataIndex; | ||||
| 						map.scaleV = data.readFloat(); | ||||
| 						break; | ||||
| 					// Смещение по U | ||||
| 					case 0xA358: | ||||
| 						data.position = dataIndex; | ||||
| 						map.offsetU = data.readFloat(); | ||||
| 						break; | ||||
| 					// Смещение по V | ||||
| 					case 0xA35A: | ||||
| 						data.position = dataIndex; | ||||
| 						map.offsetV = data.readFloat(); | ||||
| 						break; | ||||
| 					// Угол поворота | ||||
| 					case 0xA35C: | ||||
| 						data.position = dataIndex; | ||||
| 						map.rotation = data.readFloat(); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMapChunk(materialName, map, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 * @return  | ||||
| 		 */ | ||||
| 		private function parseObject(object:ObjectData, index:uint):uint { | ||||
| 			// Создаём список объектов, если надо | ||||
| 			if (objectDatas == null) { | ||||
| 				objectDatas = new Object(); | ||||
| 			} | ||||
| 			// Получаем название объекта | ||||
| 			object.name = getString(index); | ||||
| 			// Помещаем данные объекта в список | ||||
| 			objectDatas[object.name] = object; | ||||
| 			return object.name.length + 1; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parseObjectChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Меш | ||||
| 					case 0x4100: | ||||
| 						parseMeshChunk(object, dataIndex, dataLength); | ||||
| 						break; | ||||
| 					// Источник света | ||||
| 					case 0x4600: | ||||
| 						break; | ||||
| 					// Камера | ||||
| 					case 0x4700: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseObjectChunk(object, index + chunkLength, length - chunkLength); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parseMeshChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Вершины | ||||
| 					case 0x4110: | ||||
| 						parseVertices(object, dataIndex); | ||||
| 						break; | ||||
| 					// UV | ||||
| 					case 0x4140: | ||||
| 						parseUVs(object, dataIndex); | ||||
| 						break; | ||||
| 					// Трансформация | ||||
| 					case 0x4160: | ||||
| 						parseMatrix(object, dataIndex); | ||||
| 						break; | ||||
| 					// Грани | ||||
| 					case 0x4120: | ||||
| 						var facesLength:uint = parseFaces(object, dataIndex); | ||||
| 						parseFacesChunk(object, dataIndex + facesLength, dataLength - facesLength); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseMeshChunk(object, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseVertices(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.vertices = new Vector.<Vector3D>(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				object.vertices.push(new Vector3D(data.readFloat(), data.readFloat(), data.readFloat())); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseUVs(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.uvs = new Vector.<Point>(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				object.uvs.push(new Point(data.readFloat(), data.readFloat())); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseMatrix(object:ObjectData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			object.matrix = new Matrix3D(Vector.<Number>([ | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 0, | ||||
| 				data.readFloat(), data.readFloat(), data.readFloat(), 1 | ||||
| 			])); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 * @return  | ||||
| 		 */ | ||||
| 		private function parseFaces(object:ObjectData, index:uint):uint { | ||||
| 			data.position = index; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			object.faces = new Array(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				var face:FaceData = new FaceData(); | ||||
| 				face.a = data.readUnsignedShort(); | ||||
| 				face.b = data.readUnsignedShort(); | ||||
| 				face.c = data.readUnsignedShort(); | ||||
| 				object.faces.push(face); | ||||
| 				data.position += 2; // Пропускаем флаг | ||||
| 			} | ||||
| 			return 2 + num*8; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parseFacesChunk(object:ObjectData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				 | ||||
| 				switch (chunkId) { | ||||
| 					// Поверхности | ||||
| 					case 0x4130: | ||||
| 						parseSurface(object, dataIndex); | ||||
| 						break; | ||||
| 					// Группы сглаживания | ||||
| 					case 0x4150: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseFacesChunk(object, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param object | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseSurface(object:ObjectData, index:uint):void { | ||||
| 			// Создаём данные поверхности | ||||
| 			var surface:SurfaceData = new SurfaceData(); | ||||
| 			// Создаём список поверхностей, если надо | ||||
| 			if (object.surfaces == null) { | ||||
| 				object.surfaces = new Object(); | ||||
| 			} | ||||
| 			// Получаем название материала | ||||
| 			surface.materialName = getString(index); | ||||
| 			// Помещаем данные поверхности в список | ||||
| 			object.surfaces[surface.materialName] = surface; | ||||
| 			 | ||||
| 			// Получаем грани поверхности | ||||
| 			data.position = index + surface.materialName.length + 1; | ||||
| 			var num:uint = data.readUnsignedShort(); | ||||
| 			surface.faces = new Array(); | ||||
| 			for (var i:uint = 0; i < num; i++) { | ||||
| 				surface.faces.push(data.readUnsignedShort()); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parseAnimationChunk(index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Анимация объекта | ||||
| 					case 0xB001: | ||||
| 					case 0xB002: | ||||
| 					case 0xB003: | ||||
| 					case 0xB004: | ||||
| 					case 0xB005: | ||||
| 					case 0xB006: | ||||
| 					case 0xB007: | ||||
| 						var animation:AnimationData = new AnimationData(); | ||||
| 						if (animationDatas == null) { | ||||
| 							animationDatas = new Vector.<AnimationData>(); | ||||
| 						} | ||||
| 						animationDatas.push(animation); | ||||
| 						parseObjectAnimationChunk(animation, dataIndex, dataLength); | ||||
| 						break; | ||||
| 						 | ||||
| 					// Таймлайн | ||||
| 					case 0xB008: | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseAnimationChunk(index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param animation | ||||
| 		 * @param index | ||||
| 		 * @param length | ||||
| 		 */ | ||||
| 		private function parseObjectAnimationChunk(animation:AnimationData, index:uint, length:uint):void { | ||||
| 			if (length > 6) { | ||||
| 				data.position = index; | ||||
| 				var chunkId:uint = data.readUnsignedShort(); | ||||
| 				var chunkLength:uint = data.readUnsignedInt(); | ||||
| 				var dataIndex:uint = index + 6; | ||||
| 				var dataLength:uint = chunkLength - 6; | ||||
| 				switch (chunkId) { | ||||
| 					// Идентификация объекта и его связь | ||||
| 					case 0xB010: | ||||
| 						parseObjectAnimationInfo(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Точка привязки объекта (pivot) | ||||
| 					case 0xB013: | ||||
| 						parseObjectAnimationPivot(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Смещение объекта относительно родителя | ||||
| 					case 0xB020: | ||||
| 						parseObjectAnimationPosition(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Поворот объекта относительно родителя (angle-axis) | ||||
| 					case 0xB021: | ||||
| 						parseObjectAnimationRotation(animation, dataIndex); | ||||
| 						break; | ||||
| 					// Масштабирование объекта относительно родителя | ||||
| 					case 0xB022: | ||||
| 						parseObjectAnimationScale(animation, dataIndex); | ||||
| 						break; | ||||
| 				} | ||||
| 				 | ||||
| 				parseObjectAnimationChunk(animation, index + chunkLength, length - chunkLength); | ||||
|   			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param animation | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseObjectAnimationInfo(animation:AnimationData, index:uint):void { | ||||
| 			var name:String = getString(index); | ||||
| 			data.position = index + name.length + 1 + 4; | ||||
| 			animation.objectName = name; | ||||
| 			animation.parentIndex = data.readUnsignedShort(); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param animation | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseObjectAnimationPivot(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index; | ||||
| 			animation.pivot = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param animation | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseObjectAnimationPosition(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			animation.position = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param animation | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseObjectAnimationRotation(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			var angle:Number = data.readFloat(); | ||||
| 			animation.rotation = new Vector3D(-data.readFloat(), -data.readFloat(), -data.readFloat(), angle); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param animation | ||||
| 		 * @param index | ||||
| 		 */ | ||||
| 		private function parseObjectAnimationScale(animation:AnimationData, index:uint):void { | ||||
| 			data.position = index + 20; | ||||
| 			animation.scale = new Vector3D(data.readFloat(), data.readFloat(), data.readFloat()); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Считывает строку, заканчивающуюся на нулевой байт. | ||||
| 		 *  | ||||
| 		 * @param index | ||||
| 		 * @return  | ||||
| 		 */ | ||||
| 		private function getString(index:uint):String { | ||||
| 			data.position = index; | ||||
| 			var charCode:uint = data.readByte(); | ||||
| 			var res:String = ""; | ||||
| 			while (charCode != 0) { | ||||
| 				res += String.fromCharCode(charCode); | ||||
| 				charCode = data.readByte(); | ||||
| 			} | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param angle | ||||
| 		 * @param x | ||||
| 		 * @param z | ||||
| 		 * @param y | ||||
| 		 * @return  | ||||
| 		 */ | ||||
| 		private function getRotationFrom3DSAngleAxis(angle:Number, x:Number, z:Number, y:Number):Vector3D { | ||||
| 			var res:Vector3D = new Vector3D(); | ||||
| 			var s:Number = Math.sin(angle); | ||||
| 			var c:Number = Math.cos(angle); | ||||
| 			var t:Number = 1 - c; | ||||
| 			var k:Number = x*y*t + z*s; | ||||
| 			var half:Number; | ||||
| 			if (k >= 1) { | ||||
| 				half = 0.5*angle; | ||||
| 				res.z = -2*Math.atan2(x*Math.sin(half), Math.cos(half)); | ||||
| 				res.y = -0.5*Math.PI; | ||||
| 				res.x = 0; | ||||
| 				return res; | ||||
| 			} | ||||
| 			if (k <= -1) { | ||||
| 				half = 0.5*angle; | ||||
| 				res.z = 2*Math.atan2(x*Math.sin(half), Math.cos(half)); | ||||
| 				res.y = 0.5*Math.PI; | ||||
| 				res.x = 0; | ||||
| 				return res; | ||||
| 			} | ||||
| 			res.z = -Math.atan2(y*s - x*z*t, 1 - (y*y + z*z)*t); | ||||
| 			res.y = -Math.asin(k); | ||||
| 			res.x = -Math.atan2(x*s - y*z*t, 1 - (x*x + z*z)*t);			 | ||||
| 			return res; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| import flash.geom.Matrix; | ||||
| import flash.geom.Matrix3D; | ||||
| import flash.geom.Vector3D; | ||||
| import __AS3__.vec.Vector; | ||||
| import flash.geom.Point; | ||||
| import alternativa.engine3d.objects.Mesh; | ||||
|  | ||||
| class MaterialData { | ||||
| 	public var name:String; | ||||
| 	public var color:uint; | ||||
| 	public var specular:uint; | ||||
| 	public var glossiness:uint; | ||||
| 	public var transparency:uint; | ||||
| 	public var diffuseMap:MapData; | ||||
| 	public var opacityMap:MapData; | ||||
| 	//public var normalMap:MapData; | ||||
| 	public var matrix:Matrix; | ||||
| } | ||||
|  | ||||
| class MapData { | ||||
| 	public var filename:String; | ||||
| 	public var scaleU:Number = 1; | ||||
| 	public var scaleV:Number = 1; | ||||
| 	public var offsetU:Number = 0; | ||||
| 	public var offsetV:Number = 0; | ||||
| 	public var rotation:Number = 0; | ||||
| } | ||||
|  | ||||
| class ObjectData { | ||||
| 	public var name:String; | ||||
| 	public var vertices:Vector.<Vector3D>; | ||||
| 	public var uvs:Vector.<Point>; | ||||
| 	public var matrix:Matrix3D; | ||||
| 	public var faces:Array;  | ||||
| 	public var surfaces:Object; | ||||
| } | ||||
|  | ||||
| class FaceData { | ||||
| 	public var a:uint; | ||||
| 	public var b:uint; | ||||
| 	public var c:uint; | ||||
| } | ||||
|  | ||||
| class SurfaceData { | ||||
| 	public var materialName:String; | ||||
| 	public var faces:Array; | ||||
| } | ||||
|  | ||||
| class AnimationData { | ||||
| 	public var objectName:String; | ||||
| 	public var object:Mesh; | ||||
| 	public var parentIndex:uint; | ||||
| 	public var pivot:Vector3D; | ||||
| 	public var position:Vector3D; | ||||
| 	public var rotation:Vector3D; | ||||
| 	public var scale:Vector3D; | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
| 	public class TextureFilesData { | ||||
| 		 | ||||
| 		public var diffuseMap:String; | ||||
| 		public var opacityMap:String; | ||||
| 		 | ||||
| 		public function TextureFilesData(diffuseMap:String, opacityMap:String) { | ||||
| 			this.diffuseMap = diffuseMap; | ||||
| 			this.opacityMap = opacityMap; | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
|  | ||||
| 	/** | ||||
| 	 * Структура для хранения имён файла диффузной текстуры и файла карты прозрачности. | ||||
| 	 */ | ||||
| 	public class TextureInfo { | ||||
| 		/** | ||||
| 		 * Имя файла диффузной текстуры. | ||||
| 		 */		 | ||||
| 		public var diffuseMapFileName:String; | ||||
| 		/** | ||||
| 		 * Имя файла карты прозрачности. | ||||
| 		 */ | ||||
| 		public var opacityMapFileName:String; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт новый экземпляр. | ||||
| 		 *  | ||||
| 		 * @param diffuseMapFileName имя файла диффузной текстуры | ||||
| 		 * @param opacityMapFileName имя файла карты прозрачности | ||||
| 		 */ | ||||
| 		public function TextureInfo(diffuseMapFileName:String = null, opacityMapFileName:String = null) { | ||||
| 			this.diffuseMapFileName = diffuseMapFileName; | ||||
| 			this.opacityMapFileName = opacityMapFileName; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт строковое представление объекта. | ||||
| 		 *  | ||||
| 		 * @return строковое представление объекта | ||||
| 		 */ | ||||
| 		public function toString():String { | ||||
| 			return "[TextureInfo diffuseMapFileName=" + diffuseMapFileName + ", opacityMapFileName=" + opacityMapFileName + "]"; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,268 +0,0 @@ | ||||
| package alternativa.engine3d.loaders { | ||||
| 	import alternativa.engine3d.loaders.events.LoaderEvent; | ||||
| 	import alternativa.engine3d.loaders.events.LoaderProgressEvent; | ||||
| 	 | ||||
| 	import flash.display.Bitmap; | ||||
| 	import flash.display.BitmapData; | ||||
| 	import flash.display.BitmapDataChannel; | ||||
| 	import flash.display.BlendMode; | ||||
| 	import flash.display.Loader; | ||||
| 	import flash.display.LoaderInfo; | ||||
| 	import flash.events.Event; | ||||
| 	import flash.events.EventDispatcher; | ||||
| 	import flash.events.IOErrorEvent; | ||||
| 	import flash.events.ProgressEvent; | ||||
| 	import flash.geom.Matrix; | ||||
| 	import flash.geom.Point; | ||||
| 	import flash.net.URLRequest; | ||||
| 	import flash.system.LoaderContext; | ||||
|  | ||||
| 	/** | ||||
| 	 * Событие посылается, когда начинается загрузка ресурса. | ||||
| 	 *  | ||||
| 	 * @eventType flash.events.Event.OPEN | ||||
| 	 */ | ||||
| 	[Event (name="open", type="flash.events.Event")] | ||||
| 	/** | ||||
| 	 * Событие посылается, когда загрузка ресурса успешно завершена. | ||||
| 	 *  | ||||
| 	 * @eventType flash.events.Event.COMPLETE | ||||
| 	 */ | ||||
| 	[Event (name="complete", type="flash.events.Event")] | ||||
| 	/** | ||||
| 	 * Событие посылается при возникновении ошибки загрузки. | ||||
| 	 *  | ||||
| 	 * @eventType flash.events.IOErrorEvent.IO_ERROR | ||||
| 	 */ | ||||
| 	[Event (name="ioError", type="flash.events.IOErrorEvent")] | ||||
| 	/** | ||||
| 	 * Событие посылается, когда начинается загрузка очередной части ресурса. | ||||
| 	 *  | ||||
| 	 * @eventType alternativa.engine3d.loaders.events.LoaderEvent.PART_OPEN | ||||
| 	 */ | ||||
| 	[Event (name="partOpen", type="alternativa.engine3d.loaders.events.LoaderEvent")] | ||||
| 	/** | ||||
| 	 * Событие посылается, когда загрузка очередной части ресурса успешно завершена. | ||||
| 	 *  | ||||
| 	 * @eventType alternativa.engine3d.loaders.events.LoaderEvent.PART_COMPLETE | ||||
| 	 */ | ||||
| 	[Event (name="partComplete", type="alternativa.engine3d.loaders.events.LoaderEvent")] | ||||
| 	/** | ||||
| 	 * Событие посылается для отображения прогресса загрузки. | ||||
| 	 *  | ||||
| 	 * @eventType alternativa.engine3d.loaders.events.LoaderProgressEvent.LOADER_PROGRESS | ||||
| 	 */ | ||||
| 	[Event (name="loaderProgress", type="alternativa.engine3d.loaders.events.LoaderProgressEvent")] | ||||
|  | ||||
| 	/** | ||||
| 	 * Загрузчик текстуры, состоящей из одного или двух файлов. В случае, если указан второй файл, он используется для заполнения альфа-канала | ||||
| 	 * получаемой текстуры. | ||||
| 	 */ | ||||
| 	public class TextureLoader extends EventDispatcher { | ||||
| 		 | ||||
| 		private static const IDLE:int = -1; | ||||
| 		private static const LOADING_DIFFUSE_MAP:int = 0; | ||||
| 		private static const LOADING_ALPHA_MAP:int = 1; | ||||
| 		 | ||||
| 		private var state:int = IDLE; | ||||
| 		private var bitmapLoader:Loader; | ||||
| 		private var loaderContext:LoaderContext; | ||||
| 		private var alphaTextureUrl:String; | ||||
| 		private var _bitmapData:BitmapData; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт новый экземпляр. Если указан URL диффузной части текстуры, то сразу начинается загрузка. | ||||
| 		 *  | ||||
| 		 * @param diffuseTextureUrl URL диффузной части текстуры | ||||
| 		 * @param alphaTextureUrl URL карты прозрачности | ||||
| 		 * @param loaderContext LoaderContext, используемый при загрузке | ||||
| 		 */ | ||||
| 		public function TextureLoader() { | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Загруженная текстура. | ||||
| 		 */ | ||||
| 		public function get bitmapData():BitmapData { | ||||
| 			return _bitmapData; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Загрузка текстурных карт. При успешной загрузке посылается сообщение <code>Event.COMPLETE</code>. | ||||
| 		 *  | ||||
| 		 * @param diffuseTextureUrl URL файла диффузной карты | ||||
| 		 * @param alphaTextureUrl URL файла карты прозрачности  | ||||
| 		 * @param loaderContext LoaderContext, используемый при загрузке | ||||
| 		 */		 | ||||
| 		public function load(diffuseTextureUrl:String, alphaTextureUrl:String = null, loaderContext:LoaderContext = null):void { | ||||
| 			unload(); | ||||
| 			this.alphaTextureUrl = alphaTextureUrl == "" ? null : alphaTextureUrl; | ||||
| 			this.loaderContext = loaderContext; | ||||
| 			 | ||||
| 			loadPart(LOADING_DIFFUSE_MAP, diffuseTextureUrl); | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Прекращвет текущую загрузку. Если нет активных загрузок, не происходит ничего. | ||||
| 		 */ | ||||
| 		public function close():void { | ||||
| 			if (state == IDLE) return; | ||||
| 			state = IDLE; | ||||
| 			bitmapLoader.unload(); | ||||
| 			destroyLoader(); | ||||
| 			alphaTextureUrl = null; | ||||
| 			loaderContext = null; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Очищает внутренние ссылки на загруженные объекты, чтобы сборщик мусора смог их удалить. | ||||
| 		 */ | ||||
| 		public function unload():void { | ||||
| 			close(); | ||||
| 			_bitmapData = null; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Очищает временные внутренние ссылки. | ||||
| 		 */ | ||||
| 		private function cleanup():void { | ||||
| 			destroyLoader(); | ||||
| 			alphaTextureUrl = null; | ||||
| 			loaderContext = null; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Запускает загрузку части текстуры. | ||||
| 		 *  | ||||
| 		 * @param state фаза загрузки | ||||
| 		 * @param url URL загружаемого файла | ||||
| 		 */		 | ||||
| 		private function loadPart(state:int, url:String):void { | ||||
| 			this.state = state; | ||||
| 			createLoader(); | ||||
| 			bitmapLoader.load(new URLRequest(url), loaderContext); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Обрабатывает начало загрузки очередной части текстуры. | ||||
| 		 */ | ||||
| 		private function onPartLoadingOpen(e:Event):void { | ||||
| 			if (_bitmapData == null && hasEventListener(Event.OPEN)) { | ||||
| 				dispatchEvent(new Event(Event.OPEN)); | ||||
| 			} | ||||
| 			if (hasEventListener(LoaderEvent.PART_OPEN)) { | ||||
| 				dispatchEvent(new LoaderEvent(LoaderEvent.PART_OPEN, 2, state == LOADING_DIFFUSE_MAP ? 0 : 1)); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function onPartLoadingProgress(e:ProgressEvent):void { | ||||
| 			if (hasEventListener(LoaderProgressEvent.LOADER_PROGRESS)) { | ||||
| 				var partNumber:int = state == LOADING_DIFFUSE_MAP ? 0 : 1; | ||||
| 				var totalProgress:Number = 0.5*(partNumber + e.bytesLoaded/e.bytesTotal); | ||||
| 				dispatchEvent(new LoaderProgressEvent(LoaderProgressEvent.LOADER_PROGRESS, 2, partNumber, totalProgress, e.bytesLoaded, e.bytesTotal)); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */		 | ||||
| 		private function onPartLoadingComplete(e:Event):void { | ||||
| 			switch (state) { | ||||
| 				case LOADING_DIFFUSE_MAP: { | ||||
| 					// Загрузилась диффузная текстура. При необходимости загружается карта прозрачности. | ||||
| 					_bitmapData = Bitmap(bitmapLoader.content).bitmapData; | ||||
| 					destroyLoader(); | ||||
| 					dispatchPartComplete(0); | ||||
| 					if (alphaTextureUrl != null) { | ||||
| 						loadPart(LOADING_ALPHA_MAP, alphaTextureUrl); | ||||
| 					} else { | ||||
| 						complete(); | ||||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
| 				case LOADING_ALPHA_MAP: { | ||||
| 					// Загрузилась карта прозрачности. Выполняется копирование прозрачности в альфа-канал диффузной текстуры. | ||||
| 					var pt:Point = new Point(); | ||||
| 					var tmpBmd:BitmapData = _bitmapData; | ||||
| 					_bitmapData = new BitmapData(_bitmapData.width, _bitmapData.height); | ||||
| 					_bitmapData.copyPixels(tmpBmd, tmpBmd.rect, pt); | ||||
| 					 | ||||
| 					var alpha:BitmapData = Bitmap(bitmapLoader.content).bitmapData; | ||||
| 					destroyLoader(); | ||||
| 					if (_bitmapData.width != alpha.width || _bitmapData.height != alpha.height) { | ||||
| 						tmpBmd.draw(alpha, new Matrix(_bitmapData.width/alpha.width, 0, 0, _bitmapData.height/alpha.height), null, BlendMode.NORMAL, null, true); | ||||
| 						alpha.dispose(); | ||||
| 						alpha = tmpBmd; | ||||
| 					} else { | ||||
| 						tmpBmd.dispose(); | ||||
| 					} | ||||
| 					_bitmapData.copyChannel(alpha, alpha.rect, pt, BitmapDataChannel.RED, BitmapDataChannel.ALPHA); | ||||
| 					alpha.dispose(); | ||||
| 					dispatchPartComplete(1); | ||||
| 					complete(); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт событие завершения загрузки части текстуры. | ||||
| 		 *  | ||||
| 		 * @param partnNumber номер загруженной части текстуры | ||||
| 		 */ | ||||
| 		private function dispatchPartComplete(partNumber:int):void { | ||||
| 			if (hasEventListener(LoaderEvent.PART_COMPLETE)) { | ||||
| 				dispatchEvent(new LoaderEvent(LoaderEvent.PART_COMPLETE, 2, partNumber)); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function onLoadError(e:Event):void { | ||||
| 			state = IDLE; | ||||
| 			cleanup(); | ||||
| 			dispatchEvent(e); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function complete():void { | ||||
| 			state = IDLE; | ||||
| 			cleanup(); | ||||
| 			if (hasEventListener(Event.COMPLETE)) { | ||||
| 				dispatchEvent(new Event(Event.COMPLETE)); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		private function createLoader():void { | ||||
| 			bitmapLoader = new Loader(); | ||||
| 			var loaderInfo:LoaderInfo = bitmapLoader.contentLoaderInfo; | ||||
| 			loaderInfo.addEventListener(Event.OPEN, onPartLoadingOpen); | ||||
| 			loaderInfo.addEventListener(ProgressEvent.PROGRESS, onPartLoadingProgress); | ||||
| 			loaderInfo.addEventListener(Event.COMPLETE, onPartLoadingComplete); | ||||
| 			loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * | ||||
| 		 */ | ||||
| 		private function destroyLoader():void { | ||||
| 			if (bitmapLoader == null) return; | ||||
| 			bitmapLoader.unload(); | ||||
| 			var loaderInfo:LoaderInfo = bitmapLoader.contentLoaderInfo; | ||||
| 			loaderInfo.removeEventListener(Event.OPEN, onPartLoadingOpen); | ||||
| 			loaderInfo.removeEventListener(ProgressEvent.PROGRESS, onPartLoadingProgress); | ||||
| 			loaderInfo.removeEventListener(Event.COMPLETE, onPartLoadingComplete); | ||||
| 			loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onLoadError); | ||||
| 			bitmapLoader = null; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,23 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 112 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/events | ||||
| END | ||||
| LoaderProgressEvent.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 135 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/events/LoaderProgressEvent.as | ||||
| END | ||||
| BatchTextureLoaderErrorEvent.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 144 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/events/BatchTextureLoaderErrorEvent.as | ||||
| END | ||||
| LoaderEvent.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 127 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/events/LoaderEvent.as | ||||
| END | ||||
| @@ -1,64 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/loaders/events | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-08-27T08:28:22.626310Z | ||||
| 18884 | ||||
| mike | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| LoaderProgressEvent.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| a4e491b33c3847206877f52b1adb6103 | ||||
| 2009-08-27T08:28:22.626310Z | ||||
| 18884 | ||||
| mike | ||||
|  | ||||
| BatchTextureLoaderErrorEvent.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 7664b6633f2dffac1b835c85e5bb8a77 | ||||
| 2009-08-27T08:28:22.626310Z | ||||
| 18884 | ||||
| mike | ||||
|  | ||||
| LoaderEvent.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:16.000000Z | ||||
| 7a6829911979a4184d4fbc159e27ba16 | ||||
| 2009-08-27T08:28:22.626310Z | ||||
| 18884 | ||||
| mike | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 8 | ||||
| @@ -1,57 +0,0 @@ | ||||
| package alternativa.engine3d.loaders.events { | ||||
| 	import flash.events.ErrorEvent; | ||||
| 	import flash.events.Event; | ||||
|  | ||||
| 	/** | ||||
| 	 * Класс представляет событие ошибки, генерируемое пакетным загрузчиком текстур. | ||||
| 	 */ | ||||
| 	public class BatchTextureLoaderErrorEvent extends ErrorEvent { | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 */ | ||||
| 		public static const LOADER_ERROR:String = "loaderError"; | ||||
| 		 | ||||
| 		// Имя текстуры, с которой произошла проблема | ||||
| 		private var _textureName:String; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт новый экземпляр. | ||||
| 		 *  | ||||
| 		 * @param type тип события | ||||
| 		 * @param textureName имя текстуры, с которой произошла проблема | ||||
| 		 * @param text описание ошибки | ||||
| 		 */ | ||||
| 		public function BatchTextureLoaderErrorEvent(type:String, textureName:String, text:String) { | ||||
| 			super(type); | ||||
| 			this.text = text; | ||||
| 			_textureName = textureName; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Имя текстуры, с которой произошла проблема. | ||||
| 		 */ | ||||
| 		public function get textureName():String { | ||||
| 			return _textureName; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Клонирует объект. | ||||
| 		 *  | ||||
| 		 * @return клон объекта | ||||
| 		 */ | ||||
| 		override public function clone():Event { | ||||
| 			return new BatchTextureLoaderErrorEvent(type, _textureName, text); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт строкове представление объекта. | ||||
| 		 *  | ||||
| 		 * @return строкове представление объекта | ||||
| 		 */ | ||||
| 		override public function toString():String { | ||||
| 			return "[BatchTextureLoaderErrorEvent textureName=" + _textureName + ", text=" + text + "]"; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,68 +0,0 @@ | ||||
| package alternativa.engine3d.loaders.events { | ||||
| 	import flash.events.Event; | ||||
|  | ||||
| 	/** | ||||
| 	 * Событие загрузчиков ресурсов, состоящих из нескольких частей. | ||||
| 	 */ | ||||
| 	public class LoaderEvent extends Event { | ||||
| 		/** | ||||
| 		 * Событие начала загрузки очередной части ресурса. | ||||
| 		 */ | ||||
| 		public static const PART_OPEN:String = "partOpen"; | ||||
| 		/** | ||||
| 		 * Событие окончания загрузки очередной части ресурса. | ||||
| 		 */ | ||||
| 		public static const PART_COMPLETE:String = "partComplete"; | ||||
|  | ||||
| 		// Общее количество загружаемых частей | ||||
| 		private var _partsTotal:int; | ||||
| 		// Номер загружаемой в настоящий момент части. Нумерация начинается с нуля. | ||||
| 		private var _currentPart:int; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт новый экземпляр. | ||||
| 		 *  | ||||
| 		 * @param type тип события | ||||
| 		 * @param totalParts общее количество загружаемых частей | ||||
| 		 * @param currentPart номер части, к которой относится событие. Нумерация начинается с нуля | ||||
| 		 */ | ||||
| 		public function LoaderEvent(type:String, partsTotal:int, currentPart:int) { | ||||
| 			super(type); | ||||
| 			_partsTotal = partsTotal; | ||||
| 			_currentPart= currentPart; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Общее количество загружаемых частей. | ||||
| 		 */ | ||||
| 		public function get partsTotal():int { | ||||
| 			return _partsTotal; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Номер загружаемой в настоящий момент части. Нумерация начинается с нуля. | ||||
| 		 */ | ||||
| 		public function get currentPart():int { | ||||
| 			return _currentPart; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Клонирует объект. | ||||
| 		 *  | ||||
| 		 * @return клон объекта | ||||
| 		 */ | ||||
| 		override public function clone():Event { | ||||
| 			return new LoaderEvent(type, _partsTotal, _currentPart); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт строкове представление объекта. | ||||
| 		 *  | ||||
| 		 * @return строкове представление объекта | ||||
| 		 */ | ||||
| 		override public function toString():String { | ||||
| 			return "[LoaderEvent type=" + type + ", partsTotal=" + _partsTotal + ", currentPart=" + _currentPart + "]"; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,79 +0,0 @@ | ||||
| package alternativa.engine3d.loaders.events { | ||||
| 	import flash.events.Event; | ||||
| 	import flash.events.ProgressEvent; | ||||
|  | ||||
| 	/** | ||||
| 	 * Событие прогресса загрузки ресурсов, состоящих из нескольких частей. | ||||
| 	 */ | ||||
| 	public class LoaderProgressEvent extends ProgressEvent { | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Событие прогресса загрузки очередной части ресурса. | ||||
| 		 */ | ||||
| 		public static const LOADER_PROGRESS:String = "loaderProgress"; | ||||
| 		 | ||||
| 		// Общее количество загружаемых частей | ||||
| 		private var _partsTotal:int; | ||||
| 		// Номер загружаемой в настоящий момент части. Нумерация начинается с нуля. | ||||
| 		private var _currentPart:int; | ||||
| 		// Общий прогресс загрузки, выраженный числом в интервале [0, 1]  | ||||
| 		private var _totalProgress:Number = 0; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт новый экземпляр. | ||||
| 		 *  | ||||
| 		 * @param type тип события | ||||
| 		 * @param totalParts общее количество загружаемых частей | ||||
| 		 * @param currentPart номер загружаемой в настоящий момент части. Нумерация начинается с нуля | ||||
| 		 * @param totalProgress общий прогресс загрузки, выраженный числом в интервале [0, 1] | ||||
| 		 * @param bytesLoaded количество загруженных байт текущей части | ||||
| 		 * @param bytesTotal объём текущей части | ||||
| 		 */ | ||||
| 		public function LoaderProgressEvent(type:String, partsTotal:int, currentPart:int, totalProgress:Number = 0, bytesLoaded:uint=0, bytesTotal:uint=0) { | ||||
| 			super(type, false, false, bytesLoaded, bytesTotal); | ||||
| 			_partsTotal = partsTotal; | ||||
| 			_currentPart= currentPart; | ||||
| 			_totalProgress = totalProgress; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Общее количество загружаемых частей. | ||||
| 		 */ | ||||
| 		public function get partsTotal():int { | ||||
| 			return _partsTotal; | ||||
| 		} | ||||
|  | ||||
| 		/** | ||||
| 		 * Номер загружаемой в настоящий момент части. Нумерация начинается с нуля. | ||||
| 		 */ | ||||
| 		public function get currentPart():int { | ||||
| 			return _currentPart; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Общий прогресс загрузки, выраженный числом в интервале [0, 1].  | ||||
| 		 */ | ||||
| 		public function get totalProgress():Number { | ||||
| 			return _totalProgress; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Клонирует объект. | ||||
| 		 *  | ||||
| 		 * @return клон объекта | ||||
| 		 */ | ||||
| 		override public function clone():Event { | ||||
| 			return new LoaderProgressEvent(type, _partsTotal, _currentPart, _totalProgress, bytesLoaded, bytesTotal); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Создаёт строкове представление объекта. | ||||
| 		 *  | ||||
| 		 * @return строкове представление объекта | ||||
| 		 */ | ||||
| 		override public function toString():String { | ||||
| 			return "[LoaderProgressEvent partsTotal=" + _partsTotal + ", currentPart=" + _currentPart + ", totalProgress=" + _totalProgress.toFixed(2) + "]"; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,71 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 105 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects | ||||
| END | ||||
| Sprite3D.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 117 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/Sprite3D.as | ||||
| END | ||||
| LOD.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 112 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/LOD.as | ||||
| END | ||||
| Reference.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 118 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/Reference.as | ||||
| END | ||||
| Axes.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 113 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/Axes.as | ||||
| END | ||||
| Occluder.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 117 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/Occluder.as | ||||
| END | ||||
| SkeletalMesh.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 121 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/SkeletalMesh.as | ||||
| END | ||||
| WireQuad.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 117 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/WireQuad.as | ||||
| END | ||||
| Bone.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 113 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/Bone.as | ||||
| END | ||||
| WireBoundBox.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 121 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/WireBoundBox.as | ||||
| END | ||||
| AnimSprite.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 119 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/AnimSprite.as | ||||
| END | ||||
| Mesh.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 113 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects/Mesh.as | ||||
| END | ||||
| @@ -1,171 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/objects | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-10-20T14:53:05.299873Z | ||||
| 22340 | ||||
| int | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| Sprite3D.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| f0c6d684f0acaaa391d71c15058932b2 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| LOD.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 0f469e3fe64fa8bf4fed1266f136f6c4 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Reference.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 06b31aca995fd2e76926e30caeac383f | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Axes.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 1928c9eff46ec25a70dd03f6e3672576 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Occluder.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 9e0f1d140b7b942c17a832d594df4128 | ||||
| 2009-10-20T14:53:05.299873Z | ||||
| 22340 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| SkeletalMesh.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| de5e885c73b684aed98bb4236ab07f95 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| WireQuad.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 44938f9931ae4fcaf1c3cd83695e317c | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Bone.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 23e5f3ca40ed5ddf8da9d45c70463811 | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| WireBoundBox.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 7e38ddd083865225310aaa81fe9f9e0e | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| AnimSprite.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 96cda79b177ed928bd06912d23eb564c | ||||
| 2009-10-15T16:00:46.512753Z | ||||
| 22064 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| Mesh.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 18042cdbb27292d71550b9fb1914e838 | ||||
| 2009-10-19T11:39:18.186364Z | ||||
| 22296 | ||||
| int | ||||
| has-props | ||||
|  | ||||
| @@ -1 +0,0 @@ | ||||
| 8 | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 847 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/AnimSprite.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/AnimSprite.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/AnimSprite.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/AnimSprite.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/AnimSprite.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/AnimSprite.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/AnimSprite.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 805 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/Axes.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/Axes.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/Axes.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/Axes.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/Axes.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/Axes.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/Axes.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 805 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/Bone.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/Bone.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/Bone.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/Bone.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/Bone.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/Bone.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/Bone.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 798 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/LOD.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/LOD.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/LOD.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/LOD.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/LOD.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/LOD.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/LOD.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,5 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 120 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/Mesh.as:17447,17456-18883 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 833 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/Occluder.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/Occluder.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/Occluder.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/Occluder.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/Occluder.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/Occluder.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/Occluder.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 840 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/Reference.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/Reference.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/Reference.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/Reference.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/Reference.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/Reference.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/Reference.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 861 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/SkeletalMesh.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/SkeletalMesh.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/SkeletalMesh.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/SkeletalMesh.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/SkeletalMesh.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/SkeletalMesh.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/SkeletalMesh.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 833 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/Sprite3D.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/Sprite3D.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/Sprite3D.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/Sprite3D.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/Sprite3D.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/Sprite3D.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/Sprite3D.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 861 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/WireBoundBox.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/WireBoundBox.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/WireBoundBox.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/WireBoundBox.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/WireBoundBox.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/WireBoundBox.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/WireBoundBox.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,11 +0,0 @@ | ||||
| K 13 | ||||
| svn:mergeinfo | ||||
| V 833 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0/src/alternativa/engine3d/core/WireQuad.as:5796-7235 | ||||
| /platform/clients/fp10/libraries/Alternativa3D/branches/7.0.2/src/alternativa/engine3d/objects/WireQuad.as:17447,17456-18883 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4/alternativa/engine3d/core/WireQuad.as:304-463 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.MouseEvents/src/alternativa/engine3d/core/WireQuad.as:1556-1900 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/branches/5.4.SingularMapping/src/alternativa/engine3d/core/WireQuad.as:2042-2060 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/alternativa/engine3d/core/WireQuad.as:304-494 | ||||
| /platform/clients/fp9/libraries/Alternativa3D/trunk/src/alternativa/engine3d/core/WireQuad.as:1465-2616,2621-2676,2680-2696,2710-2743,2778-2783 | ||||
| END | ||||
| @@ -1,72 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
|  | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Geometry; | ||||
| 	import alternativa.engine3d.core.MipMap; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.display.BitmapData; | ||||
| 	import flash.geom.Matrix3D; | ||||
|  | ||||
| 	use namespace alternativa3d;	 | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Анимированный спрайт.  | ||||
| 	 * Анимация осуществляется путём переключения изображений, | ||||
| 	 * хранящихся в списке textures | ||||
| 	 */ | ||||
| 	public class AnimSprite extends Sprite3D { | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Список кадров изображений  | ||||
| 		 */ | ||||
| 		public var textures:Vector.<BitmapData>; | ||||
| 		public var mipMaps:Vector.<MipMap>; | ||||
| 		/** | ||||
| 		 * Устанавливаемый кадр  | ||||
| 		 */ | ||||
| 		public var frame:uint = 0; | ||||
| 		 | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			if (mipMapping == 0) { | ||||
| 				texture = textures[frame]; | ||||
| 			} else { | ||||
| 				mipMap = mipMaps[frame]; | ||||
| 			} | ||||
| 			super.draw(camera, object, parentCanvas); | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function debug(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			if (mipMapping == 0) { | ||||
| 				texture = textures[frame]; | ||||
| 			} else { | ||||
| 				mipMap = mipMaps[frame]; | ||||
| 			} | ||||
| 			super.debug(camera, object, parentCanvas); | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function getGeometry(camera:Camera3D, object:Object3D):Geometry { | ||||
| 			if (mipMapping == 0) { | ||||
| 				texture = textures[frame]; | ||||
| 			} else { | ||||
| 				mipMap = mipMaps[frame]; | ||||
| 			} | ||||
| 			return super.getGeometry(camera, object); | ||||
| 		} | ||||
| 		 | ||||
| 		override public function calculateBoundBox(matrix:Matrix3D = null, boundBox:BoundBox = null):BoundBox { | ||||
| 			if (mipMapping == 0) { | ||||
| 				texture = textures[frame]; | ||||
| 			} else { | ||||
| 				mipMap = mipMaps[frame]; | ||||
| 			} | ||||
| 			return super.calculateBoundBox(matrix, boundBox); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,120 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.display.Graphics; | ||||
| 	import flash.geom.Utils3D; | ||||
| 	import flash.text.TextField; | ||||
| 	import flash.text.TextFieldAutoSize; | ||||
| 	import flash.text.TextFormat; | ||||
| 	 | ||||
| 	use namespace alternativa3d;	 | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Вспомогательный объект, иллюстрирующий систему коордщинат | ||||
| 	 */ | ||||
| 	public class Axes extends Object3D { | ||||
| 		 | ||||
| 		public var axisLength:Number; | ||||
| 		public var lineThickness:Number; | ||||
| 		public var dotRadius:Number; | ||||
| 		public var textSize:Number; | ||||
| 		 | ||||
| 		public function Axes(axisLength:Number = 30, lineThickness:Number = 0, dotRadius:Number = 2, textSize:Number = 10):void { | ||||
| 			this.axisLength = axisLength; | ||||
| 			this.lineThickness = lineThickness; | ||||
| 			this.dotRadius = dotRadius; | ||||
| 			this.textSize = textSize; | ||||
| 			_boundBox = new BoundBox(); | ||||
| 			_boundBox.setSize(-dotRadius, -dotRadius, -dotRadius, axisLength, axisLength, axisLength); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
|  | ||||
| 			var p:Vector.<Number> = Vector.<Number>([0, 0, 0, axisLength, 0, 0, 0, axisLength, 0, 0, 0, axisLength]); | ||||
| 			var d:Vector.<Number> = new Vector.<Number>(8); | ||||
| 			object.cameraMatrix.transformVectors(p, p); | ||||
|  | ||||
| 			// Центр за камерой | ||||
| 			if (p[2] < camera.nearClipping) return; | ||||
|  | ||||
| 			Utils3D.projectVectors(camera.projectionMatrix, p, d, new Vector.<Number>()); | ||||
| 			var size:Number = camera.viewSize/p[2]; | ||||
| 			 | ||||
| 			// Подготовка канваса | ||||
| 			var canvas:Canvas = parentCanvas.getChildCanvas(true, false, object.alpha, object.blendMode, object.colorTransform, object.filters); | ||||
|  | ||||
| 			var gfx:Graphics = canvas.gfx; | ||||
| 			var text:TextField; | ||||
| 			 | ||||
| 			// Ось X | ||||
| 			if (p[5] >= camera.nearClipping) { | ||||
| 				gfx.lineStyle(lineThickness*size, 0xFF0000); | ||||
| 				gfx.moveTo(d[0], d[1]); | ||||
| 				gfx.lineTo(d[2], d[3]); | ||||
| 				 | ||||
| 				text = new TextField(); | ||||
| 				text.autoSize = TextFieldAutoSize.LEFT; | ||||
| 				text.selectable = false; | ||||
| 				text.x = d[2]; | ||||
| 				text.y = d[3]; | ||||
| 				text.text = "X"; | ||||
| 				text.setTextFormat(new TextFormat("Tahoma", textSize*size, 0xFF0000)); | ||||
| 				 | ||||
| 				canvas.addChild(text); | ||||
| 				canvas._numChildren++; | ||||
| 			} | ||||
| 			 | ||||
| 			// Ось Y | ||||
| 			if (p[8] >= camera.nearClipping) { | ||||
| 				gfx.lineStyle(lineThickness*size, 0x00FF00); | ||||
| 				gfx.moveTo(d[0], d[1]); | ||||
| 				gfx.lineTo(d[4], d[5]); | ||||
|  | ||||
| 				text = new TextField(); | ||||
| 				text.autoSize = TextFieldAutoSize.LEFT; | ||||
| 				text.selectable = false; | ||||
| 				text.x = d[4]; | ||||
| 				text.y = d[5]; | ||||
| 				text.text = "Y"; | ||||
| 				text.setTextFormat(new TextFormat("Tahoma", textSize*size, 0x00FF00)); | ||||
|  | ||||
| 				canvas.addChild(text); | ||||
| 				canvas._numChildren++; | ||||
| 			} | ||||
| 			 | ||||
| 			// Ось Z | ||||
| 			if (p[11] >= camera.nearClipping) { | ||||
| 				gfx.lineStyle(lineThickness*size, 0x0000FF); | ||||
| 				gfx.moveTo(d[0], d[1]); | ||||
| 				gfx.lineTo(d[6], d[7]); | ||||
|  | ||||
| 				text = new TextField(); | ||||
| 				text.autoSize = TextFieldAutoSize.LEFT; | ||||
| 				text.selectable = false; | ||||
| 				text.x = d[6]; | ||||
| 				text.y = d[7]; | ||||
| 				text.text = "Z"; | ||||
| 				text.setTextFormat(new TextFormat("Tahoma", textSize*size, 0x0000FF)); | ||||
|  | ||||
| 				canvas.addChild(text); | ||||
| 				canvas._numChildren++; | ||||
| 			} | ||||
| 			 | ||||
| 			// Начало координат | ||||
| 			gfx.lineStyle(); | ||||
| 			gfx.beginFill(0xFFFFFF); | ||||
| 			gfx.drawCircle(d[0], d[1], dotRadius*size); | ||||
| 			 | ||||
| 			//debugDrawBoundRaduis(camera, object, canvas); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,60 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
|  | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	 | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Vector3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class Bone extends Mesh { | ||||
| 		 | ||||
| 		public var localTransform:Vector.<Vector3D>; | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		alternativa3d var localMatrix:Matrix3D; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		alternativa3d var length:Number; | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		alternativa3d var distance:Number; | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		alternativa3d var _numChildren:uint = 0; | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		alternativa3d var children:Vector.<Bone> = new Vector.<Bone>(); | ||||
| 		 | ||||
| 		public function Bone(length:Number, distance:Number) { | ||||
| 			this.length = length; | ||||
| 			this.distance = distance; | ||||
| 		} | ||||
| 		 | ||||
| 		public function addChild(child:Bone):void { | ||||
| 			children[_numChildren++] = child; | ||||
| 			child.localTransform = child.matrix.decompose(); | ||||
| 			child.localMatrix = new Matrix3D(); | ||||
| 		} | ||||
| 		 | ||||
| 		public function calculateMatrix():void { | ||||
| 			for (var i:int = 0; i < _numChildren; i++) { | ||||
| 				var child:Bone = children[i];  | ||||
| 				child.matrix.identity(); | ||||
| 				child.matrix.prepend(matrix); | ||||
| 				child.localMatrix.recompose(child.localTransform); | ||||
| 				child.matrix.prepend(child.localMatrix); | ||||
| 				child.calculateMatrix(); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
|  | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Geometry; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 		 | ||||
| 	/** | ||||
| 	 * Объект, имеющий набор объектов с разной детализацией. | ||||
| 	 * При отрисовке, он выбирает в зависимости от расстояния от камеры  | ||||
| 	 * объект с нужной детализацией и отрисовывает его вместо себя. | ||||
| 	 * Это позволяет получить лучший визуальный результат и большую производительность. | ||||
| 	 */ | ||||
| 	public class LOD extends Object3D { | ||||
|  | ||||
| 		/** | ||||
| 		 * Объекты с разной детализацией  | ||||
| 		 */ | ||||
| 		public var lodObjects:Vector.<Object3D>; | ||||
| 		/** | ||||
| 		 * Расстояния до камеры соответствующие объектам с разной детализацией  | ||||
| 		 */ | ||||
| 		public var lodDistances:Vector.<Number>; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		private function getLODObject(object:Object3D):Object3D { | ||||
| 			var cameraDistance:Number = object.cameraMatrix.position.length; | ||||
| 			// Поиск ближайшего лода | ||||
| 			var min:Number = Infinity; | ||||
| 			var length:uint = lodObjects.length; | ||||
| 			var lod:Object3D; | ||||
| 			for (var i:int = 0; i < length; i++) { | ||||
| 				var d:Number = Math.abs(cameraDistance - lodDistances[i]);  | ||||
| 				if (d < min) { | ||||
| 					min = d; | ||||
| 					lod = lodObjects[i]; | ||||
| 				} | ||||
| 			} | ||||
| 			return lod; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private  | ||||
| 		 */ | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			getLODObject(object).draw(camera, object, parentCanvas); | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function debug(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			getLODObject(object).debug(camera, object, parentCanvas); | ||||
| 		}		 | ||||
| 		 | ||||
| 		override alternativa3d function getGeometry(camera:Camera3D, object:Object3D):Geometry { | ||||
| 			return getLODObject(object).getGeometry(camera, object); | ||||
| 		} | ||||
| 		 | ||||
| 		override public function get boundBox():BoundBox { | ||||
| 			return (lodObjects[0] as Object3D).boundBox; | ||||
| 		} | ||||
| 		 | ||||
| 		override public function calculateBoundBox(matrix:Matrix3D = null, boundBox:BoundBox = null):BoundBox { | ||||
| 			return (lodObjects[0] as Object3D).calculateBoundBox(matrix, boundBox); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,412 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
|  | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Debug; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Utils3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Полигональный объект-перекрытие. | ||||
| 	 * Объекты, которые он перекрывает от видимости камеры, исключаются из отрисовки. | ||||
| 	 * Сам окклюдер не отрисовывается. | ||||
| 	 * Должен быть конвексным | ||||
| 	 */ | ||||
| 	public class Occluder extends Object3D { | ||||
| 		/** | ||||
| 		 * Режим представления полигонов.  | ||||
| 		 * Если false, в indices записаны треугольники (тройки индексов). | ||||
| 		 * Если true, в indices записаны многоугольники в виде: количество вершин грани, индексы вершин | ||||
| 		 */ | ||||
| 		public var poly:Boolean = false; | ||||
| 		public var vertices:Vector.<Number>; | ||||
| 		public var edges:Vector.<int>; // Два индекса - вершины, два - грани | ||||
| 		public var indices:Vector.<int>; | ||||
| 		public var normals:Vector.<Number>; | ||||
| 		 | ||||
| 		// Отношение площади перекрытия к площади вьюпорта (0 - 1) | ||||
| 		/** | ||||
| 		 * Минимальное отношение площади перекрытия окклюдером вьюпорта к площади вьюпорта (от 0 до 1) | ||||
| 		 * Если окклюдер перекрывает больше, он помещается в очередь и учитывается  | ||||
| 		 * при дальнейшей отрисовке в пределах кадра, иначе игнорируется | ||||
| 		 */ | ||||
| 		public var minSize:Number = 0; | ||||
| 		 | ||||
| 		private const cameraVertices:Vector.<Number> = new Vector.<Number>(); | ||||
| 		private const visibilityMap:Vector.<Boolean> = new Vector.<Boolean>; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Коприрование геометрии меша  | ||||
| 		 * @param mesh Объект копирования | ||||
| 		 * Меш, геометрия которого копируется, обязан быть конвексным, иначе окклюдер будет некорректно работать | ||||
| 		 */ | ||||
| 		public function copyFrom(mesh:Mesh):void { | ||||
| 			poly = mesh.poly; | ||||
| 			vertices = mesh.vertices; | ||||
| 			indices = mesh.indices; | ||||
| 			normals = mesh.normals; | ||||
| 			 | ||||
| 			matrix.identity(); | ||||
| 			matrix.prepend(mesh.matrix); | ||||
| 			if (_boundBox != null) { | ||||
| 				_boundBox.copyFrom(mesh._boundBox); | ||||
| 			} else { | ||||
| 				_boundBox = mesh._boundBox; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		override public function calculateBoundBox(matrix:Matrix3D = null, boundBox:BoundBox = null):BoundBox { | ||||
| 			var v:Vector.<Number> = vertices; | ||||
| 			// Если указана матрица трансформации, переводим | ||||
| 			if (matrix != null) { | ||||
| 				matrix.transformVectors(vertices, cameraVertices); | ||||
| 				v = cameraVertices; | ||||
| 			} | ||||
| 			// Если указан баунд-бокс | ||||
| 			if (boundBox != null) { | ||||
| 				boundBox.infinity(); | ||||
| 			} else { | ||||
| 				boundBox = new BoundBox(); | ||||
| 			} | ||||
| 			// Ищем баунд-бокс | ||||
| 			for (var i:int = 0, length:int = vertices.length; i < length;) { | ||||
| 				boundBox.addPoint(v[i++], v[i++], v[i++]); | ||||
| 			} | ||||
| 			return boundBox; | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Расчёт рёбер по имеющимся вершинам и граням  | ||||
| 		 */ | ||||
| 		public function calculateEdges():void { | ||||
| 			// Подготавливаем массив рёбер | ||||
| 			if (edges == null) edges = new Vector.<int>(); | ||||
| 			 | ||||
| 			// Собираем рёбра | ||||
| 			for (var i:int = 0, j:int = 0, n:int = 0, k:int = 0, a:int, b:int, length:int = indices.length; i < length;) { | ||||
| 				if (i == k) { | ||||
| 					k = poly ? (indices[i++] + i) : (i + 3); | ||||
| 					a = indices[int(k - 1)]; | ||||
| 				} | ||||
| 				b = indices[i]; | ||||
| 				edges[j++] = a; | ||||
| 				edges[j++] = b; | ||||
| 				edges[j++] = n; | ||||
| 				edges[j++] = -1; | ||||
| 				if (++i == k) n++; else a = b; | ||||
| 			} | ||||
| 			edges.length = j; | ||||
| 			 | ||||
| 			// Убираем дубли | ||||
| 			length = j, i = 0; k = 0; | ||||
| 			var ac:int, bc:int; | ||||
| 			while (i < length) { | ||||
| 				if ((a = edges[i++]) >= 0) { | ||||
| 					b = edges[i++]; | ||||
| 					edges[k++] = a; | ||||
| 					edges[k++] = b; | ||||
| 					edges[k++] = edges[i++]; | ||||
| 					j = ++i; | ||||
| 					while (j < length) { | ||||
| 						ac = edges[j++];  | ||||
| 						bc = edges[j++]; | ||||
| 						if (ac == a && bc == b || ac == b && bc == a) { | ||||
| 							edges[int(j - 2)] = -1; | ||||
| 							edges[k] = edges[j]; | ||||
| 							break; | ||||
| 						} | ||||
| 						j += 2; | ||||
| 					} | ||||
| 					k++; | ||||
| 				} else i += 3; | ||||
| 			} | ||||
| 			edges.length = k; | ||||
| 		} | ||||
| 		 | ||||
| 		static private const inverseCameraMatrix:Matrix3D = new Matrix3D(); | ||||
| 		static private const center:Vector.<Number> = new Vector.<Number>(3, true); | ||||
| 		private var cameraX:Number; | ||||
| 		private var cameraY:Number; | ||||
| 		private var cameraZ:Number; | ||||
| 		static private const projectedEdges:Vector.<Number> = new Vector.<Number>(); | ||||
| 		static private const uvts:Vector.<Number> = new Vector.<Number>(); | ||||
| 		static private const viewEdges:Vector.<Number> = new Vector.<Number>(); | ||||
| 		static private const debugEdges:Vector.<Number> = new Vector.<Number>(); | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			// Перевод в координаты камеры | ||||
| 			object.cameraMatrix.transformVectors(vertices, cameraVertices); | ||||
| 			// Определение центра камеры в объекте | ||||
| 			inverseCameraMatrix.identity(); | ||||
| 			inverseCameraMatrix.prepend(object.cameraMatrix); | ||||
| 			inverseCameraMatrix.invert(); | ||||
| 			center[0] = center[1] = center[2] = 0; | ||||
| 			inverseCameraMatrix.transformVectors(center, center); | ||||
| 			cameraX = center[0], cameraY = center[1], cameraZ = center[2]; | ||||
| 			// Расчёт карты видимости граней | ||||
| 			for (var i:int = 0, n:int = 0, normalsLength:int = normals.length >> 2, cameraInside:Boolean = true, infront:Boolean; i < normalsLength;) visibilityMap[i++] = infront = normals[n++]*cameraX + normals[n++]*cameraY + normals[n++]*cameraZ > normals[n++], cameraInside &&= !infront; | ||||
| 			// Если камера внутри окклюдера | ||||
| 			if (cameraInside) return; | ||||
| 			// Подготовка окклюдера в камере | ||||
| 			var occludeAll:Boolean = true, culling:int = object.culling, direction:Boolean, ax:Number, ay:Number, az:Number, bx:Number, by:Number, bz:Number, t:Number; | ||||
| 			var planeOccluder:Vector.<Number>, edgeOccluder:Vector.<Number>, planeOccluderLength:int = 0, edgeOccluderLength:int = 0, viewEdgesLength:int = 0; | ||||
| 			if (camera.occlusionPlanes.length > camera.numOccluders) { | ||||
| 				planeOccluder = camera.occlusionPlanes[camera.numOccluders]; | ||||
| 				edgeOccluder = camera.occlusionEdges[camera.numOccluders]; | ||||
| 			} else { | ||||
| 				planeOccluder = camera.occlusionPlanes[camera.numOccluders] = new Vector.<Number>(); | ||||
| 				edgeOccluder = camera.occlusionEdges[camera.numOccluders] = new Vector.<Number>(); | ||||
| 			} | ||||
| 			for (i = edges.length - 1; i > 0;) { | ||||
| 				if ((direction = visibilityMap[edges[i--]]) != visibilityMap[edges[i--]]) { | ||||
| 					// Определение порядка вершин (против часовой) | ||||
| 					if (direction) ax = cameraVertices[n = int(edges[i--]*3)], ay = cameraVertices[++n], az = cameraVertices[++n], bx = cameraVertices[n = int(edges[i--]*3)], by = cameraVertices[++n], bz = cameraVertices[++n] else bx = cameraVertices[n = int(edges[i--]*3)], by = cameraVertices[++n], bz = cameraVertices[++n], ax = cameraVertices[n = int(edges[i--]*3)], ay = cameraVertices[++n], az = cameraVertices[++n]; | ||||
| 					// Клиппинг | ||||
| 					if (culling > 0) { | ||||
| 						if (az <= -ax && bz <= -bx) { | ||||
| 							if (occludeAll && by*ax - bx*ay > 0) occludeAll = false; | ||||
| 							continue; | ||||
| 						} else if (bz > -bx && az <= -ax) { | ||||
| 							t = (ax + az)/(ax + az - bx - bz), ax = ax + (bx - ax)*t, ay = ay + (by - ay)*t, az = az + (bz - az)*t; | ||||
| 						} else if (bz <= -bx && az > -ax) { | ||||
| 							t = (ax + az)/(ax + az - bx - bz), bx = ax + (bx - ax)*t, by = ay + (by - ay)*t, bz = az + (bz - az)*t; | ||||
| 						} | ||||
| 						if (az <= ax && bz <= bx) { | ||||
| 							if (occludeAll && by*ax - bx*ay > 0) occludeAll = false; | ||||
| 							continue; | ||||
| 						} else if (bz > bx && az <= ax) { | ||||
| 							t = (az - ax)/(az - ax + bx - bz), ax = ax + (bx - ax)*t, ay = ay + (by - ay)*t, az = az + (bz - az)*t; | ||||
| 						} else if (bz <= bx && az > ax) { | ||||
| 							t = (az - ax)/(az - ax + bx - bz), bx = ax + (bx - ax)*t, by = ay + (by - ay)*t, bz = az + (bz - az)*t; | ||||
| 						} | ||||
| 						if (az <= -ay && bz <= -by) { | ||||
| 							if (occludeAll && by*ax - bx*ay > 0) occludeAll = false; | ||||
| 							continue; | ||||
| 						} else if (bz > -by && az <= -ay) { | ||||
| 							t = (ay + az)/(ay + az - by - bz), ax = ax + (bx - ax)*t, ay = ay + (by - ay)*t, az = az + (bz - az)*t; | ||||
| 						} else if (bz <= -by && az > -ay) { | ||||
| 							t = (ay + az)/(ay + az - by - bz), bx = ax + (bx - ax)*t, by = ay + (by - ay)*t, bz = az + (bz - az)*t; | ||||
| 						} | ||||
| 						if (az <= ay && bz <= by) { | ||||
| 							if (occludeAll && by*ax - bx*ay > 0) occludeAll = false; | ||||
| 							continue; | ||||
| 						} else if (bz > by && az <= ay) { | ||||
| 							t = (az - ay)/(az - ay + by - bz), ax = ax + (bx - ax)*t, ay = ay + (by - ay)*t, az = az + (bz - az)*t; | ||||
| 						} else if (bz <= by && az > ay) { | ||||
| 							t = (az - ay)/(az - ay + by - bz), bx = ax + (bx - ax)*t, by = ay + (by - ay)*t, bz = az + (bz - az)*t; | ||||
| 						} | ||||
| 						occludeAll = false; | ||||
| 					} | ||||
| 					// Расчёт нормали плоскости отсечения | ||||
| 					planeOccluder[planeOccluderLength++] = bz*ay - by*az, planeOccluder[planeOccluderLength++] = bx*az - bz*ax, planeOccluder[planeOccluderLength++] = by*ax - bx*ay; | ||||
| 					// Сохранение рёбер | ||||
| 					edgeOccluder[edgeOccluderLength++] = ax, edgeOccluder[edgeOccluderLength++] = ay, edgeOccluder[edgeOccluderLength++] = az, edgeOccluder[edgeOccluderLength++] = bx, edgeOccluder[edgeOccluderLength++] = by, edgeOccluder[edgeOccluderLength++] = bz; | ||||
| 				} else i -= 2; | ||||
| 			} | ||||
| 			if (planeOccluderLength > 0) { | ||||
| 				// Проверка размера на экране | ||||
| 				if (minSize > 0) { | ||||
| 					// Проецирование рёбер контура  | ||||
| 					var projectedEdgesLength:int = projectedEdges.length = ((edgeOccluder.length = edgeOccluderLength)/3) << 1; | ||||
| 					Utils3D.projectVectors(camera.projectionMatrix, edgeOccluder, projectedEdges, uvts); | ||||
| 					// Клиппинг рамки вьюпорта | ||||
| 					if (culling > 0) { | ||||
| 						if (culling & 4) viewEdges[viewEdgesLength++] = -camera.viewSizeX, viewEdges[viewEdgesLength++] = -camera.viewSizeY, viewEdges[viewEdgesLength++] = -camera.viewSizeX, viewEdges[viewEdgesLength++] = camera.viewSizeY; | ||||
| 						if (culling & 8) viewEdges[viewEdgesLength++] = camera.viewSizeX, viewEdges[viewEdgesLength++] = camera.viewSizeY, viewEdges[viewEdgesLength++] = camera.viewSizeX, viewEdges[viewEdgesLength++] = -camera.viewSizeY; | ||||
| 						if (culling & 16) viewEdges[viewEdgesLength++] = camera.viewSizeX, viewEdges[viewEdgesLength++] = -camera.viewSizeY, viewEdges[viewEdgesLength++] = -camera.viewSizeX, viewEdges[viewEdgesLength++] = -camera.viewSizeY; | ||||
| 						if (culling & 32) viewEdges[viewEdgesLength++] = -camera.viewSizeX, viewEdges[viewEdgesLength++] = camera.viewSizeY, viewEdges[viewEdgesLength++] = camera.viewSizeX, viewEdges[viewEdgesLength++] = camera.viewSizeY; | ||||
| 						if (viewEdgesLength > 0) { | ||||
| 							for (i = 0; i < projectedEdgesLength;) { | ||||
| 								ax = projectedEdges[i++], ay = projectedEdges[i++], bx = projectedEdges[i++], by = projectedEdges[i++];  | ||||
| 								var nx:Number = ay - by, ny:Number = bx - ax, no:Number = nx*ax + ny*ay; | ||||
| 								for (var j:int = 0, j2:int = 0; j < viewEdgesLength;) { | ||||
| 									ax = viewEdges[j++], ay = viewEdges[j++], bx = viewEdges[j++], by = viewEdges[j++], az = ax*nx + ay*ny - no, bz = bx*nx + by*ny - no; | ||||
| 									if (az < 0 || bz < 0) { | ||||
| 										if (az >= 0 && bz < 0) { | ||||
| 											t = az/(az - bz), viewEdges[j2++] = ax + (bx - ax)*t, viewEdges[j2++] = ay + (by - ay)*t, viewEdges[j2++] = bx, viewEdges[j2++] = by; | ||||
| 										} else if (az < 0 && bz >= 0) { | ||||
| 											t = az/(az - bz), viewEdges[j2++] = ax, viewEdges[j2++] = ay, viewEdges[j2++] = ax + (bx - ax)*t, viewEdges[j2++] = ay + (by - ay)*t; | ||||
| 										} else { | ||||
| 											viewEdges[j2++] = ax, viewEdges[j2++] = ay, viewEdges[j2++] = bx, viewEdges[j2++] = by; | ||||
| 										} | ||||
| 									} | ||||
| 								} | ||||
| 								viewEdgesLength = j2; | ||||
| 								if (viewEdgesLength == 0) break; | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 					// Нахождение площади перекрытия | ||||
| 					var square:Number = 0; | ||||
| 					for (i = 0, az = projectedEdges[i++], bz = projectedEdges[i++], i += 2; i < projectedEdgesLength;) ax = projectedEdges[i++] - az, ay = projectedEdges[i++] - bz, bx = projectedEdges[i++] - az, by = projectedEdges[i++] - bz, square += bx*ay - by*ax; | ||||
| 					for (i = 0; i < viewEdgesLength;) ax = viewEdges[i++] - az, ay = viewEdges[i++] - bz, bx = viewEdges[i++] - az, by = viewEdges[i++] - bz, square += bx*ay - by*ax; | ||||
| 					if (square/(camera.viewSizeX*camera.viewSizeY*8) < minSize) return; | ||||
| 				} | ||||
| 				// Добавление окклюдера | ||||
| 				camera.numOccluders++; | ||||
| 				planeOccluder.length = planeOccluderLength; | ||||
| 				edgeOccluder.length = edgeOccluderLength; | ||||
| 			} else { | ||||
| 				if (occludeAll) camera.numOccluders = 0, camera.occludedAll = true else return; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function debug(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			var inDebug:int = camera.checkInDebug(this); | ||||
| 			if (inDebug == 0) return; | ||||
| 			var canvas:Canvas = parentCanvas.getChildCanvas(true, false); | ||||
| 			 | ||||
| 			// Рёбра | ||||
| 			if (inDebug & Debug.EDGES) { | ||||
| 				object.cameraMatrix.transformVectors(vertices, cameraVertices); | ||||
| 				inverseCameraMatrix.identity(); | ||||
| 				inverseCameraMatrix.prepend(object.cameraMatrix); | ||||
| 				inverseCameraMatrix.invert(); | ||||
| 				center[0] = center[1] = center[2] = 0; | ||||
| 				inverseCameraMatrix.transformVectors(center, center); | ||||
| 				cameraX = center[0], cameraY = center[1], cameraZ = center[2]; | ||||
| 				// Расчёт карты видимости граней | ||||
| 				for (var i:int = 0, n:int = 0, normalsLength:int = normals.length >> 2, cameraInside:Boolean = true, infront:Boolean; i < normalsLength;) visibilityMap[i++] = infront = normals[n++]*cameraX + normals[n++]*cameraY + normals[n++]*cameraZ > normals[n++], cameraInside &&= !infront; | ||||
| 				// Если камера внутри окклюдера | ||||
| 				if (!cameraInside) { | ||||
| 					// Подготовка окклюдера в камере | ||||
| 					var occludeAll:Boolean = true, culling:int = object.culling, direction:Boolean, ax:Number, ay:Number, az:Number, bx:Number, by:Number, bz:Number, t:Number; | ||||
| 					var debugEdgesLength:int = 0, viewEdgesLength:int = 0; | ||||
| 					for (i = edges.length - 1; i > 0;) { | ||||
| 						if ((direction = visibilityMap[edges[i--]]) != visibilityMap[edges[i--]]) { | ||||
| 							// Определение порядка вершин (против часовой) | ||||
| 							if (direction) ax = cameraVertices[n = int(edges[i--]*3)], ay = cameraVertices[++n], az = cameraVertices[++n], bx = cameraVertices[n = int(edges[i--]*3)], by = cameraVertices[++n], bz = cameraVertices[++n] else bx = cameraVertices[n = int(edges[i--]*3)], by = cameraVertices[++n], bz = cameraVertices[++n], ax = cameraVertices[n = int(edges[i--]*3)], ay = cameraVertices[++n], az = cameraVertices[++n]; | ||||
| 							// Клиппинг | ||||
| 							if (culling > 0) { | ||||
| 								if (az <= -ax && bz <= -bx) { | ||||
| 									if (occludeAll && by*ax - bx*ay > 0) occludeAll = false; | ||||
| 									continue; | ||||
| 								} else if (bz > -bx && az <= -ax) { | ||||
| 									t = (ax + az)/(ax + az - bx - bz), ax = ax + (bx - ax)*t, ay = ay + (by - ay)*t, az = az + (bz - az)*t; | ||||
| 								} else if (bz <= -bx && az > -ax) { | ||||
| 									t = (ax + az)/(ax + az - bx - bz), bx = ax + (bx - ax)*t, by = ay + (by - ay)*t, bz = az + (bz - az)*t; | ||||
| 								} | ||||
| 								if (az <= ax && bz <= bx) { | ||||
| 									if (occludeAll && by*ax - bx*ay > 0) occludeAll = false; | ||||
| 									continue; | ||||
| 								} else if (bz > bx && az <= ax) { | ||||
| 									t = (az - ax)/(az - ax + bx - bz), ax = ax + (bx - ax)*t, ay = ay + (by - ay)*t, az = az + (bz - az)*t; | ||||
| 								} else if (bz <= bx && az > ax) { | ||||
| 									t = (az - ax)/(az - ax + bx - bz), bx = ax + (bx - ax)*t, by = ay + (by - ay)*t, bz = az + (bz - az)*t; | ||||
| 								} | ||||
| 								if (az <= -ay && bz <= -by) { | ||||
| 									if (occludeAll && by*ax - bx*ay > 0) occludeAll = false; | ||||
| 									continue; | ||||
| 								} else if (bz > -by && az <= -ay) { | ||||
| 									t = (ay + az)/(ay + az - by - bz), ax = ax + (bx - ax)*t, ay = ay + (by - ay)*t, az = az + (bz - az)*t; | ||||
| 								} else if (bz <= -by && az > -ay) { | ||||
| 									t = (ay + az)/(ay + az - by - bz), bx = ax + (bx - ax)*t, by = ay + (by - ay)*t, bz = az + (bz - az)*t; | ||||
| 								} | ||||
| 								if (az <= ay && bz <= by) { | ||||
| 									if (occludeAll && by*ax - bx*ay > 0) occludeAll = false; | ||||
| 									continue; | ||||
| 								} else if (bz > by && az <= ay) { | ||||
| 									t = (az - ay)/(az - ay + by - bz), ax = ax + (bx - ax)*t, ay = ay + (by - ay)*t, az = az + (bz - az)*t; | ||||
| 								} else if (bz <= by && az > ay) { | ||||
| 									t = (az - ay)/(az - ay + by - bz), bx = ax + (bx - ax)*t, by = ay + (by - ay)*t, bz = az + (bz - az)*t; | ||||
| 								} | ||||
| 								occludeAll = false; | ||||
| 							} | ||||
| 							debugEdges[debugEdgesLength++] = ax; | ||||
| 							debugEdges[debugEdgesLength++] = ay; | ||||
| 							debugEdges[debugEdgesLength++] = az; | ||||
| 							debugEdges[debugEdgesLength++] = bx; | ||||
| 							debugEdges[debugEdgesLength++] = by; | ||||
| 							debugEdges[debugEdgesLength++] = bz; | ||||
| 						} else i -= 2; | ||||
| 					} | ||||
| 					if (debugEdgesLength > 0) { | ||||
| 						// Проецирование рёбер контура  | ||||
| 						var projectedEdgesLength:int = projectedEdges.length = ((debugEdges.length = debugEdgesLength)/3) << 1; | ||||
| 						Utils3D.projectVectors(camera.projectionMatrix, debugEdges, projectedEdges, uvts); | ||||
| 						// Проверка размера на экране | ||||
| 						var square:Number = Number.MAX_VALUE; | ||||
| 						if (minSize > 0) { | ||||
| 							// Клиппинг рамки вьюпорта | ||||
| 							if (culling > 0) { | ||||
| 								if (culling & 4) viewEdges[viewEdgesLength++] = -camera.viewSizeX, viewEdges[viewEdgesLength++] = -camera.viewSizeY, viewEdges[viewEdgesLength++] = -camera.viewSizeX, viewEdges[viewEdgesLength++] = camera.viewSizeY; | ||||
| 								if (culling & 8) viewEdges[viewEdgesLength++] = camera.viewSizeX, viewEdges[viewEdgesLength++] = camera.viewSizeY, viewEdges[viewEdgesLength++] = camera.viewSizeX, viewEdges[viewEdgesLength++] = -camera.viewSizeY; | ||||
| 								if (culling & 16) viewEdges[viewEdgesLength++] = camera.viewSizeX, viewEdges[viewEdgesLength++] = -camera.viewSizeY, viewEdges[viewEdgesLength++] = -camera.viewSizeX, viewEdges[viewEdgesLength++] = -camera.viewSizeY; | ||||
| 								if (culling & 32) viewEdges[viewEdgesLength++] = -camera.viewSizeX, viewEdges[viewEdgesLength++] = camera.viewSizeY, viewEdges[viewEdgesLength++] = camera.viewSizeX, viewEdges[viewEdgesLength++] = camera.viewSizeY; | ||||
| 								if (viewEdgesLength > 0) { | ||||
| 									for (i = 0; i < projectedEdgesLength;) { | ||||
| 										ax = projectedEdges[i++], ay = projectedEdges[i++], bx = projectedEdges[i++], by = projectedEdges[i++];  | ||||
| 										var nx:Number = ay - by, ny:Number = bx - ax, no:Number = nx*ax + ny*ay; | ||||
| 										for (var j:int = 0, j2:int = 0; j < viewEdgesLength;) { | ||||
| 											ax = viewEdges[j++], ay = viewEdges[j++], bx = viewEdges[j++], by = viewEdges[j++], az = ax*nx + ay*ny - no, bz = bx*nx + by*ny - no; | ||||
| 											if (az < 0 || bz < 0) { | ||||
| 												if (az >= 0 && bz < 0) { | ||||
| 													t = az/(az - bz), viewEdges[j2++] = ax + (bx - ax)*t, viewEdges[j2++] = ay + (by - ay)*t, viewEdges[j2++] = bx, viewEdges[j2++] = by; | ||||
| 												} else if (az < 0 && bz >= 0) { | ||||
| 													t = az/(az - bz), viewEdges[j2++] = ax, viewEdges[j2++] = ay, viewEdges[j2++] = ax + (bx - ax)*t, viewEdges[j2++] = ay + (by - ay)*t; | ||||
| 												} else { | ||||
| 													viewEdges[j2++] = ax, viewEdges[j2++] = ay, viewEdges[j2++] = bx, viewEdges[j2++] = by; | ||||
| 												} | ||||
| 											} | ||||
| 										} | ||||
| 										viewEdgesLength = j2; | ||||
| 										if (viewEdgesLength == 0) break; | ||||
| 									} | ||||
| 								} | ||||
| 							} | ||||
| 							// Нахождение площади перекрытия | ||||
| 							square = 0; | ||||
| 							for (i = 0, az = projectedEdges[i++], bz = projectedEdges[i++], i += 2; i < projectedEdgesLength;) ax = projectedEdges[i++] - az, ay = projectedEdges[i++] - bz, bx = projectedEdges[i++] - az, by = projectedEdges[i++] - bz, square += bx*ay - by*ax; | ||||
| 							for (i = 0; i < viewEdgesLength;) ax = viewEdges[i++] - az, ay = viewEdges[i++] - bz, bx = viewEdges[i++] - az, by = viewEdges[i++] - bz, square += bx*ay - by*ax; | ||||
| 						} | ||||
| 						if (canvas == null) canvas = parentCanvas.getChildCanvas(true, false); | ||||
| 						var color:int, thickness:Number; | ||||
| 						if (square/(camera.viewSizeX*camera.viewSizeY*8) >= minSize) { | ||||
| 							color = 0x0000FF, thickness = 3; | ||||
| 						} else { | ||||
| 							color = 0x0077AA, thickness = 1; | ||||
| 						} | ||||
| 						for (i = 0; i < projectedEdges.length;) { | ||||
| 							ax = projectedEdges[i++], ay = projectedEdges[i++], bx = projectedEdges[i++], by = projectedEdges[i++]; | ||||
| 							canvas.gfx.moveTo(ax, ay); | ||||
| 							canvas.gfx.lineStyle(thickness, color); | ||||
| 							canvas.gfx.lineTo(ax + (bx - ax)*0.8, ay + (by - ay)*0.8); | ||||
| 							canvas.gfx.lineStyle(thickness, 0xFF0000); | ||||
| 							canvas.gfx.lineTo(bx, by); | ||||
| 						} | ||||
| 						for (i = 0; i < viewEdgesLength;) { | ||||
| 							canvas.gfx.moveTo(viewEdges[i++], viewEdges[i++]); | ||||
| 							canvas.gfx.lineTo(viewEdges[i++], viewEdges[i++]); | ||||
| 						} | ||||
| 					} else { | ||||
| 						if (occludeAll) { | ||||
| 							if (canvas == null) canvas = parentCanvas.getChildCanvas(true, false); | ||||
| 							canvas.gfx.lineStyle(6, 0xFF0000); | ||||
| 							canvas.gfx.moveTo(-camera.viewSizeX, -camera.viewSizeY); | ||||
| 							canvas.gfx.lineTo(-camera.viewSizeX, camera.viewSizeY); | ||||
| 							canvas.gfx.lineTo(camera.viewSizeX, camera.viewSizeY); | ||||
| 							canvas.gfx.lineTo(camera.viewSizeX, -camera.viewSizeY); | ||||
| 							canvas.gfx.lineTo(-camera.viewSizeX, -camera.viewSizeY); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			// Оси, центры, имена, баунды | ||||
| 			if (inDebug & Debug.AXES) object.drawAxes(camera, canvas); | ||||
| 			if (inDebug & Debug.CENTERS) object.drawCenter(camera, canvas); | ||||
| 			if (inDebug & Debug.NAMES) object.drawName(camera, canvas); | ||||
| 			if (inDebug & Debug.BOUNDS) object.drawBoundBox(camera, canvas); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,56 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Geometry; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d;	 | ||||
|  | ||||
| 	/** | ||||
| 	 * Объект-ссылка. | ||||
| 	 * Может ссылаться на любой трёхмерный объект, в том числе контейнер с любой вложенностью или Reference. | ||||
| 	 * При отрисовке он отрисовывает вместо себя объект,  | ||||
| 	 * на который ссылается, подставляя только свою трансформацию, alpha, blendMode, colorTransform и filters. | ||||
| 	 */ | ||||
| 	public class Reference extends Object3D { | ||||
|  | ||||
| 		/** | ||||
| 		 * Объект, который подставляется при отрисовке вместо себя  | ||||
| 		 */ | ||||
| 		public var referenceObject:Object3D; | ||||
| 		 | ||||
| 		public function Reference(referenceObject:Object3D = null) { | ||||
| 			this.referenceObject = referenceObject; | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function get canDraw():Boolean { | ||||
| 			return referenceObject.canDraw; | ||||
| 		} | ||||
|  | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			referenceObject.draw(camera, object, parentCanvas); | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function debug(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			referenceObject.debug(camera, object, parentCanvas); | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function getGeometry(camera:Camera3D, object:Object3D):Geometry { | ||||
| 			return referenceObject.getGeometry(camera, object); | ||||
| 		} | ||||
| 		 | ||||
| 		override public function get boundBox():BoundBox { | ||||
| 			return referenceObject.boundBox; | ||||
| 		} | ||||
| 		 | ||||
| 		override public function calculateBoundBox(matrix:Matrix3D = null, boundBox:BoundBox = null):BoundBox { | ||||
| 			return referenceObject.calculateBoundBox(matrix, boundBox); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,148 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	 | ||||
| 	import flash.geom.Matrix3D; | ||||
| 	import flash.geom.Vector3D; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class SkeletalMesh extends Mesh { | ||||
| 	 | ||||
| 		alternativa3d var _numBones:uint = 0; | ||||
| 		alternativa3d var bones:Vector.<Bone> = new Vector.<Bone>(); | ||||
| 		private var weights:Vector.<Vector.<Number>>; | ||||
| 		private var originalVertices:Vector.<Number>; | ||||
| 		private var originalBonesMatrices:Vector.<Matrix3D>; | ||||
| 		private var boneVertices:Vector.<Number>; | ||||
| 		 | ||||
| 		public function initBones():void { | ||||
| 			// Инициализируем массив весов и сохраняем оригинальные матрицы костей | ||||
| 			originalBonesMatrices = new Vector.<Matrix3D>(_numBones, true); | ||||
| 			weights = new Vector.<Vector.<Number>>(_numBones, true); | ||||
| 			for (var j:int = 0; j < _numBones; j++) { | ||||
| 				originalBonesMatrices[j] = new Matrix3D(); | ||||
| 				originalBonesMatrices[j].prepend(bones[j].matrix); | ||||
| 				originalBonesMatrices[j].invert(); | ||||
| 				weights[j] = new Vector.<Number>(numVertices, true); | ||||
| 			} | ||||
| 			// Формируем вспомогательные массивы для вершин   | ||||
| 			originalVertices = new Vector.<Number>(numVertices*3, true); | ||||
| 			boneVertices = new Vector.<Number>(numVertices*3, true); | ||||
| 			 | ||||
| 			// Обрабатываем вершины | ||||
| 			var v:Vector3D = new Vector3D(); | ||||
| 			for (var i:int = 0; i < numVertices; i++) { | ||||
| 				var k:int = i*3; | ||||
| 				// Сохраняем оригинальные координаты вершин | ||||
| 				originalVertices[k] = vertices[k]; | ||||
| 				originalVertices[k + 1] = vertices[k + 1]; | ||||
| 				originalVertices[k + 2] = vertices[k + 2]; | ||||
| 				 | ||||
| 				// Находим веса для каждой кости | ||||
| 				var sumWeight:Number = 0; | ||||
| 				for (j = 0; j < _numBones; j++) { | ||||
| 					// Находим расстояние от вершины до кости | ||||
| 					var b1:Vector3D = bones[j].matrix.transformVector(new Vector3D()); | ||||
| 					var b2:Vector3D = bones[j].matrix.transformVector(new Vector3D(0, 0, bones[j].length)); | ||||
| 					v.x = originalVertices[k]; | ||||
| 					v.y = originalVertices[k + 1]; | ||||
| 					v.z = originalVertices[k + 2]; | ||||
| 					var w:Number = 1 - distanceToBone(b1, b2, v)/bones[j].distance; | ||||
| 					//trace(w); | ||||
| 					w = (w > 0) ? w : 0; | ||||
| 					weights[j][i] = w; | ||||
| 					sumWeight += w; | ||||
| 				} | ||||
| 				   | ||||
| 				// Нормализуем веса | ||||
| 				if (sumWeight > 0) { | ||||
| 					for (j = 0; j < _numBones; j++) { | ||||
| 						weights[j][i] /= sumWeight; | ||||
| 					} | ||||
| 				} else { | ||||
| 					// Если вершина не относится ни к какой кости, помечаем | ||||
| 					for (j = 0; j < _numBones; j++) {  | ||||
| 						weights[j][i] = -1; | ||||
| 					} | ||||
| 				} | ||||
| 				 | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function distanceToBone(b1:Vector3D, b2:Vector3D, p:Vector3D):Number { | ||||
| 		    var v:Vector3D = b2.subtract(b1); | ||||
| 		    var w:Vector3D = p.subtract(b1); | ||||
| 		 | ||||
| 		    var c1:Number = w.dotProduct(v); | ||||
| 		    if ( c1 <= 0 ) | ||||
| 		        return Vector3D.distance(p, b1); | ||||
| 		 | ||||
| 		    var c2:Number = v.dotProduct(v); | ||||
| 		    if ( c2 <= c1 ) | ||||
| 		        return Vector3D.distance(p, b2); | ||||
| 		 | ||||
| 		    v.scaleBy(c1 / c2); | ||||
| 		    var Pb:Vector3D = b1.add(v); | ||||
| 		    return Vector3D.distance(p, Pb); | ||||
| 			 | ||||
| 			 | ||||
| 		} | ||||
| 		 | ||||
| 		private var m:Matrix3D = new Matrix3D(); | ||||
| 		public function calculateBones():void { | ||||
| 			// Обнуление координат | ||||
| 			for (var i:int = 0; i < numVertices*3; i++) { | ||||
| 				vertices[i] = 0; | ||||
| 			} | ||||
| 			// Добавление трансформации через кости | ||||
| 			for (var j:int = 0; j < _numBones; j++) { | ||||
| 				m.identity(); | ||||
| 				m.prepend(bones[j].matrix); | ||||
| 				m.prepend(originalBonesMatrices[j]); | ||||
| 				m.transformVectors(originalVertices, boneVertices); | ||||
| 				var boneWeights:Vector.<Number> = weights[j]; | ||||
| 				for (i = 0; i < numVertices; i++) { | ||||
| 					var weight:Number = boneWeights[i]; | ||||
| 					var k1:int = i*3; | ||||
| 					var k2:int = k1 + 1; | ||||
| 					var k3:int = k1 + 2; | ||||
| 					if (weight >= 0) { | ||||
| 						vertices[k1] += boneVertices[k1]*weight; | ||||
| 						vertices[k2] += boneVertices[k2]*weight; | ||||
| 						vertices[k3] += boneVertices[k3]*weight; | ||||
| 					} else { | ||||
| 						vertices[k1] = originalVertices[k1]; | ||||
| 						vertices[k2] = originalVertices[k2]; | ||||
| 						vertices[k3] = originalVertices[k3]; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public function addBone(bone:Bone):void { | ||||
| 			bones[_numBones++] = bone; | ||||
| 		} | ||||
| /* | ||||
| 		public function removeChild(bone:Bone):void { | ||||
| 			var i:int = bones.indexOf(bone); | ||||
| 			if (i < 0) throw new ArgumentError(); | ||||
| 			children.splice(i, 1); | ||||
| 			_numBones--; | ||||
| 			var len:uint = drawChildren.length; | ||||
| 			for (i = 0; i < len; i++) { | ||||
| 				if (drawChildren[i] == bone) { | ||||
| 					drawChildren.splice(i, 1); | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			bone._parent = null; | ||||
| 			bone.setStage(null); | ||||
| 		} | ||||
| */	 | ||||
|  | ||||
|  | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,506 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
|  | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Debug; | ||||
| 	import alternativa.engine3d.core.Fragment; | ||||
| 	import alternativa.engine3d.core.Geometry; | ||||
| 	import alternativa.engine3d.core.MipMap; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.display.BitmapData; | ||||
| 	import flash.geom.Matrix; | ||||
| 	import flash.geom.Matrix3D; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Плоский, всегда развёрнутый к камере трёхмерный объект | ||||
| 	 */ | ||||
| 	public class Sprite3D extends Object3D { | ||||
| 		public var texture:BitmapData; | ||||
| 		public var smooth:Boolean = false; | ||||
| 		/** | ||||
| 		 * Режим сортировки на случай конфликта | ||||
| 		 * 0 - без сортировки | ||||
| 		 * 1 - сортировка по средним Z | ||||
| 		 * 2 - проход по предрасчитанному BSP. Для расчёта BSP нужен calculateBSP() | ||||
| 		 * 3 - построение динамического BSP при отрисовке | ||||
| 		 */ | ||||
| 		public var sorting:int = 0; | ||||
| 		/** | ||||
| 		 * Применение мипмаппинга | ||||
| 		 * 0 - без мипмаппинга | ||||
| 		 * 1 - мипмаппинг по удалённости от камеры. Требуется установка свойства mipMap | ||||
| 		 */ | ||||
| 		public var mipMapping:int = 0; | ||||
| 		public var mipMap:MipMap; | ||||
| 		/** | ||||
| 		 * X точки привязки  | ||||
| 		 */ | ||||
| 		public var originX:Number = 0.5; | ||||
| 		/** | ||||
| 		 * Y точки привязки  | ||||
| 		 */ | ||||
| 		public var originY:Number = 0.5; | ||||
| 		/** | ||||
| 		 * Режим отсечения объекта по пирамиде видимости камеры. | ||||
| 		 * 0 - весь объект | ||||
| 		 * 2 - клиппинг граней по пирамиде видимости камеры  | ||||
| 		 */ | ||||
| 		public var clipping:int = 0; | ||||
| 		/** | ||||
| 		 * Угол поворота в радианах в плоскости экрана  | ||||
| 		 */ | ||||
| 		public var rotation:Number = 0; | ||||
| 		/** | ||||
| 		 * Зависимость размера на экране от удалённости от камеры | ||||
| 		 */ | ||||
| 		public var perspectiveScale:Boolean = true; | ||||
| 		 | ||||
| 		// Вспомогательные | ||||
| 		static private const vertices:Vector.<Number> = new Vector.<Number>(); | ||||
| 		static private const axes:Vector.<Number> = Vector.<Number>([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]); | ||||
| 		static private const cameraAxes:Vector.<Number> = new Vector.<Number>(12, true); | ||||
| 		static private const textureMatrix:Matrix = new Matrix(); | ||||
| 		static private var drawTexture:BitmapData; | ||||
| 		private var projectionX:Number; | ||||
| 		private var projectionY:Number; | ||||
| 		 | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			var verticesLength:int = calculateVertices(object, camera); | ||||
| 			if (verticesLength > 0) { | ||||
| 				var canvas:Canvas = parentCanvas.getChildCanvas(true, false, object.alpha, object.blendMode, object.colorTransform, object.filters); | ||||
| 				canvas.gfx.beginBitmapFill(drawTexture, textureMatrix, false, smooth); | ||||
| 				var x:Number = vertices[0]*projectionX; | ||||
| 				var y:Number = vertices[1]*projectionY; | ||||
| 				if (rotation == 0) { | ||||
| 					canvas.gfx.drawRect(x, y, vertices[6]*projectionX - x, vertices[7]*projectionY - y); | ||||
| 				} else { | ||||
| 					canvas.gfx.moveTo(x, y); | ||||
| 					for (var i:int = 3; i < verticesLength; i++) { | ||||
| 						x = vertices[i]*projectionX; i++; | ||||
| 						y = vertices[i]*projectionY; i++; | ||||
| 						canvas.gfx.lineTo(x, y); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function debug(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			var debugResult:int = camera.checkInDebug(this); | ||||
| 			if (debugResult == 0) return; | ||||
| 			var canvas:Canvas = parentCanvas.getChildCanvas(true, false); | ||||
| 			var i:int, length:int, x:Number, y:Number, t:Number = 0.1; | ||||
| 			// Рёбра | ||||
| 			if (debugResult & Debug.EDGES) { | ||||
| 				if ((length = calculateVertices(object, camera)) > 0) { | ||||
| 					if (canvas == null) canvas = parentCanvas.getChildCanvas(true, false); | ||||
| 					canvas.gfx.lineStyle(0, 0xFFFFFF); | ||||
| 					if (rotation == 0) { | ||||
| 						x = vertices[0]*projectionX, y = vertices[1]*projectionY; | ||||
| 						canvas.gfx.drawRect(x, y, vertices[6]*projectionX - x, vertices[7]*projectionY - y); | ||||
| 					} else { | ||||
| 						// Отрисовка | ||||
| 						canvas.gfx.moveTo(vertices[length - 3]*projectionX, vertices[length - 2]*projectionY); | ||||
| 						for (i = 0; i < length; i++) canvas.gfx.lineTo(vertices[i++]*projectionX, vertices[i++]*projectionY); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			// Вершины | ||||
| 			if (debugResult & Debug.VERTICES) { | ||||
| 				if ((length = calculateVertices(object, camera)) > 0) { | ||||
| 					if (canvas == null) canvas = parentCanvas.getChildCanvas(true, false); | ||||
| 					canvas.gfx.lineStyle(); | ||||
| 					if (rotation == 0) { | ||||
| 						var x1:Number = vertices[0]*projectionX, y1:Number = vertices[1]*projectionY; | ||||
| 						var x2:Number = vertices[6]*projectionX, y2:Number = vertices[7]*projectionY; | ||||
| 						if (x1 > -camera.viewSizeX + t && x1 < camera.viewSizeX - t && y1 > -camera.viewSizeY + t && y1 < camera.viewSizeY - t) { | ||||
| 							canvas.gfx.beginFill(0xFFFF00); | ||||
| 							canvas.gfx.drawCircle(x1, y1, 2); | ||||
| 						} | ||||
| 						if (x1 > -camera.viewSizeX + t && x1 < camera.viewSizeX - t && y2 > -camera.viewSizeY + t && y2 < camera.viewSizeY - t) { | ||||
| 							canvas.gfx.beginFill(0xFFFF00); | ||||
| 							canvas.gfx.drawCircle(x1, y2, 2); | ||||
| 						} | ||||
| 						if (x2 > -camera.viewSizeX + t && x2 < camera.viewSizeX - t && y2 > -camera.viewSizeY + t && y2 < camera.viewSizeY - t) { | ||||
| 							canvas.gfx.beginFill(0xFFFF00); | ||||
| 							canvas.gfx.drawCircle(x2, y2, 2); | ||||
| 						} | ||||
| 						if (x2 > -camera.viewSizeX + t && x2 < camera.viewSizeX - t && y1 > -camera.viewSizeY + t && y1 < camera.viewSizeY - t) { | ||||
| 							canvas.gfx.beginFill(0xFFFF00); | ||||
| 							canvas.gfx.drawCircle(x2, y1, 2); | ||||
| 						} | ||||
| 					} else { | ||||
| 						for (i = 0; i < length; i++) { | ||||
| 							x = vertices[i++]*projectionX, y = vertices[i++]*projectionY; | ||||
| 							if (x > -camera.viewSizeX + t && x < camera.viewSizeX - t && y > -camera.viewSizeY + t && y < camera.viewSizeY - t) { | ||||
| 								canvas.gfx.beginFill(0xFFFF00); | ||||
| 								canvas.gfx.drawCircle(x, y, 2); | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			// Оси, центры, имена, баунды | ||||
| 			if (debugResult & Debug.AXES) object.drawAxes(camera, canvas); | ||||
| 			if (debugResult & Debug.CENTERS) object.drawCenter(camera, canvas); | ||||
| 			if (debugResult & Debug.NAMES) object.drawName(camera, canvas); | ||||
| 			if (debugResult & Debug.BOUNDS) object.drawBoundBox(camera, canvas); | ||||
| 		} | ||||
| 		 | ||||
| 		override alternativa3d function getGeometry(camera:Camera3D, object:Object3D):Geometry { | ||||
| 			var verticesLength:int = calculateVertices(object, camera); | ||||
| 			if (verticesLength > 0) { | ||||
| 				var geometry:Geometry = Geometry.create(); | ||||
| 				geometry.fragment = Fragment.create(); | ||||
| 				geometry.numVertices = verticesLength/3; | ||||
| 				geometry.fragment.num = geometry.numVertices; | ||||
| 				geometry.verticesLength = verticesLength; | ||||
| 				if (geometry.uvts.length < verticesLength) { | ||||
| 					geometry.uvts.length = verticesLength; | ||||
| 				} | ||||
| 				for (var i:int = 0, j:int = 0; i < geometry.numVertices; i++) { | ||||
| 					geometry.vertices[j] = vertices[j]; j++; | ||||
| 					geometry.vertices[j] = vertices[j]; j++; | ||||
| 					geometry.vertices[j] = vertices[j]; j++; | ||||
| 					geometry.fragment.indices[i] = i; | ||||
| 				} | ||||
| 				geometry.cameraMatrix.identity(); | ||||
| 				geometry.cameraMatrix.prepend(object.cameraMatrix); | ||||
| 				geometry.alpha = object.alpha; | ||||
| 				geometry.blendMode = object.blendMode; | ||||
| 				geometry.colorTransform = object.colorTransform; | ||||
| 				geometry.filters = object.filters; | ||||
| 				geometry.sorting = sorting; | ||||
| 				geometry.texture = drawTexture; | ||||
| 				geometry.repeatTexture = false; | ||||
| 				geometry.smooth = smooth; | ||||
| 				if (camera.debugMode) { | ||||
| 					geometry.debugResult = camera.checkInDebug(this); | ||||
| 				} | ||||
| 				geometry.viewAligned = true; | ||||
| 				geometry.textureMatrix.a = textureMatrix.a; | ||||
| 				geometry.textureMatrix.b = textureMatrix.b; | ||||
| 				geometry.textureMatrix.c = textureMatrix.c; | ||||
| 				geometry.textureMatrix.d = textureMatrix.d; | ||||
| 				geometry.textureMatrix.tx = textureMatrix.tx; | ||||
| 				geometry.textureMatrix.ty = textureMatrix.ty; | ||||
| 				geometry.projectionX = projectionX; | ||||
| 				geometry.projectionY = projectionY; | ||||
| 				return geometry; | ||||
| 			} else { | ||||
| 				return null; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		private function calculateVertices(object:Object3D, camera:Camera3D):int { | ||||
| 			// Трансформация локальных осей в камеру | ||||
| 			object.cameraMatrix.transformVectors(axes, cameraAxes); | ||||
| 			var x:Number = cameraAxes[0]; | ||||
| 			var y:Number = cameraAxes[1]; | ||||
| 			var z:Number = cameraAxes[2]; | ||||
| 			if (z <= camera.nearClipping || z >= camera.farClipping) return 0; | ||||
| 			// Проекция | ||||
| 			projectionX = camera.viewSizeX/z; | ||||
| 			projectionY = camera.viewSizeY/z; | ||||
| 			var projectionZ:Number = camera.focalLength/z; | ||||
| 			// Нахождение среднего размера спрайта | ||||
| 			var ax:Number = (cameraAxes[3] - x)/camera.perspectiveScaleX; | ||||
| 			var ay:Number = (cameraAxes[4] - y)/camera.perspectiveScaleY; | ||||
| 			var az:Number = cameraAxes[5] - z; | ||||
| 			var size:Number = Math.sqrt(ax*ax + ay*ay + az*az);  | ||||
| 			ax = (cameraAxes[6] - x)/camera.perspectiveScaleX; | ||||
| 			ay = (cameraAxes[7] - y)/camera.perspectiveScaleY; | ||||
| 			az = cameraAxes[8] - z; | ||||
| 			size += Math.sqrt(ax*ax + ay*ay + az*az); | ||||
| 			ax = (cameraAxes[9] - x)/camera.perspectiveScaleX; | ||||
| 			ay = (cameraAxes[10] - y)/camera.perspectiveScaleY; | ||||
| 			az = cameraAxes[11] - z; | ||||
| 			size += Math.sqrt(ax*ax + ay*ay + az*az); | ||||
| 			size /= 3; | ||||
| 			// Определение текстуры и коррекция размера | ||||
| 			if (mipMapping == 0) { | ||||
| 				drawTexture = texture; | ||||
| 			} else { | ||||
| 				var level:int = mipMap.getLevel(z/size, camera); | ||||
| 				size *= Math.pow(2, level); | ||||
| 				drawTexture = mipMap.textures[level]; | ||||
| 			} | ||||
| 			// Учёт флага масштабирования | ||||
| 			if (!perspectiveScale) { | ||||
| 				size /= projectionZ; | ||||
| 			} | ||||
| 			var x1:Number; | ||||
| 			var y1:Number; | ||||
| 			var x2:Number; | ||||
| 			var y2:Number; | ||||
| 			// Если не задано вращение | ||||
| 			if (rotation == 0) { | ||||
| 				// Размеры спрайта в матрице камеры | ||||
| 				var cameraWidth:Number = size*drawTexture.width*camera.perspectiveScaleX; | ||||
| 				var cameraHeight:Number = size*drawTexture.height*camera.perspectiveScaleY; | ||||
| 				 | ||||
| 				// Расчёт вершин в матрице камеры | ||||
| 				x1 = x - originX*cameraWidth; | ||||
| 				y1 = y - originY*cameraHeight; | ||||
| 				x2 = x1 + cameraWidth; | ||||
| 				y2 = y1 + cameraHeight; | ||||
|  | ||||
| 				// Отсечение по вьюпорту | ||||
| 				if (object.culling > 0 && (x1 > z || y1 > z || x2 < -z || y2 < -z)) return 0;  | ||||
| 				 | ||||
| 				// Подготовка матрицы отрисовки | ||||
| 				textureMatrix.a = textureMatrix.d = size*projectionZ; | ||||
| 				textureMatrix.b = textureMatrix.c = 0; | ||||
| 				textureMatrix.tx = x1*projectionX; | ||||
| 				textureMatrix.ty = y1*projectionY; | ||||
| 				 | ||||
| 				// Подрезка | ||||
| 				if (clipping == 2) { | ||||
| 					if (x1 < -z) x1 = -z; | ||||
| 					if (y1 < -z) y1 = -z; | ||||
| 					if (x2 > z) x2 = z; | ||||
| 					if (y2 > z) y2 = z; | ||||
| 				} | ||||
|  | ||||
| 				// Заполняем вершины | ||||
| 				vertices[0] = x1; | ||||
| 				vertices[1] = y1; | ||||
| 				vertices[2] = z; | ||||
| 				vertices[3] = x1; | ||||
| 				vertices[4] = y2; | ||||
| 				vertices[5] = z; | ||||
| 				vertices[6] = x2; | ||||
| 				vertices[7] = y2; | ||||
| 				vertices[8] = z; | ||||
| 				vertices[9] = x2; | ||||
| 				vertices[10] = y1; | ||||
| 				vertices[11] = z; | ||||
| 				 | ||||
| 				return 12; | ||||
| 				 | ||||
| 			} else { | ||||
| 			 | ||||
| 				// Размер спрайта в камере без коррекции под FOV90 | ||||
| 				var textureWidth:Number = drawTexture.width; | ||||
| 				var textureHeight:Number = drawTexture.height; | ||||
|  | ||||
| 				// Расчёт векторов ширины и высоты | ||||
| 				var sin:Number = Math.sin(rotation)*size; | ||||
| 				var cos:Number = Math.cos(rotation)*size; | ||||
| 				var cameraWidthX:Number = cos*textureWidth*camera.perspectiveScaleX; | ||||
| 				var cameraWidthY:Number = -sin*textureWidth*camera.perspectiveScaleY; | ||||
| 				var cameraHeightX:Number = sin*textureHeight*camera.perspectiveScaleX; | ||||
| 				var cameraHeightY:Number = cos*textureHeight*camera.perspectiveScaleY; | ||||
| 				 | ||||
| 				// Заполняем вершины | ||||
| 				var length:int = 12; | ||||
| 				vertices[0] = x1 = x - originX*cameraWidthX - originY*cameraHeightX; | ||||
| 				vertices[1] = y1 = y - originX*cameraWidthY - originY*cameraHeightY; | ||||
| 				vertices[2] = z; | ||||
| 				vertices[3] = x1 + cameraHeightX; | ||||
| 				vertices[4] = y1 + cameraHeightY; | ||||
| 				vertices[5] = z; | ||||
| 				vertices[6] = x1 + cameraWidthX + cameraHeightX; | ||||
| 				vertices[7] = y1 + cameraWidthY + cameraHeightY; | ||||
| 				vertices[8] = z; | ||||
| 				vertices[9] = x1 + cameraWidthX; | ||||
| 				vertices[10] = y1 + cameraWidthY; | ||||
| 				vertices[11] = z; | ||||
| 				 | ||||
| 				if (object.culling > 0) { | ||||
| 					// Отсечение по вьюпорту | ||||
| 					var i:int, infront:Boolean, behind:Boolean, inside:Boolean; | ||||
| 					var clipLeft:Boolean = false; | ||||
| 					if (object.culling & 4) { | ||||
| 						for (i = 0; i < length; i += 3) if ((inside = -vertices[i] < z) && (infront = true) && behind || !inside && (behind = true) && infront) break; | ||||
| 						if (behind) if (!infront) return 0; else clipLeft = true; | ||||
| 						infront = false; behind = false; | ||||
| 					}	 | ||||
| 					var clipRight:Boolean = false; | ||||
| 					if (object.culling & 8) { | ||||
| 						for (i = 0; i < length; i += 3) if ((inside = vertices[i] < z) && (infront = true) && behind || !inside && (behind = true) && infront) break; | ||||
| 						if (behind) if (!infront) return 0; else clipRight = true; | ||||
| 						infront = false; behind = false; | ||||
| 					}	 | ||||
| 					var clipTop:Boolean = false; | ||||
| 					if (object.culling & 16) { | ||||
| 						for (i = 1; i < length; i += 3) if ((inside = -vertices[i] < z) && (infront = true) && behind || !inside && (behind = true) && infront) break; | ||||
| 						if (behind) if (!infront) return 0; else clipTop = true; | ||||
| 						infront = false; behind = false; | ||||
| 					}	 | ||||
| 					var clipBottom:Boolean = false; | ||||
| 					if (object.culling & 32) { | ||||
| 						for (i = 1; i < length; i += 3) if ((inside = vertices[i] < z) && (infront = true) && behind || !inside && (behind = true) && infront) break; | ||||
| 						if (behind) if (!infront) return 0; else clipBottom = true; | ||||
| 					} | ||||
| 					// Подрезка | ||||
| 					if (clipping == 2) { | ||||
| 						var n:int = 0, t:Number, bx:Number, by:Number; | ||||
| 						if (clipLeft) { | ||||
| 							ax = x = vertices[0]; ay = y = vertices[1]; | ||||
| 							for (i = 3; i <= length; i++) { | ||||
| 								if (i < length) { | ||||
| 									bx = vertices[i++]; by = vertices[i++]; | ||||
| 								} else { | ||||
| 									bx = x; by = y; | ||||
| 								} | ||||
| 								if (-bx < z && -ax >= z || -bx >= z && -ax < z) { | ||||
| 									t = (ax + z)/(ax - bx); | ||||
| 									vertices[n++] = ax + (bx - ax)*t; | ||||
| 									vertices[n++] = ay + (by - ay)*t; | ||||
| 									vertices[n++] = z; | ||||
| 								} | ||||
| 								if (-bx < z) { | ||||
| 									vertices[n++] = bx; vertices[n++] = by; vertices[n++] = z; | ||||
| 								} | ||||
| 								ax = bx; ay = by; | ||||
| 							} | ||||
| 							if (n == 0) return 0; | ||||
| 							length = n; n = 0; | ||||
| 						} | ||||
| 						if (clipRight) { | ||||
| 							ax = x = vertices[0]; ay = y = vertices[1]; | ||||
| 							for (i = 3; i <= length; i++) { | ||||
| 								if (i < length) { | ||||
| 									bx = vertices[i++]; by = vertices[i++]; | ||||
| 								} else { | ||||
| 									bx = x; by = y; | ||||
| 								} | ||||
| 								if (bx < z && ax >= z || bx >= z && ax < z) { | ||||
| 									t = (z - ax)/(bx - ax); | ||||
| 									vertices[n++] = ax + (bx - ax)*t; | ||||
| 									vertices[n++] = ay + (by - ay)*t; | ||||
| 									vertices[n++] = z; | ||||
| 								} | ||||
| 								if (bx < z) { | ||||
| 									vertices[n++] = bx; vertices[n++] = by; vertices[n++] = z; | ||||
| 								} | ||||
| 								ax = bx; ay = by; | ||||
| 							} | ||||
| 							if (n == 0) return 0; | ||||
| 							length = n; n = 0; | ||||
| 						} | ||||
| 						if (clipTop) { | ||||
| 							ax = x = vertices[0]; ay = y = vertices[1]; | ||||
| 							for (i = 3; i <= length; i++) { | ||||
| 								if (i < length) { | ||||
| 									bx = vertices[i++]; by = vertices[i++]; | ||||
| 								} else { | ||||
| 									bx = x; by = y; | ||||
| 								} | ||||
| 								if (-by < z && -ay >= z || -by >= z && -ay < z) { | ||||
| 									t = (ay + z)/(ay - by); | ||||
| 									vertices[n++] = ax + (bx - ax)*t; | ||||
| 									vertices[n++] = ay + (by - ay)*t; | ||||
| 									vertices[n++] = z; | ||||
| 								} | ||||
| 								if (-by < z) { | ||||
| 									vertices[n++] = bx; vertices[n++] = by; vertices[n++] = z; | ||||
| 								} | ||||
| 								ax = bx; ay = by; | ||||
| 							} | ||||
| 							if (n == 0) return 0; | ||||
| 							length = n; n = 0; | ||||
| 						} | ||||
| 						if (clipBottom) { | ||||
| 							ax = x = vertices[0]; ay = y = vertices[1]; | ||||
| 							for (i = 3; i <= length; i++) { | ||||
| 								if (i < length) { | ||||
| 									bx = vertices[i++]; by = vertices[i++]; | ||||
| 								} else { | ||||
| 									bx = x; by = y; | ||||
| 								} | ||||
| 								if (by < z && ay >= z || by >= z && ay < z) { | ||||
| 									t = (z - ay)/(by - ay); | ||||
| 									vertices[n++] = ax + (bx - ax)*t; | ||||
| 									vertices[n++] = ay + (by - ay)*t; | ||||
| 									vertices[n++] = z; | ||||
| 								} | ||||
| 								if (by < z) { | ||||
| 									vertices[n++] = bx; vertices[n++] = by; vertices[n++] = z; | ||||
| 								} | ||||
| 								ax = bx; ay = by; | ||||
| 							} | ||||
| 							if (n == 0) return 0; | ||||
| 							length = n; n = 0; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				 | ||||
| 				// Подготовка матрицы отрисовки | ||||
| 				textureMatrix.a = textureMatrix.d = cos*projectionZ; | ||||
| 				textureMatrix.b = -sin*projectionZ; | ||||
| 				textureMatrix.c = sin*projectionZ; | ||||
| 				textureMatrix.tx = x1*projectionX; | ||||
| 				textureMatrix.ty = y1*projectionY; | ||||
| 				 | ||||
| 				return length; | ||||
| 				 | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		override public function calculateBoundBox(matrix:Matrix3D = null, boundBox:BoundBox = null):BoundBox { | ||||
| 			// Если указан баунд-бокс | ||||
| 			if (boundBox != null) { | ||||
| 				boundBox.infinity(); | ||||
| 			} else { | ||||
| 				boundBox = new BoundBox(); | ||||
| 			} | ||||
| 			// Расчёт локального радиуса | ||||
| 			var t:BitmapData = (mipMapping == 0) ? texture : mipMap.textures[0]; | ||||
| 			var w:Number = ((originX >= 0.5) ? originX : (1 - originX))*t.width; | ||||
| 			var h:Number = ((originY >= 0.5) ? originY : (1 - originY))*t.height; | ||||
| 			var radius:Number = Math.sqrt(w*w + h*h); | ||||
| 			// Если указана матрица трансформации, переводим | ||||
| 			if (matrix != null) { | ||||
| 				matrix.transformVectors(axes, cameraAxes); | ||||
| 				var cz:Number = cameraAxes[2]; | ||||
| 				var cx:Number = cameraAxes[0]; | ||||
| 				var cy:Number = cameraAxes[1]; | ||||
| 				// Нахождение среднего размера спрайта | ||||
| 				var ax:Number = cameraAxes[3] - cx; | ||||
| 				var ay:Number = cameraAxes[4] - cy; | ||||
| 				var az:Number = cameraAxes[5] - cz; | ||||
| 				var size:Number = Math.sqrt(ax*ax + ay*ay + az*az);  | ||||
| 				ax = cameraAxes[6] - cx; | ||||
| 				ay = cameraAxes[7] - cy; | ||||
| 				az = cameraAxes[8] - cz; | ||||
| 				size += Math.sqrt(ax*ax + ay*ay + az*az); | ||||
| 				ax = cameraAxes[9] - cx; | ||||
| 				ay = cameraAxes[10] - cy; | ||||
| 				az = cameraAxes[11] - cz; | ||||
| 				size = radius*(size + Math.sqrt(ax*ax + ay*ay + az*az))/3; | ||||
| 				boundBox.setSize(cx - size, cy - size, cz - size, cx + size, cy + size, cz + size); | ||||
| 			} else { | ||||
| 				boundBox.setSize(-radius, -radius, -radius, radius, radius, radius); | ||||
| 			} | ||||
| 			return boundBox; | ||||
| 		} | ||||
| 		 | ||||
| 		public function copyFrom(source:Sprite3D):void { | ||||
| 			visible = source.visible; | ||||
| 			alpha = source.alpha; | ||||
| 			blendMode = source.blendMode; | ||||
| 			originX = source.originX; | ||||
| 			originY = source.originY; | ||||
| 			smooth = source.smooth; | ||||
| 			clipping = source.clipping; | ||||
| 			rotation = source.rotation; | ||||
| 			perspectiveScale = source.perspectiveScale; | ||||
| 			texture = source.texture; | ||||
| 			mipMapping = source.mipMapping; | ||||
| 			mipMap = source.mipMap; | ||||
| 			matrix.identity(); | ||||
| 			matrix.append(source.matrix); | ||||
| 			if (source.boundBox != null) { | ||||
| 				if (boundBox == null) boundBox = new BoundBox(); | ||||
| 				boundBox.copyFrom(source.boundBox); | ||||
| 			} else boundBox = null; | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,93 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
|  | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.geom.Utils3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class WireBoundBox extends Object3D { | ||||
| 		 | ||||
| 		static private const cameraVertices:Vector.<Number> = new Vector.<Number>(24, true); | ||||
| 		static private const projectedVertices:Vector.<Number> = new Vector.<Number>(16, true); | ||||
| 		static private const uvts:Vector.<Number> = new Vector.<Number>(24, true); | ||||
| 		public var thickness:Number = 0; | ||||
| 		public var color:uint = 0xFFFFFF; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			 | ||||
| 			cameraVertices[0] = _boundBox.minX; | ||||
| 			cameraVertices[1] = _boundBox.minY; | ||||
| 			cameraVertices[2] = _boundBox.minZ; | ||||
| 			 | ||||
| 			cameraVertices[3] = _boundBox.minX; | ||||
| 			cameraVertices[4] = _boundBox.minY; | ||||
| 			cameraVertices[5] = _boundBox.maxZ; | ||||
| 			 | ||||
| 			cameraVertices[6] = _boundBox.minX; | ||||
| 			cameraVertices[7] = _boundBox.maxY; | ||||
| 			cameraVertices[8] = _boundBox.minZ; | ||||
| 			 | ||||
| 			cameraVertices[9] = _boundBox.minX; | ||||
| 			cameraVertices[10] = _boundBox.maxY; | ||||
| 			cameraVertices[11] = _boundBox.maxZ; | ||||
| 			 | ||||
| 			cameraVertices[12] = _boundBox.maxX; | ||||
| 			cameraVertices[13] = _boundBox.minY; | ||||
| 			cameraVertices[14] = _boundBox.minZ; | ||||
| 			 | ||||
| 			cameraVertices[15] = _boundBox.maxX; | ||||
| 			cameraVertices[16] = _boundBox.minY; | ||||
| 			cameraVertices[17] = _boundBox.maxZ; | ||||
|  | ||||
| 			cameraVertices[18] = _boundBox.maxX; | ||||
| 			cameraVertices[19] = _boundBox.maxY; | ||||
| 			cameraVertices[20] = _boundBox.minZ; | ||||
|  | ||||
| 			cameraVertices[21] = _boundBox.maxX; | ||||
| 			cameraVertices[22] = _boundBox.maxY; | ||||
| 			cameraVertices[23] = _boundBox.maxZ; | ||||
| 			 | ||||
| 			object.cameraMatrix.transformVectors(cameraVertices, cameraVertices); | ||||
| 			for (var i:int = 0; i < 8; i++) { | ||||
| 				if (cameraVertices[int(i*3 + 2)] <= 0) return; | ||||
| 			} | ||||
|  | ||||
| 			// Подготовка канваса | ||||
| 			var canvas:Canvas = parentCanvas.getChildCanvas(true, false, object.alpha, object.blendMode, object.colorTransform, object.filters); | ||||
| 			 | ||||
| 			// Проецируем точки | ||||
| 			Utils3D.projectVectors(camera.projectionMatrix, cameraVertices, projectedVertices, uvts); | ||||
| 			 | ||||
| 			// Отрисовка | ||||
| 			canvas.gfx.lineStyle(thickness, color); | ||||
| 			canvas.gfx.moveTo(projectedVertices[0], projectedVertices[1]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[2], projectedVertices[3]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[6], projectedVertices[7]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[4], projectedVertices[5]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[0], projectedVertices[1]); | ||||
| 			canvas.gfx.moveTo(projectedVertices[8], projectedVertices[9]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[10], projectedVertices[11]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[14], projectedVertices[15]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[12], projectedVertices[13]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[8], projectedVertices[9]); | ||||
| 			canvas.gfx.moveTo(projectedVertices[0], projectedVertices[1]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[8], projectedVertices[9]); | ||||
| 			canvas.gfx.moveTo(projectedVertices[2], projectedVertices[3]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[10], projectedVertices[11]); | ||||
| 			canvas.gfx.moveTo(projectedVertices[4], projectedVertices[5]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[12], projectedVertices[13]); | ||||
| 			canvas.gfx.moveTo(projectedVertices[6], projectedVertices[7]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[14], projectedVertices[15]); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,48 +0,0 @@ | ||||
| package alternativa.engine3d.objects { | ||||
|  | ||||
| 	import __AS3__.vec.Vector; | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.Camera3D; | ||||
| 	import alternativa.engine3d.core.Canvas; | ||||
| 	import alternativa.engine3d.core.Object3D; | ||||
| 	 | ||||
| 	import flash.geom.Utils3D; | ||||
| 	 | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class WireQuad extends Object3D { | ||||
| 		 | ||||
| 		public var vertices:Vector.<Number>; | ||||
| 		static private const cameraVertices:Vector.<Number> = new Vector.<Number>(12, true); | ||||
| 		static private const projectedVertices:Vector.<Number> = new Vector.<Number>(8, true); | ||||
| 		static private const uvts:Vector.<Number> = new Vector.<Number>(12, true); | ||||
| 		public var thickness:Number = 0; | ||||
| 		public var color:uint = 0xFFFFFF; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * @private | ||||
| 		 */ | ||||
| 		override alternativa3d function draw(camera:Camera3D, object:Object3D, parentCanvas:Canvas):void { | ||||
| 			object.cameraMatrix.transformVectors(vertices, cameraVertices); | ||||
| 			for (var i:int = 0; i < 4; i++) { | ||||
| 				if (cameraVertices[(i*3 + 2)] <= 0) return; | ||||
| 			} | ||||
|  | ||||
| 			// Подготовка канваса | ||||
| 			var canvas:Canvas = parentCanvas.getChildCanvas(true, false, object.alpha, object.blendMode, object.colorTransform, object.filters); | ||||
|  | ||||
| 			// Проецируем точки | ||||
| 			Utils3D.projectVectors(camera.projectionMatrix, cameraVertices, projectedVertices, uvts); | ||||
| 			 | ||||
| 			// Отрисовка | ||||
| 			canvas.gfx.lineStyle(thickness, color); | ||||
| 			canvas.gfx.moveTo(projectedVertices[0], projectedVertices[1]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[2], projectedVertices[3]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[4], projectedVertices[5]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[6], projectedVertices[7]); | ||||
| 			canvas.gfx.lineTo(projectedVertices[0], projectedVertices[1]); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,23 +0,0 @@ | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 108 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/primitives | ||||
| END | ||||
| Plane.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 117 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/primitives/Plane.as | ||||
| END | ||||
| GeoSphere.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 121 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/primitives/GeoSphere.as | ||||
| END | ||||
| Box.as | ||||
| K 25 | ||||
| svn:wc:ra_dav:version-url | ||||
| V 115 | ||||
| /!svn/ver/22370/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/primitives/Box.as | ||||
| END | ||||
| @@ -1,64 +0,0 @@ | ||||
| 8 | ||||
|  | ||||
| dir | ||||
| 46043 | ||||
| http://svndev.alternativaplatform.com/platform/clients/fp10/libraries/Alternativa3D/tags/7.2.1/src/alternativa/engine3d/primitives | ||||
| http://svndev.alternativaplatform.com | ||||
|  | ||||
|  | ||||
|  | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
|  | ||||
| svn:special svn:externals svn:needs-lock | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| d9e2387a-1f3e-40e2-b57f-9df5970a2fa5 | ||||
|  | ||||
| Plane.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 13b9ee2e1ab4d9ba5b8336d1441b06bc | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
| GeoSphere.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| fd6e025bfc60d5fb6775ad0dd70d1c5c | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
| Box.as | ||||
| file | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| 2010-10-28T04:31:17.000000Z | ||||
| 192ecbd6a9964c01be629f1666a530f8 | ||||
| 2009-10-18T15:26:30.880098Z | ||||
| 22239 | ||||
| int | ||||
|  | ||||
| @@ -1,233 +0,0 @@ | ||||
| package alternativa.engine3d.primitives { | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.objects.Mesh; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class Box extends Mesh { | ||||
| 		 | ||||
| 		public function Box(width:Number = 100, length:Number = 100, height:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, heightSegments:uint = 1, reverse:Boolean = false) { | ||||
| 			 | ||||
| 			var wp:uint = widthSegments + 1; | ||||
| 			var lp:uint = lengthSegments + 1; | ||||
| 			var hp:uint = heightSegments + 1; | ||||
| 			 | ||||
| 			createEmptyGeometry((wp*(lp + hp) + lp*hp) << 1, (widthSegments*(lengthSegments + heightSegments) + lengthSegments*heightSegments) << 2); | ||||
| 			 | ||||
| 			var wh:Number = width*0.5; | ||||
| 			var lh:Number = length*0.5; | ||||
| 			var hh:Number = height*0.5; | ||||
| 			var wd:Number = 1/widthSegments; | ||||
| 			var ld:Number = 1/lengthSegments; | ||||
| 			var hd:Number = 1/heightSegments; | ||||
| 			var ws:Number = width/widthSegments; | ||||
| 			var ls:Number = length/lengthSegments; | ||||
| 			var hs:Number = height/heightSegments; | ||||
| 			var x:uint; | ||||
| 			var y:uint; | ||||
| 			var z:uint; | ||||
| 			 | ||||
| 			var v:uint = 0; | ||||
| 			var f:uint = 0; | ||||
|   			 | ||||
| 			// Нижняя грань | ||||
| 			for (x = 0; x < wp; x++) { | ||||
| 				for (y = 0; y < lp; y++) { | ||||
| 					vertices[v] = x*ws - wh; | ||||
| 					uvts[v++] = (widthSegments - x)*wd; | ||||
| 					vertices[v] = y*ls - lh; | ||||
| 					uvts[v++] = (lengthSegments - y)*ld; | ||||
| 					vertices[v++] = -hh; | ||||
| 					 | ||||
| 					if (x < widthSegments && y < lengthSegments) { | ||||
| 						if (reverse) { | ||||
| 							indices[f++] = (x + 1)*lp + y + 1; | ||||
| 							indices[f++] = x*lp + y + 1; | ||||
| 							indices[f++] = x*lp + y; | ||||
|  | ||||
| 							indices[f++] = (x + 1)*lp + y; | ||||
| 							indices[f++] = (x + 1)*lp + y + 1; | ||||
| 							indices[f++] = x*lp + y; | ||||
| 						} else { | ||||
| 							indices[f++] = x*lp + y; | ||||
| 							indices[f++] = (x + 1)*lp + y + 1; | ||||
| 							indices[f++] = (x + 1)*lp + y; | ||||
| 							 | ||||
| 							indices[f++] = x*lp + y; | ||||
| 							indices[f++] = x*lp + y + 1; | ||||
| 							indices[f++] = (x + 1)*lp + y + 1; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			var o:uint = wp*lp; | ||||
|  | ||||
| 			// Верхняя грань | ||||
| 			for (x = 0; x < wp; x++) { | ||||
| 				for (y = 0; y < lp; y++) { | ||||
| 					vertices[v] = x*ws - wh; | ||||
| 					uvts[v++] = x*wd; | ||||
| 					vertices[v] = y*ls - lh; | ||||
| 					uvts[v++] = (lengthSegments - y)*ld; | ||||
| 					vertices[v++] = hh; | ||||
| 					 | ||||
| 					if (x < widthSegments && y < lengthSegments) { | ||||
| 						if (reverse) { | ||||
| 							indices[f++] = o + x*lp + y + 1; | ||||
| 							indices[f++] = o + (x + 1)*lp + y + 1; | ||||
| 							indices[f++] = o + x*lp + y; | ||||
|  | ||||
| 							indices[f++] = o + (x + 1)*lp + y + 1; | ||||
| 							indices[f++] = o + (x + 1)*lp + y; | ||||
| 							indices[f++] = o + x*lp + y; | ||||
| 						} else { | ||||
| 							indices[f++] = o + x*lp + y; | ||||
| 							indices[f++] = o + (x + 1)*lp + y; | ||||
| 							indices[f++] = o + (x + 1)*lp + y + 1; | ||||
| 							 | ||||
| 							indices[f++] = o + x*lp + y; | ||||
| 							indices[f++] = o + (x + 1)*lp + y + 1; | ||||
| 							indices[f++] = o + x*lp + y + 1; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			o += wp*lp; | ||||
|  | ||||
| 			// Передняя грань | ||||
| 			for (x = 0; x < wp; x++) { | ||||
| 				for (z = 0; z < hp; z++) { | ||||
| 					vertices[v] = x*ws - wh; | ||||
| 					uvts[v++] = x*wd; | ||||
| 					vertices[v] = -lh; | ||||
| 					uvts[v++] = (heightSegments - z)*hd; | ||||
| 					vertices[v++] = z*hs - hh; | ||||
| 					 | ||||
| 					if (x < widthSegments && z < heightSegments) { | ||||
| 						if (reverse) { | ||||
| 							indices[f++] = o + x*hp + z + 1; | ||||
| 							indices[f++] = o + (x + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + x*hp + z; | ||||
|  | ||||
| 							indices[f++] = o + (x + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + (x + 1)*hp + z; | ||||
| 							indices[f++] = o + x*hp + z; | ||||
| 						} else { | ||||
| 							indices[f++] = o + x*hp + z; | ||||
| 							indices[f++] = o + (x + 1)*hp + z; | ||||
| 							indices[f++] = o + (x + 1)*hp + z + 1; | ||||
| 							 | ||||
| 							indices[f++] = o + x*hp + z; | ||||
| 							indices[f++] = o + (x + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + x*hp + z + 1; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			o += wp*hp; | ||||
|  | ||||
| 			// Задняя грань | ||||
| 			for (x = 0; x < wp; x++) { | ||||
| 				for (z = 0; z < hp; z++) { | ||||
| 					vertices[v] = x*ws - wh; | ||||
| 					uvts[v++] = (widthSegments - x)*wd; | ||||
| 					vertices[v] = lh; | ||||
| 					uvts[v++] = (heightSegments - z)*hd; | ||||
| 					vertices[v++] = z*hs - hh; | ||||
| 					 | ||||
| 					if (x < widthSegments && z < heightSegments) { | ||||
| 						if (reverse) { | ||||
| 							indices[f++] = o + (x + 1)*hp + z; | ||||
| 							indices[f++] = o + (x + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + x*hp + z + 1; | ||||
|  | ||||
| 							indices[f++] = o + (x + 1)*hp + z; | ||||
| 							indices[f++] = o + x*hp + z + 1; | ||||
| 							indices[f++] = o + x*hp + z; | ||||
| 						} else { | ||||
| 							indices[f++] = o + x*hp + z; | ||||
| 							indices[f++] = o + x*hp + z + 1; | ||||
| 							indices[f++] = o + (x + 1)*hp + z; | ||||
| 							 | ||||
| 							indices[f++] = o + x*hp + z + 1; | ||||
| 							indices[f++] = o + (x + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + (x + 1)*hp + z; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			o += wp*hp; | ||||
|  | ||||
| 			// Левая грань | ||||
| 			for (y = 0; y < lp; y++) { | ||||
| 				for (z = 0; z < hp; z++) { | ||||
| 					vertices[v] = -wh; | ||||
| 					uvts[v++] = (lengthSegments - y)*ld; | ||||
| 					vertices[v] = y*ls - lh; | ||||
| 					uvts[v++] = (heightSegments - z)*hd; | ||||
| 					vertices[v++] = z*hs - hh; | ||||
| 					 | ||||
| 					if (y < lengthSegments && z < heightSegments) { | ||||
| 						if (reverse) { | ||||
| 							indices[f++] = o + (y + 1)*hp + z; | ||||
| 							indices[f++] = o + (y + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + y*hp + z + 1; | ||||
|  | ||||
| 							indices[f++] = o + (y + 1)*hp + z; | ||||
| 							indices[f++] = o + y*hp + z + 1; | ||||
| 							indices[f++] = o + y*hp + z; | ||||
| 						} else { | ||||
| 							indices[f++] = o + y*hp + z; | ||||
| 							indices[f++] = o + y*hp + z + 1; | ||||
| 							indices[f++] = o + (y + 1)*hp + z; | ||||
| 							 | ||||
| 							indices[f++] = o + y*hp + z + 1; | ||||
| 							indices[f++] = o + (y + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + (y + 1)*hp + z; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			o += lp*hp; | ||||
|  | ||||
| 			// Правая грань | ||||
| 			for (y = 0; y < lp; y++) { | ||||
| 				for (z = 0; z < hp; z++) { | ||||
| 					vertices[v] = wh; | ||||
| 					uvts[v++] = y*ld; | ||||
| 					vertices[v] = y*ls - lh; | ||||
| 					uvts[v++] = (heightSegments - z)*hd; | ||||
| 					vertices[v++] = z*hs - hh; | ||||
| 					 | ||||
| 					if (y < lengthSegments && z < heightSegments) { | ||||
| 						if (reverse) { | ||||
| 							indices[f++] = o + y*hp + z + 1; | ||||
| 							indices[f++] = o + (y + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + y*hp + z; | ||||
|  | ||||
| 							indices[f++] = o + (y + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + (y + 1)*hp + z; | ||||
| 							indices[f++] = o + y*hp + z; | ||||
| 						} else { | ||||
| 							indices[f++] = o + y*hp + z; | ||||
| 							indices[f++] = o + (y + 1)*hp + z; | ||||
| 							indices[f++] = o + (y + 1)*hp + z + 1; | ||||
| 							 | ||||
| 							indices[f++] = o + y*hp + z; | ||||
| 							indices[f++] = o + (y + 1)*hp + z + 1; | ||||
| 							indices[f++] = o + y*hp + z + 1; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			 | ||||
| 		    // Установка границ | ||||
| 		    _boundBox = new BoundBox(); | ||||
| 		    _boundBox.setSize(-wh, -lh, -hh, wh, lh, hh); | ||||
| 			 | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,244 +0,0 @@ | ||||
| package alternativa.engine3d.primitives { | ||||
|  | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.objects.Mesh; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	public class GeoSphere extends Mesh { | ||||
|  | ||||
| 		public function GeoSphere(radius:Number = 100, segments:uint = 2, reverse:Boolean = false) { | ||||
|  | ||||
| 			const sections:uint = 20; | ||||
|  | ||||
| 			var i:uint; | ||||
|  | ||||
| 			var theta:Number; | ||||
| 			var sin:Number; | ||||
| 			var cos:Number; | ||||
| 			// z расстояние до нижней и верхней крышки полюса   | ||||
| 			var subz:Number = 4.472136E-001*radius; | ||||
| 			// радиус на расстоянии subz  | ||||
| 			var subrad:Number = 2*subz; | ||||
|  | ||||
| 			var v:uint = 0; | ||||
|  | ||||
| 			var f:uint = sections*segments*segments; | ||||
| 			createEmptyGeometry(f/2 + 2, f); | ||||
| 			 | ||||
| 			vertices[v++] = 0; | ||||
| 			vertices[v++] = 0; | ||||
| 			vertices[v++] = radius; | ||||
| 			 | ||||
| 			// Создание вершин верхней крышки | ||||
| 			for (i = 0; i < 5; i++) { | ||||
| 				theta = Math.PI*2*i/5; | ||||
| 				sin = Math.sin(theta); | ||||
| 				cos = Math.cos(theta); | ||||
| 				vertices[v++] = subrad*cos; | ||||
| 				vertices[v++] = subrad*sin; | ||||
| 				vertices[v++] = subz; | ||||
| 			} | ||||
| 			// Создание вершин нижней крышки | ||||
| 			for (i = 0; i < 5; i++) { | ||||
| 				theta = Math.PI*((i << 1) + 1)/5; | ||||
| 				sin = Math.sin(theta); | ||||
| 				cos = Math.cos(theta); | ||||
| 				vertices[v++] = subrad*cos; | ||||
| 				vertices[v++] = subrad*sin; | ||||
| 				vertices[v++] = -subz; | ||||
| 			} | ||||
|  | ||||
| 			vertices[v++] = 0; | ||||
| 			vertices[v++] = 0; | ||||
| 			vertices[v++] = -radius; | ||||
| 			 | ||||
| 			for (i = 1; i < 6; i++) { | ||||
| 				v = interpolate(0, i, segments, v); | ||||
| 			} | ||||
| 			for (i = 1; i < 6; i++) { | ||||
| 				v = interpolate(i, i % 5 + 1, segments, v); | ||||
| 			} | ||||
| 			for (i = 1; i < 6; i++) { | ||||
| 				v = interpolate(i, i + 5, segments, v); | ||||
| 			} | ||||
| 			for (i = 1; i < 6; i++) { | ||||
| 				v = interpolate(i, (i + 3) % 5 + 6, segments, v); | ||||
| 			} | ||||
| 			for (i = 1; i < 6; i++) { | ||||
| 				v = interpolate(i + 5, i % 5 + 6, segments, v); | ||||
| 			} | ||||
| 			for (i = 6; i < 11; i++) { | ||||
| 				v = interpolate(11, i, segments, v); | ||||
| 			} | ||||
| 			for (f = 0; f < 5; f++) { | ||||
| 				for (i = 1; i <= segments - 2; i++) { | ||||
| 					v = interpolate(12 + f*(segments - 1) + i, 12 + (f + 1) % 5*(segments - 1) + i, i + 1, v); | ||||
| 				} | ||||
| 			} | ||||
| 			for (f = 0; f < 5; f++) { | ||||
| 				for (i = 1; i <= segments - 2; i++) { | ||||
| 					v = interpolate(12 + (f + 15)*(segments - 1) + i, 12 + (f + 10)*(segments - 1) + i, i + 1, v); | ||||
| 				} | ||||
| 			} | ||||
| 			for (f = 0; f < 5; f++) { | ||||
| 				for (i = 1; i <= segments - 2; i++) { | ||||
| 					v = interpolate(12 + ((f + 1) % 5 + 15)*(segments - 1) + segments - 2 - i, 12 + (f + 10)*(segments - 1) + segments - 2 - i, i + 1, v); | ||||
| 				} | ||||
| 			} | ||||
| 			for (f = 0; f < 5; f++) { | ||||
| 				for (i = 1; i <= segments - 2; i++) { | ||||
| 					v = interpolate(12 + ((f + 1) % 5 + 25)*(segments - 1) + i, 12 + (f + 25)*(segments - 1) + i, i + 1, v); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			for (i = 0; i < numVertices; i++) { | ||||
| 				var j:uint = i*3; | ||||
| 				uvts[j] = Math.atan2(vertices[j + 1], vertices[j])/(Math.PI*2); | ||||
| 				uvts[j] = 0.5 + (reverse ? -uvts[j] : uvts[j]); | ||||
| 				uvts[j + 1] = 0.5 + Math.asin(vertices[j + 2]/radius)/Math.PI; | ||||
| 			} | ||||
|  | ||||
| 		    var num:uint = 0; | ||||
| 		    for (f = 0; f <= sections - 1; f++) { | ||||
| 		        for (var row:uint = 0; row <= segments - 1; row++) { | ||||
| 		            for (var column:uint = 0; column <= row; column++) { | ||||
| 		                var a:uint = findVertices(segments, f, row, column); | ||||
| 		                var b:uint = findVertices(segments, f, row + 1, column); | ||||
| 		                var c:uint = findVertices(segments, f, row + 1, column + 1); | ||||
| 		                 | ||||
| 		                if (reverse) { | ||||
| 		                	indices[num++] = a; | ||||
| 		                	indices[num++] = c; | ||||
| 		                	indices[num++] = b; | ||||
| 		                } else { | ||||
| 		                	indices[num++] = a; | ||||
| 		                	indices[num++] = b; | ||||
| 		                	indices[num++] = c; | ||||
| 		                } | ||||
| 		                 | ||||
| 		                if (column < row) { | ||||
| 		                    var d:uint = findVertices(segments, f, row, column + 1); | ||||
| 		                    if (reverse) { | ||||
| 			                	indices[num++] = a; | ||||
| 			                	indices[num++] = d; | ||||
| 			                	indices[num++] = c; | ||||
| 		                    } else { | ||||
| 			                	indices[num++] = a; | ||||
| 			                	indices[num++] = c; | ||||
| 			                	indices[num++] = d; | ||||
| 		                    } | ||||
| 		                } | ||||
| 		            } | ||||
| 		        } | ||||
| 		    } | ||||
| 		     | ||||
| 		    // Установка границ | ||||
| 		    _boundBox = new BoundBox(); | ||||
| 		    _boundBox.setSize(-radius, -radius, -radius, radius, radius, radius); | ||||
| 		} | ||||
|  | ||||
| 		private function interpolate(a:uint, b:uint, num:uint, v:uint):uint { | ||||
| 			if (num < 2) { | ||||
| 				return v; | ||||
| 			} | ||||
| 			a *= 3; | ||||
| 			b *= 3; | ||||
| 			var ax:Number = vertices[a]; | ||||
| 			var ay:Number = vertices[a + 1]; | ||||
| 			var az:Number = vertices[a + 2]; | ||||
| 			var bx:Number = vertices[b]; | ||||
| 			var by:Number = vertices[b + 1]; | ||||
| 			var bz:Number = vertices[b + 2]; | ||||
| 			var cos:Number = (ax*bx + ay*by + az*bz)/(ax*ax + ay*ay + az*az); | ||||
| 			cos = (cos < -1) ? -1 : ((cos > 1) ? 1 : cos); | ||||
| 			var theta:Number = Math.acos(cos); | ||||
| 			var sin:Number = Math.sin(theta); | ||||
| 			for (var e:uint = 1; e < num; e++) { | ||||
| 				var theta1:Number = theta*e/num; | ||||
| 				var theta2:Number = theta*(num - e)/num; | ||||
| 				var st1:Number = Math.sin(theta1); | ||||
| 				var st2:Number = Math.sin(theta2); | ||||
| 				vertices[v++] = (ax*st2 + bx*st1)/sin; | ||||
| 				vertices[v++] = (ay*st2 + by*st1)/sin; | ||||
| 				vertices[v++] = (az*st2 + bz*st1)/sin; | ||||
| 			} | ||||
| 			return v; | ||||
| 		} | ||||
|  | ||||
| 		private function findVertices(segments:uint, section:uint, row:uint, column:uint):uint { | ||||
| 			if (row == 0) { | ||||
| 				if (section < 5) { | ||||
| 					return (0); | ||||
| 				} | ||||
| 				if (section > 14) { | ||||
| 					return (11); | ||||
| 				} | ||||
| 				return (section - 4); | ||||
| 			} | ||||
| 			if (row == segments && column == 0) { | ||||
| 				if (section < 5) { | ||||
| 					return (section + 1); | ||||
| 				} | ||||
| 				if (section < 10) { | ||||
| 					return ((section + 4) % 5 + 6); | ||||
| 				} | ||||
| 				if (section < 15) { | ||||
| 					return ((section + 1) % 5 + 1); | ||||
| 				} | ||||
| 				return ((section + 1) % 5 + 6); | ||||
| 			} | ||||
| 			if (row == segments && column == segments) { | ||||
| 				if (section < 5) { | ||||
| 					return ((section + 1) % 5 + 1); | ||||
| 				} | ||||
| 				if (section < 10) { | ||||
| 					return (section + 1); | ||||
| 				} | ||||
| 				if (section < 15) { | ||||
| 					return (section - 9); | ||||
| 				} | ||||
| 				return (section - 9); | ||||
| 			} | ||||
| 			if (row == segments) { | ||||
| 				if (section < 5) { | ||||
| 					return (12 + (5 + section)*(segments - 1) + column - 1); | ||||
| 				} | ||||
| 				if (section < 10) { | ||||
| 					return (12 + (20 + (section + 4) % 5)*(segments - 1) + column - 1); | ||||
| 				} | ||||
| 				if (section < 15) { | ||||
| 					return (12 + (section - 5)*(segments - 1) + segments - 1 - column); | ||||
| 				} | ||||
| 				return (12 + (5 + section)*(segments - 1) + segments - 1 - column); | ||||
| 			} | ||||
| 			if (column == 0) { | ||||
| 				if (section < 5) { | ||||
| 					return (12 + section*(segments - 1) + row - 1); | ||||
| 				} | ||||
| 				if (section < 10) { | ||||
| 					return (12 + (section % 5 + 15)*(segments - 1) + row - 1); | ||||
| 				} | ||||
| 				if (section < 15) { | ||||
| 					return (12 + ((section + 1) % 5 + 15)*(segments - 1) + segments - 1 - row); | ||||
| 				} | ||||
| 				return (12 + ((section + 1) % 5 + 25)*(segments - 1) + row - 1); | ||||
| 			} | ||||
| 			if (column == row) { | ||||
| 				if (section < 5) { | ||||
| 					return (12 + (section + 1) % 5*(segments - 1) + row - 1); | ||||
| 				} | ||||
| 				if (section < 10) { | ||||
| 					return (12 + (section % 5 + 10)*(segments - 1) + row - 1); | ||||
| 				} | ||||
| 				if (section < 15) { | ||||
| 					return (12 + (section % 5 + 10)*(segments - 1) + segments - row - 1); | ||||
| 				} | ||||
| 				return (12 + (section % 5 + 25)*(segments - 1) + row - 1); | ||||
| 			} | ||||
| 			return (12 + 30*(segments - 1) + section*(segments - 1)*(segments - 2)/2 + (row - 1)*(row - 2)/2 + column - 1); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
| @@ -1,67 +0,0 @@ | ||||
| package alternativa.engine3d.primitives { | ||||
| 	 | ||||
| 	import alternativa.engine3d.alternativa3d; | ||||
| 	import alternativa.engine3d.core.BoundBox; | ||||
| 	import alternativa.engine3d.objects.Mesh; | ||||
|  | ||||
| 	use namespace alternativa3d; | ||||
| 	 | ||||
| 	/** | ||||
| 	 *  | ||||
| 	 */ | ||||
| 	public class Plane extends Mesh { | ||||
| 		 | ||||
| 		/** | ||||
| 		 *  | ||||
| 		 * @param width | ||||
| 		 * @param length | ||||
| 		 * @param widthSegments | ||||
| 		 * @param lengthSegments | ||||
| 		 */ | ||||
| 		public function Plane(width:Number = 100, length:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1) { | ||||
| 			 | ||||
| 			var wp:uint = widthSegments + 1; | ||||
| 			var lp:uint = lengthSegments + 1; | ||||
| 			 | ||||
| 			createEmptyGeometry(wp*lp, (widthSegments*lengthSegments) << 2); | ||||
| 			 | ||||
| 			var wh:Number = width*0.5; | ||||
| 			var lh:Number = length*0.5; | ||||
| 			var wd:Number = 1/widthSegments; | ||||
| 			var ld:Number = 1/lengthSegments; | ||||
| 			var ws:Number = width/widthSegments; | ||||
| 			var ls:Number = length/lengthSegments; | ||||
| 			var x:uint; | ||||
| 			var y:uint; | ||||
| 			var z:uint; | ||||
| 			 | ||||
| 			var v:uint = 0; | ||||
| 			var f:uint = 0; | ||||
|   			 | ||||
| 			// Верхняя грань | ||||
| 			for (x = 0; x < wp; x++) { | ||||
| 				for (y = 0; y < lp; y++) { | ||||
| 					vertices[v] = x*ws - wh; | ||||
| 					uvts[v++] = x*wd; | ||||
| 					vertices[v] = y*ls - lh; | ||||
| 					uvts[v++] = (lengthSegments - y)*ld; | ||||
| 					vertices[v++] = 0; | ||||
| 					 | ||||
| 					if (x < widthSegments && y < lengthSegments) { | ||||
| 						indices[f++] = x*lp + y; | ||||
| 						indices[f++] = (x + 1)*lp + y; | ||||
| 						indices[f++] = (x + 1)*lp + y + 1; | ||||
| 							 | ||||
| 						indices[f++] = x*lp + y; | ||||
| 						indices[f++] = (x + 1)*lp + y + 1; | ||||
| 						indices[f++] = x*lp + y + 1; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		    // Установка границ | ||||
| 		    _boundBox = new BoundBox(); | ||||
| 		    _boundBox.setSize(-wh, -lh, 0, wh, lh, 0); | ||||
| 		} | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Pyogenics
					Pyogenics