mirror of
https://github.com/MapMakersAndProgrammers/alternativa3d-archive.git
synced 2025-10-26 09:49:07 -07:00
more versions added
This commit is contained in:
BIN
Alternativa3D8/.DS_Store
vendored
Normal file
BIN
Alternativa3D8/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
Alternativa3D8/8.0.0.0/.DS_Store
vendored
Normal file
BIN
Alternativa3D8/8.0.0.0/.DS_Store
vendored
Normal file
Binary file not shown.
33
Alternativa3D8/8.0.0.0/.actionScriptProperties
Normal file
33
Alternativa3D8/8.0.0.0/.actionScriptProperties
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<actionScriptProperties mainApplicationPath="Alternativa3D.as" version="3">
|
||||
<compiler additionalCompilerArguments="" copyDependentFiles="false" enableModuleDebug="true" generateAccessible="false" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="false" htmlPlayerVersion="11.0.0" htmlPlayerVersionCheck="true" outputFolderPath="bin" sourceFolderPath="src" strict="true" useApolloConfig="false" verifyDigests="true" warn="true">
|
||||
<compilerSourcePath/>
|
||||
<libraryPath defaultLinkType="1">
|
||||
<libraryPathEntry kind="4" path="">
|
||||
<excludedEntries>
|
||||
<libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flex.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="4" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="true">
|
||||
<crossDomainRsls>
|
||||
<crossDomainRslEntry autoExtract="true" policyFileUrl="" rslUrl="framework_3.2.0.3958.swz"/>
|
||||
<crossDomainRslEntry autoExtract="true" policyFileUrl="" rslUrl="framework_3.2.0.3958.swf"/>
|
||||
</crossDomainRsls>
|
||||
</libraryPathEntry>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/utilities.swc" useDefaultLinkType="false"/>
|
||||
</excludedEntries>
|
||||
</libraryPathEntry>
|
||||
</libraryPath>
|
||||
<sourceAttachmentPath/>
|
||||
</compiler>
|
||||
<applications>
|
||||
<application path="Alternativa3D.as"/>
|
||||
</applications>
|
||||
<modules/>
|
||||
<buildCSSFiles/>
|
||||
</actionScriptProperties>
|
||||
72
Alternativa3D8/8.0.0.0/.flexLibProperties
Normal file
72
Alternativa3D8/8.0.0.0/.flexLibProperties
Normal file
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<flexLibProperties version="1">
|
||||
<includeClasses>
|
||||
<classEntry path="alternativa.engine3d.materials.Material"/>
|
||||
<classEntry path="alternativa.Alternativa3D"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeSource"/>
|
||||
<classEntry path="alternativa.engine3d.core.Object3DContainer"/>
|
||||
<classEntry path="alternativa.engine3d.core.RayIntersectionData"/>
|
||||
<classEntry path="alternativa.engine3d.objects.Skin"/>
|
||||
<classEntry path="alternativa.engine3d.controllers.SimpleObjectController"/>
|
||||
<classEntry path="alternativa.engine3d.animation.TransformAnimation"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeParam"/>
|
||||
<classEntry path="alternativa.engine3d.animation.Track"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.events.LoaderErrorEvent"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeVisualScene"/>
|
||||
<classEntry path="alternativa.engine3d.core.Face"/>
|
||||
<classEntry path="alternativa.engine3d.core.Wrapper"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeLogger"/>
|
||||
<classEntry path="alternativa.engine3d.materials.TextureMaterial"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeVertices"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeInput"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.Parser3DS"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.MaterialLoader"/>
|
||||
<classEntry path="alternativa.engine3d.animation.AnimationState"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeEffect"/>
|
||||
<classEntry path="alternativa.engine3d.core.Vertex"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeNode"/>
|
||||
<classEntry path="alternativa.engine3d.primitives.Box"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.events.LoaderProgressEvent"/>
|
||||
<classEntry path="alternativa.engine3d.objects.Joint"/>
|
||||
<classEntry path="alternativa.engine3d.animation.AnimationController"/>
|
||||
<classEntry path="alternativa.engine3d.animation.keys.Key"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.collada"/>
|
||||
<classEntry path="alternativa.engine3d.core.Object3D"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeMaterial"/>
|
||||
<classEntry path="alternativa.engine3d.core.View"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeEffectParam"/>
|
||||
<classEntry path="alternativa.engine3d.objects.LightMapGenerator"/>
|
||||
<classEntry path="alternativa.engine3d.animation.keys.MatrixKey"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.events.LoaderEvent"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaePrimitive"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.ParserCollada"/>
|
||||
<classEntry path="alternativa.engine3d.animation.AnimationTimer"/>
|
||||
<classEntry path="alternativa.engine3d.animation.Animation"/>
|
||||
<classEntry path="alternativa.engine3d.core.Geometry"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeObject"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeImage"/>
|
||||
<classEntry path="alternativa.engine3d.animation.AnimationGroup"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeSampler"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeElement"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeGeometry"/>
|
||||
<classEntry path="alternativa.engine3d.animation.keys.PointKey"/>
|
||||
<classEntry path="alternativa.engine3d.objects.Terrain"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeInstanceMaterial"/>
|
||||
<classEntry path="alternativa.engine3d.objects.Mesh"/>
|
||||
<classEntry path="alternativa.engine3d.materials.AGALMiniAssembler"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeInstanceController"/>
|
||||
<classEntry path="alternativa.engine3d.animation.MatrixAnimation"/>
|
||||
<classEntry path="alternativa.engine3d.primitives.GeoSphere"/>
|
||||
<classEntry path="alternativa.engine3d.materials.FillMaterial"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeController"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeArray"/>
|
||||
<classEntry path="alternativa.engine3d.alternativa3d"/>
|
||||
<classEntry path="alternativa.engine3d.animation.keys.ValueKey"/>
|
||||
<classEntry path="alternativa.engine3d.core.Camera3D"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeDocument"/>
|
||||
<classEntry path="alternativa.engine3d.lights.DirectionalLight"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeChannel"/>
|
||||
</includeClasses>
|
||||
<includeResources/>
|
||||
<namespaceManifests/>
|
||||
</flexLibProperties>
|
||||
18
Alternativa3D8/8.0.0.0/.project
Normal file
18
Alternativa3D8/8.0.0.0/.project
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Alternativa3D</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.adobe.flexbuilder.project.flexbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.adobe.flexbuilder.project.flexlibnature</nature>
|
||||
<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
11
Alternativa3D8/8.0.0.0/.settings/.svn/all-wcprops
Normal file
11
Alternativa3D8/8.0.0.0/.settings/.svn/all-wcprops
Normal file
@@ -0,0 +1,11 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 84
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/.settings
|
||||
END
|
||||
org.eclipse.core.resources.prefs
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 117
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/.settings/org.eclipse.core.resources.prefs
|
||||
END
|
||||
40
Alternativa3D8/8.0.0.0/.settings/.svn/entries
Normal file
40
Alternativa3D8/8.0.0.0/.settings/.svn/entries
Normal file
@@ -0,0 +1,40 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/.settings
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-07-12T16:10:41.079324Z
|
||||
37192
|
||||
andrei
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
org.eclipse.core.resources.prefs
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
c51cf81ad3ee39a5d225bf0b3d086097
|
||||
2010-07-12T16:10:41.079324Z
|
||||
37192
|
||||
andrei
|
||||
|
||||
1
Alternativa3D8/8.0.0.0/.settings/.svn/format
Normal file
1
Alternativa3D8/8.0.0.0/.settings/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,3 @@
|
||||
#Wed Jul 07 06:01:58 YEKST 2010
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
||||
@@ -0,0 +1,3 @@
|
||||
#Wed Jul 07 06:01:58 YEKST 2010
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
||||
BIN
Alternativa3D8/8.0.0.0/.svn/.DS_Store
vendored
Normal file
BIN
Alternativa3D8/8.0.0.0/.svn/.DS_Store
vendored
Normal file
Binary file not shown.
29
Alternativa3D8/8.0.0.0/.svn/all-wcprops
Normal file
29
Alternativa3D8/8.0.0.0/.svn/all-wcprops
Normal file
@@ -0,0 +1,29 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 74
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0
|
||||
END
|
||||
.flexLibProperties
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 93
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/.flexLibProperties
|
||||
END
|
||||
.project
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 83
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/.project
|
||||
END
|
||||
pom.xml
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 82
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/pom.xml
|
||||
END
|
||||
.actionScriptProperties
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 98
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/.actionScriptProperties
|
||||
END
|
||||
85
Alternativa3D8/8.0.0.0/.svn/entries
Normal file
85
Alternativa3D8/8.0.0.0/.svn/entries
Normal file
@@ -0,0 +1,85 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-09-07T08:18:39.899421Z
|
||||
40841
|
||||
kviring
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
META-INF
|
||||
dir
|
||||
|
||||
.flexLibProperties
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
aa248478f6d55395984212a379db95e7
|
||||
2010-08-16T14:14:55.364125Z
|
||||
39296
|
||||
danilova
|
||||
|
||||
.project
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
5cfe073356c81d48a97889a21f8ec909
|
||||
2010-07-05T10:51:44.109746Z
|
||||
36756
|
||||
andrei
|
||||
|
||||
src
|
||||
dir
|
||||
|
||||
pom.xml
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
dc5b91ae6e8ea34948eaab9f8fb5eea7
|
||||
2010-09-07T08:18:39.899421Z
|
||||
40841
|
||||
kviring
|
||||
|
||||
.actionScriptProperties
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
11daad588e13c4f6b3c79618f699bd7a
|
||||
2010-08-02T14:22:25.507763Z
|
||||
38300
|
||||
danilova
|
||||
|
||||
.settings
|
||||
dir
|
||||
|
||||
1
Alternativa3D8/8.0.0.0/.svn/format
Normal file
1
Alternativa3D8/8.0.0.0/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<actionScriptProperties mainApplicationPath="Alternativa3D.as" version="3">
|
||||
<compiler additionalCompilerArguments="" copyDependentFiles="false" enableModuleDebug="true" generateAccessible="false" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="false" htmlPlayerVersion="11.0.0" htmlPlayerVersionCheck="true" outputFolderPath="bin" sourceFolderPath="src" strict="true" useApolloConfig="false" verifyDigests="true" warn="true">
|
||||
<compilerSourcePath/>
|
||||
<libraryPath defaultLinkType="1">
|
||||
<libraryPathEntry kind="4" path="">
|
||||
<excludedEntries>
|
||||
<libraryPathEntry kind="1" linkType="1" path="${PROJECT_FRAMEWORKS}/locale/{locale}"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/flex.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/qtp.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/rpc.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/datavisualization.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="4" path="${PROJECT_FRAMEWORKS}/libs/framework.swc" useDefaultLinkType="true">
|
||||
<crossDomainRsls>
|
||||
<crossDomainRslEntry autoExtract="true" policyFileUrl="" rslUrl="framework_3.2.0.3958.swz"/>
|
||||
<crossDomainRslEntry autoExtract="true" policyFileUrl="" rslUrl="framework_3.2.0.3958.swf"/>
|
||||
</crossDomainRsls>
|
||||
</libraryPathEntry>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_dmv.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/automation_agent.swc" useDefaultLinkType="false"/>
|
||||
<libraryPathEntry kind="3" linkType="1" path="${PROJECT_FRAMEWORKS}/libs/utilities.swc" useDefaultLinkType="false"/>
|
||||
</excludedEntries>
|
||||
</libraryPathEntry>
|
||||
</libraryPath>
|
||||
<sourceAttachmentPath/>
|
||||
</compiler>
|
||||
<applications>
|
||||
<application path="Alternativa3D.as"/>
|
||||
</applications>
|
||||
<modules/>
|
||||
<buildCSSFiles/>
|
||||
</actionScriptProperties>
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<flexLibProperties version="1">
|
||||
<includeClasses>
|
||||
<classEntry path="alternativa.engine3d.materials.Material"/>
|
||||
<classEntry path="alternativa.Alternativa3D"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeSource"/>
|
||||
<classEntry path="alternativa.engine3d.core.Object3DContainer"/>
|
||||
<classEntry path="alternativa.engine3d.core.RayIntersectionData"/>
|
||||
<classEntry path="alternativa.engine3d.objects.Skin"/>
|
||||
<classEntry path="alternativa.engine3d.controllers.SimpleObjectController"/>
|
||||
<classEntry path="alternativa.engine3d.animation.TransformAnimation"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeParam"/>
|
||||
<classEntry path="alternativa.engine3d.animation.Track"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.events.LoaderErrorEvent"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeVisualScene"/>
|
||||
<classEntry path="alternativa.engine3d.core.Face"/>
|
||||
<classEntry path="alternativa.engine3d.core.Wrapper"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeLogger"/>
|
||||
<classEntry path="alternativa.engine3d.materials.TextureMaterial"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeVertices"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeInput"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.Parser3DS"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.MaterialLoader"/>
|
||||
<classEntry path="alternativa.engine3d.animation.AnimationState"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeEffect"/>
|
||||
<classEntry path="alternativa.engine3d.core.Vertex"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeNode"/>
|
||||
<classEntry path="alternativa.engine3d.primitives.Box"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.events.LoaderProgressEvent"/>
|
||||
<classEntry path="alternativa.engine3d.objects.Joint"/>
|
||||
<classEntry path="alternativa.engine3d.animation.AnimationController"/>
|
||||
<classEntry path="alternativa.engine3d.animation.keys.Key"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.collada"/>
|
||||
<classEntry path="alternativa.engine3d.core.Object3D"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeMaterial"/>
|
||||
<classEntry path="alternativa.engine3d.core.View"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeEffectParam"/>
|
||||
<classEntry path="alternativa.engine3d.objects.LightMapGenerator"/>
|
||||
<classEntry path="alternativa.engine3d.animation.keys.MatrixKey"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.events.LoaderEvent"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaePrimitive"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.ParserCollada"/>
|
||||
<classEntry path="alternativa.engine3d.animation.AnimationTimer"/>
|
||||
<classEntry path="alternativa.engine3d.animation.Animation"/>
|
||||
<classEntry path="alternativa.engine3d.core.Geometry"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeObject"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeImage"/>
|
||||
<classEntry path="alternativa.engine3d.animation.AnimationGroup"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeSampler"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeElement"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeGeometry"/>
|
||||
<classEntry path="alternativa.engine3d.animation.keys.PointKey"/>
|
||||
<classEntry path="alternativa.engine3d.objects.Terrain"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeInstanceMaterial"/>
|
||||
<classEntry path="alternativa.engine3d.objects.Mesh"/>
|
||||
<classEntry path="alternativa.engine3d.materials.AGALMiniAssembler"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeInstanceController"/>
|
||||
<classEntry path="alternativa.engine3d.animation.MatrixAnimation"/>
|
||||
<classEntry path="alternativa.engine3d.primitives.GeoSphere"/>
|
||||
<classEntry path="alternativa.engine3d.materials.FillMaterial"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeController"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeArray"/>
|
||||
<classEntry path="alternativa.engine3d.alternativa3d"/>
|
||||
<classEntry path="alternativa.engine3d.animation.keys.ValueKey"/>
|
||||
<classEntry path="alternativa.engine3d.core.Camera3D"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeDocument"/>
|
||||
<classEntry path="alternativa.engine3d.lights.DirectionalLight"/>
|
||||
<classEntry path="alternativa.engine3d.loaders.collada.DaeChannel"/>
|
||||
</includeClasses>
|
||||
<includeResources/>
|
||||
<namespaceManifests/>
|
||||
</flexLibProperties>
|
||||
18
Alternativa3D8/8.0.0.0/.svn/text-base/.project.svn-base
Normal file
18
Alternativa3D8/8.0.0.0/.svn/text-base/.project.svn-base
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Alternativa3D</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>com.adobe.flexbuilder.project.flexbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.adobe.flexbuilder.project.flexlibnature</nature>
|
||||
<nature>com.adobe.flexbuilder.project.actionscriptnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
40
Alternativa3D8/8.0.0.0/.svn/text-base/pom.xml.svn-base
Normal file
40
Alternativa3D8/8.0.0.0/.svn/text-base/pom.xml.svn-base
Normal file
@@ -0,0 +1,40 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>platform.clients.fp10.libraries</groupId>
|
||||
<artifactId>Alternativa3D</artifactId>
|
||||
<packaging>swc</packaging>
|
||||
<version>8.0.0.0</version>
|
||||
<parent>
|
||||
<groupId>platform.clients.fp10.tools.maven</groupId>
|
||||
<artifactId>BasePom</artifactId>
|
||||
<version>2.0.6.0</version>
|
||||
</parent>
|
||||
<scm>
|
||||
<connection>scm:svn:http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0</connection>
|
||||
</scm>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>platform.clients.fp10.libraries</groupId>
|
||||
<artifactId>AlternativaOSGi</artifactId>
|
||||
<type>swc</type>
|
||||
<scope>external</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.adobe.flex.framework</groupId>
|
||||
<artifactId>playerglobal</artifactId>
|
||||
<version>11.6.0</version>
|
||||
<type>swc</type>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>platform.clients.fp10.libraries</groupId>
|
||||
<artifactId>AlternativaOSGi</artifactId>
|
||||
<type>swc</type>
|
||||
<version>2.0.3.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
</project>
|
||||
11
Alternativa3D8/8.0.0.0/META-INF/.svn/all-wcprops
Normal file
11
Alternativa3D8/8.0.0.0/META-INF/.svn/all-wcprops
Normal file
@@ -0,0 +1,11 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 83
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/META-INF
|
||||
END
|
||||
MANIFEST.MF
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 95
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/META-INF/MANIFEST.MF
|
||||
END
|
||||
40
Alternativa3D8/8.0.0.0/META-INF/.svn/entries
Normal file
40
Alternativa3D8/8.0.0.0/META-INF/.svn/entries
Normal file
@@ -0,0 +1,40 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/META-INF
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-09-07T07:58:05.516450Z
|
||||
40837
|
||||
kviring
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
MANIFEST.MF
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
68b329da9893e34099c7d8ad5cb9c940
|
||||
2010-09-07T07:58:05.516450Z
|
||||
40837
|
||||
kviring
|
||||
|
||||
1
Alternativa3D8/8.0.0.0/META-INF/.svn/format
Normal file
1
Alternativa3D8/8.0.0.0/META-INF/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
1
Alternativa3D8/8.0.0.0/META-INF/MANIFEST.MF
Normal file
1
Alternativa3D8/8.0.0.0/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
40
Alternativa3D8/8.0.0.0/pom.xml
Normal file
40
Alternativa3D8/8.0.0.0/pom.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>platform.clients.fp10.libraries</groupId>
|
||||
<artifactId>Alternativa3D</artifactId>
|
||||
<packaging>swc</packaging>
|
||||
<version>8.0.0.0</version>
|
||||
<parent>
|
||||
<groupId>platform.clients.fp10.tools.maven</groupId>
|
||||
<artifactId>BasePom</artifactId>
|
||||
<version>2.0.6.0</version>
|
||||
</parent>
|
||||
<scm>
|
||||
<connection>scm:svn:http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0</connection>
|
||||
</scm>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>platform.clients.fp10.libraries</groupId>
|
||||
<artifactId>AlternativaOSGi</artifactId>
|
||||
<type>swc</type>
|
||||
<scope>external</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.adobe.flex.framework</groupId>
|
||||
<artifactId>playerglobal</artifactId>
|
||||
<version>11.6.0</version>
|
||||
<type>swc</type>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>platform.clients.fp10.libraries</groupId>
|
||||
<artifactId>AlternativaOSGi</artifactId>
|
||||
<type>swc</type>
|
||||
<version>2.0.3.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
</project>
|
||||
BIN
Alternativa3D8/8.0.0.0/src/.DS_Store
vendored
Normal file
BIN
Alternativa3D8/8.0.0.0/src/.DS_Store
vendored
Normal file
Binary file not shown.
5
Alternativa3D8/8.0.0.0/src/.svn/all-wcprops
Normal file
5
Alternativa3D8/8.0.0.0/src/.svn/all-wcprops
Normal file
@@ -0,0 +1,5 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 78
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src
|
||||
END
|
||||
31
Alternativa3D8/8.0.0.0/src/.svn/entries
Normal file
31
Alternativa3D8/8.0.0.0/src/.svn/entries
Normal file
@@ -0,0 +1,31 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-09-07T03:52:15.124692Z
|
||||
40766
|
||||
kviring
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
alternativa
|
||||
dir
|
||||
|
||||
1
Alternativa3D8/8.0.0.0/src/.svn/format
Normal file
1
Alternativa3D8/8.0.0.0/src/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
11
Alternativa3D8/8.0.0.0/src/alternativa/.svn/all-wcprops
Normal file
11
Alternativa3D8/8.0.0.0/src/alternativa/.svn/all-wcprops
Normal file
@@ -0,0 +1,11 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 90
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa
|
||||
END
|
||||
Alternativa3D.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 107
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/Alternativa3D.as
|
||||
END
|
||||
43
Alternativa3D8/8.0.0.0/src/alternativa/.svn/entries
Normal file
43
Alternativa3D8/8.0.0.0/src/alternativa/.svn/entries
Normal file
@@ -0,0 +1,43 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-09-07T03:52:15.124692Z
|
||||
40766
|
||||
kviring
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
Alternativa3D.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
4b1fb7cae69512fe427ddcd0698ff204
|
||||
2010-07-05T10:51:44.109746Z
|
||||
36756
|
||||
andrei
|
||||
|
||||
engine3d
|
||||
dir
|
||||
|
||||
1
Alternativa3D8/8.0.0.0/src/alternativa/.svn/format
Normal file
1
Alternativa3D8/8.0.0.0/src/alternativa/.svn/format
Normal file
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,14 @@
|
||||
package alternativa {
|
||||
|
||||
/**
|
||||
* Класс содержит информацию о версии библиотеки.
|
||||
* Также используется для интеграции библиотеки в среду разработки Adobe Flash.
|
||||
*/
|
||||
public class Alternativa3D {
|
||||
|
||||
/**
|
||||
* Версия библиотеки в формате: поколение.feature-версия.fix-версия
|
||||
*/
|
||||
public static const version:String = "8.0.0";
|
||||
}
|
||||
}
|
||||
14
Alternativa3D8/8.0.0.0/src/alternativa/Alternativa3D.as
Normal file
14
Alternativa3D8/8.0.0.0/src/alternativa/Alternativa3D.as
Normal file
@@ -0,0 +1,14 @@
|
||||
package alternativa {
|
||||
|
||||
/**
|
||||
* Класс содержит информацию о версии библиотеки.
|
||||
* Также используется для интеграции библиотеки в среду разработки Adobe Flash.
|
||||
*/
|
||||
public class Alternativa3D {
|
||||
|
||||
/**
|
||||
* Версия библиотеки в формате: поколение.feature-версия.fix-версия
|
||||
*/
|
||||
public static const version:String = "8.0.0";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 99
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d
|
||||
END
|
||||
alternativa3d.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 116
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/alternativa3d.as
|
||||
END
|
||||
64
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/.svn/entries
Normal file
64
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/.svn/entries
Normal file
@@ -0,0 +1,64 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-09-07T03:52:15.124692Z
|
||||
40766
|
||||
kviring
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
animation
|
||||
dir
|
||||
|
||||
materials
|
||||
dir
|
||||
|
||||
alternativa3d.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
64183f832985e252cc4bc98977484bc9
|
||||
2010-07-05T10:54:14.992364Z
|
||||
36757
|
||||
andrei
|
||||
|
||||
controllers
|
||||
dir
|
||||
|
||||
core
|
||||
dir
|
||||
|
||||
loaders
|
||||
dir
|
||||
|
||||
objects
|
||||
dir
|
||||
|
||||
lights
|
||||
dir
|
||||
|
||||
primitives
|
||||
dir
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,3 @@
|
||||
package alternativa.engine3d {
|
||||
public namespace alternativa3d = "http://alternativaplatform.com/en/alternativa3d";
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package alternativa.engine3d {
|
||||
public namespace alternativa3d = "http://alternativaplatform.com/en/alternativa3d";
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 109
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation
|
||||
END
|
||||
Animation.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 122
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/Animation.as
|
||||
END
|
||||
AnimationState.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 127
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/AnimationState.as
|
||||
END
|
||||
AnimationTimer.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 127
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/AnimationTimer.as
|
||||
END
|
||||
AnimationController.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 132
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/AnimationController.as
|
||||
END
|
||||
MatrixAnimation.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 128
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/MatrixAnimation.as
|
||||
END
|
||||
Track.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 118
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/Track.as
|
||||
END
|
||||
TransformAnimation.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 131
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/TransformAnimation.as
|
||||
END
|
||||
AnimationGroup.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 127
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/AnimationGroup.as
|
||||
END
|
||||
@@ -0,0 +1,127 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-08-10T12:17:35.626193Z
|
||||
38879
|
||||
andrei
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
Animation.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
4f09f5105c18af3e1d1eaeaa3265291a
|
||||
2010-08-10T12:17:35.626193Z
|
||||
38879
|
||||
andrei
|
||||
|
||||
AnimationState.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
d243972e57ee15ebbe7edfdddd727587
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
AnimationTimer.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
64e35461ff8635018335e8f1fea285b8
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
AnimationController.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
8caac737e6d0a3a5b2021035b7d13d5c
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
MatrixAnimation.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
58ed79f98f0be1f2469169849c8fe494
|
||||
2010-08-05T14:27:38.542088Z
|
||||
38487
|
||||
int
|
||||
|
||||
Track.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
95c9471657c79636c7c34b94381f31bd
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
keys
|
||||
dir
|
||||
|
||||
TransformAnimation.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
dcd46a0dda92899b515152a7107750c2
|
||||
2010-08-05T14:27:38.542088Z
|
||||
38487
|
||||
int
|
||||
|
||||
AnimationGroup.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
036c59f75a704fae589ba703afadb7cb
|
||||
2010-08-10T12:17:35.626193Z
|
||||
38879
|
||||
andrei
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,180 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
|
||||
/**
|
||||
* Анимация объекта.
|
||||
*/
|
||||
public class Animation {
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
protected static const WEIGHTS_X:uint = 0;
|
||||
protected static const WEIGHTS_Y:uint = 1;
|
||||
protected static const WEIGHTS_Z:uint = 2;
|
||||
protected static const WEIGHTS_ROT_X:uint = 3;
|
||||
protected static const WEIGHTS_ROT_Y:uint = 4;
|
||||
protected static const WEIGHTS_ROT_Z:uint = 5;
|
||||
protected static const WEIGHTS_SCALE_X:uint = 6;
|
||||
protected static const WEIGHTS_SCALE_Y:uint = 7;
|
||||
protected static const WEIGHTS_SCALE_Z:uint = 8;
|
||||
// protected static const WEIGHTS_BOUND_BOX:uint = 9;
|
||||
|
||||
/**
|
||||
* Анимируемый объект.
|
||||
*/
|
||||
public var object:Object3D = null;
|
||||
|
||||
/**
|
||||
* Вес анимации по отношению к другим анимациям этого параметра.
|
||||
* Анимация с более высоким весом оказывает большее влияние на конечное значение параметра.
|
||||
* Вес наследуется на дочерние анимации.
|
||||
*/
|
||||
public var weight:Number = 1.0;
|
||||
|
||||
/**
|
||||
* Скорость проигрывания анимации. Скорость наследуется на дочерние анимации.
|
||||
*/
|
||||
public var speed:Number = 1.0;
|
||||
|
||||
/**
|
||||
* Длина анимации, включая дочерние анимации.
|
||||
* После изменения длины треков и длины дочерних анимаций необходимо вызвать updateLength().
|
||||
* @see #updateLength()
|
||||
*/
|
||||
public var length:Number = 0.0;
|
||||
|
||||
/**
|
||||
* Создает анимацию
|
||||
*
|
||||
* @param object анимируемый объект
|
||||
* @param weight вес анимации
|
||||
* @param speed скорость проигрывания анимации
|
||||
*/
|
||||
public function Animation(object:Object3D = null, weight:Number = 1.0, speed:Number = 1.0) {
|
||||
this.object = object;
|
||||
this.weight = weight;
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Пересчитывает длину анимации.
|
||||
*/
|
||||
public function updateLength():void {
|
||||
length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчет кадра анимации.
|
||||
*
|
||||
* @param position время кадра
|
||||
*/
|
||||
public function sample(position:Number):void {
|
||||
prepareBlending();
|
||||
blend(position, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготавливает объект к выполнению смешения анимаций.
|
||||
* Для смешения нескольких анимаций, необходимо на каждой из них вызвать prepareBlending() и затем blend().
|
||||
* Для смешения и проигрывания нескольких анимаций может быть удобнее использовать класс AnimationController.
|
||||
*
|
||||
* @see #blend()
|
||||
* @see AnimationController
|
||||
*/
|
||||
public function prepareBlending():void {
|
||||
if (object != null) {
|
||||
if (object.weightsSum != null) {
|
||||
object.weightsSum[0] = 0; object.weightsSum[1] = 0; object.weightsSum[2] = 0;
|
||||
object.weightsSum[3] = 0; object.weightsSum[4] = 0; object.weightsSum[5] = 0;
|
||||
object.weightsSum[6] = 0; object.weightsSum[7] = 0; object.weightsSum[8] = 0;
|
||||
// object.weightsSum[9] = 0;
|
||||
} else {
|
||||
object.weightsSum = new Vector.<Number>(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет смешение анимации с другими анимациями этого параметра.
|
||||
* Перед вызовом этого метода, на всех анимациях которые требуется смешать, нужно вызвать метод prepareBlending().
|
||||
* Не вызывать метод, если вес меньше нуля.
|
||||
* Для смешения и проигрывания нескольких анимаций может быть удобнее использовать класс AnimationController.
|
||||
*
|
||||
* @param position время анимации
|
||||
* @param weight вес анимации
|
||||
*
|
||||
* @see #prepareBlending()
|
||||
* @see AnimationController
|
||||
*/
|
||||
public function blend(position:Number, weight:Number):void {
|
||||
position = (position < 0) ? 0 : (position > length) ? length : position;
|
||||
control(position, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчитывает значение интерполяции параметра для текущей анимации и заданного веса.
|
||||
* @param param индекс параметра
|
||||
* @param weight вес анимации
|
||||
*/
|
||||
protected function calculateBlendInterpolation(param:int, weight:Number):Number {
|
||||
var sum:Number = object.weightsSum[param];
|
||||
sum += weight;
|
||||
object.weightsSum[param] = sum;
|
||||
return weight/sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Реализация расчета кадра анимации.
|
||||
* @param position время кадра анимации
|
||||
* @param weight вес анимации
|
||||
*/
|
||||
protected function control(position:Number, weight:Number):void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает копию анимации. Копия анимации использует общие ключевые кадры с исходной анимацией.
|
||||
*/
|
||||
public function clone():Animation {
|
||||
var cloned:Animation = new Animation(object, weight, speed);
|
||||
cloned.length = length;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает копию анимации, которая будет анимировать указанный объект.
|
||||
*
|
||||
* @param object объект, который должен анимироваться копией текущей анимации
|
||||
* @return копия анимации
|
||||
*/
|
||||
public function copyTo(object:Object3D):Animation {
|
||||
var result:Animation = clone();
|
||||
result.object = object;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает часть анимации в промежутке времени между start и end.
|
||||
* @param start начало части анимации
|
||||
* @param end конец части анимации
|
||||
* @return часть анимации
|
||||
*/
|
||||
public function slice(start:Number, end:Number = Number.MAX_VALUE):Animation {
|
||||
return new Animation(object, weight, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Интерполяция между двумя ненормализованными углами.
|
||||
*/
|
||||
protected function interpolateAngle(angle1:Number, angle2:Number, weight1:Number):Number {
|
||||
const PI2:Number = 2*Math.PI;
|
||||
angle1 = (angle1 > Math.PI) ? angle1%PI2 - PI2 : (angle1 <= -Math.PI) ? (angle1%PI2) + PI2 : angle1;
|
||||
angle2 = (angle2 > Math.PI) ? angle2%PI2 - PI2 : (angle2 <= -Math.PI) ? (angle2%PI2) + PI2 : angle2;
|
||||
var delta:Number = angle2 - angle1;
|
||||
delta = (delta > Math.PI) ? delta - PI2 : (delta < -Math.PI) ? delta + PI2 : delta;
|
||||
return angle1 + weight1 * delta;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
/**
|
||||
* Управляет проигрыванием и смешением анимаций.
|
||||
*/
|
||||
public class AnimationController {
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Включение/выключение контроллера.
|
||||
*/
|
||||
public var enabled:Boolean = true;
|
||||
|
||||
private var _animations:Object = new Object();
|
||||
|
||||
/**
|
||||
* Создает экземпляр контроллера.
|
||||
*/
|
||||
public function AnimationController() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Проиграть анимацию сначала.
|
||||
*
|
||||
* @param name имя анимации для проигрывания
|
||||
* @param fade время в течение которого вес анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function replay(name:String, fade:Number = 0):void {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state == null) {
|
||||
throw new ArgumentError('Animation with name "' + name + '" not found');
|
||||
}
|
||||
state.replay(fade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Продолжить проигрывание анимации с текущей позиции.
|
||||
*
|
||||
* @param name имя анимации для проигрывания
|
||||
* @param fade время в течение которого вес анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function play(name:String, fade:Number = 0):void {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state == null) {
|
||||
throw new ArgumentError('Animation with name "' + name + '" not found');
|
||||
}
|
||||
state.play(fade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Остановить анимацию.
|
||||
*
|
||||
* @param name имя анимации для останова
|
||||
* @param fade время в течение которого вес анимации должен уменьшиться с максимального значения до 0.
|
||||
*/
|
||||
public function stop(name:String, fade:Number = 0):void {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state == null) {
|
||||
throw new ArgumentError('Animation with name "' + name + '" not found');
|
||||
}
|
||||
state.stop(fade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проиграть все анимации сначала.
|
||||
*
|
||||
* @param fade время в течение которого вес каждой анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function replayAll(fade:Number = 0):void {
|
||||
for each (var state:AnimationState in _animations) {
|
||||
state.replay(fade);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Продолжить проигрывание всех анимаций с текущей позиции.
|
||||
*
|
||||
* @param fade время в течение которого вес каждой анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function playAll(fade:Number = 0):void {
|
||||
for each (var state:AnimationState in _animations) {
|
||||
state.play(fade);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Остановить все анимации.
|
||||
*
|
||||
* @param fade время в течение которого вес каждой анимации должен уменьшиться с максимального значения до 0.
|
||||
*/
|
||||
public function stopAll(fade:Number = 0):void {
|
||||
for each (var state:AnimationState in _animations) {
|
||||
state.stop(fade);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Проиграть анимации за прошедшее время и выполнить их смешение.
|
||||
* Для автоматического ежекадрового обновления можно использовать класс AnimationTimer.
|
||||
*
|
||||
* @param interval прошедшее время.
|
||||
*
|
||||
* @see AnimationTimer
|
||||
*/
|
||||
public function update(interval:Number):void {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
var state:AnimationState;
|
||||
for each (state in _animations) {
|
||||
state.prepareBlending();
|
||||
}
|
||||
for each (state in _animations) {
|
||||
state.update(interval);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет анимацию в контроллер и возвращает объект состояния проигрывания анимации.
|
||||
*
|
||||
* @param name имя анимации
|
||||
* @param animation добавляемая анимация
|
||||
* @param loop проиграть анимацию сначала после достижения конца
|
||||
* @return экземляр класса AnimationState через который выполняется управление проигрыванием анимации.
|
||||
*
|
||||
* @see AnimationState
|
||||
*/
|
||||
public function addAnimation(name:String, animation:Animation, loop:Boolean = true):AnimationState {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state != null) {
|
||||
throw new ArgumentError('Animation with this name "' + name + '" already exist');
|
||||
}
|
||||
state = new AnimationState(this, animation, name, loop);
|
||||
_animations[name] = state;
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает анимацию из контроллера.
|
||||
*
|
||||
* @param name имя анимации для удаления.
|
||||
*/
|
||||
public function removeAnimation(name:String):void {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state == null) {
|
||||
throw new ArgumentError('Animation with name"' + name + '" not exists');
|
||||
}
|
||||
delete _animations[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает объект состояния проигрывания анимации по имени.
|
||||
*
|
||||
* @param name имя анимации.
|
||||
*
|
||||
* @see AnimationState
|
||||
*/
|
||||
public function getAnimation(name:String):AnimationState {
|
||||
return _animations[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает словарь со всеми анимациями. Свойство - имя анимации, значение - экземпляр класса AnimationState.
|
||||
*
|
||||
* @see AnimationState
|
||||
*/
|
||||
public function get animations():Object {
|
||||
var result:Object = new Object();
|
||||
for (var name:String in _animations) {
|
||||
result[name] = _animations[name];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
import alternativa.engine3d.core.Object3DContainer;
|
||||
import alternativa.engine3d.objects.Joint;
|
||||
import alternativa.engine3d.objects.Skin;
|
||||
|
||||
/**
|
||||
* Группа анимаций. Предназначена для объединения и синхронизации анимаций.
|
||||
*/
|
||||
public class AnimationGroup extends Animation {
|
||||
|
||||
private var _numAnimations:int = 0;
|
||||
private var _animations:Vector.<Animation> = new Vector.<Animation>();
|
||||
|
||||
/**
|
||||
* Создает группу анимаций.
|
||||
*
|
||||
* @param object анимируемый объект
|
||||
* @param weight вес анимации
|
||||
* @param speed скорость проигрывания анимации
|
||||
*/
|
||||
public function AnimationGroup(object:Object3D = null, weight:Number = 1.0, speed:Number = 1.0) {
|
||||
super(object, weight, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function updateLength():void {
|
||||
super.updateLength();
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
var animation:Animation = _animations[i];
|
||||
animation.updateLength();
|
||||
var len:Number = animation.length;
|
||||
if (len > length) {
|
||||
length = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function prepareBlending():void {
|
||||
super.prepareBlending();
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
_animations[i].prepareBlending();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function blend(position:Number, weight:Number):void {
|
||||
super.blend(position, weight);
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
var animation:Animation = _animations[i];
|
||||
if (animation.weight != 0) {
|
||||
animation.blend(position*animation.speed, weight*animation.weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getObjectNumChildren(object:Object3D):int {
|
||||
if (object is Skin) {
|
||||
return Skin(object).numJoints;
|
||||
} else if (object is Joint) {
|
||||
return Joint(object).numJoints;
|
||||
} else if (object is Object3DContainer) {
|
||||
return Object3DContainer(object).numChildren;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getObjectChildAt(object:Object3D, index:int):Object3D {
|
||||
if (object is Skin) {
|
||||
return Skin(object).getJointAt(index);
|
||||
} else if (object is Joint) {
|
||||
return Joint(object).getJointAt(index);
|
||||
} else if (object is Object3DContainer) {
|
||||
return Object3DContainer(object).getChildAt(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Animation {
|
||||
var cloned:AnimationGroup = new AnimationGroup(object, weight, speed);
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
cloned.addAnimation(_animations[i].clone());
|
||||
}
|
||||
cloned.length = length;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает копию анимации, которая будет анимировать заданную иерархию.
|
||||
* Переносятся и копируются только те анимации, которые анимирует объекты с аналогичными именами
|
||||
* из заданной иерархии.
|
||||
*
|
||||
* @param object объект, который должен анимироваться копией текущей анимации
|
||||
* @return копия анимации
|
||||
*/
|
||||
override public function copyTo(object:Object3D):Animation {
|
||||
if (object == null) {
|
||||
throw new ArgumentError("Object must be not null");
|
||||
}
|
||||
var base:Object3D = this.object;
|
||||
if (base == null) {
|
||||
throw new ArgumentError("Base animation object must be not null");
|
||||
}
|
||||
var group:AnimationGroup = new AnimationGroup(object, weight, speed);
|
||||
copyAnimationForEachObject(object, group);
|
||||
if (group._numAnimations == 1 && group._animations[0].object == object) {
|
||||
// Если только одна анимация и та принадлежит объекту, то вернуть эту анимацию
|
||||
return group._animations[0];
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
private function copyAnimationForEachObject(object:Object3D, group:AnimationGroup):void {
|
||||
var i:int;
|
||||
var name:String = object.name;
|
||||
var from:Object3D;
|
||||
if (name != null && name.length > 0) {
|
||||
collectAnimations(name, this, group, object);
|
||||
}
|
||||
var count:int = getObjectNumChildren(object);
|
||||
for (i = 0; i < count; i++) {
|
||||
var child:Object3D = getObjectChildAt(object, i);
|
||||
copyAnimationForEachObject(child, group);
|
||||
}
|
||||
}
|
||||
|
||||
private function collectAnimations(name:String, animations:AnimationGroup, collector:AnimationGroup, object:Object3D, from:Object3D = null):Object3D {
|
||||
for (var i:int = 0; i < animations._numAnimations; i++) {
|
||||
var animation:Animation = animations._animations[i];
|
||||
var group:AnimationGroup = animation as AnimationGroup;
|
||||
if (group != null) {
|
||||
from = collectAnimations(name, group, collector, object, from);
|
||||
} else {
|
||||
if (animation.object != null && animation.object.name == name && (from == null || animation.object == from)) {
|
||||
from = animation.object;
|
||||
collector.addAnimation(animation.copyTo(object));
|
||||
}
|
||||
}
|
||||
}
|
||||
return from;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function slice(start:Number, end:Number = Number.MAX_VALUE):Animation {
|
||||
var group:AnimationGroup = new AnimationGroup(object, weight, speed);
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
var animation:Animation = _animations[i];
|
||||
group.addAnimation(animation.slice(start * animation.speed, end * animation.speed));
|
||||
}
|
||||
group.updateLength();
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет дочернюю анимацию и обновляет длину анимации после этого.
|
||||
*/
|
||||
public function addAnimation(animation:Animation):Animation {
|
||||
if (animation == null) {
|
||||
throw new Error("Animation cannot be null");
|
||||
}
|
||||
_animations[_numAnimations++] = animation;
|
||||
if (animation.length > length) {
|
||||
length = animation.length;
|
||||
}
|
||||
return animation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает дочернюю анимацию и обновляет длину анимации.
|
||||
*/
|
||||
public function removeAnimation(animation:Animation):Animation {
|
||||
var index:int = _animations.indexOf(animation);
|
||||
if (index < 0) throw new ArgumentError("Animation not found");
|
||||
_numAnimations--;
|
||||
var j:int = index + 1;
|
||||
while (index < _numAnimations) {
|
||||
_animations[index] = _animations[j];
|
||||
index++;
|
||||
j++;
|
||||
}
|
||||
_animations.length = _numAnimations;
|
||||
// Пересчитываем длину
|
||||
length = 0;
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
var anim:Animation = _animations[i];
|
||||
if (anim.length > length) {
|
||||
length = anim.length;
|
||||
}
|
||||
}
|
||||
return animation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Количество дочерних анимаций.
|
||||
*/
|
||||
public function get numAnimations():int {
|
||||
return _numAnimations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает анимацию по индексу.
|
||||
*/
|
||||
public function getAnimationAt(index:int):Animation {
|
||||
return _animations[index];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
/**
|
||||
* Cостояние проигрывания анимации в контроллере.
|
||||
*/
|
||||
public final class AnimationState {
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Проигрываемая анимация.
|
||||
*/
|
||||
public var animation:Animation;
|
||||
|
||||
/**
|
||||
* Зацикленность анимации. Зацикленная анимация будет проигрываться сначала после достижения конца.
|
||||
*/
|
||||
public var loop:Boolean;
|
||||
|
||||
/**
|
||||
* Для незацикленной анимации задает время с отсчетом от конца анимации после которого начнется затухание анимации.
|
||||
* 0 - без затухания, 1 - затухание с начала анимации.
|
||||
*/
|
||||
public var endingFadeOut:Number = 0;
|
||||
|
||||
private var fadeInTime:Number;
|
||||
private var fadedIn:Boolean;
|
||||
private var fadeInPosition:Number;
|
||||
private var fadeOutTime:Number;
|
||||
private var fadedOut:Boolean;
|
||||
private var fadeOutPosition:Number;
|
||||
|
||||
private var manualControl:Boolean = false;
|
||||
|
||||
private var _controller:AnimationController;
|
||||
|
||||
private var _name:String;
|
||||
private var _played:Boolean = false;
|
||||
private var _position:Number = 0;
|
||||
|
||||
/**
|
||||
* Конструктор состояния анимации, вызывается в AnimationController.
|
||||
*
|
||||
* @see AnimationController
|
||||
*/
|
||||
public function AnimationState(controller:AnimationController, animation:Animation, name:String, loop:Boolean) {
|
||||
this.animation = animation;
|
||||
this._controller = controller;
|
||||
this._name = name;
|
||||
this.loop = loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проиграть анимацию сначала.
|
||||
*
|
||||
* @param fade время в течение которого вес анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function replay(fade:Number = 0):void {
|
||||
if (!_played) {
|
||||
play(fade);
|
||||
_position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Продолжить проигрывание анимации с текущей позиции.
|
||||
*
|
||||
* @param fade время в течение которого вес анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function play(fade:Number = 0):void {
|
||||
if (!_played) {
|
||||
_played = true;
|
||||
fadeInTime = fade;
|
||||
fadedIn = true;
|
||||
if (fadedOut) {
|
||||
fadeInPosition = fadeInTime*(1 - fadeOutPosition/fadeOutTime);
|
||||
fadedOut = false;
|
||||
} else {
|
||||
fadeInPosition = 0;
|
||||
}
|
||||
manualControl = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Остановить проигрывание анимации.
|
||||
*
|
||||
* @param fade время в течение которого вес анимации должен уменьшиться с максимального значения до 0.
|
||||
*/
|
||||
public function stop(fade:Number = 0):void {
|
||||
if (_played) {
|
||||
_played = false;
|
||||
fadeOutTime = fade;
|
||||
if (fadedIn) {
|
||||
fadeOutPosition = fadeOutTime*(1 - fadeInPosition/fadeInTime);
|
||||
fadedIn = false;
|
||||
fadedOut = true;
|
||||
} else {
|
||||
if (!fadedOut) {
|
||||
fadeOutPosition = 0;
|
||||
fadedOut = true;
|
||||
}
|
||||
}
|
||||
manualControl = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function prepareBlending():void {
|
||||
if (animation != null) {
|
||||
animation.prepareBlending();
|
||||
}
|
||||
}
|
||||
|
||||
private function loopPosition():void {
|
||||
if (_position < 0) {
|
||||
// _position = (length <= 0) ? 0 : _position % length;
|
||||
_position = 0;
|
||||
} else {
|
||||
if (_position >= animation.length) {
|
||||
_position = (animation.length <= 0) ? 0 : _position % animation.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function fading(position:Number):Number {
|
||||
if (position > 1) {
|
||||
return 1;
|
||||
}
|
||||
if (position < 0) {
|
||||
return 0;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function update(interval:Number):void {
|
||||
if (animation == null) {
|
||||
return;
|
||||
}
|
||||
var weight:Number = animation.weight;
|
||||
if (_played) {
|
||||
_position += interval*animation.speed;
|
||||
if (loop) {
|
||||
loopPosition();
|
||||
if (fadedIn) {
|
||||
fadeInPosition += interval;
|
||||
if (fadeInPosition < fadeInTime) {
|
||||
weight *= fading(fadeInPosition/fadeInTime);
|
||||
} else {
|
||||
fadedIn = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_position < 0) {
|
||||
_position = 0;
|
||||
if (interval < 0) {
|
||||
_played = false;
|
||||
}
|
||||
weight = 0;
|
||||
} else {
|
||||
if (_position > animation.length) {
|
||||
if (interval > 0) {
|
||||
_position = 0;
|
||||
_played = false;
|
||||
} else {
|
||||
_position = animation.length;
|
||||
}
|
||||
weight = 0;
|
||||
} else {
|
||||
if ((_position/animation.length + endingFadeOut) > 1) {
|
||||
fadedOut = true;
|
||||
fadeOutTime = endingFadeOut;
|
||||
fadeOutPosition = _position/animation.length + endingFadeOut - 1;
|
||||
} else {
|
||||
fadedOut = false;
|
||||
}
|
||||
if (fadedIn) {
|
||||
fadeInPosition += interval;
|
||||
}
|
||||
if ((fadedIn && (fadeInPosition < fadeInTime)) && fadedOut) {
|
||||
var w1:Number = fading(fadeInPosition/fadeInTime);
|
||||
var w2:Number = fading(1 - fadeOutPosition/fadeOutTime);
|
||||
if (w1 < w2) {
|
||||
weight *= w1;
|
||||
} else {
|
||||
weight *= w2;
|
||||
fadedIn = false;
|
||||
}
|
||||
} else {
|
||||
if (fadedIn) {
|
||||
if (fadeInPosition < fadeInTime) {
|
||||
weight *= fading(fadeInPosition/fadeInTime);
|
||||
} else {
|
||||
fadedIn = false;
|
||||
}
|
||||
} else if (fadedOut) {
|
||||
weight *= fading(1 - fadeOutPosition/fadeOutTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!manualControl) {
|
||||
if (fadedOut) {
|
||||
_position += interval*animation.speed;
|
||||
if (loop) {
|
||||
loopPosition();
|
||||
} else {
|
||||
if (_position < 0) {
|
||||
_position = 0;
|
||||
} else {
|
||||
if (_position >= animation.length) {
|
||||
_position = animation.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
fadeOutPosition += interval;
|
||||
if (fadeOutPosition < fadeOutTime) {
|
||||
weight *= fading(1 - fadeOutPosition/fadeOutTime);
|
||||
} else {
|
||||
fadedOut = false;
|
||||
weight = 0;
|
||||
}
|
||||
} else {
|
||||
weight = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (weight != 0) {
|
||||
animation.blend(_position, weight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Контроллер, управляющий воспроизведением анимации.
|
||||
*/
|
||||
public function get controller():AnimationController {
|
||||
return _controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Имя анимации в контроллере.
|
||||
*/
|
||||
public function get name():String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проигрывается анимация в данный момент или нет.
|
||||
*/
|
||||
public function get played():Boolean {
|
||||
return _played;
|
||||
}
|
||||
|
||||
/**
|
||||
* Позиция проигрывания анимации.
|
||||
*/
|
||||
public function get position():Number {
|
||||
return _position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set position(value:Number):void {
|
||||
_position = value;
|
||||
manualControl = true;
|
||||
_played = false;
|
||||
fadedIn = false;
|
||||
fadedOut = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import flash.utils.getTimer;
|
||||
|
||||
/**
|
||||
* Выполняет ежекадровое обновление контроллеров.
|
||||
*/
|
||||
public class AnimationTimer {
|
||||
|
||||
/**
|
||||
* Соотношение виртуального времени реальному
|
||||
*/
|
||||
public var timeScale:Number = 1.0;
|
||||
|
||||
private var _numControllers:int;
|
||||
private var _controllers:Vector.<AnimationController> = new Vector.<AnimationController>();
|
||||
|
||||
private var lastTime:int = -1;
|
||||
|
||||
/**
|
||||
* Создает экземпляр контроллера.
|
||||
*/
|
||||
public function AnimationTimer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Начинает отсчет времени.
|
||||
*/
|
||||
public function start():void {
|
||||
lastTime = getTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет контроллеры с времени последнего вызова start() или update().
|
||||
*
|
||||
* @see #start()
|
||||
*/
|
||||
public function update():void {
|
||||
if (lastTime >= 0) {
|
||||
var time:int = getTimer();
|
||||
var interval:Number = 0.001*timeScale*(time - lastTime);
|
||||
for (var i:int = 0; i < _numControllers; i++) {
|
||||
var controller:AnimationController = _controllers[i];
|
||||
controller.update(interval);
|
||||
}
|
||||
lastTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Приостанавливает отсчет времени.
|
||||
*/
|
||||
public function stop():void {
|
||||
lastTime = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает <code>true</code> если таймер в данный момент остановлен.
|
||||
*/
|
||||
public function get stoped():Boolean {
|
||||
return lastTime == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет контроллер.
|
||||
*/
|
||||
public function addController(controller:AnimationController):AnimationController {
|
||||
if (controller == null) {
|
||||
throw new Error("Controller cannot be null");
|
||||
}
|
||||
_controllers[_numControllers++] = controller;
|
||||
return controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает контроллер.
|
||||
*/
|
||||
public function removeController(controller:AnimationController):AnimationController {
|
||||
var index:int = _controllers.indexOf(controller);
|
||||
if (index < 0) throw new ArgumentError("Controller not found");
|
||||
_numControllers--;
|
||||
var j:int = index + 1;
|
||||
while (index < _numControllers) {
|
||||
_controllers[index] = _controllers[j];
|
||||
index++;
|
||||
j++;
|
||||
}
|
||||
_controllers.length = _numControllers;
|
||||
return controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает количество контроллеров.
|
||||
*/
|
||||
public function get numControllers():int {
|
||||
return _numControllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает контроллер по индексу.
|
||||
*
|
||||
* @param index индекс контроллера.
|
||||
*/
|
||||
public function getControllerAt(index:int):AnimationController {
|
||||
return _controllers[index];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.animation.keys.MatrixKey;
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
/**
|
||||
* Анимация матрицы объекта.
|
||||
*/
|
||||
public class MatrixAnimation extends Animation {
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами анимации матрицы.
|
||||
*/
|
||||
public var matrix:Track;
|
||||
|
||||
private var matrixKey:MatrixKey = new MatrixKey(0, null);
|
||||
|
||||
/**
|
||||
* Создает новый экземпляр объекта.
|
||||
*
|
||||
* @param object объект, матрица которого анимируется.
|
||||
* @param weight вес анимации.
|
||||
* @param speed скорость проигрывания анимации.
|
||||
*/
|
||||
public function MatrixAnimation(object:Object3D = null, weight:Number = 1.0, speed:Number = 1.0) {
|
||||
super(object, weight, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function control(position:Number, weight:Number):void {
|
||||
if (matrix != null && object != null) {
|
||||
matrix.getKey(position, matrixKey);
|
||||
var t:Vector3D = matrixKey.translation;
|
||||
var r:Vector3D = matrixKey.rotation;
|
||||
var s:Vector3D = matrixKey.scale;
|
||||
var c:Number;
|
||||
c = calculateBlendInterpolation(WEIGHTS_X, weight);
|
||||
object.x = (1 - c)*object.x + c*t.x;
|
||||
c = calculateBlendInterpolation(WEIGHTS_Y, weight);
|
||||
object.y = (1 - c)*object.y + c*t.y;
|
||||
c = calculateBlendInterpolation(WEIGHTS_Z, weight);
|
||||
object.z = (1 - c)*object.z + c*t.z;
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_X, weight);
|
||||
object.rotationX = interpolateAngle(object.rotationX, r.x, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Y, weight);
|
||||
object.rotationY = interpolateAngle(object.rotationY, r.y, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Z, weight);
|
||||
object.rotationZ = interpolateAngle(object.rotationZ, r.z, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_X, weight);
|
||||
object.scaleX = (1 - c)*object.scaleX + c*s.x;
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Y, weight);
|
||||
object.scaleY = (1 - c)*object.scaleY + c*s.y;
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Z, weight);
|
||||
object.scaleZ = (1 - c)*object.scaleZ + c*s.z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Animation {
|
||||
var cloned:MatrixAnimation = new MatrixAnimation(object, weight, speed);
|
||||
cloned.matrix = matrix;
|
||||
cloned.length = length;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function slice(start:Number, end:Number = Number.MAX_VALUE):Animation {
|
||||
var animation:MatrixAnimation = new MatrixAnimation(object, weight, speed);
|
||||
animation.matrix = (matrix != null) ? matrix.slice(start, end) : null;
|
||||
animation.updateLength();
|
||||
return animation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function updateLength():void {
|
||||
super.updateLength();
|
||||
if (matrix != null) {
|
||||
var len:Number = matrix.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.animation.keys.Key;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами.
|
||||
*/
|
||||
public class Track {
|
||||
|
||||
/**
|
||||
* Ключевые кадры.
|
||||
*/
|
||||
public var keyList:Key;
|
||||
|
||||
/**
|
||||
* Добавляет ключевой кадр.
|
||||
*/
|
||||
public function addKey(key:Key):void {
|
||||
key.next = keyList;
|
||||
keyList = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сортирует ключевые кадры по времени.
|
||||
*/
|
||||
public function sortKeys():void {
|
||||
keyList = sortKeysByTime(keyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает кадр соответствующий заданному времени.
|
||||
*
|
||||
* @param time время кадра.
|
||||
* @param key если не <code>null</code>, результат будет записан в этот объект.
|
||||
*/
|
||||
public function getKey(time:Number, key:Key = null):Key {
|
||||
var prev:Key;
|
||||
var next:Key = keyList;
|
||||
while (next != null && next.time < time) {
|
||||
prev = next;
|
||||
next = next.next;
|
||||
}
|
||||
if (prev != null) return prev.interpolate(time, next, key);
|
||||
if (next != null) return next.interpolate(time, null, key);
|
||||
return null;
|
||||
}
|
||||
|
||||
private function sortKeysByTime(list:Key):Key {
|
||||
var left:Key = list;
|
||||
var right:Key = list.next;
|
||||
while (right != null && right.next != null) {
|
||||
list = list.next;
|
||||
right = right.next.next;
|
||||
}
|
||||
right = list.next;
|
||||
list.next = null;
|
||||
if (left.next != null) {
|
||||
left = sortKeysByTime(left);
|
||||
}
|
||||
if (right.next != null) {
|
||||
right = sortKeysByTime(right);
|
||||
}
|
||||
var flag:Boolean = left.time < right.time;
|
||||
if (flag) {
|
||||
list = left;
|
||||
left = left.next;
|
||||
} else {
|
||||
list = right;
|
||||
right = right.next;
|
||||
}
|
||||
var last:Key = list;
|
||||
while (true) {
|
||||
if (left == null) {
|
||||
last.next = right;
|
||||
return list;
|
||||
} else if (right == null) {
|
||||
last.next = left;
|
||||
return list;
|
||||
}
|
||||
if (flag) {
|
||||
if (left.time < right.time) {
|
||||
last = left;
|
||||
left = left.next;
|
||||
} else {
|
||||
last.next = right;
|
||||
last = right;
|
||||
right = right.next;
|
||||
flag = false;
|
||||
}
|
||||
} else {
|
||||
if (right.time < left.time) {
|
||||
last = right;
|
||||
right = right.next;
|
||||
} else {
|
||||
last.next = left;
|
||||
last = left;
|
||||
left = left.next;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает время последнего ключевого кадра.
|
||||
*/
|
||||
public function get length():Number {
|
||||
if (keyList != null) {
|
||||
var key:Key = keyList;
|
||||
while (key.next != null) {
|
||||
key = key.next;
|
||||
}
|
||||
return key.time;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает часть трека в промежутке между start и end.
|
||||
* Ключи в треке должны быть отсортированы.
|
||||
*
|
||||
* @param start начало времени промежутка трека
|
||||
* @param end конец времени промежутка трека
|
||||
* @return часть трека
|
||||
*/
|
||||
public function slice(start:Number, end:Number = Number.MAX_VALUE):Track {
|
||||
var track:Track = new Track();
|
||||
var prev:Key;
|
||||
var next:Key = keyList;
|
||||
while (next != null && next.time <= start) {
|
||||
prev = next;
|
||||
next = next.next;
|
||||
}
|
||||
var key:Key;
|
||||
if (prev != null) {
|
||||
key = prev.interpolate(start, next);
|
||||
} else {
|
||||
if (next != null) {
|
||||
// Время до начала анимации
|
||||
key = next.interpolate(next.time, next.next);
|
||||
start = next.time;
|
||||
} else {
|
||||
// Пустой трек
|
||||
return track;
|
||||
}
|
||||
}
|
||||
key.time -= start;
|
||||
track.keyList = key;
|
||||
prev = next;
|
||||
next = next.next;
|
||||
while (next != null && next.time < end) {
|
||||
key.next = next.interpolate(next.time, next.next);
|
||||
key = key.next;
|
||||
key.time -= start;
|
||||
prev = next;
|
||||
next = next.next;
|
||||
}
|
||||
if (next != null) {
|
||||
// Время между prev.time и next.time
|
||||
key.next = prev.interpolate(end, next);
|
||||
key.next.time -= start;
|
||||
} else {
|
||||
// Последний ключ
|
||||
key.next = prev.interpolate(prev.time, null);
|
||||
key.next.time -= start;
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.animation.keys.PointKey;
|
||||
import alternativa.engine3d.animation.keys.ValueKey;
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
/**
|
||||
* Анимация компонентов положения и ориентации объекта.
|
||||
*/
|
||||
public class TransformAnimation extends Animation {
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами положения объекта.
|
||||
*/
|
||||
public var translation:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами вращения объекта.
|
||||
*/
|
||||
public var rotation:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами масштаба объекта.
|
||||
*/
|
||||
public var scale:Track;
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами перемещения объекта по оси X.
|
||||
*/
|
||||
public var x:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами перемещения объекта по оси Y.
|
||||
*/
|
||||
public var y:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами перемещения объекта по оси Z.
|
||||
*/
|
||||
public var z:Track;
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами вращения объекта по оси X.
|
||||
*/
|
||||
public var rotationX:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами вращения объекта по оси Y.
|
||||
*/
|
||||
public var rotationY:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами вращения объекта по оси Z.
|
||||
*/
|
||||
public var rotationZ:Track;
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами масштаба объекта по оси X.
|
||||
*/
|
||||
public var scaleX:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами масштаба объекта по оси Y.
|
||||
*/
|
||||
public var scaleY:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами масштаба объекта по оси Z.
|
||||
*/
|
||||
public var scaleZ:Track;
|
||||
|
||||
private var valueKey:ValueKey = new ValueKey(0, 0);
|
||||
private var pointKey:PointKey = new PointKey(0, 0, 0, 0);
|
||||
|
||||
/**
|
||||
* Конструктор анимации.
|
||||
*
|
||||
* @param object анимируемый объект.
|
||||
* @param weight вес анимации.
|
||||
* @param speed скорость проигрывания анимации.
|
||||
*/
|
||||
public function TransformAnimation(object:Object3D = null, weight:Number = 1.0, speed:Number = 1.0) {
|
||||
super(object, weight, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function control(position:Number, weight:Number):void {
|
||||
if (object == null) {
|
||||
return;
|
||||
}
|
||||
var c:Number;
|
||||
//var t:Vector3D = object.translation;
|
||||
//var r:Vector3D = object.rotation;
|
||||
//var s:Vector3D = object.scale;
|
||||
if (translation != null) {
|
||||
translation.getKey(position, pointKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_X, weight);
|
||||
object.x = (1 - c)*object.x + c*pointKey.x;
|
||||
c = calculateBlendInterpolation(WEIGHTS_Y, weight);
|
||||
object.y = (1 - c)*object.y + c*pointKey.y;
|
||||
c = calculateBlendInterpolation(WEIGHTS_Z, weight);
|
||||
object.z = (1 - c)*object.z + c*pointKey.z;
|
||||
} else {
|
||||
if (x != null) {
|
||||
x.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_X, weight);
|
||||
object.x = (1 - c)*object.x + c*valueKey.value;
|
||||
}
|
||||
if (y != null) {
|
||||
y.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_Y, weight);
|
||||
object.y = (1 - c)*object.y + c*valueKey.value;
|
||||
}
|
||||
if (z != null) {
|
||||
z.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_Z, weight);
|
||||
object.z = (1 - c)*object.z + c*valueKey.value;
|
||||
}
|
||||
}
|
||||
if (rotation != null) {
|
||||
rotation.getKey(position, pointKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_X, weight);
|
||||
object.rotationX = interpolateAngle(object.rotationX, pointKey.x, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Y, weight);
|
||||
object.rotationY = interpolateAngle(object.rotationY, pointKey.y, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Z, weight);
|
||||
object.rotationZ = interpolateAngle(object.rotationZ, pointKey.z, c);
|
||||
} else {
|
||||
if (rotationX != null) {
|
||||
rotationX.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_X, weight);
|
||||
object.rotationX = interpolateAngle(object.rotationX, valueKey.value, c);
|
||||
}
|
||||
if (rotationY != null) {
|
||||
rotationY.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Y, weight);
|
||||
object.rotationY = interpolateAngle(object.rotationY, valueKey.value, c);
|
||||
}
|
||||
if (rotationZ != null) {
|
||||
rotationZ.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Z, weight);
|
||||
object.rotationZ = interpolateAngle(object.rotationZ, valueKey.value, c);
|
||||
}
|
||||
}
|
||||
if (scale != null) {
|
||||
scale.getKey(position, pointKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_X, weight);
|
||||
object.scaleX = (1 - c)*object.scaleX + c*pointKey.x;
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Y, weight);
|
||||
object.scaleY = (1 - c)*object.scaleY + c*pointKey.y;
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Z, weight);
|
||||
object.scaleZ = (1 - c)*object.scaleZ + c*pointKey.z;
|
||||
} else {
|
||||
if (scaleX != null) {
|
||||
scaleX.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_X, weight);
|
||||
object.scaleX = (1 - c)*object.scaleX + c*valueKey.value;
|
||||
}
|
||||
if (scaleY != null) {
|
||||
scaleY.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Y, weight);
|
||||
object.scaleY = (1 - c)*object.scaleY + c*valueKey.value;
|
||||
}
|
||||
if (scaleZ != null) {
|
||||
scaleZ.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Z, weight);
|
||||
object.scaleZ = (1 - c)*object.scaleZ + c*valueKey.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function slice(start:Number, end:Number = Number.MAX_VALUE):Animation {
|
||||
var animation:TransformAnimation = new TransformAnimation(object, weight, speed);
|
||||
animation.translation = (translation != null) ? translation.slice(start, end) : null;
|
||||
animation.rotation = (rotation != null) ? rotation.slice(start, end) : null;
|
||||
animation.scale = (scale != null) ? scale.slice(start, end) : null;
|
||||
animation.x = (x != null) ? x.slice(start, end) : null;
|
||||
animation.y = (y != null) ? y.slice(start, end) : null;
|
||||
animation.z = (z != null) ? z.slice(start, end) : null;
|
||||
animation.rotationX = (rotationX != null) ? rotationX.slice(start, end) : null;
|
||||
animation.rotationY = (rotationY != null) ? rotationY.slice(start, end) : null;
|
||||
animation.rotationZ = (rotationZ != null) ? rotationZ.slice(start, end) : null;
|
||||
animation.scaleX = (scaleX != null) ? scaleX.slice(start, end) : null;
|
||||
animation.scaleY = (scaleY != null) ? scaleY.slice(start, end) : null;
|
||||
animation.scaleZ = (scaleZ != null) ? scaleZ.slice(start, end) : null;
|
||||
animation.updateLength();
|
||||
return animation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function updateLength():void {
|
||||
super.updateLength();
|
||||
var len:Number;
|
||||
if (translation != null) {
|
||||
len = translation.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (rotation != null) {
|
||||
len = rotation.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (scale != null) {
|
||||
len = scale.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (x != null) {
|
||||
len = x.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (y != null) {
|
||||
len = y.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (z != null) {
|
||||
len = z.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (rotationX != null) {
|
||||
len = rotationX.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (rotationY != null) {
|
||||
len = rotationY.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (rotationZ != null) {
|
||||
len = rotationZ.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (scaleX != null) {
|
||||
len = scaleX.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (scaleY != null) {
|
||||
len = scaleY.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (scaleZ != null) {
|
||||
len = scaleZ.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Animation {
|
||||
var cloned:TransformAnimation = new TransformAnimation(object, weight, speed);
|
||||
cloned.translation = translation;
|
||||
cloned.rotation = rotation;
|
||||
cloned.scale = scale;
|
||||
cloned.x = x;
|
||||
cloned.y = y;
|
||||
cloned.z = z;
|
||||
cloned.rotationX = rotationX;
|
||||
cloned.rotationY = rotationY;
|
||||
cloned.rotationZ = rotationZ;
|
||||
cloned.scaleX = scaleX;
|
||||
cloned.scaleY = scaleY;
|
||||
cloned.scaleZ = scaleZ;
|
||||
cloned.length = length;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
|
||||
/**
|
||||
* Анимация объекта.
|
||||
*/
|
||||
public class Animation {
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
protected static const WEIGHTS_X:uint = 0;
|
||||
protected static const WEIGHTS_Y:uint = 1;
|
||||
protected static const WEIGHTS_Z:uint = 2;
|
||||
protected static const WEIGHTS_ROT_X:uint = 3;
|
||||
protected static const WEIGHTS_ROT_Y:uint = 4;
|
||||
protected static const WEIGHTS_ROT_Z:uint = 5;
|
||||
protected static const WEIGHTS_SCALE_X:uint = 6;
|
||||
protected static const WEIGHTS_SCALE_Y:uint = 7;
|
||||
protected static const WEIGHTS_SCALE_Z:uint = 8;
|
||||
// protected static const WEIGHTS_BOUND_BOX:uint = 9;
|
||||
|
||||
/**
|
||||
* Анимируемый объект.
|
||||
*/
|
||||
public var object:Object3D = null;
|
||||
|
||||
/**
|
||||
* Вес анимации по отношению к другим анимациям этого параметра.
|
||||
* Анимация с более высоким весом оказывает большее влияние на конечное значение параметра.
|
||||
* Вес наследуется на дочерние анимации.
|
||||
*/
|
||||
public var weight:Number = 1.0;
|
||||
|
||||
/**
|
||||
* Скорость проигрывания анимации. Скорость наследуется на дочерние анимации.
|
||||
*/
|
||||
public var speed:Number = 1.0;
|
||||
|
||||
/**
|
||||
* Длина анимации, включая дочерние анимации.
|
||||
* После изменения длины треков и длины дочерних анимаций необходимо вызвать updateLength().
|
||||
* @see #updateLength()
|
||||
*/
|
||||
public var length:Number = 0.0;
|
||||
|
||||
/**
|
||||
* Создает анимацию
|
||||
*
|
||||
* @param object анимируемый объект
|
||||
* @param weight вес анимации
|
||||
* @param speed скорость проигрывания анимации
|
||||
*/
|
||||
public function Animation(object:Object3D = null, weight:Number = 1.0, speed:Number = 1.0) {
|
||||
this.object = object;
|
||||
this.weight = weight;
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Пересчитывает длину анимации.
|
||||
*/
|
||||
public function updateLength():void {
|
||||
length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчет кадра анимации.
|
||||
*
|
||||
* @param position время кадра
|
||||
*/
|
||||
public function sample(position:Number):void {
|
||||
prepareBlending();
|
||||
blend(position, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Подготавливает объект к выполнению смешения анимаций.
|
||||
* Для смешения нескольких анимаций, необходимо на каждой из них вызвать prepareBlending() и затем blend().
|
||||
* Для смешения и проигрывания нескольких анимаций может быть удобнее использовать класс AnimationController.
|
||||
*
|
||||
* @see #blend()
|
||||
* @see AnimationController
|
||||
*/
|
||||
public function prepareBlending():void {
|
||||
if (object != null) {
|
||||
if (object.weightsSum != null) {
|
||||
object.weightsSum[0] = 0; object.weightsSum[1] = 0; object.weightsSum[2] = 0;
|
||||
object.weightsSum[3] = 0; object.weightsSum[4] = 0; object.weightsSum[5] = 0;
|
||||
object.weightsSum[6] = 0; object.weightsSum[7] = 0; object.weightsSum[8] = 0;
|
||||
// object.weightsSum[9] = 0;
|
||||
} else {
|
||||
object.weightsSum = new Vector.<Number>(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет смешение анимации с другими анимациями этого параметра.
|
||||
* Перед вызовом этого метода, на всех анимациях которые требуется смешать, нужно вызвать метод prepareBlending().
|
||||
* Не вызывать метод, если вес меньше нуля.
|
||||
* Для смешения и проигрывания нескольких анимаций может быть удобнее использовать класс AnimationController.
|
||||
*
|
||||
* @param position время анимации
|
||||
* @param weight вес анимации
|
||||
*
|
||||
* @see #prepareBlending()
|
||||
* @see AnimationController
|
||||
*/
|
||||
public function blend(position:Number, weight:Number):void {
|
||||
position = (position < 0) ? 0 : (position > length) ? length : position;
|
||||
control(position, weight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчитывает значение интерполяции параметра для текущей анимации и заданного веса.
|
||||
* @param param индекс параметра
|
||||
* @param weight вес анимации
|
||||
*/
|
||||
protected function calculateBlendInterpolation(param:int, weight:Number):Number {
|
||||
var sum:Number = object.weightsSum[param];
|
||||
sum += weight;
|
||||
object.weightsSum[param] = sum;
|
||||
return weight/sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Реализация расчета кадра анимации.
|
||||
* @param position время кадра анимации
|
||||
* @param weight вес анимации
|
||||
*/
|
||||
protected function control(position:Number, weight:Number):void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает копию анимации. Копия анимации использует общие ключевые кадры с исходной анимацией.
|
||||
*/
|
||||
public function clone():Animation {
|
||||
var cloned:Animation = new Animation(object, weight, speed);
|
||||
cloned.length = length;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает копию анимации, которая будет анимировать указанный объект.
|
||||
*
|
||||
* @param object объект, который должен анимироваться копией текущей анимации
|
||||
* @return копия анимации
|
||||
*/
|
||||
public function copyTo(object:Object3D):Animation {
|
||||
var result:Animation = clone();
|
||||
result.object = object;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает часть анимации в промежутке времени между start и end.
|
||||
* @param start начало части анимации
|
||||
* @param end конец части анимации
|
||||
* @return часть анимации
|
||||
*/
|
||||
public function slice(start:Number, end:Number = Number.MAX_VALUE):Animation {
|
||||
return new Animation(object, weight, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Интерполяция между двумя ненормализованными углами.
|
||||
*/
|
||||
protected function interpolateAngle(angle1:Number, angle2:Number, weight1:Number):Number {
|
||||
const PI2:Number = 2*Math.PI;
|
||||
angle1 = (angle1 > Math.PI) ? angle1%PI2 - PI2 : (angle1 <= -Math.PI) ? (angle1%PI2) + PI2 : angle1;
|
||||
angle2 = (angle2 > Math.PI) ? angle2%PI2 - PI2 : (angle2 <= -Math.PI) ? (angle2%PI2) + PI2 : angle2;
|
||||
var delta:Number = angle2 - angle1;
|
||||
delta = (delta > Math.PI) ? delta - PI2 : (delta < -Math.PI) ? delta + PI2 : delta;
|
||||
return angle1 + weight1 * delta;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
/**
|
||||
* Управляет проигрыванием и смешением анимаций.
|
||||
*/
|
||||
public class AnimationController {
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Включение/выключение контроллера.
|
||||
*/
|
||||
public var enabled:Boolean = true;
|
||||
|
||||
private var _animations:Object = new Object();
|
||||
|
||||
/**
|
||||
* Создает экземпляр контроллера.
|
||||
*/
|
||||
public function AnimationController() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Проиграть анимацию сначала.
|
||||
*
|
||||
* @param name имя анимации для проигрывания
|
||||
* @param fade время в течение которого вес анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function replay(name:String, fade:Number = 0):void {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state == null) {
|
||||
throw new ArgumentError('Animation with name "' + name + '" not found');
|
||||
}
|
||||
state.replay(fade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Продолжить проигрывание анимации с текущей позиции.
|
||||
*
|
||||
* @param name имя анимации для проигрывания
|
||||
* @param fade время в течение которого вес анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function play(name:String, fade:Number = 0):void {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state == null) {
|
||||
throw new ArgumentError('Animation with name "' + name + '" not found');
|
||||
}
|
||||
state.play(fade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Остановить анимацию.
|
||||
*
|
||||
* @param name имя анимации для останова
|
||||
* @param fade время в течение которого вес анимации должен уменьшиться с максимального значения до 0.
|
||||
*/
|
||||
public function stop(name:String, fade:Number = 0):void {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state == null) {
|
||||
throw new ArgumentError('Animation with name "' + name + '" not found');
|
||||
}
|
||||
state.stop(fade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проиграть все анимации сначала.
|
||||
*
|
||||
* @param fade время в течение которого вес каждой анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function replayAll(fade:Number = 0):void {
|
||||
for each (var state:AnimationState in _animations) {
|
||||
state.replay(fade);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Продолжить проигрывание всех анимаций с текущей позиции.
|
||||
*
|
||||
* @param fade время в течение которого вес каждой анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function playAll(fade:Number = 0):void {
|
||||
for each (var state:AnimationState in _animations) {
|
||||
state.play(fade);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Остановить все анимации.
|
||||
*
|
||||
* @param fade время в течение которого вес каждой анимации должен уменьшиться с максимального значения до 0.
|
||||
*/
|
||||
public function stopAll(fade:Number = 0):void {
|
||||
for each (var state:AnimationState in _animations) {
|
||||
state.stop(fade);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Проиграть анимации за прошедшее время и выполнить их смешение.
|
||||
* Для автоматического ежекадрового обновления можно использовать класс AnimationTimer.
|
||||
*
|
||||
* @param interval прошедшее время.
|
||||
*
|
||||
* @see AnimationTimer
|
||||
*/
|
||||
public function update(interval:Number):void {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
var state:AnimationState;
|
||||
for each (state in _animations) {
|
||||
state.prepareBlending();
|
||||
}
|
||||
for each (state in _animations) {
|
||||
state.update(interval);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет анимацию в контроллер и возвращает объект состояния проигрывания анимации.
|
||||
*
|
||||
* @param name имя анимации
|
||||
* @param animation добавляемая анимация
|
||||
* @param loop проиграть анимацию сначала после достижения конца
|
||||
* @return экземляр класса AnimationState через который выполняется управление проигрыванием анимации.
|
||||
*
|
||||
* @see AnimationState
|
||||
*/
|
||||
public function addAnimation(name:String, animation:Animation, loop:Boolean = true):AnimationState {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state != null) {
|
||||
throw new ArgumentError('Animation with this name "' + name + '" already exist');
|
||||
}
|
||||
state = new AnimationState(this, animation, name, loop);
|
||||
_animations[name] = state;
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает анимацию из контроллера.
|
||||
*
|
||||
* @param name имя анимации для удаления.
|
||||
*/
|
||||
public function removeAnimation(name:String):void {
|
||||
var state:AnimationState = _animations[name];
|
||||
if (state == null) {
|
||||
throw new ArgumentError('Animation with name"' + name + '" not exists');
|
||||
}
|
||||
delete _animations[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает объект состояния проигрывания анимации по имени.
|
||||
*
|
||||
* @param name имя анимации.
|
||||
*
|
||||
* @see AnimationState
|
||||
*/
|
||||
public function getAnimation(name:String):AnimationState {
|
||||
return _animations[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает словарь со всеми анимациями. Свойство - имя анимации, значение - экземпляр класса AnimationState.
|
||||
*
|
||||
* @see AnimationState
|
||||
*/
|
||||
public function get animations():Object {
|
||||
var result:Object = new Object();
|
||||
for (var name:String in _animations) {
|
||||
result[name] = _animations[name];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
import alternativa.engine3d.core.Object3DContainer;
|
||||
import alternativa.engine3d.objects.Joint;
|
||||
import alternativa.engine3d.objects.Skin;
|
||||
|
||||
/**
|
||||
* Группа анимаций. Предназначена для объединения и синхронизации анимаций.
|
||||
*/
|
||||
public class AnimationGroup extends Animation {
|
||||
|
||||
private var _numAnimations:int = 0;
|
||||
private var _animations:Vector.<Animation> = new Vector.<Animation>();
|
||||
|
||||
/**
|
||||
* Создает группу анимаций.
|
||||
*
|
||||
* @param object анимируемый объект
|
||||
* @param weight вес анимации
|
||||
* @param speed скорость проигрывания анимации
|
||||
*/
|
||||
public function AnimationGroup(object:Object3D = null, weight:Number = 1.0, speed:Number = 1.0) {
|
||||
super(object, weight, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function updateLength():void {
|
||||
super.updateLength();
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
var animation:Animation = _animations[i];
|
||||
animation.updateLength();
|
||||
var len:Number = animation.length;
|
||||
if (len > length) {
|
||||
length = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function prepareBlending():void {
|
||||
super.prepareBlending();
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
_animations[i].prepareBlending();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function blend(position:Number, weight:Number):void {
|
||||
super.blend(position, weight);
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
var animation:Animation = _animations[i];
|
||||
if (animation.weight != 0) {
|
||||
animation.blend(position*animation.speed, weight*animation.weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getObjectNumChildren(object:Object3D):int {
|
||||
if (object is Skin) {
|
||||
return Skin(object).numJoints;
|
||||
} else if (object is Joint) {
|
||||
return Joint(object).numJoints;
|
||||
} else if (object is Object3DContainer) {
|
||||
return Object3DContainer(object).numChildren;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getObjectChildAt(object:Object3D, index:int):Object3D {
|
||||
if (object is Skin) {
|
||||
return Skin(object).getJointAt(index);
|
||||
} else if (object is Joint) {
|
||||
return Joint(object).getJointAt(index);
|
||||
} else if (object is Object3DContainer) {
|
||||
return Object3DContainer(object).getChildAt(index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Animation {
|
||||
var cloned:AnimationGroup = new AnimationGroup(object, weight, speed);
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
cloned.addAnimation(_animations[i].clone());
|
||||
}
|
||||
cloned.length = length;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает копию анимации, которая будет анимировать заданную иерархию.
|
||||
* Переносятся и копируются только те анимации, которые анимирует объекты с аналогичными именами
|
||||
* из заданной иерархии.
|
||||
*
|
||||
* @param object объект, который должен анимироваться копией текущей анимации
|
||||
* @return копия анимации
|
||||
*/
|
||||
override public function copyTo(object:Object3D):Animation {
|
||||
if (object == null) {
|
||||
throw new ArgumentError("Object must be not null");
|
||||
}
|
||||
var base:Object3D = this.object;
|
||||
if (base == null) {
|
||||
throw new ArgumentError("Base animation object must be not null");
|
||||
}
|
||||
var group:AnimationGroup = new AnimationGroup(object, weight, speed);
|
||||
copyAnimationForEachObject(object, group);
|
||||
if (group._numAnimations == 1 && group._animations[0].object == object) {
|
||||
// Если только одна анимация и та принадлежит объекту, то вернуть эту анимацию
|
||||
return group._animations[0];
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
private function copyAnimationForEachObject(object:Object3D, group:AnimationGroup):void {
|
||||
var i:int;
|
||||
var name:String = object.name;
|
||||
var from:Object3D;
|
||||
if (name != null && name.length > 0) {
|
||||
collectAnimations(name, this, group, object);
|
||||
}
|
||||
var count:int = getObjectNumChildren(object);
|
||||
for (i = 0; i < count; i++) {
|
||||
var child:Object3D = getObjectChildAt(object, i);
|
||||
copyAnimationForEachObject(child, group);
|
||||
}
|
||||
}
|
||||
|
||||
private function collectAnimations(name:String, animations:AnimationGroup, collector:AnimationGroup, object:Object3D, from:Object3D = null):Object3D {
|
||||
for (var i:int = 0; i < animations._numAnimations; i++) {
|
||||
var animation:Animation = animations._animations[i];
|
||||
var group:AnimationGroup = animation as AnimationGroup;
|
||||
if (group != null) {
|
||||
from = collectAnimations(name, group, collector, object, from);
|
||||
} else {
|
||||
if (animation.object != null && animation.object.name == name && (from == null || animation.object == from)) {
|
||||
from = animation.object;
|
||||
collector.addAnimation(animation.copyTo(object));
|
||||
}
|
||||
}
|
||||
}
|
||||
return from;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function slice(start:Number, end:Number = Number.MAX_VALUE):Animation {
|
||||
var group:AnimationGroup = new AnimationGroup(object, weight, speed);
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
var animation:Animation = _animations[i];
|
||||
group.addAnimation(animation.slice(start * animation.speed, end * animation.speed));
|
||||
}
|
||||
group.updateLength();
|
||||
return group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет дочернюю анимацию и обновляет длину анимации после этого.
|
||||
*/
|
||||
public function addAnimation(animation:Animation):Animation {
|
||||
if (animation == null) {
|
||||
throw new Error("Animation cannot be null");
|
||||
}
|
||||
_animations[_numAnimations++] = animation;
|
||||
if (animation.length > length) {
|
||||
length = animation.length;
|
||||
}
|
||||
return animation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает дочернюю анимацию и обновляет длину анимации.
|
||||
*/
|
||||
public function removeAnimation(animation:Animation):Animation {
|
||||
var index:int = _animations.indexOf(animation);
|
||||
if (index < 0) throw new ArgumentError("Animation not found");
|
||||
_numAnimations--;
|
||||
var j:int = index + 1;
|
||||
while (index < _numAnimations) {
|
||||
_animations[index] = _animations[j];
|
||||
index++;
|
||||
j++;
|
||||
}
|
||||
_animations.length = _numAnimations;
|
||||
// Пересчитываем длину
|
||||
length = 0;
|
||||
for (var i:int = 0; i < _numAnimations; i++) {
|
||||
var anim:Animation = _animations[i];
|
||||
if (anim.length > length) {
|
||||
length = anim.length;
|
||||
}
|
||||
}
|
||||
return animation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Количество дочерних анимаций.
|
||||
*/
|
||||
public function get numAnimations():int {
|
||||
return _numAnimations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает анимацию по индексу.
|
||||
*/
|
||||
public function getAnimationAt(index:int):Animation {
|
||||
return _animations[index];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
/**
|
||||
* Cостояние проигрывания анимации в контроллере.
|
||||
*/
|
||||
public final class AnimationState {
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Проигрываемая анимация.
|
||||
*/
|
||||
public var animation:Animation;
|
||||
|
||||
/**
|
||||
* Зацикленность анимации. Зацикленная анимация будет проигрываться сначала после достижения конца.
|
||||
*/
|
||||
public var loop:Boolean;
|
||||
|
||||
/**
|
||||
* Для незацикленной анимации задает время с отсчетом от конца анимации после которого начнется затухание анимации.
|
||||
* 0 - без затухания, 1 - затухание с начала анимации.
|
||||
*/
|
||||
public var endingFadeOut:Number = 0;
|
||||
|
||||
private var fadeInTime:Number;
|
||||
private var fadedIn:Boolean;
|
||||
private var fadeInPosition:Number;
|
||||
private var fadeOutTime:Number;
|
||||
private var fadedOut:Boolean;
|
||||
private var fadeOutPosition:Number;
|
||||
|
||||
private var manualControl:Boolean = false;
|
||||
|
||||
private var _controller:AnimationController;
|
||||
|
||||
private var _name:String;
|
||||
private var _played:Boolean = false;
|
||||
private var _position:Number = 0;
|
||||
|
||||
/**
|
||||
* Конструктор состояния анимации, вызывается в AnimationController.
|
||||
*
|
||||
* @see AnimationController
|
||||
*/
|
||||
public function AnimationState(controller:AnimationController, animation:Animation, name:String, loop:Boolean) {
|
||||
this.animation = animation;
|
||||
this._controller = controller;
|
||||
this._name = name;
|
||||
this.loop = loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проиграть анимацию сначала.
|
||||
*
|
||||
* @param fade время в течение которого вес анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function replay(fade:Number = 0):void {
|
||||
if (!_played) {
|
||||
play(fade);
|
||||
_position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Продолжить проигрывание анимации с текущей позиции.
|
||||
*
|
||||
* @param fade время в течение которого вес анимации должен увеличиться с нуля до максимального значения.
|
||||
*/
|
||||
public function play(fade:Number = 0):void {
|
||||
if (!_played) {
|
||||
_played = true;
|
||||
fadeInTime = fade;
|
||||
fadedIn = true;
|
||||
if (fadedOut) {
|
||||
fadeInPosition = fadeInTime*(1 - fadeOutPosition/fadeOutTime);
|
||||
fadedOut = false;
|
||||
} else {
|
||||
fadeInPosition = 0;
|
||||
}
|
||||
manualControl = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Остановить проигрывание анимации.
|
||||
*
|
||||
* @param fade время в течение которого вес анимации должен уменьшиться с максимального значения до 0.
|
||||
*/
|
||||
public function stop(fade:Number = 0):void {
|
||||
if (_played) {
|
||||
_played = false;
|
||||
fadeOutTime = fade;
|
||||
if (fadedIn) {
|
||||
fadeOutPosition = fadeOutTime*(1 - fadeInPosition/fadeInTime);
|
||||
fadedIn = false;
|
||||
fadedOut = true;
|
||||
} else {
|
||||
if (!fadedOut) {
|
||||
fadeOutPosition = 0;
|
||||
fadedOut = true;
|
||||
}
|
||||
}
|
||||
manualControl = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function prepareBlending():void {
|
||||
if (animation != null) {
|
||||
animation.prepareBlending();
|
||||
}
|
||||
}
|
||||
|
||||
private function loopPosition():void {
|
||||
if (_position < 0) {
|
||||
// _position = (length <= 0) ? 0 : _position % length;
|
||||
_position = 0;
|
||||
} else {
|
||||
if (_position >= animation.length) {
|
||||
_position = (animation.length <= 0) ? 0 : _position % animation.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function fading(position:Number):Number {
|
||||
if (position > 1) {
|
||||
return 1;
|
||||
}
|
||||
if (position < 0) {
|
||||
return 0;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function update(interval:Number):void {
|
||||
if (animation == null) {
|
||||
return;
|
||||
}
|
||||
var weight:Number = animation.weight;
|
||||
if (_played) {
|
||||
_position += interval*animation.speed;
|
||||
if (loop) {
|
||||
loopPosition();
|
||||
if (fadedIn) {
|
||||
fadeInPosition += interval;
|
||||
if (fadeInPosition < fadeInTime) {
|
||||
weight *= fading(fadeInPosition/fadeInTime);
|
||||
} else {
|
||||
fadedIn = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_position < 0) {
|
||||
_position = 0;
|
||||
if (interval < 0) {
|
||||
_played = false;
|
||||
}
|
||||
weight = 0;
|
||||
} else {
|
||||
if (_position > animation.length) {
|
||||
if (interval > 0) {
|
||||
_position = 0;
|
||||
_played = false;
|
||||
} else {
|
||||
_position = animation.length;
|
||||
}
|
||||
weight = 0;
|
||||
} else {
|
||||
if ((_position/animation.length + endingFadeOut) > 1) {
|
||||
fadedOut = true;
|
||||
fadeOutTime = endingFadeOut;
|
||||
fadeOutPosition = _position/animation.length + endingFadeOut - 1;
|
||||
} else {
|
||||
fadedOut = false;
|
||||
}
|
||||
if (fadedIn) {
|
||||
fadeInPosition += interval;
|
||||
}
|
||||
if ((fadedIn && (fadeInPosition < fadeInTime)) && fadedOut) {
|
||||
var w1:Number = fading(fadeInPosition/fadeInTime);
|
||||
var w2:Number = fading(1 - fadeOutPosition/fadeOutTime);
|
||||
if (w1 < w2) {
|
||||
weight *= w1;
|
||||
} else {
|
||||
weight *= w2;
|
||||
fadedIn = false;
|
||||
}
|
||||
} else {
|
||||
if (fadedIn) {
|
||||
if (fadeInPosition < fadeInTime) {
|
||||
weight *= fading(fadeInPosition/fadeInTime);
|
||||
} else {
|
||||
fadedIn = false;
|
||||
}
|
||||
} else if (fadedOut) {
|
||||
weight *= fading(1 - fadeOutPosition/fadeOutTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!manualControl) {
|
||||
if (fadedOut) {
|
||||
_position += interval*animation.speed;
|
||||
if (loop) {
|
||||
loopPosition();
|
||||
} else {
|
||||
if (_position < 0) {
|
||||
_position = 0;
|
||||
} else {
|
||||
if (_position >= animation.length) {
|
||||
_position = animation.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
fadeOutPosition += interval;
|
||||
if (fadeOutPosition < fadeOutTime) {
|
||||
weight *= fading(1 - fadeOutPosition/fadeOutTime);
|
||||
} else {
|
||||
fadedOut = false;
|
||||
weight = 0;
|
||||
}
|
||||
} else {
|
||||
weight = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (weight != 0) {
|
||||
animation.blend(_position, weight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Контроллер, управляющий воспроизведением анимации.
|
||||
*/
|
||||
public function get controller():AnimationController {
|
||||
return _controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Имя анимации в контроллере.
|
||||
*/
|
||||
public function get name():String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проигрывается анимация в данный момент или нет.
|
||||
*/
|
||||
public function get played():Boolean {
|
||||
return _played;
|
||||
}
|
||||
|
||||
/**
|
||||
* Позиция проигрывания анимации.
|
||||
*/
|
||||
public function get position():Number {
|
||||
return _position;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set position(value:Number):void {
|
||||
_position = value;
|
||||
manualControl = true;
|
||||
_played = false;
|
||||
fadedIn = false;
|
||||
fadedOut = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import flash.utils.getTimer;
|
||||
|
||||
/**
|
||||
* Выполняет ежекадровое обновление контроллеров.
|
||||
*/
|
||||
public class AnimationTimer {
|
||||
|
||||
/**
|
||||
* Соотношение виртуального времени реальному
|
||||
*/
|
||||
public var timeScale:Number = 1.0;
|
||||
|
||||
private var _numControllers:int;
|
||||
private var _controllers:Vector.<AnimationController> = new Vector.<AnimationController>();
|
||||
|
||||
private var lastTime:int = -1;
|
||||
|
||||
/**
|
||||
* Создает экземпляр контроллера.
|
||||
*/
|
||||
public function AnimationTimer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Начинает отсчет времени.
|
||||
*/
|
||||
public function start():void {
|
||||
lastTime = getTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет контроллеры с времени последнего вызова start() или update().
|
||||
*
|
||||
* @see #start()
|
||||
*/
|
||||
public function update():void {
|
||||
if (lastTime >= 0) {
|
||||
var time:int = getTimer();
|
||||
var interval:Number = 0.001*timeScale*(time - lastTime);
|
||||
for (var i:int = 0; i < _numControllers; i++) {
|
||||
var controller:AnimationController = _controllers[i];
|
||||
controller.update(interval);
|
||||
}
|
||||
lastTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Приостанавливает отсчет времени.
|
||||
*/
|
||||
public function stop():void {
|
||||
lastTime = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает <code>true</code> если таймер в данный момент остановлен.
|
||||
*/
|
||||
public function get stoped():Boolean {
|
||||
return lastTime == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет контроллер.
|
||||
*/
|
||||
public function addController(controller:AnimationController):AnimationController {
|
||||
if (controller == null) {
|
||||
throw new Error("Controller cannot be null");
|
||||
}
|
||||
_controllers[_numControllers++] = controller;
|
||||
return controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Убирает контроллер.
|
||||
*/
|
||||
public function removeController(controller:AnimationController):AnimationController {
|
||||
var index:int = _controllers.indexOf(controller);
|
||||
if (index < 0) throw new ArgumentError("Controller not found");
|
||||
_numControllers--;
|
||||
var j:int = index + 1;
|
||||
while (index < _numControllers) {
|
||||
_controllers[index] = _controllers[j];
|
||||
index++;
|
||||
j++;
|
||||
}
|
||||
_controllers.length = _numControllers;
|
||||
return controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает количество контроллеров.
|
||||
*/
|
||||
public function get numControllers():int {
|
||||
return _numControllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает контроллер по индексу.
|
||||
*
|
||||
* @param index индекс контроллера.
|
||||
*/
|
||||
public function getControllerAt(index:int):AnimationController {
|
||||
return _controllers[index];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.animation.keys.MatrixKey;
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
/**
|
||||
* Анимация матрицы объекта.
|
||||
*/
|
||||
public class MatrixAnimation extends Animation {
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами анимации матрицы.
|
||||
*/
|
||||
public var matrix:Track;
|
||||
|
||||
private var matrixKey:MatrixKey = new MatrixKey(0, null);
|
||||
|
||||
/**
|
||||
* Создает новый экземпляр объекта.
|
||||
*
|
||||
* @param object объект, матрица которого анимируется.
|
||||
* @param weight вес анимации.
|
||||
* @param speed скорость проигрывания анимации.
|
||||
*/
|
||||
public function MatrixAnimation(object:Object3D = null, weight:Number = 1.0, speed:Number = 1.0) {
|
||||
super(object, weight, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function control(position:Number, weight:Number):void {
|
||||
if (matrix != null && object != null) {
|
||||
matrix.getKey(position, matrixKey);
|
||||
var t:Vector3D = matrixKey.translation;
|
||||
var r:Vector3D = matrixKey.rotation;
|
||||
var s:Vector3D = matrixKey.scale;
|
||||
var c:Number;
|
||||
c = calculateBlendInterpolation(WEIGHTS_X, weight);
|
||||
object.x = (1 - c)*object.x + c*t.x;
|
||||
c = calculateBlendInterpolation(WEIGHTS_Y, weight);
|
||||
object.y = (1 - c)*object.y + c*t.y;
|
||||
c = calculateBlendInterpolation(WEIGHTS_Z, weight);
|
||||
object.z = (1 - c)*object.z + c*t.z;
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_X, weight);
|
||||
object.rotationX = interpolateAngle(object.rotationX, r.x, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Y, weight);
|
||||
object.rotationY = interpolateAngle(object.rotationY, r.y, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Z, weight);
|
||||
object.rotationZ = interpolateAngle(object.rotationZ, r.z, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_X, weight);
|
||||
object.scaleX = (1 - c)*object.scaleX + c*s.x;
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Y, weight);
|
||||
object.scaleY = (1 - c)*object.scaleY + c*s.y;
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Z, weight);
|
||||
object.scaleZ = (1 - c)*object.scaleZ + c*s.z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Animation {
|
||||
var cloned:MatrixAnimation = new MatrixAnimation(object, weight, speed);
|
||||
cloned.matrix = matrix;
|
||||
cloned.length = length;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function slice(start:Number, end:Number = Number.MAX_VALUE):Animation {
|
||||
var animation:MatrixAnimation = new MatrixAnimation(object, weight, speed);
|
||||
animation.matrix = (matrix != null) ? matrix.slice(start, end) : null;
|
||||
animation.updateLength();
|
||||
return animation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function updateLength():void {
|
||||
super.updateLength();
|
||||
if (matrix != null) {
|
||||
var len:Number = matrix.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.animation.keys.Key;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами.
|
||||
*/
|
||||
public class Track {
|
||||
|
||||
/**
|
||||
* Ключевые кадры.
|
||||
*/
|
||||
public var keyList:Key;
|
||||
|
||||
/**
|
||||
* Добавляет ключевой кадр.
|
||||
*/
|
||||
public function addKey(key:Key):void {
|
||||
key.next = keyList;
|
||||
keyList = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сортирует ключевые кадры по времени.
|
||||
*/
|
||||
public function sortKeys():void {
|
||||
keyList = sortKeysByTime(keyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает кадр соответствующий заданному времени.
|
||||
*
|
||||
* @param time время кадра.
|
||||
* @param key если не <code>null</code>, результат будет записан в этот объект.
|
||||
*/
|
||||
public function getKey(time:Number, key:Key = null):Key {
|
||||
var prev:Key;
|
||||
var next:Key = keyList;
|
||||
while (next != null && next.time < time) {
|
||||
prev = next;
|
||||
next = next.next;
|
||||
}
|
||||
if (prev != null) return prev.interpolate(time, next, key);
|
||||
if (next != null) return next.interpolate(time, null, key);
|
||||
return null;
|
||||
}
|
||||
|
||||
private function sortKeysByTime(list:Key):Key {
|
||||
var left:Key = list;
|
||||
var right:Key = list.next;
|
||||
while (right != null && right.next != null) {
|
||||
list = list.next;
|
||||
right = right.next.next;
|
||||
}
|
||||
right = list.next;
|
||||
list.next = null;
|
||||
if (left.next != null) {
|
||||
left = sortKeysByTime(left);
|
||||
}
|
||||
if (right.next != null) {
|
||||
right = sortKeysByTime(right);
|
||||
}
|
||||
var flag:Boolean = left.time < right.time;
|
||||
if (flag) {
|
||||
list = left;
|
||||
left = left.next;
|
||||
} else {
|
||||
list = right;
|
||||
right = right.next;
|
||||
}
|
||||
var last:Key = list;
|
||||
while (true) {
|
||||
if (left == null) {
|
||||
last.next = right;
|
||||
return list;
|
||||
} else if (right == null) {
|
||||
last.next = left;
|
||||
return list;
|
||||
}
|
||||
if (flag) {
|
||||
if (left.time < right.time) {
|
||||
last = left;
|
||||
left = left.next;
|
||||
} else {
|
||||
last.next = right;
|
||||
last = right;
|
||||
right = right.next;
|
||||
flag = false;
|
||||
}
|
||||
} else {
|
||||
if (right.time < left.time) {
|
||||
last = right;
|
||||
right = right.next;
|
||||
} else {
|
||||
last.next = left;
|
||||
last = left;
|
||||
left = left.next;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает время последнего ключевого кадра.
|
||||
*/
|
||||
public function get length():Number {
|
||||
if (keyList != null) {
|
||||
var key:Key = keyList;
|
||||
while (key.next != null) {
|
||||
key = key.next;
|
||||
}
|
||||
return key.time;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает часть трека в промежутке между start и end.
|
||||
* Ключи в треке должны быть отсортированы.
|
||||
*
|
||||
* @param start начало времени промежутка трека
|
||||
* @param end конец времени промежутка трека
|
||||
* @return часть трека
|
||||
*/
|
||||
public function slice(start:Number, end:Number = Number.MAX_VALUE):Track {
|
||||
var track:Track = new Track();
|
||||
var prev:Key;
|
||||
var next:Key = keyList;
|
||||
while (next != null && next.time <= start) {
|
||||
prev = next;
|
||||
next = next.next;
|
||||
}
|
||||
var key:Key;
|
||||
if (prev != null) {
|
||||
key = prev.interpolate(start, next);
|
||||
} else {
|
||||
if (next != null) {
|
||||
// Время до начала анимации
|
||||
key = next.interpolate(next.time, next.next);
|
||||
start = next.time;
|
||||
} else {
|
||||
// Пустой трек
|
||||
return track;
|
||||
}
|
||||
}
|
||||
key.time -= start;
|
||||
track.keyList = key;
|
||||
prev = next;
|
||||
next = next.next;
|
||||
while (next != null && next.time < end) {
|
||||
key.next = next.interpolate(next.time, next.next);
|
||||
key = key.next;
|
||||
key.time -= start;
|
||||
prev = next;
|
||||
next = next.next;
|
||||
}
|
||||
if (next != null) {
|
||||
// Время между prev.time и next.time
|
||||
key.next = prev.interpolate(end, next);
|
||||
key.next.time -= start;
|
||||
} else {
|
||||
// Последний ключ
|
||||
key.next = prev.interpolate(prev.time, null);
|
||||
key.next.time -= start;
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package alternativa.engine3d.animation {
|
||||
|
||||
import alternativa.engine3d.animation.keys.PointKey;
|
||||
import alternativa.engine3d.animation.keys.ValueKey;
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
/**
|
||||
* Анимация компонентов положения и ориентации объекта.
|
||||
*/
|
||||
public class TransformAnimation extends Animation {
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами положения объекта.
|
||||
*/
|
||||
public var translation:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами вращения объекта.
|
||||
*/
|
||||
public var rotation:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами масштаба объекта.
|
||||
*/
|
||||
public var scale:Track;
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами перемещения объекта по оси X.
|
||||
*/
|
||||
public var x:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами перемещения объекта по оси Y.
|
||||
*/
|
||||
public var y:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами перемещения объекта по оси Z.
|
||||
*/
|
||||
public var z:Track;
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами вращения объекта по оси X.
|
||||
*/
|
||||
public var rotationX:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами вращения объекта по оси Y.
|
||||
*/
|
||||
public var rotationY:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами вращения объекта по оси Z.
|
||||
*/
|
||||
public var rotationZ:Track;
|
||||
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами масштаба объекта по оси X.
|
||||
*/
|
||||
public var scaleX:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами масштаба объекта по оси Y.
|
||||
*/
|
||||
public var scaleY:Track;
|
||||
/**
|
||||
* Временная шкала с ключевыми кадрами масштаба объекта по оси Z.
|
||||
*/
|
||||
public var scaleZ:Track;
|
||||
|
||||
private var valueKey:ValueKey = new ValueKey(0, 0);
|
||||
private var pointKey:PointKey = new PointKey(0, 0, 0, 0);
|
||||
|
||||
/**
|
||||
* Конструктор анимации.
|
||||
*
|
||||
* @param object анимируемый объект.
|
||||
* @param weight вес анимации.
|
||||
* @param speed скорость проигрывания анимации.
|
||||
*/
|
||||
public function TransformAnimation(object:Object3D = null, weight:Number = 1.0, speed:Number = 1.0) {
|
||||
super(object, weight, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override protected function control(position:Number, weight:Number):void {
|
||||
if (object == null) {
|
||||
return;
|
||||
}
|
||||
var c:Number;
|
||||
//var t:Vector3D = object.translation;
|
||||
//var r:Vector3D = object.rotation;
|
||||
//var s:Vector3D = object.scale;
|
||||
if (translation != null) {
|
||||
translation.getKey(position, pointKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_X, weight);
|
||||
object.x = (1 - c)*object.x + c*pointKey.x;
|
||||
c = calculateBlendInterpolation(WEIGHTS_Y, weight);
|
||||
object.y = (1 - c)*object.y + c*pointKey.y;
|
||||
c = calculateBlendInterpolation(WEIGHTS_Z, weight);
|
||||
object.z = (1 - c)*object.z + c*pointKey.z;
|
||||
} else {
|
||||
if (x != null) {
|
||||
x.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_X, weight);
|
||||
object.x = (1 - c)*object.x + c*valueKey.value;
|
||||
}
|
||||
if (y != null) {
|
||||
y.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_Y, weight);
|
||||
object.y = (1 - c)*object.y + c*valueKey.value;
|
||||
}
|
||||
if (z != null) {
|
||||
z.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_Z, weight);
|
||||
object.z = (1 - c)*object.z + c*valueKey.value;
|
||||
}
|
||||
}
|
||||
if (rotation != null) {
|
||||
rotation.getKey(position, pointKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_X, weight);
|
||||
object.rotationX = interpolateAngle(object.rotationX, pointKey.x, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Y, weight);
|
||||
object.rotationY = interpolateAngle(object.rotationY, pointKey.y, c);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Z, weight);
|
||||
object.rotationZ = interpolateAngle(object.rotationZ, pointKey.z, c);
|
||||
} else {
|
||||
if (rotationX != null) {
|
||||
rotationX.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_X, weight);
|
||||
object.rotationX = interpolateAngle(object.rotationX, valueKey.value, c);
|
||||
}
|
||||
if (rotationY != null) {
|
||||
rotationY.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Y, weight);
|
||||
object.rotationY = interpolateAngle(object.rotationY, valueKey.value, c);
|
||||
}
|
||||
if (rotationZ != null) {
|
||||
rotationZ.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_ROT_Z, weight);
|
||||
object.rotationZ = interpolateAngle(object.rotationZ, valueKey.value, c);
|
||||
}
|
||||
}
|
||||
if (scale != null) {
|
||||
scale.getKey(position, pointKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_X, weight);
|
||||
object.scaleX = (1 - c)*object.scaleX + c*pointKey.x;
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Y, weight);
|
||||
object.scaleY = (1 - c)*object.scaleY + c*pointKey.y;
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Z, weight);
|
||||
object.scaleZ = (1 - c)*object.scaleZ + c*pointKey.z;
|
||||
} else {
|
||||
if (scaleX != null) {
|
||||
scaleX.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_X, weight);
|
||||
object.scaleX = (1 - c)*object.scaleX + c*valueKey.value;
|
||||
}
|
||||
if (scaleY != null) {
|
||||
scaleY.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Y, weight);
|
||||
object.scaleY = (1 - c)*object.scaleY + c*valueKey.value;
|
||||
}
|
||||
if (scaleZ != null) {
|
||||
scaleZ.getKey(position, valueKey);
|
||||
c = calculateBlendInterpolation(WEIGHTS_SCALE_Z, weight);
|
||||
object.scaleZ = (1 - c)*object.scaleZ + c*valueKey.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function slice(start:Number, end:Number = Number.MAX_VALUE):Animation {
|
||||
var animation:TransformAnimation = new TransformAnimation(object, weight, speed);
|
||||
animation.translation = (translation != null) ? translation.slice(start, end) : null;
|
||||
animation.rotation = (rotation != null) ? rotation.slice(start, end) : null;
|
||||
animation.scale = (scale != null) ? scale.slice(start, end) : null;
|
||||
animation.x = (x != null) ? x.slice(start, end) : null;
|
||||
animation.y = (y != null) ? y.slice(start, end) : null;
|
||||
animation.z = (z != null) ? z.slice(start, end) : null;
|
||||
animation.rotationX = (rotationX != null) ? rotationX.slice(start, end) : null;
|
||||
animation.rotationY = (rotationY != null) ? rotationY.slice(start, end) : null;
|
||||
animation.rotationZ = (rotationZ != null) ? rotationZ.slice(start, end) : null;
|
||||
animation.scaleX = (scaleX != null) ? scaleX.slice(start, end) : null;
|
||||
animation.scaleY = (scaleY != null) ? scaleY.slice(start, end) : null;
|
||||
animation.scaleZ = (scaleZ != null) ? scaleZ.slice(start, end) : null;
|
||||
animation.updateLength();
|
||||
return animation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function updateLength():void {
|
||||
super.updateLength();
|
||||
var len:Number;
|
||||
if (translation != null) {
|
||||
len = translation.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (rotation != null) {
|
||||
len = rotation.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (scale != null) {
|
||||
len = scale.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (x != null) {
|
||||
len = x.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (y != null) {
|
||||
len = y.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (z != null) {
|
||||
len = z.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (rotationX != null) {
|
||||
len = rotationX.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (rotationY != null) {
|
||||
len = rotationY.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (rotationZ != null) {
|
||||
len = rotationZ.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (scaleX != null) {
|
||||
len = scaleX.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (scaleY != null) {
|
||||
len = scaleY.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
if (scaleZ != null) {
|
||||
len = scaleZ.length;
|
||||
length = (len > length) ? len : length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Animation {
|
||||
var cloned:TransformAnimation = new TransformAnimation(object, weight, speed);
|
||||
cloned.translation = translation;
|
||||
cloned.rotation = rotation;
|
||||
cloned.scale = scale;
|
||||
cloned.x = x;
|
||||
cloned.y = y;
|
||||
cloned.z = z;
|
||||
cloned.rotationX = rotationX;
|
||||
cloned.rotationY = rotationY;
|
||||
cloned.rotationZ = rotationZ;
|
||||
cloned.scaleX = scaleX;
|
||||
cloned.scaleY = scaleY;
|
||||
cloned.scaleZ = scaleZ;
|
||||
cloned.length = length;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 114
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/keys
|
||||
END
|
||||
MatrixKey.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 127
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/keys/MatrixKey.as
|
||||
END
|
||||
PointKey.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 126
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/keys/PointKey.as
|
||||
END
|
||||
ValueKey.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 126
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/keys/ValueKey.as
|
||||
END
|
||||
Key.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 121
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/keys/Key.as
|
||||
END
|
||||
@@ -0,0 +1,76 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/animation/keys
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
MatrixKey.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
494ab0c528743ef278fdda8ccb0f669f
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
PointKey.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
42c52d4ec09ada3ba69a2412bfca8d0e
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
ValueKey.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
60a17c8fd871989feed5646ac4ed0e98
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
Key.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:33.000000Z
|
||||
553285159808a04b934a6ec2a15240af
|
||||
2010-07-19T06:57:34.804173Z
|
||||
37580
|
||||
andrei
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,40 @@
|
||||
package alternativa.engine3d.animation.keys {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Ключевой кадр.
|
||||
*/
|
||||
public class Key {
|
||||
|
||||
/**
|
||||
* Время кадра.
|
||||
*/
|
||||
public var time:Number;
|
||||
/**
|
||||
* Ссылка на следующий ключевой кадр на верменной шкале.
|
||||
*
|
||||
* @see alternativa.engine3d.animation.Track
|
||||
*/
|
||||
public var next:Key;
|
||||
|
||||
/**
|
||||
* Создает экземпляр ключевого кадра.
|
||||
*
|
||||
* @param time время кадра.
|
||||
*/
|
||||
public function Key(time:Number) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function interpolate(time:Number, next:Key, key:Key = null):Key {
|
||||
return key;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package alternativa.engine3d.animation.keys {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
import flash.geom.Matrix3D;
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Ключевой кадр матричного типа.
|
||||
*/
|
||||
public class MatrixKey extends Key {
|
||||
|
||||
/**
|
||||
* Компоненты перемещения по осям X, Y, Z
|
||||
*/
|
||||
public var translation:Vector3D;
|
||||
/**
|
||||
* Компоненты вращения вокруг осей X, Y, Z. Углы должны быть в промежутке (-PI, PI]
|
||||
*/
|
||||
public var rotation:Vector3D;
|
||||
/**
|
||||
* Компоненты масштаба по осям X, Y, Z
|
||||
*/
|
||||
public var scale:Vector3D;
|
||||
|
||||
/**
|
||||
* Создает ключевой кадр матричного типа.
|
||||
*
|
||||
* @param time время кадра.
|
||||
* @param matrix значение кадра.
|
||||
*/
|
||||
public function MatrixKey(time:Number, matrix:Matrix3D = null) {
|
||||
super(time);
|
||||
if (matrix != null) {
|
||||
var v:Vector.<Vector3D> = matrix.decompose();
|
||||
translation = v[0];
|
||||
rotation = v[1];
|
||||
scale = v[2];
|
||||
} else {
|
||||
translation = new Vector3D();
|
||||
rotation = new Vector3D();
|
||||
scale = new Vector3D();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function interpolate(time:Number, next:Key, key:Key = null):Key {
|
||||
if (key != null) {
|
||||
key.time = time;
|
||||
} else {
|
||||
key = new MatrixKey(time);
|
||||
}
|
||||
var t:Vector3D = MatrixKey(key).translation;
|
||||
var r:Vector3D = MatrixKey(key).rotation;
|
||||
var s:Vector3D = MatrixKey(key).scale;
|
||||
if (next != null) {
|
||||
var nt:Vector3D = MatrixKey(next).translation;
|
||||
var nr:Vector3D = MatrixKey(next).rotation;
|
||||
var ns:Vector3D = MatrixKey(next).scale;
|
||||
var c2:Number = (time - this.time)/(next.time - this.time);
|
||||
var c1:Number = 1 - c2;
|
||||
t.x = c1 * translation.x + c2 * nt.x;
|
||||
t.y = c1 * translation.y + c2 * nt.y;
|
||||
t.z = c1 * translation.z + c2 * nt.z;
|
||||
r.x = interpolateAngle(rotation.x, nr.x, c2);
|
||||
r.y = interpolateAngle(rotation.y, nr.y, c2);
|
||||
r.z = interpolateAngle(rotation.z, nr.z, c2);
|
||||
s.x = c1 * scale.x + c2 * ns.x;
|
||||
s.y = c1 * scale.y + c2 * ns.y;
|
||||
s.z = c1 * scale.z + c2 * ns.z;
|
||||
} else {
|
||||
t.x = translation.x;
|
||||
t.y = translation.y;
|
||||
t.z = translation.z;
|
||||
r.x = rotation.x;
|
||||
r.y = rotation.y;
|
||||
r.z = rotation.z;
|
||||
s.x = scale.x;
|
||||
s.y = scale.y;
|
||||
s.z = scale.z;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Интерполяция между двумя ненормализованными углами.
|
||||
*/
|
||||
private function interpolateAngle(angle1:Number, angle2:Number, c:Number):Number {
|
||||
const PI:Number = Math.PI;
|
||||
const PITwice:Number = 2*PI;
|
||||
var delta:Number = angle2 - angle1;
|
||||
if (delta > PI) {
|
||||
delta -= PITwice;
|
||||
} else if (delta < -PI) {
|
||||
delta += PITwice;
|
||||
}
|
||||
return angle1 + c * delta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает и возвращает матрицу на основе компонентов ключа
|
||||
*/
|
||||
public function getMatrix():Matrix3D {
|
||||
var m:Matrix3D = new Matrix3D();
|
||||
var v:Vector.<Vector3D> = new Vector.<Vector3D>(3);
|
||||
v[0] = translation;
|
||||
v[1] = rotation;
|
||||
v[2] = scale;
|
||||
m.recompose(v);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает значения компонентов ключа из матрицы
|
||||
*/
|
||||
public function setMatrix(value:Matrix3D):void {
|
||||
var v:Vector.<Vector3D> = value.decompose();
|
||||
translation = v[0];
|
||||
rotation = v[1];
|
||||
scale = v[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[MatrixKey " + time + " translation:" + translation.toString() + " rotation:" + rotation + " scale:" + scale + "]]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package alternativa.engine3d.animation.keys {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Ключевой кадр точечного типа.
|
||||
*/
|
||||
public class PointKey extends Key {
|
||||
|
||||
/**
|
||||
* Координата по оси X.
|
||||
*/
|
||||
public var x:Number;
|
||||
/**
|
||||
* Координата по оси Y.
|
||||
*/
|
||||
public var y:Number;
|
||||
/**
|
||||
* Координата по оси Z.
|
||||
*/
|
||||
public var z:Number;
|
||||
|
||||
/**
|
||||
* Создает экземпляр ключевого кадра.
|
||||
*
|
||||
* @param time время кадра.
|
||||
* @param x координата по оси X
|
||||
* @param y координата по оси Y
|
||||
* @param z координата по оси Z
|
||||
*/
|
||||
public function PointKey(time:Number, x:Number, y:Number, z:Number) {
|
||||
super(time);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function interpolate(time:Number, next:Key, key:Key = null):Key {
|
||||
var x:Number;
|
||||
var y:Number;
|
||||
var z:Number;
|
||||
if (next != null) {
|
||||
var t:Number = (time - this.time)/(next.time - this.time);
|
||||
x = this.x + (PointKey(next).x - this.x)*t;
|
||||
y = this.y + (PointKey(next).y - this.y)*t;
|
||||
z = this.z + (PointKey(next).z - this.z)*t;
|
||||
} else {
|
||||
x = this.x;
|
||||
y = this.y;
|
||||
z = this.z;
|
||||
}
|
||||
if (key != null) {
|
||||
key.time = time;
|
||||
PointKey(key).x = x;
|
||||
PointKey(key).y = y;
|
||||
PointKey(key).z = z;
|
||||
return key;
|
||||
} else {
|
||||
return new PointKey(time, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[PointKey " + time.toFixed(3) + ":" + x + "," + y + "," + z + "]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package alternativa.engine3d.animation.keys {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Ключевой кадр вещественного типа.
|
||||
*/
|
||||
public class ValueKey extends Key {
|
||||
|
||||
/**
|
||||
* Значение ключевого кадра.
|
||||
*/
|
||||
public var value:Number;
|
||||
|
||||
/**
|
||||
* Создает ключевой кадр.
|
||||
*
|
||||
* @param time время кадра.
|
||||
* @param value значение кадра.
|
||||
*/
|
||||
public function ValueKey(time:Number, value:Number) {
|
||||
super(time);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function interpolate(time:Number, next:Key, key:Key = null):Key {
|
||||
var value:Number;
|
||||
if (next != null) {
|
||||
value = this.value + (ValueKey(next).value - this.value)*(time - this.time)/(next.time - this.time);
|
||||
} else {
|
||||
value = this.value;
|
||||
}
|
||||
if (key != null) {
|
||||
key.time = time;
|
||||
ValueKey(key).value = value;
|
||||
return key;
|
||||
} else {
|
||||
return new ValueKey(time, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[ValueKey " + time + ":" + value + "]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package alternativa.engine3d.animation.keys {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Ключевой кадр.
|
||||
*/
|
||||
public class Key {
|
||||
|
||||
/**
|
||||
* Время кадра.
|
||||
*/
|
||||
public var time:Number;
|
||||
/**
|
||||
* Ссылка на следующий ключевой кадр на верменной шкале.
|
||||
*
|
||||
* @see alternativa.engine3d.animation.Track
|
||||
*/
|
||||
public var next:Key;
|
||||
|
||||
/**
|
||||
* Создает экземпляр ключевого кадра.
|
||||
*
|
||||
* @param time время кадра.
|
||||
*/
|
||||
public function Key(time:Number) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function interpolate(time:Number, next:Key, key:Key = null):Key {
|
||||
return key;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package alternativa.engine3d.animation.keys {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
import flash.geom.Matrix3D;
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Ключевой кадр матричного типа.
|
||||
*/
|
||||
public class MatrixKey extends Key {
|
||||
|
||||
/**
|
||||
* Компоненты перемещения по осям X, Y, Z
|
||||
*/
|
||||
public var translation:Vector3D;
|
||||
/**
|
||||
* Компоненты вращения вокруг осей X, Y, Z. Углы должны быть в промежутке (-PI, PI]
|
||||
*/
|
||||
public var rotation:Vector3D;
|
||||
/**
|
||||
* Компоненты масштаба по осям X, Y, Z
|
||||
*/
|
||||
public var scale:Vector3D;
|
||||
|
||||
/**
|
||||
* Создает ключевой кадр матричного типа.
|
||||
*
|
||||
* @param time время кадра.
|
||||
* @param matrix значение кадра.
|
||||
*/
|
||||
public function MatrixKey(time:Number, matrix:Matrix3D = null) {
|
||||
super(time);
|
||||
if (matrix != null) {
|
||||
var v:Vector.<Vector3D> = matrix.decompose();
|
||||
translation = v[0];
|
||||
rotation = v[1];
|
||||
scale = v[2];
|
||||
} else {
|
||||
translation = new Vector3D();
|
||||
rotation = new Vector3D();
|
||||
scale = new Vector3D();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function interpolate(time:Number, next:Key, key:Key = null):Key {
|
||||
if (key != null) {
|
||||
key.time = time;
|
||||
} else {
|
||||
key = new MatrixKey(time);
|
||||
}
|
||||
var t:Vector3D = MatrixKey(key).translation;
|
||||
var r:Vector3D = MatrixKey(key).rotation;
|
||||
var s:Vector3D = MatrixKey(key).scale;
|
||||
if (next != null) {
|
||||
var nt:Vector3D = MatrixKey(next).translation;
|
||||
var nr:Vector3D = MatrixKey(next).rotation;
|
||||
var ns:Vector3D = MatrixKey(next).scale;
|
||||
var c2:Number = (time - this.time)/(next.time - this.time);
|
||||
var c1:Number = 1 - c2;
|
||||
t.x = c1 * translation.x + c2 * nt.x;
|
||||
t.y = c1 * translation.y + c2 * nt.y;
|
||||
t.z = c1 * translation.z + c2 * nt.z;
|
||||
r.x = interpolateAngle(rotation.x, nr.x, c2);
|
||||
r.y = interpolateAngle(rotation.y, nr.y, c2);
|
||||
r.z = interpolateAngle(rotation.z, nr.z, c2);
|
||||
s.x = c1 * scale.x + c2 * ns.x;
|
||||
s.y = c1 * scale.y + c2 * ns.y;
|
||||
s.z = c1 * scale.z + c2 * ns.z;
|
||||
} else {
|
||||
t.x = translation.x;
|
||||
t.y = translation.y;
|
||||
t.z = translation.z;
|
||||
r.x = rotation.x;
|
||||
r.y = rotation.y;
|
||||
r.z = rotation.z;
|
||||
s.x = scale.x;
|
||||
s.y = scale.y;
|
||||
s.z = scale.z;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Интерполяция между двумя ненормализованными углами.
|
||||
*/
|
||||
private function interpolateAngle(angle1:Number, angle2:Number, c:Number):Number {
|
||||
const PI:Number = Math.PI;
|
||||
const PITwice:Number = 2*PI;
|
||||
var delta:Number = angle2 - angle1;
|
||||
if (delta > PI) {
|
||||
delta -= PITwice;
|
||||
} else if (delta < -PI) {
|
||||
delta += PITwice;
|
||||
}
|
||||
return angle1 + c * delta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает и возвращает матрицу на основе компонентов ключа
|
||||
*/
|
||||
public function getMatrix():Matrix3D {
|
||||
var m:Matrix3D = new Matrix3D();
|
||||
var v:Vector.<Vector3D> = new Vector.<Vector3D>(3);
|
||||
v[0] = translation;
|
||||
v[1] = rotation;
|
||||
v[2] = scale;
|
||||
m.recompose(v);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает значения компонентов ключа из матрицы
|
||||
*/
|
||||
public function setMatrix(value:Matrix3D):void {
|
||||
var v:Vector.<Vector3D> = value.decompose();
|
||||
translation = v[0];
|
||||
rotation = v[1];
|
||||
scale = v[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[MatrixKey " + time + " translation:" + translation.toString() + " rotation:" + rotation + " scale:" + scale + "]]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package alternativa.engine3d.animation.keys {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Ключевой кадр точечного типа.
|
||||
*/
|
||||
public class PointKey extends Key {
|
||||
|
||||
/**
|
||||
* Координата по оси X.
|
||||
*/
|
||||
public var x:Number;
|
||||
/**
|
||||
* Координата по оси Y.
|
||||
*/
|
||||
public var y:Number;
|
||||
/**
|
||||
* Координата по оси Z.
|
||||
*/
|
||||
public var z:Number;
|
||||
|
||||
/**
|
||||
* Создает экземпляр ключевого кадра.
|
||||
*
|
||||
* @param time время кадра.
|
||||
* @param x координата по оси X
|
||||
* @param y координата по оси Y
|
||||
* @param z координата по оси Z
|
||||
*/
|
||||
public function PointKey(time:Number, x:Number, y:Number, z:Number) {
|
||||
super(time);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function interpolate(time:Number, next:Key, key:Key = null):Key {
|
||||
var x:Number;
|
||||
var y:Number;
|
||||
var z:Number;
|
||||
if (next != null) {
|
||||
var t:Number = (time - this.time)/(next.time - this.time);
|
||||
x = this.x + (PointKey(next).x - this.x)*t;
|
||||
y = this.y + (PointKey(next).y - this.y)*t;
|
||||
z = this.z + (PointKey(next).z - this.z)*t;
|
||||
} else {
|
||||
x = this.x;
|
||||
y = this.y;
|
||||
z = this.z;
|
||||
}
|
||||
if (key != null) {
|
||||
key.time = time;
|
||||
PointKey(key).x = x;
|
||||
PointKey(key).y = y;
|
||||
PointKey(key).z = z;
|
||||
return key;
|
||||
} else {
|
||||
return new PointKey(time, x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[PointKey " + time.toFixed(3) + ":" + x + "," + y + "," + z + "]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package alternativa.engine3d.animation.keys {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Ключевой кадр вещественного типа.
|
||||
*/
|
||||
public class ValueKey extends Key {
|
||||
|
||||
/**
|
||||
* Значение ключевого кадра.
|
||||
*/
|
||||
public var value:Number;
|
||||
|
||||
/**
|
||||
* Создает ключевой кадр.
|
||||
*
|
||||
* @param time время кадра.
|
||||
* @param value значение кадра.
|
||||
*/
|
||||
public function ValueKey(time:Number, value:Number) {
|
||||
super(time);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function interpolate(time:Number, next:Key, key:Key = null):Key {
|
||||
var value:Number;
|
||||
if (next != null) {
|
||||
value = this.value + (ValueKey(next).value - this.value)*(time - this.time)/(next.time - this.time);
|
||||
} else {
|
||||
value = this.value;
|
||||
}
|
||||
if (key != null) {
|
||||
key.time = time;
|
||||
ValueKey(key).value = value;
|
||||
return key;
|
||||
} else {
|
||||
return new ValueKey(time, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Строковое представление объекта.
|
||||
*/
|
||||
public function toString():String {
|
||||
return "[ValueKey " + time + ":" + value + "]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 111
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/controllers
|
||||
END
|
||||
SimpleObjectController.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 137
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/controllers/SimpleObjectController.as
|
||||
END
|
||||
@@ -0,0 +1,40 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/controllers
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-08-05T14:27:38.542088Z
|
||||
38487
|
||||
int
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
SimpleObjectController.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
54ded0747e84a4456c2a0d7f8760f3b7
|
||||
2010-08-05T14:27:38.542088Z
|
||||
38487
|
||||
int
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,471 @@
|
||||
package alternativa.engine3d.controllers {
|
||||
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.Matrix3D;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Vector3D;
|
||||
import flash.ui.Keyboard;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
/**
|
||||
* Базовый контроллер для <code>Object3D</code>.
|
||||
* @see Object3D
|
||||
*/
|
||||
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 = 1e+22;
|
||||
|
||||
/**
|
||||
* Минимальный наклон.
|
||||
*/
|
||||
public var minPitch:Number = -1e+22;
|
||||
|
||||
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 get object():Object3D {
|
||||
return _object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set object(value:Object3D):void {
|
||||
_object = value;
|
||||
updateObjectTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет инофрмацию о трансформации объекта. Метод следует вызывать после изменения матрицы объекта вне контролллера.
|
||||
*/
|
||||
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) {
|
||||
var m:Matrix3D = new Matrix3D();
|
||||
m.recompose(objectTransform);
|
||||
_object.matrix = m;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает позицию объекта.
|
||||
* @param pos Объект <code>Vector3D</code>.
|
||||
*/
|
||||
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 x Координата X.
|
||||
* @param y Координата Y.
|
||||
* @param z Координата Z.
|
||||
*/
|
||||
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 Объект <code>Vector3D</code>.
|
||||
*/
|
||||
public function lookAt(point:Vector3D):void {
|
||||
lookAtXYZ(point.x, point.y, point.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает направление камеры в заданную точку.
|
||||
* @param x Координата X.
|
||||
* @param y Координата Y.
|
||||
* @param z Координата 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);
|
||||
var m:Matrix3D = _object.matrix;
|
||||
m.recompose(objectTransform);
|
||||
_object.matrix = m;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод выполняет привязку клавиш к действиям. Одной клавише может быть назначено только одно действие.
|
||||
* @param bindings Массив, в котором поочерёдно содержатся коды клавиш и действия.
|
||||
*/
|
||||
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:String 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
package alternativa.engine3d.controllers {
|
||||
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.Matrix3D;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Vector3D;
|
||||
import flash.ui.Keyboard;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
/**
|
||||
* Базовый контроллер для <code>Object3D</code>.
|
||||
* @see Object3D
|
||||
*/
|
||||
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 = 1e+22;
|
||||
|
||||
/**
|
||||
* Минимальный наклон.
|
||||
*/
|
||||
public var minPitch:Number = -1e+22;
|
||||
|
||||
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 get object():Object3D {
|
||||
return _object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set object(value:Object3D):void {
|
||||
_object = value;
|
||||
updateObjectTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновляет инофрмацию о трансформации объекта. Метод следует вызывать после изменения матрицы объекта вне контролллера.
|
||||
*/
|
||||
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) {
|
||||
var m:Matrix3D = new Matrix3D();
|
||||
m.recompose(objectTransform);
|
||||
_object.matrix = m;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает позицию объекта.
|
||||
* @param pos Объект <code>Vector3D</code>.
|
||||
*/
|
||||
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 x Координата X.
|
||||
* @param y Координата Y.
|
||||
* @param z Координата Z.
|
||||
*/
|
||||
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 Объект <code>Vector3D</code>.
|
||||
*/
|
||||
public function lookAt(point:Vector3D):void {
|
||||
lookAtXYZ(point.x, point.y, point.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает направление камеры в заданную точку.
|
||||
* @param x Координата X.
|
||||
* @param y Координата Y.
|
||||
* @param z Координата 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);
|
||||
var m:Matrix3D = _object.matrix;
|
||||
m.recompose(objectTransform);
|
||||
_object.matrix = m;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Метод выполняет привязку клавиш к действиям. Одной клавише может быть назначено только одно действие.
|
||||
* @param bindings Массив, в котором поочерёдно содержатся коды клавиш и действия.
|
||||
*/
|
||||
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:String 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 104
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core
|
||||
END
|
||||
Object3D.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 116
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/Object3D.as
|
||||
END
|
||||
Vertex.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 114
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/Vertex.as
|
||||
END
|
||||
Face.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 112
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/Face.as
|
||||
END
|
||||
Camera3D.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 116
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/Camera3D.as
|
||||
END
|
||||
Object3DContainer.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 125
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/Object3DContainer.as
|
||||
END
|
||||
Wrapper.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 115
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/Wrapper.as
|
||||
END
|
||||
View.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 112
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/View.as
|
||||
END
|
||||
Geometry.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 116
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/Geometry.as
|
||||
END
|
||||
RayIntersectionData.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 127
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core/RayIntersectionData.as
|
||||
END
|
||||
@@ -0,0 +1,136 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/core
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-09-06T10:07:46.117529Z
|
||||
40717
|
||||
andrei
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
Object3D.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
fc035c38e62eef4dbd6434fe8a9f06fa
|
||||
2010-09-06T09:12:26.928415Z
|
||||
40690
|
||||
andrei
|
||||
|
||||
Vertex.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
6f3fcc730070238465784d05c75cb9fe
|
||||
2010-08-06T08:34:09.545008Z
|
||||
38536
|
||||
int
|
||||
|
||||
Face.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
4836f7b06691702c0284abd8f99a315b
|
||||
2010-07-19T11:10:24.638989Z
|
||||
37646
|
||||
andrei
|
||||
|
||||
Camera3D.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
c7911d5fc5d600706323b0215149364d
|
||||
2010-09-06T10:07:46.117529Z
|
||||
40717
|
||||
andrei
|
||||
|
||||
Object3DContainer.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
a48b9c735cc1e4b19a85bf3bd8a3e220
|
||||
2010-09-06T09:12:26.928415Z
|
||||
40690
|
||||
andrei
|
||||
|
||||
Wrapper.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
cbdf53c529c4cdcacedb403a530e21f9
|
||||
2010-07-13T12:03:47.876614Z
|
||||
37240
|
||||
andrei
|
||||
|
||||
View.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
4b03911fd858351018b9a1ea34ca1f8a
|
||||
2010-08-26T15:24:15.084677Z
|
||||
40135
|
||||
andrei
|
||||
|
||||
Geometry.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
c082d457ef2867318f08a72b3d5754a1
|
||||
2010-09-05T12:49:37.759741Z
|
||||
40634
|
||||
andrei
|
||||
|
||||
RayIntersectionData.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
29815f4a5f19311c632f1797481b3b01
|
||||
2010-08-05T14:27:38.542088Z
|
||||
38487
|
||||
int
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,691 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import __AS3__.vec.Vector;
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.lights.DirectionalLight;
|
||||
import alternativa.engine3d.materials.AGALMiniAssembler;
|
||||
import alternativa.engine3d.objects.Mesh;
|
||||
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.Program3D;
|
||||
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.ByteArray;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class Camera3D extends Object3D {
|
||||
|
||||
public var debug:Boolean = true;
|
||||
|
||||
/**
|
||||
* Вьюпорт камеры.
|
||||
* Если вьюпорт не указан, отрисовка осуществляться не будет.
|
||||
*/
|
||||
public var view:View;
|
||||
|
||||
/**
|
||||
* Поле зрения (field of view).
|
||||
* Указывается в радианах.
|
||||
* Значение по умолчанию <code>Math.PI/2</code> — это 90 градусов.
|
||||
*/
|
||||
public var fov:Number = Math.PI/2;
|
||||
|
||||
/**
|
||||
* Ближнее расстояние отсечения.
|
||||
* Значение по умолчанию <code>0</code>.
|
||||
*/
|
||||
public var nearClipping:Number;
|
||||
|
||||
/**
|
||||
* Дальнее расстояние отсечения.
|
||||
* Значение по умолчанию <code>Number.MAX_VALUE</code>.
|
||||
*/
|
||||
public var farClipping:Number;
|
||||
|
||||
public var lights:Vector.<DirectionalLight>;
|
||||
alternativa3d var numLights:int;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var focalLength:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var projectionMatrixData:Vector.<Number> = new Vector.<Number>(16);
|
||||
|
||||
alternativa3d var globalMatrix:Matrix3D = new Matrix3D();
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var numDraws:int;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var numTriangles:int;
|
||||
|
||||
alternativa3d var transparentObjects:Vector.<Object3D> = new Vector.<Object3D>();
|
||||
alternativa3d var numTransparent:int = 0;
|
||||
|
||||
public function Camera3D(nearClipping:Number, farClipping:Number) {
|
||||
this.nearClipping = nearClipping;
|
||||
this.farClipping = farClipping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Отрисовывает иерархию объектов, в которой находится камера.
|
||||
* Чтобы отрисовка произошла, камере должен быть назначен <code>view</code>.
|
||||
*/
|
||||
public function render():void {
|
||||
if (view != null) {
|
||||
// Расчёт параметров проецирования
|
||||
var viewSizeX:Number = view._width*0.5;
|
||||
var viewSizeY:Number = view._height*0.5;
|
||||
focalLength = Math.sqrt(viewSizeX*viewSizeX + viewSizeY*viewSizeY)/Math.tan(fov*0.5);
|
||||
projectionMatrixData[0] = focalLength/viewSizeX;
|
||||
projectionMatrixData[5] = -focalLength/viewSizeY;
|
||||
projectionMatrixData[10]= farClipping/(farClipping - nearClipping);
|
||||
projectionMatrixData[11]= 1;
|
||||
projectionMatrixData[14]= -nearClipping*farClipping/(farClipping - nearClipping);
|
||||
|
||||
projectionMatrix.rawData = projectionMatrixData;
|
||||
|
||||
composeMatrix();
|
||||
globalMatrix.identity();
|
||||
globalMatrix.append(cameraMatrix);
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
globalMatrix.append(root.cameraMatrix);
|
||||
}
|
||||
|
||||
// Расчёт матрицы перевода из глобального пространства в камеру
|
||||
var i:int;
|
||||
// Сброс счётчиков
|
||||
numDraws = 0;
|
||||
numTriangles = 0;
|
||||
// Отрисовка
|
||||
var r:Number = (view.backgroundColor >> 16)/255;
|
||||
var g:Number = ((view.backgroundColor >> 8) & 0xFF)/255;
|
||||
var b:Number = (view.backgroundColor & 0xFF)/255;
|
||||
view.clear(r, g, b, view.backgroundAlpha);
|
||||
if (root != this && root.visible) {
|
||||
if (lights != null) {
|
||||
numLights = lights.length;
|
||||
for (i = 0; i < numLights; i++) {
|
||||
var light:DirectionalLight = lights[i];
|
||||
for (var j:int = light.numSplits - 1; j >= 0; j--) {
|
||||
light.update(this, view, j);
|
||||
|
||||
if (j < (light.numSplits - 1)) {
|
||||
// view.setColorWriteMask(false, false, false, false);
|
||||
// view.clear(0, 0, 0, 0);
|
||||
// view.setColorWriteMask(true, true, true, true);
|
||||
clearZ();
|
||||
}
|
||||
|
||||
// var near:Number = light.currentSplitNear/farClipping;
|
||||
// var far:Number = light.currentSplitFar/farClipping;
|
||||
var near:Number = light.currentSplitNear;
|
||||
var far:Number = light.currentSplitFar;
|
||||
|
||||
projectionMatrixData[10]= far/(far - near);
|
||||
projectionMatrixData[14]= -near*far/(far - near);
|
||||
projectionMatrix.rawData = projectionMatrixData;
|
||||
|
||||
cameraMatrix.identity();
|
||||
cameraMatrix.append(globalMatrix);
|
||||
cameraMatrix.invert();
|
||||
//cameraMatrix.append(projectionMatrix);
|
||||
root.composeMatrix();
|
||||
root.cameraMatrix.append(cameraMatrix);
|
||||
if (root.cullingInCamera(this, 63) >= 0) {
|
||||
root.draw(this);
|
||||
for (i = 0; i < numTransparent; i++) {
|
||||
transparentObjects[i].draw(this);
|
||||
}
|
||||
numTransparent = 0;
|
||||
transparentObjects.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cameraMatrix.identity();
|
||||
cameraMatrix.append(globalMatrix);
|
||||
cameraMatrix.invert();
|
||||
//cameraMatrix.append(projectionMatrix);
|
||||
root.composeMatrix();
|
||||
root.cameraMatrix.append(cameraMatrix);
|
||||
if (root.cullingInCamera(this, 63) >= 0) {
|
||||
root.draw(this);
|
||||
for (i = 0; i < numTransparent; i++) {
|
||||
transparentObjects[i].draw(this);
|
||||
}
|
||||
numTransparent = 0;
|
||||
transparentObjects.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
view.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private var czMesh:Mesh = createMesh();
|
||||
|
||||
private function createMesh():Mesh {
|
||||
var res:Mesh = new Mesh();
|
||||
res.geometry = new Geometry();
|
||||
var g:Geometry = res.geometry;
|
||||
g.addQuadFace(g.addVertex(-1, -1, 1), g.addVertex(1, -1, 1), g.addVertex(1, 1, 1), g.addVertex(-1, 1, 1));
|
||||
return res;
|
||||
}
|
||||
|
||||
private var czProgram:Program3D;
|
||||
|
||||
private function clearZProgram():Program3D {
|
||||
if (czProgram == null) {
|
||||
var czVertex:ByteArray = new AGALMiniAssembler().assemble("VERTEX", "mov op, va0 \n");
|
||||
var czFragment:ByteArray = new AGALMiniAssembler().assemble("FRAGMENT", "mov oc, fc0 \n");
|
||||
czProgram = view.createProgram();
|
||||
czProgram.upload(czVertex, czFragment);
|
||||
}
|
||||
return czProgram;
|
||||
}
|
||||
|
||||
private function clearZ():void {
|
||||
view.setProgram(clearZProgram());
|
||||
view.setBlending("ZERO", "ONE");
|
||||
view.setDepthTest(true, "ALWAYS");
|
||||
czMesh.geometry.update(view);
|
||||
view.setVertexStream(0, czMesh.geometry.vertexBuffer, 0, "FLOAT_3");
|
||||
view.setProgramConstants("FRAGMENT", 0, 1, Vector.<Number>([1, 0, 0, 1]));
|
||||
view.setCulling("NONE");
|
||||
if (debug) {
|
||||
view.drawTrianglesSynchronized(czMesh.geometry.indexBuffer, 0, czMesh.geometry.numTriangles);
|
||||
} else {
|
||||
view.drawTriangles(czMesh.geometry.indexBuffer, 0, czMesh.geometry.numTriangles);
|
||||
}
|
||||
view.setDepthTest(true, "LESS");
|
||||
view.setBlending("ONE", "ZERO");
|
||||
}
|
||||
|
||||
/**
|
||||
* Переводит точку из глобального пространства в экранные координаты.
|
||||
* @param v Точка в глобальном пространстве.
|
||||
* @param result Экземпляр <code>Vector3D</code>, в который записывается результат.
|
||||
*/
|
||||
public function projectGlobal(v:Vector3D, result:Vector3D):void {
|
||||
/*composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
appendMatrix(root);
|
||||
}
|
||||
invertMatrix();
|
||||
var x:Number = ma*v.x + mb*v.y + mc*v.z + md;
|
||||
var y:Number = me*v.x + mf*v.y + mg*v.z + mh;
|
||||
var z:Number = mi*v.x + mj*v.y + mk*v.z + ml;
|
||||
result.x = x*viewSizeX/z + view._width/2;
|
||||
result.y = y*viewSizeY/z + view._height/2;
|
||||
result.z = z;*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчитывает луч в глобальном пространстве.
|
||||
* Прямая луча проходит через начало координат камеры и точку на плоскости вьюпорта, заданную <code>deltaX</code> и <code>deltaY</code>.
|
||||
* Луч может быть использован в методе <code>intersectRay()</code> трёхмерных объектов.
|
||||
* @param origin Начало луча. Луч начинается от <code>nearClipping</code> камеры.
|
||||
* @param direction Направление луча.
|
||||
* @param deltaX Горизонтальная координата в плоскости вьюпорта относительно его центра.
|
||||
* @param deltaY Вертикальная координата в плоскости вьюпорта относительно его центра.
|
||||
*/
|
||||
public function calculateRay(origin:Vector3D, direction:Vector3D, deltaX:Number = 0, deltaY:Number = 0):void {
|
||||
// Создание луча в камере
|
||||
/*var dx:Number = deltaX*focalLength/viewSizeX;
|
||||
var dy:Number = deltaY*focalLength/viewSizeY;
|
||||
var dz:Number = focalLength;
|
||||
var ox:Number = dx*nearClipping/focalLength;
|
||||
var oy:Number = dy*nearClipping/focalLength;
|
||||
var oz:Number = nearClipping;
|
||||
// Перевод луча в глобальное пространство
|
||||
composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
appendMatrix(root);
|
||||
}
|
||||
origin.x = ma*ox + mb*oy + mc*oz + md;
|
||||
origin.y = me*ox + mf*oy + mg*oz + mh;
|
||||
origin.z = mi*ox + mj*oy + mk*oz + ml;
|
||||
direction.x = ma*dx + mb*dy + mc*dz;
|
||||
direction.y = me*dx + mf*dy + mg*dz;
|
||||
direction.z = mi*dx + mj*dy + mk*dz;
|
||||
var directionL:Number = 1/Math.sqrt(direction.x*direction.x + direction.y*direction.y + direction.z*direction.z);
|
||||
direction.x *= directionL;
|
||||
direction.y *= directionL;
|
||||
direction.z *= directionL;*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Object3D {
|
||||
var camera:Camera3D = new Camera3D(nearClipping, farClipping);
|
||||
camera.cloneBaseProperties(this);
|
||||
camera.fov = fov;
|
||||
camera.nearClipping = nearClipping;
|
||||
camera.farClipping = farClipping;
|
||||
return camera;
|
||||
}
|
||||
|
||||
// Диаграмма
|
||||
|
||||
private var _diagram:Sprite = createDiagram();
|
||||
|
||||
/**
|
||||
* Количество кадров, через которые происходит обновление значения FPS в диаграмме.
|
||||
* @see #diagram
|
||||
*/
|
||||
public var fpsUpdatePeriod:int = 10;
|
||||
|
||||
/**
|
||||
* Количество кадров, через которые происходит обновление значения MS в диаграмме.
|
||||
* @see #diagram
|
||||
*/
|
||||
public var timerUpdatePeriod:int = 10;
|
||||
|
||||
private var fpsTextField:TextField;
|
||||
private var memoryTextField:TextField;
|
||||
private var drawsTextField: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;
|
||||
|
||||
private var fpsUpdateCounter:int;
|
||||
private var previousFrameTime:int;
|
||||
private var previousPeriodTime:int;
|
||||
|
||||
private var maxMemory:int;
|
||||
|
||||
private var timerUpdateCounter:int;
|
||||
private var timeSum:int;
|
||||
private var timeCount:int;
|
||||
private var timer:int;
|
||||
|
||||
/**
|
||||
* Начинает отсчёт времени.
|
||||
* Методы <code>startTimer()</code> и <code>stopTimer()</code> нужны для того, чтобы замерять время выполнения ежекадрово вызывающегося куска кода.
|
||||
* Результат замера показывается в диаграмме в поле MS.
|
||||
* @see #diagram
|
||||
* @see #stopTimer()
|
||||
*/
|
||||
public function startTimer():void {
|
||||
timer = getTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Заканчивает отсчёт времени.
|
||||
* Методы <code>startTimer()</code> и <code>stopTimer()</code> нужны для того, чтобы замерять время выполнения ежекадрово вызывающегося куска кода.
|
||||
* Результат замера показывается в диаграмме в поле MS.
|
||||
* @see #diagram
|
||||
* @see #startTimer()
|
||||
*/
|
||||
public function stopTimer():void {
|
||||
timeSum += getTimer() - timer;
|
||||
timeCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Диаграмма, на которой отображается отладочная информация.
|
||||
* Чтобы отобразить диаграмму, её нужно добавить на экран.
|
||||
* FPS — Среднее количество кадров в секунду за промежуток в <code>fpsUpdatePeriod</code> кадров.<br>
|
||||
* MS — Среднее время выполнения замеряемого с помощью <code>startTimer</code> - <code>stopTimer</code> участка кода в миллисекундах за промежуток в <code>timerUpdatePeriod</code> кадров.<br>
|
||||
* MEM — Количество занимаемой плеером памяти в мегабайтах.<br>
|
||||
* DRW — Количество отрисовочных вызовов в текущем кадре.<br>
|
||||
* PLG — Количество видимых полигонов в текущем кадре.<br>
|
||||
* TRI — Количество отрисованных треугольников в текущем кадре.
|
||||
* @see #fpsUpdatePeriod
|
||||
* @see #timerUpdatePeriod
|
||||
* @see #startTimer()
|
||||
* @see #stopTimer()
|
||||
*/
|
||||
public function get diagram():DisplayObject {
|
||||
return _diagram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Выравнивание диаграммы относительно рабочей области.
|
||||
* Можно использовать константы класса <code>StageAlign</code>.
|
||||
*/
|
||||
public function get diagramAlign():String {
|
||||
return _diagramAlign;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set diagramAlign(value:String):void {
|
||||
_diagramAlign = value;
|
||||
resizeDiagram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Отступ диаграммы от края рабочей области по горизонтали.
|
||||
*/
|
||||
public function get diagramHorizontalMargin():Number {
|
||||
return _diagramHorizontalMargin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set diagramHorizontalMargin(value:Number):void {
|
||||
_diagramHorizontalMargin = value;
|
||||
resizeDiagram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Отступ диаграммы от края рабочей области по вертикали.
|
||||
*/
|
||||
public function get diagramVerticalMargin():Number {
|
||||
return _diagramVerticalMargin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set diagramVerticalMargin(value:Number):void {
|
||||
_diagramVerticalMargin = value;
|
||||
resizeDiagram();
|
||||
}
|
||||
|
||||
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:";
|
||||
fpsTextField.selectable = false;
|
||||
fpsTextField.x = -3;
|
||||
fpsTextField.y = -5;
|
||||
diagram.addChild(fpsTextField);
|
||||
fpsTextField = new TextField();
|
||||
fpsTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xCCCCCC);
|
||||
fpsTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
fpsTextField.text = Number(diagram.stage.frameRate).toFixed(2);
|
||||
fpsTextField.selectable = false;
|
||||
fpsTextField.x = -3;
|
||||
fpsTextField.y = -5;
|
||||
fpsTextField.width = 85;
|
||||
diagram.addChild(fpsTextField);
|
||||
// Время выполнения метода
|
||||
timerTextField = new TextField();
|
||||
timerTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x0066FF);
|
||||
timerTextField.autoSize = TextFieldAutoSize.LEFT;
|
||||
timerTextField.text = "MS:";
|
||||
timerTextField.selectable = false;
|
||||
timerTextField.x = -3;
|
||||
timerTextField.y = 4;
|
||||
diagram.addChild(timerTextField);
|
||||
timerTextField = new TextField();
|
||||
timerTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x0066FF);
|
||||
timerTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
timerTextField.text = "";
|
||||
timerTextField.selectable = false;
|
||||
timerTextField.x = -3;
|
||||
timerTextField.y = 4;
|
||||
timerTextField.width = 85;
|
||||
diagram.addChild(timerTextField);
|
||||
// Память
|
||||
memoryTextField = new TextField();
|
||||
memoryTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xCCCC00);
|
||||
memoryTextField.autoSize = TextFieldAutoSize.LEFT;
|
||||
memoryTextField.text = "MEM:";
|
||||
memoryTextField.selectable = false;
|
||||
memoryTextField.x = -3;
|
||||
memoryTextField.y = 13;
|
||||
diagram.addChild(memoryTextField);
|
||||
memoryTextField = new TextField();
|
||||
memoryTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xCCCC00);
|
||||
memoryTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
memoryTextField.text = bytesToString(System.totalMemory);
|
||||
memoryTextField.selectable = false;
|
||||
memoryTextField.x = -3;
|
||||
memoryTextField.y = 13;
|
||||
memoryTextField.width = 85;
|
||||
diagram.addChild(memoryTextField);
|
||||
// Отрисовочные вызовы
|
||||
drawsTextField = new TextField();
|
||||
drawsTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x00CC00);
|
||||
drawsTextField.autoSize = TextFieldAutoSize.LEFT;
|
||||
drawsTextField.text = "DRW:";
|
||||
drawsTextField.selectable = false;
|
||||
drawsTextField.x = -3;
|
||||
drawsTextField.y = 22;
|
||||
diagram.addChild(drawsTextField);
|
||||
drawsTextField = new TextField();
|
||||
drawsTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x00CC00);
|
||||
drawsTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
drawsTextField.text = "0";
|
||||
drawsTextField.selectable = false;
|
||||
drawsTextField.x = -3;
|
||||
drawsTextField.y = 22;
|
||||
drawsTextField.width = 72;
|
||||
diagram.addChild(drawsTextField);
|
||||
// Треугольники
|
||||
trianglesTextField = new TextField();
|
||||
trianglesTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xFF3300); // 0xFF6600, 0xFF0033
|
||||
trianglesTextField.autoSize = TextFieldAutoSize.LEFT;
|
||||
trianglesTextField.text = "TRI:";
|
||||
trianglesTextField.selectable = false;
|
||||
trianglesTextField.x = -3;
|
||||
trianglesTextField.y = 31;
|
||||
diagram.addChild(trianglesTextField);
|
||||
trianglesTextField = new TextField();
|
||||
trianglesTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xFF3300);
|
||||
trianglesTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
trianglesTextField.text = "0";
|
||||
trianglesTextField.selectable = false;
|
||||
trianglesTextField.x = -3;
|
||||
trianglesTextField.y = 31;
|
||||
trianglesTextField.width = 72;
|
||||
diagram.addChild(trianglesTextField);
|
||||
// График
|
||||
graph = new Bitmap(new BitmapData(80, 40, true, 0x20FFFFFF));
|
||||
rect = new Rectangle(0, 0, 1, 40);
|
||||
graph.x = 0;
|
||||
graph.y = 45;
|
||||
diagram.addChild(graph);
|
||||
// Сброс параметров
|
||||
previousPeriodTime = getTimer();
|
||||
previousFrameTime = previousPeriodTime;
|
||||
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(drawsTextField);
|
||||
diagram.removeChild(trianglesTextField);
|
||||
diagram.removeChild(timerTextField);
|
||||
diagram.removeChild(graph);
|
||||
fpsTextField = null;
|
||||
memoryTextField = null;
|
||||
drawsTextField = 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 value:Number;
|
||||
var mod:int;
|
||||
var time:int = getTimer();
|
||||
var stageFrameRate:int = _diagram.stage.frameRate;
|
||||
|
||||
// FPS текст
|
||||
if (++fpsUpdateCounter == fpsUpdatePeriod) {
|
||||
value = 1000*fpsUpdatePeriod/(time - previousPeriodTime);
|
||||
if (value > stageFrameRate) value = stageFrameRate;
|
||||
mod = value*100 % 100;
|
||||
fpsTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00"));
|
||||
previousPeriodTime = time;
|
||||
fpsUpdateCounter = 0;
|
||||
}
|
||||
// FPS график
|
||||
value = 1000/(time - previousFrameTime);
|
||||
if (value > stageFrameRate) value = stageFrameRate;
|
||||
graph.bitmapData.scroll(1, 0);
|
||||
graph.bitmapData.fillRect(rect, 0x20FFFFFF);
|
||||
graph.bitmapData.setPixel32(0, 40*(1 - value/stageFrameRate), 0xFFCCCCCC);
|
||||
previousFrameTime = time;
|
||||
|
||||
// Время текст
|
||||
if (++timerUpdateCounter == timerUpdatePeriod) {
|
||||
if (timeCount > 0) {
|
||||
value = timeSum/timeCount;
|
||||
mod = value*100 % 100;
|
||||
timerTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00"));
|
||||
} else {
|
||||
timerTextField.text = "";
|
||||
}
|
||||
timerUpdateCounter = 0;
|
||||
timeSum = 0;
|
||||
timeCount = 0;
|
||||
}
|
||||
|
||||
// Память текст
|
||||
var memory:int = System.totalMemory;
|
||||
value = memory/1048576;
|
||||
mod = value*100 % 100;
|
||||
memoryTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00"));
|
||||
|
||||
// Память график
|
||||
if (memory > maxMemory) maxMemory = memory;
|
||||
graph.bitmapData.setPixel32(0, 40*(1 - memory/maxMemory), 0xFFCCCC00);
|
||||
|
||||
// Отрисовочные вызовы текст
|
||||
drawsTextField.text = formatInt(numDraws);
|
||||
|
||||
// Треугольники текст
|
||||
trianglesTextField.text = formatInt(numTriangles);
|
||||
}
|
||||
|
||||
private function formatInt(num:int):String {
|
||||
var n:int;
|
||||
var s:String;
|
||||
if (num < 1000) {
|
||||
return "" + num;
|
||||
} else if (num < 1000000) {
|
||||
n = num % 1000;
|
||||
if (n < 10) {
|
||||
s = "00" + n;
|
||||
} else if (n < 100) {
|
||||
s = "0" + n;
|
||||
} else {
|
||||
s = "" + n;
|
||||
}
|
||||
return int(num/1000) + " " + s;
|
||||
} else {
|
||||
n = (num % 1000000)/1000;
|
||||
if (n < 10) {
|
||||
s = "00" + n;
|
||||
} else if (n < 100) {
|
||||
s = "0" + n;
|
||||
} else {
|
||||
s = "" + n;
|
||||
}
|
||||
n = num % 1000;
|
||||
if (n < 10) {
|
||||
s += " 00" + n;
|
||||
} else if (n < 100) {
|
||||
s += " 0" + n;
|
||||
} else {
|
||||
s += " " + n;
|
||||
}
|
||||
return int(num/1000000) + " " + s;
|
||||
}
|
||||
}
|
||||
|
||||
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 String(bytes >> 20);// + "mb";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import __AS3__.vec.Vector;
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Грань, образованная тремя или более вершинами. Грани являются составными частями полигональных объектов.
|
||||
* @see alternativa.engine3d.core.Geometry
|
||||
* @see alternativa.engine3d.core.Vertex
|
||||
*/
|
||||
public class Face {
|
||||
|
||||
// /**
|
||||
// * Материал грани.
|
||||
// * @see alternativa.engine3d.materials.Material
|
||||
// */
|
||||
// public var material:Material;
|
||||
|
||||
alternativa3d var geometry:Geometry;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var next:Face;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var wrapper:Wrapper;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var normalX:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var normalY:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var normalZ:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var offset:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static alternativa3d var collector:Face;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static alternativa3d function create():Face {
|
||||
if (collector != null) {
|
||||
var res:Face = collector;
|
||||
collector = res.next;
|
||||
res.next = null;
|
||||
/*if (res.processNext != null) trace("!!!processNext!!!");
|
||||
if (res.geometry != null) trace("!!!geometry!!!");
|
||||
if (res.negative != null) trace("!!!negative!!!");
|
||||
if (res.positive != null) trace("!!!positive!!!");*/
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Face");
|
||||
return new Face();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function create():Face {
|
||||
if (collector != null) {
|
||||
var res:Face = collector;
|
||||
collector = res.next;
|
||||
res.next = null;
|
||||
/*if (res.processNext != null) trace("!!!processNext!!!");
|
||||
if (res.geometry != null) trace("!!!geometry!!!");
|
||||
if (res.negative != null) trace("!!!negative!!!");
|
||||
if (res.positive != null) trace("!!!positive!!!");*/
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Face");
|
||||
return new Face();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Нормаль грани.
|
||||
*/
|
||||
public function get normal():Vector3D {
|
||||
var w:Wrapper = wrapper;
|
||||
var a:Vertex = w.vertex; w = w.next;
|
||||
var b:Vertex = w.vertex; w = w.next;
|
||||
var c:Vertex = w.vertex;
|
||||
var abx:Number = b._x - a._x;
|
||||
var aby:Number = b._y - a._y;
|
||||
var abz:Number = b._z - a._z;
|
||||
var acx:Number = c._x - a._x;
|
||||
var acy:Number = c._y - a._y;
|
||||
var acz:Number = c._z - a._z;
|
||||
var nx:Number = acz*aby - acy*abz;
|
||||
var ny:Number = acx*abz - acz*abx;
|
||||
var nz:Number = acy*abx - acx*aby;
|
||||
var len:Number = nx*nx + ny*ny + nz*nz;
|
||||
if (len > 0.001) {
|
||||
len = 1/Math.sqrt(len);
|
||||
nx *= len;
|
||||
ny *= len;
|
||||
nz *= len;
|
||||
}
|
||||
return new Vector3D(nx, ny, nz, a._x*nx + a._y*ny + a._z*nz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Вершины, на базе которых построена грань.
|
||||
* @see alternativa.engine3d.core.Vertex
|
||||
*/
|
||||
public function get vertices():Vector.<Vertex> {
|
||||
var res:Vector.<Vertex> = new Vector.<Vertex>();
|
||||
var len:int = 0;
|
||||
for (var w:Wrapper = wrapper; w != null; w = w.next) {
|
||||
res[len] = w.vertex;
|
||||
len++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
alternativa3d function setVertices(value:Vector.<Vertex>):void {
|
||||
var last:Wrapper = null;
|
||||
for (var i:int = 0, count:int = value.length; i < count; i++) {
|
||||
var newWrapper:Wrapper = new Wrapper();
|
||||
newWrapper.vertex = value[i];
|
||||
if (last != null) {
|
||||
last.next = newWrapper;
|
||||
} else {
|
||||
wrapper = newWrapper;
|
||||
}
|
||||
last = newWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function calculateBestSequenceAndNormal():void {
|
||||
if (wrapper.next.next.next != null) {
|
||||
var max:Number = -1e+22;
|
||||
var s:Wrapper;
|
||||
var sm:Wrapper;
|
||||
var sp:Wrapper;
|
||||
for (w = wrapper; w != null; w = w.next) {
|
||||
var wn:Wrapper = (w.next != null) ? w.next : wrapper;
|
||||
var wm:Wrapper = (wn.next != null) ? wn.next : wrapper;
|
||||
a = w.vertex;
|
||||
b = wn.vertex;
|
||||
c = wm.vertex;
|
||||
abx = b._x - a._x;
|
||||
aby = b._y - a._y;
|
||||
abz = b._z - a._z;
|
||||
acx = c._x - a._x;
|
||||
acy = c._y - a._y;
|
||||
acz = c._z - a._z;
|
||||
nx = acz*aby - acy*abz;
|
||||
ny = acx*abz - acz*abx;
|
||||
nz = acy*abx - acx*aby;
|
||||
nl = nx*nx + ny*ny + nz*nz;
|
||||
if (nl > max) {
|
||||
max = nl;
|
||||
s = w;
|
||||
}
|
||||
}
|
||||
if (s != wrapper) {
|
||||
//for (sm = wrapper.next.next.next; sm.next != null; sm = sm.next);
|
||||
sm = wrapper.next.next.next;
|
||||
while (sm.next != null) sm = sm.next;
|
||||
//for (sp = wrapper; sp.next != s && sp.next != null; sp = sp.next);
|
||||
sp = wrapper;
|
||||
while (sp.next != s && sp.next != null) sp = sp.next;
|
||||
sm.next = wrapper;
|
||||
sp.next = null;
|
||||
wrapper = s;
|
||||
}
|
||||
}
|
||||
var w:Wrapper = wrapper;
|
||||
var a:Vertex = w.vertex;
|
||||
w = w.next;
|
||||
var b:Vertex = w.vertex;
|
||||
w = w.next;
|
||||
var c:Vertex = w.vertex;
|
||||
var abx:Number = b._x - a._x;
|
||||
var aby:Number = b._y - a._y;
|
||||
var abz:Number = b._z - a._z;
|
||||
var acx:Number = c._x - a._x;
|
||||
var acy:Number = c._y - a._y;
|
||||
var acz:Number = c._z - a._z;
|
||||
var nx:Number = acz*aby - acy*abz;
|
||||
var ny:Number = acx*abz - acz*abx;
|
||||
var nz:Number = acy*abx - acx*aby;
|
||||
var nl:Number = nx*nx + ny*ny + nz*nz;
|
||||
if (nl > 0) {
|
||||
nl = 1/Math.sqrt(nl);
|
||||
nx *= nl;
|
||||
ny *= nl;
|
||||
nz *= nl;
|
||||
normalX = nx;
|
||||
normalY = ny;
|
||||
normalZ = nz;
|
||||
}
|
||||
offset = a._x*nx + a._y*ny + a._z*nz;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,699 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.lights.DirectionalLight;
|
||||
|
||||
import flash.events.EventDispatcher;
|
||||
import flash.geom.Matrix3D;
|
||||
import flash.geom.Vector3D;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.getQualifiedClassName;
|
||||
|
||||
use namespace alternativa3d;
|
||||
public class Object3D extends EventDispatcher {
|
||||
|
||||
/**
|
||||
* Имя объекта.
|
||||
*/
|
||||
public var name:String;
|
||||
|
||||
/**
|
||||
* Флаг видимости объекта.
|
||||
*/
|
||||
public var visible:Boolean = true;
|
||||
|
||||
/**
|
||||
* Координата X.
|
||||
*/
|
||||
public var x:Number = 0;
|
||||
|
||||
/**
|
||||
* Координата Y.
|
||||
*/
|
||||
public var y:Number = 0;
|
||||
|
||||
/**
|
||||
* Координата Z.
|
||||
*/
|
||||
public var z:Number = 0;
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси X.
|
||||
* Указывается в радианах.
|
||||
*/
|
||||
public var rotationX:Number = 0;
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси Y.
|
||||
* Указывается в радианах.
|
||||
*/
|
||||
public var rotationY:Number = 0;
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси Z.
|
||||
* Указывается в радианах.
|
||||
*/
|
||||
public var rotationZ:Number = 0;
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования по оси X.
|
||||
*/
|
||||
public var scaleX:Number = 1;
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования по оси Y.
|
||||
*/
|
||||
public var scaleY:Number = 1;
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования по оси Z.
|
||||
*/
|
||||
public var scaleZ:Number = 1;
|
||||
|
||||
/**
|
||||
* Левая граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMinX:Number = -1e+22;
|
||||
|
||||
/**
|
||||
* Задняя граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMinY:Number = -1e+22;
|
||||
|
||||
/**
|
||||
* Нижняя граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMinZ:Number = -1e+22;
|
||||
|
||||
/**
|
||||
* Правая граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMaxX:Number = 1e+22;
|
||||
|
||||
/**
|
||||
* Передняя граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMaxY:Number = 1e+22;
|
||||
|
||||
/**
|
||||
* Верхняя граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMaxZ:Number = 1e+22;
|
||||
|
||||
alternativa3d var cameraMatrix:Matrix3D = new Matrix3D();
|
||||
alternativa3d var cameraMatrixData:Vector.<Number> = new Vector.<Number>(16);
|
||||
alternativa3d var projectionMatrix:Matrix3D = new Matrix3D();
|
||||
alternativa3d var _parent:Object3DContainer;
|
||||
alternativa3d var next:Object3D;
|
||||
alternativa3d var culling:int = 0;
|
||||
alternativa3d var distance:Number;
|
||||
alternativa3d var weightsSum:Vector.<Number>;
|
||||
|
||||
alternativa3d function get isTransparent():Boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает родительский объект <code>Object3DContainer</code>.
|
||||
*/
|
||||
public function get parent():Object3DContainer {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Объект <code>Matrix3D</code>, содержащий значения, влияющие на масштабирование, поворот и перемещение объекта.
|
||||
*/
|
||||
public function get matrix():Matrix3D {
|
||||
var m:Matrix3D = new Matrix3D();
|
||||
var t:Vector3D = new Vector3D(x, y, z);
|
||||
var r:Vector3D = new Vector3D(rotationX, rotationY, rotationZ);
|
||||
var s:Vector3D = new Vector3D(scaleX, scaleY, scaleZ);
|
||||
var v:Vector.<Vector3D> = new Vector.<Vector3D>();
|
||||
v[0] = t;
|
||||
v[1] = r;
|
||||
v[2] = s;
|
||||
m.recompose(v);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set matrix(value:Matrix3D):void {
|
||||
var v:Vector.<Vector3D> = value.decompose();
|
||||
var t:Vector3D = v[0];
|
||||
var r:Vector3D = v[1];
|
||||
var s:Vector3D = v[2];
|
||||
x = t.x;
|
||||
y = t.y;
|
||||
z = t.z;
|
||||
rotationX = r.x;
|
||||
rotationY = r.y;
|
||||
rotationZ = r.z;
|
||||
scaleX = s.x;
|
||||
scaleY = s.y;
|
||||
scaleZ = s.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчитывает границы объекта в его системе координат.
|
||||
*/
|
||||
public function calculateBounds():void {
|
||||
// Выворачивание баунда
|
||||
boundMinX = 1e+22;
|
||||
boundMinY = 1e+22;
|
||||
boundMinZ = 1e+22;
|
||||
boundMaxX = -1e+22;
|
||||
boundMaxY = -1e+22;
|
||||
boundMaxZ = -1e+22;
|
||||
// Заполнение баунда
|
||||
updateBounds(this, null);
|
||||
// Если баунд вывернут
|
||||
if (boundMinX > boundMaxX) {
|
||||
boundMinX = -1e+22;
|
||||
boundMinY = -1e+22;
|
||||
boundMinZ = -1e+22;
|
||||
boundMaxX = 1e+22;
|
||||
boundMaxY = 1e+22;
|
||||
boundMaxZ = 1e+22;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует точку из локальных координат в глобальные.
|
||||
* @param point Точка в локальных координатах объекта.
|
||||
* @return Точка в глобальном пространстве.
|
||||
*/
|
||||
/*public function localToGlobal(point:Vector3D):Vector3D {
|
||||
composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
appendMatrix(root);
|
||||
}
|
||||
var res:Vector3D = new Vector3D();
|
||||
res.x = ma*point.x + mb*point.y + mc*point.z + md;
|
||||
res.y = me*point.x + mf*point.y + mg*point.z + mh;
|
||||
res.z = mi*point.x + mj*point.y + mk*point.z + ml;
|
||||
return res;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Преобразует точку из глобальной системы координат в локальные координаты объекта.
|
||||
* @param point Точка в глобальном пространстве.
|
||||
* @return Точка в локальных координатах объекта.
|
||||
*/
|
||||
/*public function globalToLocal(point:Vector3D):Vector3D {
|
||||
composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
appendMatrix(root);
|
||||
}
|
||||
invertMatrix();
|
||||
var res:Vector3D = new Vector3D();
|
||||
res.x = ma*point.x + mb*point.y + mc*point.z + md;
|
||||
res.y = me*point.x + mf*point.y + mg*point.z + mh;
|
||||
res.z = mi*point.x + mj*point.y + mk*point.z + ml;
|
||||
return res;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Осуществляет поиск пересечение луча с объектом.
|
||||
* @param origin Начало луча.
|
||||
* @param direction Направление луча.
|
||||
* @param exludedObjects Ассоциативный массив, ключами которого являются экземпляры <code>Object3D</code> и его наследников. Объекты, содержащиеся в этом массиве будут исключены из проверки.
|
||||
* @param camera Камера для правильного поиска пересечения луча с объектами <code>Sprite3D</code>. Эти объекты всегда повёрнуты к камере. Если камера не указана, результат пересечения луча со спрайтом будет <code>null</code>.
|
||||
* @return Результат поиска пересечения — объект <code>RayIntersectionData</code>. Если пересечения нет, будет возвращён <code>null</code>.
|
||||
* @see RayIntersectionData
|
||||
* @see alternativa.engine3d.objects.Sprite3D
|
||||
*/
|
||||
public function intersectRay(origin:Vector3D, direction:Vector3D, exludedObjects:Dictionary = null, camera:Camera3D = null):RayIntersectionData {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает объект, являющийся точной копией исходного объекта.
|
||||
* @return Клон исходного объекта.
|
||||
*/
|
||||
public function clone():Object3D {
|
||||
var res:Object3D = new Object3D();
|
||||
res.cloneBaseProperties(this);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Копирует базовые свойства. Метод вызывается внутри <code>clone()</code>.
|
||||
* @param source Объект, с которого копируются базовые свойства.
|
||||
*/
|
||||
protected function cloneBaseProperties(source:Object3D):void {
|
||||
name = source.name;
|
||||
visible = source.visible;
|
||||
distance = source.distance;
|
||||
x = source.x;
|
||||
y = source.y;
|
||||
z = source.z;
|
||||
rotationX = source.rotationX;
|
||||
rotationY = source.rotationY;
|
||||
rotationZ = source.rotationZ;
|
||||
scaleX = source.scaleX;
|
||||
scaleY = source.scaleY;
|
||||
scaleZ = source.scaleZ;
|
||||
boundMinX = source.boundMinX;
|
||||
boundMinY = source.boundMinY;
|
||||
boundMinZ = source.boundMinZ;
|
||||
boundMaxX = source.boundMaxX;
|
||||
boundMaxY = source.boundMaxY;
|
||||
boundMaxZ = source.boundMaxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает строковое представление заданного объекта.
|
||||
* @return Строковое представление объекта.
|
||||
*/
|
||||
override public function toString():String {
|
||||
var className:String = getQualifiedClassName(this);
|
||||
return "[" + className.substr(className.indexOf("::") + 2) + " " + name + "]";
|
||||
}
|
||||
|
||||
// Переопределяемые закрытые методы
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function draw(camera:Camera3D):void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function drawInShadowMap(camera:Camera3D, light:DirectionalLight):void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function updateBounds(bounds:Object3D, matrix:Matrix3D = null):void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function composeMatrix():void {
|
||||
var cosX:Number = Math.cos(rotationX);
|
||||
var sinX:Number = Math.sin(rotationX);
|
||||
var cosY:Number = Math.cos(rotationY);
|
||||
var sinY:Number = Math.sin(rotationY);
|
||||
var cosZ:Number = Math.cos(rotationZ);
|
||||
var sinZ:Number = Math.sin(rotationZ);
|
||||
var cosZsinY:Number = cosZ*sinY;
|
||||
var sinZsinY:Number = sinZ*sinY;
|
||||
var cosYscaleX:Number = cosY*scaleX;
|
||||
var sinXscaleY:Number = sinX*scaleY;
|
||||
var cosXscaleY:Number = cosX*scaleY;
|
||||
var cosXscaleZ:Number = cosX*scaleZ;
|
||||
var sinXscaleZ:Number = sinX*scaleZ;
|
||||
cameraMatrixData[0] = cosZ*cosYscaleX;
|
||||
cameraMatrixData[4] = cosZsinY*sinXscaleY - sinZ*cosXscaleY;
|
||||
cameraMatrixData[8] = cosZsinY*cosXscaleZ + sinZ*sinXscaleZ;
|
||||
cameraMatrixData[12] = x;
|
||||
cameraMatrixData[1] = sinZ*cosYscaleX;
|
||||
cameraMatrixData[5] = sinZsinY*sinXscaleY + cosZ*cosXscaleY;
|
||||
cameraMatrixData[9] = sinZsinY*cosXscaleZ - cosZ*sinXscaleZ;
|
||||
cameraMatrixData[13] = y;
|
||||
cameraMatrixData[2] = -sinY*scaleX;
|
||||
cameraMatrixData[6] = cosY*sinXscaleY;
|
||||
cameraMatrixData[10] = cosY*cosXscaleZ;
|
||||
cameraMatrixData[14] = z;
|
||||
cameraMatrixData[3] = 0;
|
||||
cameraMatrixData[7] = 0;
|
||||
cameraMatrixData[11] = 0;
|
||||
cameraMatrixData[15] = 1;
|
||||
cameraMatrix.rawData = cameraMatrixData;
|
||||
}
|
||||
|
||||
static private const boundVertices:Vector.<Number> = new Vector.<Number>(24);
|
||||
|
||||
alternativa3d function cullingInCamera(camera:Camera3D, culling:int):int {
|
||||
if (culling > 0) {
|
||||
var i:int;
|
||||
var infront:Boolean;
|
||||
var behind:Boolean;
|
||||
// Заполнение
|
||||
boundVertices[0] = boundMinX;
|
||||
boundVertices[1] = boundMinY;
|
||||
boundVertices[2] = boundMinZ;
|
||||
boundVertices[3] = boundMaxX;
|
||||
boundVertices[4] = boundMinY;
|
||||
boundVertices[5] = boundMinZ;
|
||||
boundVertices[6] = boundMinX;
|
||||
boundVertices[7] = boundMaxY;
|
||||
boundVertices[8] = boundMinZ;
|
||||
boundVertices[9] = boundMaxX;
|
||||
boundVertices[10] = boundMaxY;
|
||||
boundVertices[11] = boundMinZ;
|
||||
boundVertices[12] = boundMinX;
|
||||
boundVertices[13] = boundMinY;
|
||||
boundVertices[14] = boundMaxZ;
|
||||
boundVertices[15] = boundMaxX;
|
||||
boundVertices[16] = boundMinY;
|
||||
boundVertices[17] = boundMaxZ;
|
||||
boundVertices[18] = boundMinX;
|
||||
boundVertices[19] = boundMaxY;
|
||||
boundVertices[20] = boundMaxZ;
|
||||
boundVertices[21] = boundMaxX;
|
||||
boundVertices[22] = boundMaxY;
|
||||
boundVertices[23] = boundMaxZ;
|
||||
// Трансформация в камеру
|
||||
cameraMatrix.transformVectors(boundVertices, boundVertices);
|
||||
// Коррекция под 90 градусов
|
||||
var sx:Number = camera.focalLength*2/camera.view._width;
|
||||
var sy:Number = camera.focalLength*2/camera.view._height;
|
||||
for (i = 0; i < 24; i += 2) {
|
||||
boundVertices[i] *= sx; i++;
|
||||
boundVertices[i] *= sy;
|
||||
}
|
||||
// Куллинг
|
||||
if (culling & 1) {
|
||||
for (i = 2, infront = false, behind = false; i <= 23; i += 3) {
|
||||
if (boundVertices[i] > camera.nearClipping) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 62;
|
||||
}
|
||||
}
|
||||
if (culling & 2) {
|
||||
for (i = 2, infront = false, behind = false; i <= 23; i += 3) {
|
||||
if (boundVertices[i] < camera.farClipping) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 61;
|
||||
}
|
||||
}
|
||||
if (culling & 4) {
|
||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
||||
if (-boundVertices[i] < boundVertices[int(i + 2)]) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 59;
|
||||
}
|
||||
}
|
||||
if (culling & 8) {
|
||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
||||
if (boundVertices[i] < boundVertices[int(i + 2)]) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 55;
|
||||
}
|
||||
}
|
||||
if (culling & 16) {
|
||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
||||
if (-boundVertices[i] < boundVertices[int(i + 1)]) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 47;
|
||||
}
|
||||
}
|
||||
if (culling & 32) {
|
||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
||||
if (boundVertices[i] < boundVertices[int(i + 1)]) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 31;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.culling = culling;
|
||||
return culling;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
/*alternativa3d function cullingInCamera(camera:Camera3D, culling:int):int {
|
||||
if (camera.occludedAll) return -1;
|
||||
var numOccluders:int = camera.numOccluders;
|
||||
var vertex:Vertex;
|
||||
// Расчёт точек баунда в координатах камеры
|
||||
if (culling > 0 || numOccluders > 0) {
|
||||
// Заполнение
|
||||
vertex = boundVertexList;
|
||||
vertex.x = boundMinX;
|
||||
vertex.y = boundMinY;
|
||||
vertex.z = boundMinZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMaxX;
|
||||
vertex.y = boundMinY;
|
||||
vertex.z = boundMinZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMinX;
|
||||
vertex.y = boundMaxY;
|
||||
vertex.z = boundMinZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMaxX;
|
||||
vertex.y = boundMaxY;
|
||||
vertex.z = boundMinZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMinX;
|
||||
vertex.y = boundMinY;
|
||||
vertex.z = boundMaxZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMaxX;
|
||||
vertex.y = boundMinY;
|
||||
vertex.z = boundMaxZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMinX;
|
||||
vertex.y = boundMaxY;
|
||||
vertex.z = boundMaxZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMaxX;
|
||||
vertex.y = boundMaxY;
|
||||
vertex.z = boundMaxZ;
|
||||
// Трансформация в камеру
|
||||
for (vertex = boundVertexList; vertex != null; vertex = vertex.next) {
|
||||
var x:Number = vertex.x;
|
||||
var y:Number = vertex.y;
|
||||
var z:Number = vertex.z;
|
||||
vertex.cameraX = ma*x + mb*y + mc*z + md;
|
||||
vertex.cameraY = me*x + mf*y + mg*z + mh;
|
||||
vertex.cameraZ = mi*x + mj*y + mk*z + ml;
|
||||
}
|
||||
}
|
||||
// Куллинг
|
||||
if (culling > 0) {
|
||||
var infront:Boolean;
|
||||
var behind:Boolean;
|
||||
if (culling & 1) {
|
||||
var near:Number = camera.nearClipping;
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (vertex.cameraZ > near) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 62;
|
||||
}
|
||||
}
|
||||
if (culling & 2) {
|
||||
var far:Number = camera.farClipping;
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (vertex.cameraZ < far) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 61;
|
||||
}
|
||||
}
|
||||
if (culling & 4) {
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (-vertex.cameraX < vertex.cameraZ) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 59;
|
||||
}
|
||||
}
|
||||
if (culling & 8) {
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (vertex.cameraX < vertex.cameraZ) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 55;
|
||||
}
|
||||
}
|
||||
if (culling & 16) {
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (-vertex.cameraY < vertex.cameraZ) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 47;
|
||||
}
|
||||
}
|
||||
if (culling & 32) {
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (vertex.cameraY < vertex.cameraZ) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 31;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Окклюдинг
|
||||
if (numOccluders > 0) {
|
||||
for (var i:int = 0; i < numOccluders; i++) {
|
||||
for (var plane:Vertex = camera.occluders[i]; plane != null; plane = plane.next) {
|
||||
for (vertex = boundVertexList; vertex != null; vertex = vertex.next) {
|
||||
if (plane.cameraX*vertex.cameraX + plane.cameraY*vertex.cameraY + plane.cameraZ*vertex.cameraZ >= 0) break;
|
||||
}
|
||||
if (vertex != null) break;
|
||||
}
|
||||
if (plane == null) return -1;
|
||||
}
|
||||
}
|
||||
this.culling = culling;
|
||||
return culling;
|
||||
}*/
|
||||
|
||||
/*protected function composeRenderMatrix():void {
|
||||
if (matrix != null) {
|
||||
cameraMatrix.identity();
|
||||
cameraMatrix.append(matrix);
|
||||
} else {
|
||||
composeVectors[0] = translation;
|
||||
composeVectors[1] = rotation;
|
||||
composeVectors[2] = scale;
|
||||
cameraMatrix.recompose(composeVectors);
|
||||
}
|
||||
}*/
|
||||
|
||||
/*public function draw(camera:Camera3D, parent:Object3DContainer = null):void {
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Возвращает объект, являющийся точной копией исходного объекта.
|
||||
* @return Клон исходного объекта.
|
||||
*/
|
||||
/*public function clone():Object3D {
|
||||
var res:Object3D = new Object3D();
|
||||
res.cloneBaseProperties(this);
|
||||
return res;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Копирует базовые свойства. Метод вызывается внутри <code>clone()</code>.
|
||||
* @param source Объект, с которого копируются базовые свойства.
|
||||
*/
|
||||
/*protected function cloneBaseProperties(source:Object3D):void {
|
||||
name = source.name;
|
||||
visible = source.visible;
|
||||
if (source.matrix != null) {
|
||||
matrix = source.matrix.clone();
|
||||
} else {
|
||||
translation.x = source.translation.x;
|
||||
translation.y = source.translation.y;
|
||||
translation.z = source.translation.z;
|
||||
rotation.x = source.rotation.x;
|
||||
rotation.y = source.rotation.y;
|
||||
rotation.z = source.rotation.z;
|
||||
scale.x = source.scale.x;
|
||||
scale.y = source.scale.y;
|
||||
scale.z = source.scale.z;
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.lights.DirectionalLight;
|
||||
|
||||
import flash.geom.Matrix3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Базовый контейнер трёхмерных объектов.
|
||||
* Логика контейнеров и child-parent-отношений идентична логике displayObject'ов во Flash.
|
||||
* Дочерние объекты отрисовываются в том порядке, в котором находятся в списке.
|
||||
*/
|
||||
public class Object3DContainer extends Object3D {
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var childrenList:Object3D;
|
||||
|
||||
/**
|
||||
* Добавляет дочерний объект. Объект добавляется в конец списка.
|
||||
* Если добавляется объект, предком которого уже является другой контейнер, то объект удаляется из списка потомков старого контейнера.
|
||||
* @param child Добавляемый дочерний объект.
|
||||
* @return Экземпляр Object3D, передаваемый в параметре <code>child</code>.
|
||||
*/
|
||||
public function addChild(child:Object3D):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child == this) throw new ArgumentError("An object cannot be added as a child of itself.");
|
||||
for (var container:Object3DContainer = _parent; container != null; container = container._parent) {
|
||||
if (container == child) throw new ArgumentError("An object cannot be added as a child to one of it's children (or children's children, etc.).");
|
||||
}
|
||||
// Удаление из старого родителя
|
||||
if (child._parent != null) child._parent.removeChild(child);
|
||||
// Добавление
|
||||
addToList(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет дочерний объект. Свойство <code>parent</code> удаленного объекта получает значение <code>null</code>.
|
||||
* @param child Удаляемый дочерний объект.
|
||||
* @return Экземпляр Object3D, передаваемый в параметре <code>child</code>.
|
||||
*/
|
||||
public function removeChild(child:Object3D):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
||||
// Удаление
|
||||
var prev:Object3D;
|
||||
var current:Object3D;
|
||||
for (current = childrenList; current != null; current = current.next) {
|
||||
if (current == child) {
|
||||
if (prev != null) {
|
||||
prev.next = current.next;
|
||||
} else {
|
||||
childrenList = current.next;
|
||||
}
|
||||
current.next = null;
|
||||
current._parent = null;
|
||||
return child;
|
||||
}
|
||||
prev = current;
|
||||
}
|
||||
throw new ArgumentError("Cannot remove child.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет дочерний объект. Объект добавляется в указанную позицию в списке.
|
||||
* @param child Добавляемый дочерний объект.
|
||||
* @param index Позиция, в которую добавляется дочерний объект.
|
||||
* @return Экземпляр Object3D, передаваемый в параметре <code>child</code>.
|
||||
*/
|
||||
public function addChildAt(child:Object3D, index:int):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child == this) throw new ArgumentError("An object cannot be added as a child of itself.");
|
||||
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
for (var container:Object3DContainer = _parent; container != null; container = container._parent) {
|
||||
if (container == child) throw new ArgumentError("An object cannot be added as a child to one of it's children (or children's children, etc.).");
|
||||
}
|
||||
// Поиск элемента по индексу
|
||||
var current:Object3D = childrenList;
|
||||
for (var i:int = 0; i < index; i++) {
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
current = current.next;
|
||||
}
|
||||
// Удаление из старого родителя
|
||||
if (child._parent != null) child._parent.removeChild(child);
|
||||
// Добавление
|
||||
addToList(child, current);
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет дочерний объект из заданной позиции. Свойство <code>parent</code> удаленного объекта получает значение <code>null</code>.
|
||||
* @param index Позиция, из которой удаляется дочерний объект.
|
||||
* @return Удаленный экземпляр Object3D.
|
||||
*/
|
||||
public function removeChildAt(index:int):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Поиск элемента по индексу
|
||||
var current:Object3D = childrenList;
|
||||
for (var i:int = 0; i < index; i++) {
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
current = current.next;
|
||||
}
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Удаление
|
||||
removeChild(current);
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает экземпляр дочернего объекта, существующий в заданной позиции.
|
||||
* @param index Позиция дочернего объекта.
|
||||
* @return Дочерний объект с заданной позицией.
|
||||
*/
|
||||
public function getChildAt(index:int):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Поиск элемента по индексу
|
||||
var current:Object3D = childrenList;
|
||||
for (var i:int = 0; i < index; i++) {
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
current = current.next;
|
||||
}
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает позицию дочернего объекта.
|
||||
* @param child Дочерний объект.
|
||||
* @return Позиция заданного дочернего объекта.
|
||||
*/
|
||||
public function getChildIndex(child:Object3D):int {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
||||
// Поиск индекса элемента
|
||||
var index:int = 0;
|
||||
for (var current:Object3D = childrenList; current != null; current = current.next) {
|
||||
if (current == child) return index;
|
||||
index++;
|
||||
}
|
||||
throw new ArgumentError("Cannot get child index.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает позицию дочернего объекта.
|
||||
* @param child Дочерний объект.
|
||||
* @param index Устанавливаемая позиция объекта.
|
||||
*/
|
||||
public function setChildIndex(child:Object3D, index:int):void {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
||||
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Поиск элемента по индексу
|
||||
var current:Object3D = childrenList;
|
||||
for (var i:int = 0; i < index; i++) {
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
current = current.next;
|
||||
}
|
||||
// Удаление
|
||||
removeChild(child);
|
||||
// Добавление
|
||||
addToList(child, current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Меняет местами два дочерних объекта в списке.
|
||||
* @param child1 Первый дочерний объект.
|
||||
* @param child2 Второй дочерний объект.
|
||||
*/
|
||||
public function swapChildren(child1:Object3D, child2:Object3D):void {
|
||||
// Проверка на ошибки
|
||||
if (child1 == null || child2 == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child1._parent != this || child2._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
||||
// Перестановка
|
||||
if (child1 != child2) {
|
||||
if (child1.next == child2) {
|
||||
removeChild(child2);
|
||||
addToList(child2, child1);
|
||||
} else if (child2.next == child1) {
|
||||
removeChild(child1);
|
||||
addToList(child1, child2);
|
||||
} else {
|
||||
var nxt:Object3D = child1.next;
|
||||
removeChild(child1);
|
||||
addToList(child1, child2);
|
||||
removeChild(child2);
|
||||
addToList(child2, nxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Меняет местами два дочерних объекта в списке по указанным позициям.
|
||||
* @param index1 Позиция первого дочернего объекта.
|
||||
* @param index2 Позиция второго дочернего объекта.
|
||||
*/
|
||||
public function swapChildrenAt(index1:int, index2:int):void {
|
||||
// Проверка на ошибки
|
||||
if (index1 < 0 || index2 < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Перестановка
|
||||
if (index1 != index2) {
|
||||
// Поиск элементов по индексам
|
||||
var i:int;
|
||||
var child1:Object3D = childrenList;
|
||||
for (i = 0; i < index1; i++) {
|
||||
if (child1 == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
child1 = child1.next;
|
||||
}
|
||||
if (child1 == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
var child2:Object3D = childrenList;
|
||||
for (i = 0; i < index2; i++) {
|
||||
if (child2 == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
child2 = child2.next;
|
||||
}
|
||||
if (child2 == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
if (child1 != child2) {
|
||||
if (child1.next == child2) {
|
||||
removeChild(child2);
|
||||
addToList(child2, child1);
|
||||
} else if (child2.next == child1) {
|
||||
removeChild(child1);
|
||||
addToList(child1, child2);
|
||||
} else {
|
||||
var nxt:Object3D = child1.next;
|
||||
removeChild(child1);
|
||||
addToList(child1, child2);
|
||||
removeChild(child2);
|
||||
addToList(child2, nxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает дочерний объект с заданным именем.
|
||||
* Если объектов с заданным именем несколько, возвратится первый попавшийся.
|
||||
* Если объект с заданным именем не содержится в контейнере, возвратится <code>null</code>.
|
||||
* @param name Имя дочернего объекта.
|
||||
* @return Дочерний объект с заданным именем.
|
||||
*/
|
||||
public function getChildByName(name:String):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (name == null) throw new TypeError("Parameter name must be non-null.");
|
||||
// Поиск объекта
|
||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||
if (child.name == name) return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Определяет, содержится ли заданный объект среди дочерних объектов.
|
||||
* Область поиска охватывает часть иерархии, начиная с данного Object3DContainer.
|
||||
* @param child Дочерний объект.
|
||||
* @return Значение <code>true</code>, если заданный объект является самим контейнером или одним из его потомков, в противном случае значение <code>false</code>.
|
||||
*/
|
||||
public function contains(child:Object3D):Boolean {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
// Поиск объекта
|
||||
if (child == this) return true;
|
||||
for (var object:Object3D = childrenList; object != null; object = object.next) {
|
||||
if (object is Object3DContainer) {
|
||||
if ((object as Object3DContainer).contains(child)) {
|
||||
return true;
|
||||
}
|
||||
} else if (object == child) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает количество дочерних объектов.
|
||||
*/
|
||||
public function get numChildren():int {
|
||||
var num:int = 0;
|
||||
for (var current:Object3D = childrenList; current != null; current = current.next) num++;
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Object3D {
|
||||
var container:Object3DContainer = new Object3DContainer();
|
||||
container.cloneBaseProperties(this);
|
||||
for (var child:Object3D = childrenList, lastChild:Object3D; child != null; child = child.next) {
|
||||
var newChild:Object3D = child.clone();
|
||||
if (container.childrenList != null) {
|
||||
lastChild.next = newChild;
|
||||
} else {
|
||||
container.childrenList = newChild;
|
||||
}
|
||||
lastChild = newChild;
|
||||
newChild._parent = container;
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function draw(camera:Camera3D):void {
|
||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||
if (child.visible) {
|
||||
child.composeMatrix();
|
||||
child.cameraMatrix.append(cameraMatrix);
|
||||
if (child.cullingInCamera(camera, culling) >= 0) {
|
||||
if (child.isTransparent) {
|
||||
camera.transparentObjects[int(camera.numTransparent++)] = child;
|
||||
} else {
|
||||
child.draw(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function drawInShadowMap(camera:Camera3D, light:DirectionalLight):void {
|
||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||
if (child.visible && !child.isTransparent) {
|
||||
child.composeMatrix();
|
||||
child.cameraMatrix.append(cameraMatrix);
|
||||
child.drawInShadowMap(camera, light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function updateBounds(bounds:Object3D, matrix:Matrix3D = null):void {
|
||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||
child.composeMatrix();
|
||||
if (matrix != null) child.cameraMatrix.append(matrix);
|
||||
child.updateBounds(bounds, child.cameraMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function addToList(child:Object3D, item:Object3D = null):void {
|
||||
child.next = item;
|
||||
child._parent = this;
|
||||
if (item == childrenList) {
|
||||
childrenList = child;
|
||||
} else {
|
||||
for (var current:Object3D = childrenList; current != null; current = current.next) {
|
||||
if (current.next == item) {
|
||||
current.next = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
/**
|
||||
* Результат проверки пересечения луча с объектом.
|
||||
*/
|
||||
public class RayIntersectionData {
|
||||
|
||||
/**
|
||||
* Объект, с которым найдено пересечение луча.
|
||||
*/
|
||||
public var object:Object3D;
|
||||
|
||||
/**
|
||||
* Ближайшая к началу луча грань объекта, с которым найдено пересечение.
|
||||
*/
|
||||
public var face:Face;
|
||||
|
||||
/**
|
||||
* Точка пересечения луча с объектом.
|
||||
*/
|
||||
public var point:Vector3D;
|
||||
|
||||
/**
|
||||
* Расстояние от начала луча до точки пересечения с объектом.
|
||||
*/
|
||||
public var distance:Number;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import __AS3__.vec.Vector;
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Вершина в трёхмерном пространстве. Вершины являются составными частями полигональных объектов. На базе вершин строятся грани.
|
||||
* @see alternativa.engine3d.core.Geometry
|
||||
* @see alternativa.engine3d.core.Face
|
||||
*/
|
||||
public class Vertex {
|
||||
|
||||
alternativa3d var geometry:Geometry;
|
||||
|
||||
/**
|
||||
* Координата X.
|
||||
*/
|
||||
public var _x:Number = 0;
|
||||
|
||||
/**
|
||||
* Координата Y.
|
||||
*/
|
||||
public var _y:Number = 0;
|
||||
|
||||
/**
|
||||
* Координата Z.
|
||||
*/
|
||||
public var _z:Number = 0;
|
||||
|
||||
/**
|
||||
* Текстурная координата по горизонтали.
|
||||
*/
|
||||
public var _u:Number = 0;
|
||||
|
||||
/**
|
||||
* Текстурная координата по вертикали.
|
||||
*/
|
||||
public var _v:Number = 0;
|
||||
|
||||
/**
|
||||
* Индексы костей, влияющих на эту вершину
|
||||
*/
|
||||
public var _jointsIndices:Vector.<uint>;
|
||||
|
||||
/**
|
||||
* Веса костей, влияющих на эту вершину.
|
||||
*/
|
||||
public var _jointsWeights:Vector.<Number>;
|
||||
|
||||
/**
|
||||
* Дополнительные аттрибуты в вершине для шейдера
|
||||
*/
|
||||
public var _attributes:Vector.<Number>;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var next:Vertex;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var value:Vertex;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var offset:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var index:int;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static alternativa3d var collector:Vertex;
|
||||
|
||||
public function get x():Number {
|
||||
return _x;
|
||||
}
|
||||
public function set x(value:Number):void {
|
||||
_x = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get y():Number {
|
||||
return _y;
|
||||
}
|
||||
public function set y(value:Number):void {
|
||||
_y = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get z():Number {
|
||||
return _z;
|
||||
}
|
||||
public function set z(value:Number):void {
|
||||
_z = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get u():Number {
|
||||
return _u;
|
||||
}
|
||||
public function set u(value:Number):void {
|
||||
_u = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get v():Number {
|
||||
return _v;
|
||||
}
|
||||
public function set v(value:Number):void {
|
||||
_v = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get jointsIndices():Vector.<uint> {
|
||||
return _jointsIndices;
|
||||
}
|
||||
public function set jointsIndices(value:Vector.<uint>):void {
|
||||
_jointsIndices = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get jointsWeights():Vector.<Number> {
|
||||
return _jointsWeights;
|
||||
}
|
||||
public function set jointsWeights(value:Vector.<Number>):void {
|
||||
_jointsWeights = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get attributes():Vector.<Number> {
|
||||
return _attributes;
|
||||
}
|
||||
public function set attributes(value:Vector.<Number>):void {
|
||||
_attributes = value;
|
||||
geometry.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static alternativa3d function createList(num:int):Vertex {
|
||||
var res:Vertex = collector;
|
||||
var last:Vertex;
|
||||
if (res != null) {
|
||||
for (last = res; num > 1; last = last.next,num--) {
|
||||
if (last.next == null) {
|
||||
//for (; num > 1; /*trace("new Vertex"), */last.next = new Vertex(), last = last.next, num--);
|
||||
while (num > 1) {
|
||||
//trace("new Vertex");
|
||||
last.next = new Vertex();
|
||||
last = last.next;
|
||||
num--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
collector = last.next;
|
||||
last.next = null;
|
||||
} else {
|
||||
//for (res = new Vertex(), /*trace("new Vertex"), */last = res; num > 1; /*trace("new Vertex"), */last.next = new Vertex(), last = last.next, num--);
|
||||
//trace("new Vertex");
|
||||
res = new Vertex();
|
||||
last = res;
|
||||
while (num > 1) {
|
||||
//trace("new Vertex");
|
||||
last.next = new Vertex();
|
||||
last = last.next;
|
||||
num--;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function create():Vertex {
|
||||
if (collector != null) {
|
||||
var res:Vertex = collector;
|
||||
collector = res.next;
|
||||
res.next = null;
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Vertex");
|
||||
return new Vertex();
|
||||
}
|
||||
}
|
||||
|
||||
alternativa3d function clone():Vertex {
|
||||
var res:Vertex = new Vertex();
|
||||
res._x = _x;
|
||||
res._y = _y;
|
||||
res._z = _z;
|
||||
res._u = _u;
|
||||
res._v = _v;
|
||||
var i:int, count:int;
|
||||
if (_attributes != null) {
|
||||
count = _attributes.length;
|
||||
res._attributes = new Vector.<Number>(count);
|
||||
for (i = 0; i < count; i++) {
|
||||
res._attributes[i] = _attributes[i];
|
||||
}
|
||||
}
|
||||
if (_jointsIndices != null) {
|
||||
count = _jointsIndices.length;
|
||||
res._jointsIndices = new Vector.<uint>(count);
|
||||
for (i = 0; i < count; i++) {
|
||||
res._jointsIndices[i] = _jointsIndices[i];
|
||||
}
|
||||
}
|
||||
if (_jointsWeights != null) {
|
||||
count = _jointsWeights.length;
|
||||
res._jointsWeights = new Vector.<Number>(count);
|
||||
for (i = 0; i < count; i++) {
|
||||
res._jointsWeights[i] = _jointsWeights[i];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package alternativa.engine3d.core {
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
import flash.display.Bitmap3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Вьюпорт, в который камера отрисовывает графику.
|
||||
* <code>View</code> — это <code>Bitmap3D</code>.
|
||||
* @see alternativa.engine3d.core.Camera3D
|
||||
*/
|
||||
public class View extends Bitmap3D {
|
||||
|
||||
public var backgroundColor:int = 0;
|
||||
public var backgroundAlpha:Number = 1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var _width:Number = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var _height:Number = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var _antialias:int;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var _depthdtencil:Boolean;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var cachedPrograms:Object = new Object();
|
||||
|
||||
/**
|
||||
* Создаёт новый вьюпорт.
|
||||
* @param width Ширина вьюпорта.
|
||||
* @param height Высота вьюпорта.
|
||||
*/
|
||||
public function View(width:Number, height:Number, rendermode:String = "AUTO", antialias:uint = 0, depthstencil:Boolean = true) {
|
||||
super(rendermode);
|
||||
setupBackbuffer(width, height, antialias, depthstencil);
|
||||
}
|
||||
|
||||
override public function setupBackbuffer(width:uint, height:uint, antialias:uint, depthstencil:Boolean):void {
|
||||
if (_width != width || _height != height || _antialias != antialias || _depthdtencil != depthstencil) {
|
||||
super.setupBackbuffer(width, height, antialias, depthstencil);
|
||||
_width = width;
|
||||
_height = height;
|
||||
_antialias = antialias;
|
||||
_depthdtencil = depthstencil;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public class Wrapper {
|
||||
|
||||
alternativa3d var next:Wrapper;
|
||||
|
||||
alternativa3d var vertex:Vertex;
|
||||
|
||||
static alternativa3d var collector:Wrapper;
|
||||
|
||||
static alternativa3d function create():Wrapper {
|
||||
if (collector != null) {
|
||||
var res:Wrapper = collector;
|
||||
collector = collector.next;
|
||||
res.next = null;
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Wrapper");
|
||||
return new Wrapper();
|
||||
}
|
||||
}
|
||||
|
||||
alternativa3d function create():Wrapper {
|
||||
if (collector != null) {
|
||||
var res:Wrapper = collector;
|
||||
collector = collector.next;
|
||||
res.next = null;
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Wrapper");
|
||||
return new Wrapper();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
691
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Camera3D.as
Normal file
691
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Camera3D.as
Normal file
@@ -0,0 +1,691 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import __AS3__.vec.Vector;
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.lights.DirectionalLight;
|
||||
import alternativa.engine3d.materials.AGALMiniAssembler;
|
||||
import alternativa.engine3d.objects.Mesh;
|
||||
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.Program3D;
|
||||
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.ByteArray;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
public class Camera3D extends Object3D {
|
||||
|
||||
public var debug:Boolean = true;
|
||||
|
||||
/**
|
||||
* Вьюпорт камеры.
|
||||
* Если вьюпорт не указан, отрисовка осуществляться не будет.
|
||||
*/
|
||||
public var view:View;
|
||||
|
||||
/**
|
||||
* Поле зрения (field of view).
|
||||
* Указывается в радианах.
|
||||
* Значение по умолчанию <code>Math.PI/2</code> — это 90 градусов.
|
||||
*/
|
||||
public var fov:Number = Math.PI/2;
|
||||
|
||||
/**
|
||||
* Ближнее расстояние отсечения.
|
||||
* Значение по умолчанию <code>0</code>.
|
||||
*/
|
||||
public var nearClipping:Number;
|
||||
|
||||
/**
|
||||
* Дальнее расстояние отсечения.
|
||||
* Значение по умолчанию <code>Number.MAX_VALUE</code>.
|
||||
*/
|
||||
public var farClipping:Number;
|
||||
|
||||
public var lights:Vector.<DirectionalLight>;
|
||||
alternativa3d var numLights:int;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var focalLength:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var projectionMatrixData:Vector.<Number> = new Vector.<Number>(16);
|
||||
|
||||
alternativa3d var globalMatrix:Matrix3D = new Matrix3D();
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var numDraws:int;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var numTriangles:int;
|
||||
|
||||
alternativa3d var transparentObjects:Vector.<Object3D> = new Vector.<Object3D>();
|
||||
alternativa3d var numTransparent:int = 0;
|
||||
|
||||
public function Camera3D(nearClipping:Number, farClipping:Number) {
|
||||
this.nearClipping = nearClipping;
|
||||
this.farClipping = farClipping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Отрисовывает иерархию объектов, в которой находится камера.
|
||||
* Чтобы отрисовка произошла, камере должен быть назначен <code>view</code>.
|
||||
*/
|
||||
public function render():void {
|
||||
if (view != null) {
|
||||
// Расчёт параметров проецирования
|
||||
var viewSizeX:Number = view._width*0.5;
|
||||
var viewSizeY:Number = view._height*0.5;
|
||||
focalLength = Math.sqrt(viewSizeX*viewSizeX + viewSizeY*viewSizeY)/Math.tan(fov*0.5);
|
||||
projectionMatrixData[0] = focalLength/viewSizeX;
|
||||
projectionMatrixData[5] = -focalLength/viewSizeY;
|
||||
projectionMatrixData[10]= farClipping/(farClipping - nearClipping);
|
||||
projectionMatrixData[11]= 1;
|
||||
projectionMatrixData[14]= -nearClipping*farClipping/(farClipping - nearClipping);
|
||||
|
||||
projectionMatrix.rawData = projectionMatrixData;
|
||||
|
||||
composeMatrix();
|
||||
globalMatrix.identity();
|
||||
globalMatrix.append(cameraMatrix);
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
globalMatrix.append(root.cameraMatrix);
|
||||
}
|
||||
|
||||
// Расчёт матрицы перевода из глобального пространства в камеру
|
||||
var i:int;
|
||||
// Сброс счётчиков
|
||||
numDraws = 0;
|
||||
numTriangles = 0;
|
||||
// Отрисовка
|
||||
var r:Number = (view.backgroundColor >> 16)/255;
|
||||
var g:Number = ((view.backgroundColor >> 8) & 0xFF)/255;
|
||||
var b:Number = (view.backgroundColor & 0xFF)/255;
|
||||
view.clear(r, g, b, view.backgroundAlpha);
|
||||
if (root != this && root.visible) {
|
||||
if (lights != null) {
|
||||
numLights = lights.length;
|
||||
for (i = 0; i < numLights; i++) {
|
||||
var light:DirectionalLight = lights[i];
|
||||
for (var j:int = light.numSplits - 1; j >= 0; j--) {
|
||||
light.update(this, view, j);
|
||||
|
||||
if (j < (light.numSplits - 1)) {
|
||||
// view.setColorWriteMask(false, false, false, false);
|
||||
// view.clear(0, 0, 0, 0);
|
||||
// view.setColorWriteMask(true, true, true, true);
|
||||
clearZ();
|
||||
}
|
||||
|
||||
// var near:Number = light.currentSplitNear/farClipping;
|
||||
// var far:Number = light.currentSplitFar/farClipping;
|
||||
var near:Number = light.currentSplitNear;
|
||||
var far:Number = light.currentSplitFar;
|
||||
|
||||
projectionMatrixData[10]= far/(far - near);
|
||||
projectionMatrixData[14]= -near*far/(far - near);
|
||||
projectionMatrix.rawData = projectionMatrixData;
|
||||
|
||||
cameraMatrix.identity();
|
||||
cameraMatrix.append(globalMatrix);
|
||||
cameraMatrix.invert();
|
||||
//cameraMatrix.append(projectionMatrix);
|
||||
root.composeMatrix();
|
||||
root.cameraMatrix.append(cameraMatrix);
|
||||
if (root.cullingInCamera(this, 63) >= 0) {
|
||||
root.draw(this);
|
||||
for (i = 0; i < numTransparent; i++) {
|
||||
transparentObjects[i].draw(this);
|
||||
}
|
||||
numTransparent = 0;
|
||||
transparentObjects.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cameraMatrix.identity();
|
||||
cameraMatrix.append(globalMatrix);
|
||||
cameraMatrix.invert();
|
||||
//cameraMatrix.append(projectionMatrix);
|
||||
root.composeMatrix();
|
||||
root.cameraMatrix.append(cameraMatrix);
|
||||
if (root.cullingInCamera(this, 63) >= 0) {
|
||||
root.draw(this);
|
||||
for (i = 0; i < numTransparent; i++) {
|
||||
transparentObjects[i].draw(this);
|
||||
}
|
||||
numTransparent = 0;
|
||||
transparentObjects.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
view.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private var czMesh:Mesh = createMesh();
|
||||
|
||||
private function createMesh():Mesh {
|
||||
var res:Mesh = new Mesh();
|
||||
res.geometry = new Geometry();
|
||||
var g:Geometry = res.geometry;
|
||||
g.addQuadFace(g.addVertex(-1, -1, 1), g.addVertex(1, -1, 1), g.addVertex(1, 1, 1), g.addVertex(-1, 1, 1));
|
||||
return res;
|
||||
}
|
||||
|
||||
private var czProgram:Program3D;
|
||||
|
||||
private function clearZProgram():Program3D {
|
||||
if (czProgram == null) {
|
||||
var czVertex:ByteArray = new AGALMiniAssembler().assemble("VERTEX", "mov op, va0 \n");
|
||||
var czFragment:ByteArray = new AGALMiniAssembler().assemble("FRAGMENT", "mov oc, fc0 \n");
|
||||
czProgram = view.createProgram();
|
||||
czProgram.upload(czVertex, czFragment);
|
||||
}
|
||||
return czProgram;
|
||||
}
|
||||
|
||||
private function clearZ():void {
|
||||
view.setProgram(clearZProgram());
|
||||
view.setBlending("ZERO", "ONE");
|
||||
view.setDepthTest(true, "ALWAYS");
|
||||
czMesh.geometry.update(view);
|
||||
view.setVertexStream(0, czMesh.geometry.vertexBuffer, 0, "FLOAT_3");
|
||||
view.setProgramConstants("FRAGMENT", 0, 1, Vector.<Number>([1, 0, 0, 1]));
|
||||
view.setCulling("NONE");
|
||||
if (debug) {
|
||||
view.drawTrianglesSynchronized(czMesh.geometry.indexBuffer, 0, czMesh.geometry.numTriangles);
|
||||
} else {
|
||||
view.drawTriangles(czMesh.geometry.indexBuffer, 0, czMesh.geometry.numTriangles);
|
||||
}
|
||||
view.setDepthTest(true, "LESS");
|
||||
view.setBlending("ONE", "ZERO");
|
||||
}
|
||||
|
||||
/**
|
||||
* Переводит точку из глобального пространства в экранные координаты.
|
||||
* @param v Точка в глобальном пространстве.
|
||||
* @param result Экземпляр <code>Vector3D</code>, в который записывается результат.
|
||||
*/
|
||||
public function projectGlobal(v:Vector3D, result:Vector3D):void {
|
||||
/*composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
appendMatrix(root);
|
||||
}
|
||||
invertMatrix();
|
||||
var x:Number = ma*v.x + mb*v.y + mc*v.z + md;
|
||||
var y:Number = me*v.x + mf*v.y + mg*v.z + mh;
|
||||
var z:Number = mi*v.x + mj*v.y + mk*v.z + ml;
|
||||
result.x = x*viewSizeX/z + view._width/2;
|
||||
result.y = y*viewSizeY/z + view._height/2;
|
||||
result.z = z;*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчитывает луч в глобальном пространстве.
|
||||
* Прямая луча проходит через начало координат камеры и точку на плоскости вьюпорта, заданную <code>deltaX</code> и <code>deltaY</code>.
|
||||
* Луч может быть использован в методе <code>intersectRay()</code> трёхмерных объектов.
|
||||
* @param origin Начало луча. Луч начинается от <code>nearClipping</code> камеры.
|
||||
* @param direction Направление луча.
|
||||
* @param deltaX Горизонтальная координата в плоскости вьюпорта относительно его центра.
|
||||
* @param deltaY Вертикальная координата в плоскости вьюпорта относительно его центра.
|
||||
*/
|
||||
public function calculateRay(origin:Vector3D, direction:Vector3D, deltaX:Number = 0, deltaY:Number = 0):void {
|
||||
// Создание луча в камере
|
||||
/*var dx:Number = deltaX*focalLength/viewSizeX;
|
||||
var dy:Number = deltaY*focalLength/viewSizeY;
|
||||
var dz:Number = focalLength;
|
||||
var ox:Number = dx*nearClipping/focalLength;
|
||||
var oy:Number = dy*nearClipping/focalLength;
|
||||
var oz:Number = nearClipping;
|
||||
// Перевод луча в глобальное пространство
|
||||
composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
appendMatrix(root);
|
||||
}
|
||||
origin.x = ma*ox + mb*oy + mc*oz + md;
|
||||
origin.y = me*ox + mf*oy + mg*oz + mh;
|
||||
origin.z = mi*ox + mj*oy + mk*oz + ml;
|
||||
direction.x = ma*dx + mb*dy + mc*dz;
|
||||
direction.y = me*dx + mf*dy + mg*dz;
|
||||
direction.z = mi*dx + mj*dy + mk*dz;
|
||||
var directionL:Number = 1/Math.sqrt(direction.x*direction.x + direction.y*direction.y + direction.z*direction.z);
|
||||
direction.x *= directionL;
|
||||
direction.y *= directionL;
|
||||
direction.z *= directionL;*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Object3D {
|
||||
var camera:Camera3D = new Camera3D(nearClipping, farClipping);
|
||||
camera.cloneBaseProperties(this);
|
||||
camera.fov = fov;
|
||||
camera.nearClipping = nearClipping;
|
||||
camera.farClipping = farClipping;
|
||||
return camera;
|
||||
}
|
||||
|
||||
// Диаграмма
|
||||
|
||||
private var _diagram:Sprite = createDiagram();
|
||||
|
||||
/**
|
||||
* Количество кадров, через которые происходит обновление значения FPS в диаграмме.
|
||||
* @see #diagram
|
||||
*/
|
||||
public var fpsUpdatePeriod:int = 10;
|
||||
|
||||
/**
|
||||
* Количество кадров, через которые происходит обновление значения MS в диаграмме.
|
||||
* @see #diagram
|
||||
*/
|
||||
public var timerUpdatePeriod:int = 10;
|
||||
|
||||
private var fpsTextField:TextField;
|
||||
private var memoryTextField:TextField;
|
||||
private var drawsTextField: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;
|
||||
|
||||
private var fpsUpdateCounter:int;
|
||||
private var previousFrameTime:int;
|
||||
private var previousPeriodTime:int;
|
||||
|
||||
private var maxMemory:int;
|
||||
|
||||
private var timerUpdateCounter:int;
|
||||
private var timeSum:int;
|
||||
private var timeCount:int;
|
||||
private var timer:int;
|
||||
|
||||
/**
|
||||
* Начинает отсчёт времени.
|
||||
* Методы <code>startTimer()</code> и <code>stopTimer()</code> нужны для того, чтобы замерять время выполнения ежекадрово вызывающегося куска кода.
|
||||
* Результат замера показывается в диаграмме в поле MS.
|
||||
* @see #diagram
|
||||
* @see #stopTimer()
|
||||
*/
|
||||
public function startTimer():void {
|
||||
timer = getTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Заканчивает отсчёт времени.
|
||||
* Методы <code>startTimer()</code> и <code>stopTimer()</code> нужны для того, чтобы замерять время выполнения ежекадрово вызывающегося куска кода.
|
||||
* Результат замера показывается в диаграмме в поле MS.
|
||||
* @see #diagram
|
||||
* @see #startTimer()
|
||||
*/
|
||||
public function stopTimer():void {
|
||||
timeSum += getTimer() - timer;
|
||||
timeCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Диаграмма, на которой отображается отладочная информация.
|
||||
* Чтобы отобразить диаграмму, её нужно добавить на экран.
|
||||
* FPS — Среднее количество кадров в секунду за промежуток в <code>fpsUpdatePeriod</code> кадров.<br>
|
||||
* MS — Среднее время выполнения замеряемого с помощью <code>startTimer</code> - <code>stopTimer</code> участка кода в миллисекундах за промежуток в <code>timerUpdatePeriod</code> кадров.<br>
|
||||
* MEM — Количество занимаемой плеером памяти в мегабайтах.<br>
|
||||
* DRW — Количество отрисовочных вызовов в текущем кадре.<br>
|
||||
* PLG — Количество видимых полигонов в текущем кадре.<br>
|
||||
* TRI — Количество отрисованных треугольников в текущем кадре.
|
||||
* @see #fpsUpdatePeriod
|
||||
* @see #timerUpdatePeriod
|
||||
* @see #startTimer()
|
||||
* @see #stopTimer()
|
||||
*/
|
||||
public function get diagram():DisplayObject {
|
||||
return _diagram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Выравнивание диаграммы относительно рабочей области.
|
||||
* Можно использовать константы класса <code>StageAlign</code>.
|
||||
*/
|
||||
public function get diagramAlign():String {
|
||||
return _diagramAlign;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set diagramAlign(value:String):void {
|
||||
_diagramAlign = value;
|
||||
resizeDiagram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Отступ диаграммы от края рабочей области по горизонтали.
|
||||
*/
|
||||
public function get diagramHorizontalMargin():Number {
|
||||
return _diagramHorizontalMargin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set diagramHorizontalMargin(value:Number):void {
|
||||
_diagramHorizontalMargin = value;
|
||||
resizeDiagram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Отступ диаграммы от края рабочей области по вертикали.
|
||||
*/
|
||||
public function get diagramVerticalMargin():Number {
|
||||
return _diagramVerticalMargin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set diagramVerticalMargin(value:Number):void {
|
||||
_diagramVerticalMargin = value;
|
||||
resizeDiagram();
|
||||
}
|
||||
|
||||
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:";
|
||||
fpsTextField.selectable = false;
|
||||
fpsTextField.x = -3;
|
||||
fpsTextField.y = -5;
|
||||
diagram.addChild(fpsTextField);
|
||||
fpsTextField = new TextField();
|
||||
fpsTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xCCCCCC);
|
||||
fpsTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
fpsTextField.text = Number(diagram.stage.frameRate).toFixed(2);
|
||||
fpsTextField.selectable = false;
|
||||
fpsTextField.x = -3;
|
||||
fpsTextField.y = -5;
|
||||
fpsTextField.width = 85;
|
||||
diagram.addChild(fpsTextField);
|
||||
// Время выполнения метода
|
||||
timerTextField = new TextField();
|
||||
timerTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x0066FF);
|
||||
timerTextField.autoSize = TextFieldAutoSize.LEFT;
|
||||
timerTextField.text = "MS:";
|
||||
timerTextField.selectable = false;
|
||||
timerTextField.x = -3;
|
||||
timerTextField.y = 4;
|
||||
diagram.addChild(timerTextField);
|
||||
timerTextField = new TextField();
|
||||
timerTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x0066FF);
|
||||
timerTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
timerTextField.text = "";
|
||||
timerTextField.selectable = false;
|
||||
timerTextField.x = -3;
|
||||
timerTextField.y = 4;
|
||||
timerTextField.width = 85;
|
||||
diagram.addChild(timerTextField);
|
||||
// Память
|
||||
memoryTextField = new TextField();
|
||||
memoryTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xCCCC00);
|
||||
memoryTextField.autoSize = TextFieldAutoSize.LEFT;
|
||||
memoryTextField.text = "MEM:";
|
||||
memoryTextField.selectable = false;
|
||||
memoryTextField.x = -3;
|
||||
memoryTextField.y = 13;
|
||||
diagram.addChild(memoryTextField);
|
||||
memoryTextField = new TextField();
|
||||
memoryTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xCCCC00);
|
||||
memoryTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
memoryTextField.text = bytesToString(System.totalMemory);
|
||||
memoryTextField.selectable = false;
|
||||
memoryTextField.x = -3;
|
||||
memoryTextField.y = 13;
|
||||
memoryTextField.width = 85;
|
||||
diagram.addChild(memoryTextField);
|
||||
// Отрисовочные вызовы
|
||||
drawsTextField = new TextField();
|
||||
drawsTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x00CC00);
|
||||
drawsTextField.autoSize = TextFieldAutoSize.LEFT;
|
||||
drawsTextField.text = "DRW:";
|
||||
drawsTextField.selectable = false;
|
||||
drawsTextField.x = -3;
|
||||
drawsTextField.y = 22;
|
||||
diagram.addChild(drawsTextField);
|
||||
drawsTextField = new TextField();
|
||||
drawsTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0x00CC00);
|
||||
drawsTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
drawsTextField.text = "0";
|
||||
drawsTextField.selectable = false;
|
||||
drawsTextField.x = -3;
|
||||
drawsTextField.y = 22;
|
||||
drawsTextField.width = 72;
|
||||
diagram.addChild(drawsTextField);
|
||||
// Треугольники
|
||||
trianglesTextField = new TextField();
|
||||
trianglesTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xFF3300); // 0xFF6600, 0xFF0033
|
||||
trianglesTextField.autoSize = TextFieldAutoSize.LEFT;
|
||||
trianglesTextField.text = "TRI:";
|
||||
trianglesTextField.selectable = false;
|
||||
trianglesTextField.x = -3;
|
||||
trianglesTextField.y = 31;
|
||||
diagram.addChild(trianglesTextField);
|
||||
trianglesTextField = new TextField();
|
||||
trianglesTextField.defaultTextFormat = new TextFormat("Tahoma", 10, 0xFF3300);
|
||||
trianglesTextField.autoSize = TextFieldAutoSize.RIGHT;
|
||||
trianglesTextField.text = "0";
|
||||
trianglesTextField.selectable = false;
|
||||
trianglesTextField.x = -3;
|
||||
trianglesTextField.y = 31;
|
||||
trianglesTextField.width = 72;
|
||||
diagram.addChild(trianglesTextField);
|
||||
// График
|
||||
graph = new Bitmap(new BitmapData(80, 40, true, 0x20FFFFFF));
|
||||
rect = new Rectangle(0, 0, 1, 40);
|
||||
graph.x = 0;
|
||||
graph.y = 45;
|
||||
diagram.addChild(graph);
|
||||
// Сброс параметров
|
||||
previousPeriodTime = getTimer();
|
||||
previousFrameTime = previousPeriodTime;
|
||||
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(drawsTextField);
|
||||
diagram.removeChild(trianglesTextField);
|
||||
diagram.removeChild(timerTextField);
|
||||
diagram.removeChild(graph);
|
||||
fpsTextField = null;
|
||||
memoryTextField = null;
|
||||
drawsTextField = 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 value:Number;
|
||||
var mod:int;
|
||||
var time:int = getTimer();
|
||||
var stageFrameRate:int = _diagram.stage.frameRate;
|
||||
|
||||
// FPS текст
|
||||
if (++fpsUpdateCounter == fpsUpdatePeriod) {
|
||||
value = 1000*fpsUpdatePeriod/(time - previousPeriodTime);
|
||||
if (value > stageFrameRate) value = stageFrameRate;
|
||||
mod = value*100 % 100;
|
||||
fpsTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00"));
|
||||
previousPeriodTime = time;
|
||||
fpsUpdateCounter = 0;
|
||||
}
|
||||
// FPS график
|
||||
value = 1000/(time - previousFrameTime);
|
||||
if (value > stageFrameRate) value = stageFrameRate;
|
||||
graph.bitmapData.scroll(1, 0);
|
||||
graph.bitmapData.fillRect(rect, 0x20FFFFFF);
|
||||
graph.bitmapData.setPixel32(0, 40*(1 - value/stageFrameRate), 0xFFCCCCCC);
|
||||
previousFrameTime = time;
|
||||
|
||||
// Время текст
|
||||
if (++timerUpdateCounter == timerUpdatePeriod) {
|
||||
if (timeCount > 0) {
|
||||
value = timeSum/timeCount;
|
||||
mod = value*100 % 100;
|
||||
timerTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00"));
|
||||
} else {
|
||||
timerTextField.text = "";
|
||||
}
|
||||
timerUpdateCounter = 0;
|
||||
timeSum = 0;
|
||||
timeCount = 0;
|
||||
}
|
||||
|
||||
// Память текст
|
||||
var memory:int = System.totalMemory;
|
||||
value = memory/1048576;
|
||||
mod = value*100 % 100;
|
||||
memoryTextField.text = int(value) + "." + ((mod >= 10) ? mod : ((mod > 0) ? ("0" + mod) : "00"));
|
||||
|
||||
// Память график
|
||||
if (memory > maxMemory) maxMemory = memory;
|
||||
graph.bitmapData.setPixel32(0, 40*(1 - memory/maxMemory), 0xFFCCCC00);
|
||||
|
||||
// Отрисовочные вызовы текст
|
||||
drawsTextField.text = formatInt(numDraws);
|
||||
|
||||
// Треугольники текст
|
||||
trianglesTextField.text = formatInt(numTriangles);
|
||||
}
|
||||
|
||||
private function formatInt(num:int):String {
|
||||
var n:int;
|
||||
var s:String;
|
||||
if (num < 1000) {
|
||||
return "" + num;
|
||||
} else if (num < 1000000) {
|
||||
n = num % 1000;
|
||||
if (n < 10) {
|
||||
s = "00" + n;
|
||||
} else if (n < 100) {
|
||||
s = "0" + n;
|
||||
} else {
|
||||
s = "" + n;
|
||||
}
|
||||
return int(num/1000) + " " + s;
|
||||
} else {
|
||||
n = (num % 1000000)/1000;
|
||||
if (n < 10) {
|
||||
s = "00" + n;
|
||||
} else if (n < 100) {
|
||||
s = "0" + n;
|
||||
} else {
|
||||
s = "" + n;
|
||||
}
|
||||
n = num % 1000;
|
||||
if (n < 10) {
|
||||
s += " 00" + n;
|
||||
} else if (n < 100) {
|
||||
s += " 0" + n;
|
||||
} else {
|
||||
s += " " + n;
|
||||
}
|
||||
return int(num/1000000) + " " + s;
|
||||
}
|
||||
}
|
||||
|
||||
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 String(bytes >> 20);// + "mb";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
225
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Face.as
Normal file
225
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Face.as
Normal file
@@ -0,0 +1,225 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import __AS3__.vec.Vector;
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Грань, образованная тремя или более вершинами. Грани являются составными частями полигональных объектов.
|
||||
* @see alternativa.engine3d.core.Geometry
|
||||
* @see alternativa.engine3d.core.Vertex
|
||||
*/
|
||||
public class Face {
|
||||
|
||||
// /**
|
||||
// * Материал грани.
|
||||
// * @see alternativa.engine3d.materials.Material
|
||||
// */
|
||||
// public var material:Material;
|
||||
|
||||
alternativa3d var geometry:Geometry;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var next:Face;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var wrapper:Wrapper;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var normalX:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var normalY:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var normalZ:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var offset:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static alternativa3d var collector:Face;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static alternativa3d function create():Face {
|
||||
if (collector != null) {
|
||||
var res:Face = collector;
|
||||
collector = res.next;
|
||||
res.next = null;
|
||||
/*if (res.processNext != null) trace("!!!processNext!!!");
|
||||
if (res.geometry != null) trace("!!!geometry!!!");
|
||||
if (res.negative != null) trace("!!!negative!!!");
|
||||
if (res.positive != null) trace("!!!positive!!!");*/
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Face");
|
||||
return new Face();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function create():Face {
|
||||
if (collector != null) {
|
||||
var res:Face = collector;
|
||||
collector = res.next;
|
||||
res.next = null;
|
||||
/*if (res.processNext != null) trace("!!!processNext!!!");
|
||||
if (res.geometry != null) trace("!!!geometry!!!");
|
||||
if (res.negative != null) trace("!!!negative!!!");
|
||||
if (res.positive != null) trace("!!!positive!!!");*/
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Face");
|
||||
return new Face();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Нормаль грани.
|
||||
*/
|
||||
public function get normal():Vector3D {
|
||||
var w:Wrapper = wrapper;
|
||||
var a:Vertex = w.vertex; w = w.next;
|
||||
var b:Vertex = w.vertex; w = w.next;
|
||||
var c:Vertex = w.vertex;
|
||||
var abx:Number = b._x - a._x;
|
||||
var aby:Number = b._y - a._y;
|
||||
var abz:Number = b._z - a._z;
|
||||
var acx:Number = c._x - a._x;
|
||||
var acy:Number = c._y - a._y;
|
||||
var acz:Number = c._z - a._z;
|
||||
var nx:Number = acz*aby - acy*abz;
|
||||
var ny:Number = acx*abz - acz*abx;
|
||||
var nz:Number = acy*abx - acx*aby;
|
||||
var len:Number = nx*nx + ny*ny + nz*nz;
|
||||
if (len > 0.001) {
|
||||
len = 1/Math.sqrt(len);
|
||||
nx *= len;
|
||||
ny *= len;
|
||||
nz *= len;
|
||||
}
|
||||
return new Vector3D(nx, ny, nz, a._x*nx + a._y*ny + a._z*nz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Вершины, на базе которых построена грань.
|
||||
* @see alternativa.engine3d.core.Vertex
|
||||
*/
|
||||
public function get vertices():Vector.<Vertex> {
|
||||
var res:Vector.<Vertex> = new Vector.<Vertex>();
|
||||
var len:int = 0;
|
||||
for (var w:Wrapper = wrapper; w != null; w = w.next) {
|
||||
res[len] = w.vertex;
|
||||
len++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
alternativa3d function setVertices(value:Vector.<Vertex>):void {
|
||||
var last:Wrapper = null;
|
||||
for (var i:int = 0, count:int = value.length; i < count; i++) {
|
||||
var newWrapper:Wrapper = new Wrapper();
|
||||
newWrapper.vertex = value[i];
|
||||
if (last != null) {
|
||||
last.next = newWrapper;
|
||||
} else {
|
||||
wrapper = newWrapper;
|
||||
}
|
||||
last = newWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function calculateBestSequenceAndNormal():void {
|
||||
if (wrapper.next.next.next != null) {
|
||||
var max:Number = -1e+22;
|
||||
var s:Wrapper;
|
||||
var sm:Wrapper;
|
||||
var sp:Wrapper;
|
||||
for (w = wrapper; w != null; w = w.next) {
|
||||
var wn:Wrapper = (w.next != null) ? w.next : wrapper;
|
||||
var wm:Wrapper = (wn.next != null) ? wn.next : wrapper;
|
||||
a = w.vertex;
|
||||
b = wn.vertex;
|
||||
c = wm.vertex;
|
||||
abx = b._x - a._x;
|
||||
aby = b._y - a._y;
|
||||
abz = b._z - a._z;
|
||||
acx = c._x - a._x;
|
||||
acy = c._y - a._y;
|
||||
acz = c._z - a._z;
|
||||
nx = acz*aby - acy*abz;
|
||||
ny = acx*abz - acz*abx;
|
||||
nz = acy*abx - acx*aby;
|
||||
nl = nx*nx + ny*ny + nz*nz;
|
||||
if (nl > max) {
|
||||
max = nl;
|
||||
s = w;
|
||||
}
|
||||
}
|
||||
if (s != wrapper) {
|
||||
//for (sm = wrapper.next.next.next; sm.next != null; sm = sm.next);
|
||||
sm = wrapper.next.next.next;
|
||||
while (sm.next != null) sm = sm.next;
|
||||
//for (sp = wrapper; sp.next != s && sp.next != null; sp = sp.next);
|
||||
sp = wrapper;
|
||||
while (sp.next != s && sp.next != null) sp = sp.next;
|
||||
sm.next = wrapper;
|
||||
sp.next = null;
|
||||
wrapper = s;
|
||||
}
|
||||
}
|
||||
var w:Wrapper = wrapper;
|
||||
var a:Vertex = w.vertex;
|
||||
w = w.next;
|
||||
var b:Vertex = w.vertex;
|
||||
w = w.next;
|
||||
var c:Vertex = w.vertex;
|
||||
var abx:Number = b._x - a._x;
|
||||
var aby:Number = b._y - a._y;
|
||||
var abz:Number = b._z - a._z;
|
||||
var acx:Number = c._x - a._x;
|
||||
var acy:Number = c._y - a._y;
|
||||
var acz:Number = c._z - a._z;
|
||||
var nx:Number = acz*aby - acy*abz;
|
||||
var ny:Number = acx*abz - acz*abx;
|
||||
var nz:Number = acy*abx - acx*aby;
|
||||
var nl:Number = nx*nx + ny*ny + nz*nz;
|
||||
if (nl > 0) {
|
||||
nl = 1/Math.sqrt(nl);
|
||||
nx *= nl;
|
||||
ny *= nl;
|
||||
nz *= nl;
|
||||
normalX = nx;
|
||||
normalY = ny;
|
||||
normalZ = nz;
|
||||
}
|
||||
offset = a._x*nx + a._y*ny + a._z*nz;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
1509
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Geometry.as
Normal file
1509
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Geometry.as
Normal file
File diff suppressed because it is too large
Load Diff
699
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Object3D.as
Normal file
699
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Object3D.as
Normal file
@@ -0,0 +1,699 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.lights.DirectionalLight;
|
||||
|
||||
import flash.events.EventDispatcher;
|
||||
import flash.geom.Matrix3D;
|
||||
import flash.geom.Vector3D;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.getQualifiedClassName;
|
||||
|
||||
use namespace alternativa3d;
|
||||
public class Object3D extends EventDispatcher {
|
||||
|
||||
/**
|
||||
* Имя объекта.
|
||||
*/
|
||||
public var name:String;
|
||||
|
||||
/**
|
||||
* Флаг видимости объекта.
|
||||
*/
|
||||
public var visible:Boolean = true;
|
||||
|
||||
/**
|
||||
* Координата X.
|
||||
*/
|
||||
public var x:Number = 0;
|
||||
|
||||
/**
|
||||
* Координата Y.
|
||||
*/
|
||||
public var y:Number = 0;
|
||||
|
||||
/**
|
||||
* Координата Z.
|
||||
*/
|
||||
public var z:Number = 0;
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси X.
|
||||
* Указывается в радианах.
|
||||
*/
|
||||
public var rotationX:Number = 0;
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси Y.
|
||||
* Указывается в радианах.
|
||||
*/
|
||||
public var rotationY:Number = 0;
|
||||
|
||||
/**
|
||||
* Угол поворота вокруг оси Z.
|
||||
* Указывается в радианах.
|
||||
*/
|
||||
public var rotationZ:Number = 0;
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования по оси X.
|
||||
*/
|
||||
public var scaleX:Number = 1;
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования по оси Y.
|
||||
*/
|
||||
public var scaleY:Number = 1;
|
||||
|
||||
/**
|
||||
* Коэффициент масштабирования по оси Z.
|
||||
*/
|
||||
public var scaleZ:Number = 1;
|
||||
|
||||
/**
|
||||
* Левая граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMinX:Number = -1e+22;
|
||||
|
||||
/**
|
||||
* Задняя граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMinY:Number = -1e+22;
|
||||
|
||||
/**
|
||||
* Нижняя граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMinZ:Number = -1e+22;
|
||||
|
||||
/**
|
||||
* Правая граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMaxX:Number = 1e+22;
|
||||
|
||||
/**
|
||||
* Передняя граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMaxY:Number = 1e+22;
|
||||
|
||||
/**
|
||||
* Верхняя граница объекта в его системе координат.
|
||||
*/
|
||||
public var boundMaxZ:Number = 1e+22;
|
||||
|
||||
alternativa3d var cameraMatrix:Matrix3D = new Matrix3D();
|
||||
alternativa3d var cameraMatrixData:Vector.<Number> = new Vector.<Number>(16);
|
||||
alternativa3d var projectionMatrix:Matrix3D = new Matrix3D();
|
||||
alternativa3d var _parent:Object3DContainer;
|
||||
alternativa3d var next:Object3D;
|
||||
alternativa3d var culling:int = 0;
|
||||
alternativa3d var distance:Number;
|
||||
alternativa3d var weightsSum:Vector.<Number>;
|
||||
|
||||
alternativa3d function get isTransparent():Boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает родительский объект <code>Object3DContainer</code>.
|
||||
*/
|
||||
public function get parent():Object3DContainer {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Объект <code>Matrix3D</code>, содержащий значения, влияющие на масштабирование, поворот и перемещение объекта.
|
||||
*/
|
||||
public function get matrix():Matrix3D {
|
||||
var m:Matrix3D = new Matrix3D();
|
||||
var t:Vector3D = new Vector3D(x, y, z);
|
||||
var r:Vector3D = new Vector3D(rotationX, rotationY, rotationZ);
|
||||
var s:Vector3D = new Vector3D(scaleX, scaleY, scaleZ);
|
||||
var v:Vector.<Vector3D> = new Vector.<Vector3D>();
|
||||
v[0] = t;
|
||||
v[1] = r;
|
||||
v[2] = s;
|
||||
m.recompose(v);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public function set matrix(value:Matrix3D):void {
|
||||
var v:Vector.<Vector3D> = value.decompose();
|
||||
var t:Vector3D = v[0];
|
||||
var r:Vector3D = v[1];
|
||||
var s:Vector3D = v[2];
|
||||
x = t.x;
|
||||
y = t.y;
|
||||
z = t.z;
|
||||
rotationX = r.x;
|
||||
rotationY = r.y;
|
||||
rotationZ = r.z;
|
||||
scaleX = s.x;
|
||||
scaleY = s.y;
|
||||
scaleZ = s.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Расчитывает границы объекта в его системе координат.
|
||||
*/
|
||||
public function calculateBounds():void {
|
||||
// Выворачивание баунда
|
||||
boundMinX = 1e+22;
|
||||
boundMinY = 1e+22;
|
||||
boundMinZ = 1e+22;
|
||||
boundMaxX = -1e+22;
|
||||
boundMaxY = -1e+22;
|
||||
boundMaxZ = -1e+22;
|
||||
// Заполнение баунда
|
||||
updateBounds(this, null);
|
||||
// Если баунд вывернут
|
||||
if (boundMinX > boundMaxX) {
|
||||
boundMinX = -1e+22;
|
||||
boundMinY = -1e+22;
|
||||
boundMinZ = -1e+22;
|
||||
boundMaxX = 1e+22;
|
||||
boundMaxY = 1e+22;
|
||||
boundMaxZ = 1e+22;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует точку из локальных координат в глобальные.
|
||||
* @param point Точка в локальных координатах объекта.
|
||||
* @return Точка в глобальном пространстве.
|
||||
*/
|
||||
/*public function localToGlobal(point:Vector3D):Vector3D {
|
||||
composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
appendMatrix(root);
|
||||
}
|
||||
var res:Vector3D = new Vector3D();
|
||||
res.x = ma*point.x + mb*point.y + mc*point.z + md;
|
||||
res.y = me*point.x + mf*point.y + mg*point.z + mh;
|
||||
res.z = mi*point.x + mj*point.y + mk*point.z + ml;
|
||||
return res;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Преобразует точку из глобальной системы координат в локальные координаты объекта.
|
||||
* @param point Точка в глобальном пространстве.
|
||||
* @return Точка в локальных координатах объекта.
|
||||
*/
|
||||
/*public function globalToLocal(point:Vector3D):Vector3D {
|
||||
composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
appendMatrix(root);
|
||||
}
|
||||
invertMatrix();
|
||||
var res:Vector3D = new Vector3D();
|
||||
res.x = ma*point.x + mb*point.y + mc*point.z + md;
|
||||
res.y = me*point.x + mf*point.y + mg*point.z + mh;
|
||||
res.z = mi*point.x + mj*point.y + mk*point.z + ml;
|
||||
return res;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Осуществляет поиск пересечение луча с объектом.
|
||||
* @param origin Начало луча.
|
||||
* @param direction Направление луча.
|
||||
* @param exludedObjects Ассоциативный массив, ключами которого являются экземпляры <code>Object3D</code> и его наследников. Объекты, содержащиеся в этом массиве будут исключены из проверки.
|
||||
* @param camera Камера для правильного поиска пересечения луча с объектами <code>Sprite3D</code>. Эти объекты всегда повёрнуты к камере. Если камера не указана, результат пересечения луча со спрайтом будет <code>null</code>.
|
||||
* @return Результат поиска пересечения — объект <code>RayIntersectionData</code>. Если пересечения нет, будет возвращён <code>null</code>.
|
||||
* @see RayIntersectionData
|
||||
* @see alternativa.engine3d.objects.Sprite3D
|
||||
*/
|
||||
public function intersectRay(origin:Vector3D, direction:Vector3D, exludedObjects:Dictionary = null, camera:Camera3D = null):RayIntersectionData {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает объект, являющийся точной копией исходного объекта.
|
||||
* @return Клон исходного объекта.
|
||||
*/
|
||||
public function clone():Object3D {
|
||||
var res:Object3D = new Object3D();
|
||||
res.cloneBaseProperties(this);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Копирует базовые свойства. Метод вызывается внутри <code>clone()</code>.
|
||||
* @param source Объект, с которого копируются базовые свойства.
|
||||
*/
|
||||
protected function cloneBaseProperties(source:Object3D):void {
|
||||
name = source.name;
|
||||
visible = source.visible;
|
||||
distance = source.distance;
|
||||
x = source.x;
|
||||
y = source.y;
|
||||
z = source.z;
|
||||
rotationX = source.rotationX;
|
||||
rotationY = source.rotationY;
|
||||
rotationZ = source.rotationZ;
|
||||
scaleX = source.scaleX;
|
||||
scaleY = source.scaleY;
|
||||
scaleZ = source.scaleZ;
|
||||
boundMinX = source.boundMinX;
|
||||
boundMinY = source.boundMinY;
|
||||
boundMinZ = source.boundMinZ;
|
||||
boundMaxX = source.boundMaxX;
|
||||
boundMaxY = source.boundMaxY;
|
||||
boundMaxZ = source.boundMaxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает строковое представление заданного объекта.
|
||||
* @return Строковое представление объекта.
|
||||
*/
|
||||
override public function toString():String {
|
||||
var className:String = getQualifiedClassName(this);
|
||||
return "[" + className.substr(className.indexOf("::") + 2) + " " + name + "]";
|
||||
}
|
||||
|
||||
// Переопределяемые закрытые методы
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function draw(camera:Camera3D):void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function drawInShadowMap(camera:Camera3D, light:DirectionalLight):void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function updateBounds(bounds:Object3D, matrix:Matrix3D = null):void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function composeMatrix():void {
|
||||
var cosX:Number = Math.cos(rotationX);
|
||||
var sinX:Number = Math.sin(rotationX);
|
||||
var cosY:Number = Math.cos(rotationY);
|
||||
var sinY:Number = Math.sin(rotationY);
|
||||
var cosZ:Number = Math.cos(rotationZ);
|
||||
var sinZ:Number = Math.sin(rotationZ);
|
||||
var cosZsinY:Number = cosZ*sinY;
|
||||
var sinZsinY:Number = sinZ*sinY;
|
||||
var cosYscaleX:Number = cosY*scaleX;
|
||||
var sinXscaleY:Number = sinX*scaleY;
|
||||
var cosXscaleY:Number = cosX*scaleY;
|
||||
var cosXscaleZ:Number = cosX*scaleZ;
|
||||
var sinXscaleZ:Number = sinX*scaleZ;
|
||||
cameraMatrixData[0] = cosZ*cosYscaleX;
|
||||
cameraMatrixData[4] = cosZsinY*sinXscaleY - sinZ*cosXscaleY;
|
||||
cameraMatrixData[8] = cosZsinY*cosXscaleZ + sinZ*sinXscaleZ;
|
||||
cameraMatrixData[12] = x;
|
||||
cameraMatrixData[1] = sinZ*cosYscaleX;
|
||||
cameraMatrixData[5] = sinZsinY*sinXscaleY + cosZ*cosXscaleY;
|
||||
cameraMatrixData[9] = sinZsinY*cosXscaleZ - cosZ*sinXscaleZ;
|
||||
cameraMatrixData[13] = y;
|
||||
cameraMatrixData[2] = -sinY*scaleX;
|
||||
cameraMatrixData[6] = cosY*sinXscaleY;
|
||||
cameraMatrixData[10] = cosY*cosXscaleZ;
|
||||
cameraMatrixData[14] = z;
|
||||
cameraMatrixData[3] = 0;
|
||||
cameraMatrixData[7] = 0;
|
||||
cameraMatrixData[11] = 0;
|
||||
cameraMatrixData[15] = 1;
|
||||
cameraMatrix.rawData = cameraMatrixData;
|
||||
}
|
||||
|
||||
static private const boundVertices:Vector.<Number> = new Vector.<Number>(24);
|
||||
|
||||
alternativa3d function cullingInCamera(camera:Camera3D, culling:int):int {
|
||||
if (culling > 0) {
|
||||
var i:int;
|
||||
var infront:Boolean;
|
||||
var behind:Boolean;
|
||||
// Заполнение
|
||||
boundVertices[0] = boundMinX;
|
||||
boundVertices[1] = boundMinY;
|
||||
boundVertices[2] = boundMinZ;
|
||||
boundVertices[3] = boundMaxX;
|
||||
boundVertices[4] = boundMinY;
|
||||
boundVertices[5] = boundMinZ;
|
||||
boundVertices[6] = boundMinX;
|
||||
boundVertices[7] = boundMaxY;
|
||||
boundVertices[8] = boundMinZ;
|
||||
boundVertices[9] = boundMaxX;
|
||||
boundVertices[10] = boundMaxY;
|
||||
boundVertices[11] = boundMinZ;
|
||||
boundVertices[12] = boundMinX;
|
||||
boundVertices[13] = boundMinY;
|
||||
boundVertices[14] = boundMaxZ;
|
||||
boundVertices[15] = boundMaxX;
|
||||
boundVertices[16] = boundMinY;
|
||||
boundVertices[17] = boundMaxZ;
|
||||
boundVertices[18] = boundMinX;
|
||||
boundVertices[19] = boundMaxY;
|
||||
boundVertices[20] = boundMaxZ;
|
||||
boundVertices[21] = boundMaxX;
|
||||
boundVertices[22] = boundMaxY;
|
||||
boundVertices[23] = boundMaxZ;
|
||||
// Трансформация в камеру
|
||||
cameraMatrix.transformVectors(boundVertices, boundVertices);
|
||||
// Коррекция под 90 градусов
|
||||
var sx:Number = camera.focalLength*2/camera.view._width;
|
||||
var sy:Number = camera.focalLength*2/camera.view._height;
|
||||
for (i = 0; i < 24; i += 2) {
|
||||
boundVertices[i] *= sx; i++;
|
||||
boundVertices[i] *= sy;
|
||||
}
|
||||
// Куллинг
|
||||
if (culling & 1) {
|
||||
for (i = 2, infront = false, behind = false; i <= 23; i += 3) {
|
||||
if (boundVertices[i] > camera.nearClipping) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 62;
|
||||
}
|
||||
}
|
||||
if (culling & 2) {
|
||||
for (i = 2, infront = false, behind = false; i <= 23; i += 3) {
|
||||
if (boundVertices[i] < camera.farClipping) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 61;
|
||||
}
|
||||
}
|
||||
if (culling & 4) {
|
||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
||||
if (-boundVertices[i] < boundVertices[int(i + 2)]) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 59;
|
||||
}
|
||||
}
|
||||
if (culling & 8) {
|
||||
for (i = 0, infront = false, behind = false; i <= 21; i += 3) {
|
||||
if (boundVertices[i] < boundVertices[int(i + 2)]) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 55;
|
||||
}
|
||||
}
|
||||
if (culling & 16) {
|
||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
||||
if (-boundVertices[i] < boundVertices[int(i + 1)]) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 47;
|
||||
}
|
||||
}
|
||||
if (culling & 32) {
|
||||
for (i = 1, infront = false, behind = false; i <= 22; i += 3) {
|
||||
if (boundVertices[i] < boundVertices[int(i + 1)]) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 31;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.culling = culling;
|
||||
return culling;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
/*alternativa3d function cullingInCamera(camera:Camera3D, culling:int):int {
|
||||
if (camera.occludedAll) return -1;
|
||||
var numOccluders:int = camera.numOccluders;
|
||||
var vertex:Vertex;
|
||||
// Расчёт точек баунда в координатах камеры
|
||||
if (culling > 0 || numOccluders > 0) {
|
||||
// Заполнение
|
||||
vertex = boundVertexList;
|
||||
vertex.x = boundMinX;
|
||||
vertex.y = boundMinY;
|
||||
vertex.z = boundMinZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMaxX;
|
||||
vertex.y = boundMinY;
|
||||
vertex.z = boundMinZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMinX;
|
||||
vertex.y = boundMaxY;
|
||||
vertex.z = boundMinZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMaxX;
|
||||
vertex.y = boundMaxY;
|
||||
vertex.z = boundMinZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMinX;
|
||||
vertex.y = boundMinY;
|
||||
vertex.z = boundMaxZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMaxX;
|
||||
vertex.y = boundMinY;
|
||||
vertex.z = boundMaxZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMinX;
|
||||
vertex.y = boundMaxY;
|
||||
vertex.z = boundMaxZ;
|
||||
vertex = vertex.next;
|
||||
vertex.x = boundMaxX;
|
||||
vertex.y = boundMaxY;
|
||||
vertex.z = boundMaxZ;
|
||||
// Трансформация в камеру
|
||||
for (vertex = boundVertexList; vertex != null; vertex = vertex.next) {
|
||||
var x:Number = vertex.x;
|
||||
var y:Number = vertex.y;
|
||||
var z:Number = vertex.z;
|
||||
vertex.cameraX = ma*x + mb*y + mc*z + md;
|
||||
vertex.cameraY = me*x + mf*y + mg*z + mh;
|
||||
vertex.cameraZ = mi*x + mj*y + mk*z + ml;
|
||||
}
|
||||
}
|
||||
// Куллинг
|
||||
if (culling > 0) {
|
||||
var infront:Boolean;
|
||||
var behind:Boolean;
|
||||
if (culling & 1) {
|
||||
var near:Number = camera.nearClipping;
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (vertex.cameraZ > near) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 62;
|
||||
}
|
||||
}
|
||||
if (culling & 2) {
|
||||
var far:Number = camera.farClipping;
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (vertex.cameraZ < far) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 61;
|
||||
}
|
||||
}
|
||||
if (culling & 4) {
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (-vertex.cameraX < vertex.cameraZ) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 59;
|
||||
}
|
||||
}
|
||||
if (culling & 8) {
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (vertex.cameraX < vertex.cameraZ) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 55;
|
||||
}
|
||||
}
|
||||
if (culling & 16) {
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (-vertex.cameraY < vertex.cameraZ) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 47;
|
||||
}
|
||||
}
|
||||
if (culling & 32) {
|
||||
for (vertex = boundVertexList, infront = false, behind = false; vertex != null; vertex = vertex.next) {
|
||||
if (vertex.cameraY < vertex.cameraZ) {
|
||||
infront = true;
|
||||
if (behind) break;
|
||||
} else {
|
||||
behind = true;
|
||||
if (infront) break;
|
||||
}
|
||||
}
|
||||
if (behind) {
|
||||
if (!infront) return -1;
|
||||
} else {
|
||||
culling &= 31;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Окклюдинг
|
||||
if (numOccluders > 0) {
|
||||
for (var i:int = 0; i < numOccluders; i++) {
|
||||
for (var plane:Vertex = camera.occluders[i]; plane != null; plane = plane.next) {
|
||||
for (vertex = boundVertexList; vertex != null; vertex = vertex.next) {
|
||||
if (plane.cameraX*vertex.cameraX + plane.cameraY*vertex.cameraY + plane.cameraZ*vertex.cameraZ >= 0) break;
|
||||
}
|
||||
if (vertex != null) break;
|
||||
}
|
||||
if (plane == null) return -1;
|
||||
}
|
||||
}
|
||||
this.culling = culling;
|
||||
return culling;
|
||||
}*/
|
||||
|
||||
/*protected function composeRenderMatrix():void {
|
||||
if (matrix != null) {
|
||||
cameraMatrix.identity();
|
||||
cameraMatrix.append(matrix);
|
||||
} else {
|
||||
composeVectors[0] = translation;
|
||||
composeVectors[1] = rotation;
|
||||
composeVectors[2] = scale;
|
||||
cameraMatrix.recompose(composeVectors);
|
||||
}
|
||||
}*/
|
||||
|
||||
/*public function draw(camera:Camera3D, parent:Object3DContainer = null):void {
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Возвращает объект, являющийся точной копией исходного объекта.
|
||||
* @return Клон исходного объекта.
|
||||
*/
|
||||
/*public function clone():Object3D {
|
||||
var res:Object3D = new Object3D();
|
||||
res.cloneBaseProperties(this);
|
||||
return res;
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Копирует базовые свойства. Метод вызывается внутри <code>clone()</code>.
|
||||
* @param source Объект, с которого копируются базовые свойства.
|
||||
*/
|
||||
/*protected function cloneBaseProperties(source:Object3D):void {
|
||||
name = source.name;
|
||||
visible = source.visible;
|
||||
if (source.matrix != null) {
|
||||
matrix = source.matrix.clone();
|
||||
} else {
|
||||
translation.x = source.translation.x;
|
||||
translation.y = source.translation.y;
|
||||
translation.z = source.translation.z;
|
||||
rotation.x = source.rotation.x;
|
||||
rotation.y = source.rotation.y;
|
||||
rotation.z = source.rotation.z;
|
||||
scale.x = source.scale.x;
|
||||
scale.y = source.scale.y;
|
||||
scale.z = source.scale.z;
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.lights.DirectionalLight;
|
||||
|
||||
import flash.geom.Matrix3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Базовый контейнер трёхмерных объектов.
|
||||
* Логика контейнеров и child-parent-отношений идентична логике displayObject'ов во Flash.
|
||||
* Дочерние объекты отрисовываются в том порядке, в котором находятся в списке.
|
||||
*/
|
||||
public class Object3DContainer extends Object3D {
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var childrenList:Object3D;
|
||||
|
||||
/**
|
||||
* Добавляет дочерний объект. Объект добавляется в конец списка.
|
||||
* Если добавляется объект, предком которого уже является другой контейнер, то объект удаляется из списка потомков старого контейнера.
|
||||
* @param child Добавляемый дочерний объект.
|
||||
* @return Экземпляр Object3D, передаваемый в параметре <code>child</code>.
|
||||
*/
|
||||
public function addChild(child:Object3D):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child == this) throw new ArgumentError("An object cannot be added as a child of itself.");
|
||||
for (var container:Object3DContainer = _parent; container != null; container = container._parent) {
|
||||
if (container == child) throw new ArgumentError("An object cannot be added as a child to one of it's children (or children's children, etc.).");
|
||||
}
|
||||
// Удаление из старого родителя
|
||||
if (child._parent != null) child._parent.removeChild(child);
|
||||
// Добавление
|
||||
addToList(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет дочерний объект. Свойство <code>parent</code> удаленного объекта получает значение <code>null</code>.
|
||||
* @param child Удаляемый дочерний объект.
|
||||
* @return Экземпляр Object3D, передаваемый в параметре <code>child</code>.
|
||||
*/
|
||||
public function removeChild(child:Object3D):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
||||
// Удаление
|
||||
var prev:Object3D;
|
||||
var current:Object3D;
|
||||
for (current = childrenList; current != null; current = current.next) {
|
||||
if (current == child) {
|
||||
if (prev != null) {
|
||||
prev.next = current.next;
|
||||
} else {
|
||||
childrenList = current.next;
|
||||
}
|
||||
current.next = null;
|
||||
current._parent = null;
|
||||
return child;
|
||||
}
|
||||
prev = current;
|
||||
}
|
||||
throw new ArgumentError("Cannot remove child.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет дочерний объект. Объект добавляется в указанную позицию в списке.
|
||||
* @param child Добавляемый дочерний объект.
|
||||
* @param index Позиция, в которую добавляется дочерний объект.
|
||||
* @return Экземпляр Object3D, передаваемый в параметре <code>child</code>.
|
||||
*/
|
||||
public function addChildAt(child:Object3D, index:int):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child == this) throw new ArgumentError("An object cannot be added as a child of itself.");
|
||||
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
for (var container:Object3DContainer = _parent; container != null; container = container._parent) {
|
||||
if (container == child) throw new ArgumentError("An object cannot be added as a child to one of it's children (or children's children, etc.).");
|
||||
}
|
||||
// Поиск элемента по индексу
|
||||
var current:Object3D = childrenList;
|
||||
for (var i:int = 0; i < index; i++) {
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
current = current.next;
|
||||
}
|
||||
// Удаление из старого родителя
|
||||
if (child._parent != null) child._parent.removeChild(child);
|
||||
// Добавление
|
||||
addToList(child, current);
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет дочерний объект из заданной позиции. Свойство <code>parent</code> удаленного объекта получает значение <code>null</code>.
|
||||
* @param index Позиция, из которой удаляется дочерний объект.
|
||||
* @return Удаленный экземпляр Object3D.
|
||||
*/
|
||||
public function removeChildAt(index:int):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Поиск элемента по индексу
|
||||
var current:Object3D = childrenList;
|
||||
for (var i:int = 0; i < index; i++) {
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
current = current.next;
|
||||
}
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Удаление
|
||||
removeChild(current);
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает экземпляр дочернего объекта, существующий в заданной позиции.
|
||||
* @param index Позиция дочернего объекта.
|
||||
* @return Дочерний объект с заданной позицией.
|
||||
*/
|
||||
public function getChildAt(index:int):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Поиск элемента по индексу
|
||||
var current:Object3D = childrenList;
|
||||
for (var i:int = 0; i < index; i++) {
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
current = current.next;
|
||||
}
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает позицию дочернего объекта.
|
||||
* @param child Дочерний объект.
|
||||
* @return Позиция заданного дочернего объекта.
|
||||
*/
|
||||
public function getChildIndex(child:Object3D):int {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
||||
// Поиск индекса элемента
|
||||
var index:int = 0;
|
||||
for (var current:Object3D = childrenList; current != null; current = current.next) {
|
||||
if (current == child) return index;
|
||||
index++;
|
||||
}
|
||||
throw new ArgumentError("Cannot get child index.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Устанавливает позицию дочернего объекта.
|
||||
* @param child Дочерний объект.
|
||||
* @param index Устанавливаемая позиция объекта.
|
||||
*/
|
||||
public function setChildIndex(child:Object3D, index:int):void {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
||||
if (index < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Поиск элемента по индексу
|
||||
var current:Object3D = childrenList;
|
||||
for (var i:int = 0; i < index; i++) {
|
||||
if (current == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
current = current.next;
|
||||
}
|
||||
// Удаление
|
||||
removeChild(child);
|
||||
// Добавление
|
||||
addToList(child, current);
|
||||
}
|
||||
|
||||
/**
|
||||
* Меняет местами два дочерних объекта в списке.
|
||||
* @param child1 Первый дочерний объект.
|
||||
* @param child2 Второй дочерний объект.
|
||||
*/
|
||||
public function swapChildren(child1:Object3D, child2:Object3D):void {
|
||||
// Проверка на ошибки
|
||||
if (child1 == null || child2 == null) throw new TypeError("Parameter child must be non-null.");
|
||||
if (child1._parent != this || child2._parent != this) throw new ArgumentError("The supplied Object3D must be a child of the caller.");
|
||||
// Перестановка
|
||||
if (child1 != child2) {
|
||||
if (child1.next == child2) {
|
||||
removeChild(child2);
|
||||
addToList(child2, child1);
|
||||
} else if (child2.next == child1) {
|
||||
removeChild(child1);
|
||||
addToList(child1, child2);
|
||||
} else {
|
||||
var nxt:Object3D = child1.next;
|
||||
removeChild(child1);
|
||||
addToList(child1, child2);
|
||||
removeChild(child2);
|
||||
addToList(child2, nxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Меняет местами два дочерних объекта в списке по указанным позициям.
|
||||
* @param index1 Позиция первого дочернего объекта.
|
||||
* @param index2 Позиция второго дочернего объекта.
|
||||
*/
|
||||
public function swapChildrenAt(index1:int, index2:int):void {
|
||||
// Проверка на ошибки
|
||||
if (index1 < 0 || index2 < 0) throw new RangeError("The supplied index is out of bounds.");
|
||||
// Перестановка
|
||||
if (index1 != index2) {
|
||||
// Поиск элементов по индексам
|
||||
var i:int;
|
||||
var child1:Object3D = childrenList;
|
||||
for (i = 0; i < index1; i++) {
|
||||
if (child1 == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
child1 = child1.next;
|
||||
}
|
||||
if (child1 == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
var child2:Object3D = childrenList;
|
||||
for (i = 0; i < index2; i++) {
|
||||
if (child2 == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
child2 = child2.next;
|
||||
}
|
||||
if (child2 == null) throw new RangeError("The supplied index is out of bounds.");
|
||||
if (child1 != child2) {
|
||||
if (child1.next == child2) {
|
||||
removeChild(child2);
|
||||
addToList(child2, child1);
|
||||
} else if (child2.next == child1) {
|
||||
removeChild(child1);
|
||||
addToList(child1, child2);
|
||||
} else {
|
||||
var nxt:Object3D = child1.next;
|
||||
removeChild(child1);
|
||||
addToList(child1, child2);
|
||||
removeChild(child2);
|
||||
addToList(child2, nxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает дочерний объект с заданным именем.
|
||||
* Если объектов с заданным именем несколько, возвратится первый попавшийся.
|
||||
* Если объект с заданным именем не содержится в контейнере, возвратится <code>null</code>.
|
||||
* @param name Имя дочернего объекта.
|
||||
* @return Дочерний объект с заданным именем.
|
||||
*/
|
||||
public function getChildByName(name:String):Object3D {
|
||||
// Проверка на ошибки
|
||||
if (name == null) throw new TypeError("Parameter name must be non-null.");
|
||||
// Поиск объекта
|
||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||
if (child.name == name) return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Определяет, содержится ли заданный объект среди дочерних объектов.
|
||||
* Область поиска охватывает часть иерархии, начиная с данного Object3DContainer.
|
||||
* @param child Дочерний объект.
|
||||
* @return Значение <code>true</code>, если заданный объект является самим контейнером или одним из его потомков, в противном случае значение <code>false</code>.
|
||||
*/
|
||||
public function contains(child:Object3D):Boolean {
|
||||
// Проверка на ошибки
|
||||
if (child == null) throw new TypeError("Parameter child must be non-null.");
|
||||
// Поиск объекта
|
||||
if (child == this) return true;
|
||||
for (var object:Object3D = childrenList; object != null; object = object.next) {
|
||||
if (object is Object3DContainer) {
|
||||
if ((object as Object3DContainer).contains(child)) {
|
||||
return true;
|
||||
}
|
||||
} else if (object == child) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает количество дочерних объектов.
|
||||
*/
|
||||
public function get numChildren():int {
|
||||
var num:int = 0;
|
||||
for (var current:Object3D = childrenList; current != null; current = current.next) num++;
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
override public function clone():Object3D {
|
||||
var container:Object3DContainer = new Object3DContainer();
|
||||
container.cloneBaseProperties(this);
|
||||
for (var child:Object3D = childrenList, lastChild:Object3D; child != null; child = child.next) {
|
||||
var newChild:Object3D = child.clone();
|
||||
if (container.childrenList != null) {
|
||||
lastChild.next = newChild;
|
||||
} else {
|
||||
container.childrenList = newChild;
|
||||
}
|
||||
lastChild = newChild;
|
||||
newChild._parent = container;
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function draw(camera:Camera3D):void {
|
||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||
if (child.visible) {
|
||||
child.composeMatrix();
|
||||
child.cameraMatrix.append(cameraMatrix);
|
||||
if (child.cullingInCamera(camera, culling) >= 0) {
|
||||
if (child.isTransparent) {
|
||||
camera.transparentObjects[int(camera.numTransparent++)] = child;
|
||||
} else {
|
||||
child.draw(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function drawInShadowMap(camera:Camera3D, light:DirectionalLight):void {
|
||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||
if (child.visible && !child.isTransparent) {
|
||||
child.composeMatrix();
|
||||
child.cameraMatrix.append(cameraMatrix);
|
||||
child.drawInShadowMap(camera, light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
override alternativa3d function updateBounds(bounds:Object3D, matrix:Matrix3D = null):void {
|
||||
for (var child:Object3D = childrenList; child != null; child = child.next) {
|
||||
child.composeMatrix();
|
||||
if (matrix != null) child.cameraMatrix.append(matrix);
|
||||
child.updateBounds(bounds, child.cameraMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function addToList(child:Object3D, item:Object3D = null):void {
|
||||
child.next = item;
|
||||
child._parent = this;
|
||||
if (item == childrenList) {
|
||||
childrenList = child;
|
||||
} else {
|
||||
for (var current:Object3D = childrenList; current != null; current = current.next) {
|
||||
if (current.next == item) {
|
||||
current.next = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
/**
|
||||
* Результат проверки пересечения луча с объектом.
|
||||
*/
|
||||
public class RayIntersectionData {
|
||||
|
||||
/**
|
||||
* Объект, с которым найдено пересечение луча.
|
||||
*/
|
||||
public var object:Object3D;
|
||||
|
||||
/**
|
||||
* Ближайшая к началу луча грань объекта, с которым найдено пересечение.
|
||||
*/
|
||||
public var face:Face;
|
||||
|
||||
/**
|
||||
* Точка пересечения луча с объектом.
|
||||
*/
|
||||
public var point:Vector3D;
|
||||
|
||||
/**
|
||||
* Расстояние от начала луча до точки пересечения с объектом.
|
||||
*/
|
||||
public var distance:Number;
|
||||
|
||||
}
|
||||
}
|
||||
224
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Vertex.as
Normal file
224
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/Vertex.as
Normal file
@@ -0,0 +1,224 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import __AS3__.vec.Vector;
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Вершина в трёхмерном пространстве. Вершины являются составными частями полигональных объектов. На базе вершин строятся грани.
|
||||
* @see alternativa.engine3d.core.Geometry
|
||||
* @see alternativa.engine3d.core.Face
|
||||
*/
|
||||
public class Vertex {
|
||||
|
||||
alternativa3d var geometry:Geometry;
|
||||
|
||||
/**
|
||||
* Координата X.
|
||||
*/
|
||||
public var _x:Number = 0;
|
||||
|
||||
/**
|
||||
* Координата Y.
|
||||
*/
|
||||
public var _y:Number = 0;
|
||||
|
||||
/**
|
||||
* Координата Z.
|
||||
*/
|
||||
public var _z:Number = 0;
|
||||
|
||||
/**
|
||||
* Текстурная координата по горизонтали.
|
||||
*/
|
||||
public var _u:Number = 0;
|
||||
|
||||
/**
|
||||
* Текстурная координата по вертикали.
|
||||
*/
|
||||
public var _v:Number = 0;
|
||||
|
||||
/**
|
||||
* Индексы костей, влияющих на эту вершину
|
||||
*/
|
||||
public var _jointsIndices:Vector.<uint>;
|
||||
|
||||
/**
|
||||
* Веса костей, влияющих на эту вершину.
|
||||
*/
|
||||
public var _jointsWeights:Vector.<Number>;
|
||||
|
||||
/**
|
||||
* Дополнительные аттрибуты в вершине для шейдера
|
||||
*/
|
||||
public var _attributes:Vector.<Number>;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var next:Vertex;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var value:Vertex;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var offset:Number;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var index:int;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static alternativa3d var collector:Vertex;
|
||||
|
||||
public function get x():Number {
|
||||
return _x;
|
||||
}
|
||||
public function set x(value:Number):void {
|
||||
_x = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get y():Number {
|
||||
return _y;
|
||||
}
|
||||
public function set y(value:Number):void {
|
||||
_y = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get z():Number {
|
||||
return _z;
|
||||
}
|
||||
public function set z(value:Number):void {
|
||||
_z = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get u():Number {
|
||||
return _u;
|
||||
}
|
||||
public function set u(value:Number):void {
|
||||
_u = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get v():Number {
|
||||
return _v;
|
||||
}
|
||||
public function set v(value:Number):void {
|
||||
_v = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get jointsIndices():Vector.<uint> {
|
||||
return _jointsIndices;
|
||||
}
|
||||
public function set jointsIndices(value:Vector.<uint>):void {
|
||||
_jointsIndices = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get jointsWeights():Vector.<Number> {
|
||||
return _jointsWeights;
|
||||
}
|
||||
public function set jointsWeights(value:Vector.<Number>):void {
|
||||
_jointsWeights = value;
|
||||
geometry.reset();
|
||||
}
|
||||
public function get attributes():Vector.<Number> {
|
||||
return _attributes;
|
||||
}
|
||||
public function set attributes(value:Vector.<Number>):void {
|
||||
_attributes = value;
|
||||
geometry.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
static alternativa3d function createList(num:int):Vertex {
|
||||
var res:Vertex = collector;
|
||||
var last:Vertex;
|
||||
if (res != null) {
|
||||
for (last = res; num > 1; last = last.next,num--) {
|
||||
if (last.next == null) {
|
||||
//for (; num > 1; /*trace("new Vertex"), */last.next = new Vertex(), last = last.next, num--);
|
||||
while (num > 1) {
|
||||
//trace("new Vertex");
|
||||
last.next = new Vertex();
|
||||
last = last.next;
|
||||
num--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
collector = last.next;
|
||||
last.next = null;
|
||||
} else {
|
||||
//for (res = new Vertex(), /*trace("new Vertex"), */last = res; num > 1; /*trace("new Vertex"), */last.next = new Vertex(), last = last.next, num--);
|
||||
//trace("new Vertex");
|
||||
res = new Vertex();
|
||||
last = res;
|
||||
while (num > 1) {
|
||||
//trace("new Vertex");
|
||||
last.next = new Vertex();
|
||||
last = last.next;
|
||||
num--;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d function create():Vertex {
|
||||
if (collector != null) {
|
||||
var res:Vertex = collector;
|
||||
collector = res.next;
|
||||
res.next = null;
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Vertex");
|
||||
return new Vertex();
|
||||
}
|
||||
}
|
||||
|
||||
alternativa3d function clone():Vertex {
|
||||
var res:Vertex = new Vertex();
|
||||
res._x = _x;
|
||||
res._y = _y;
|
||||
res._z = _z;
|
||||
res._u = _u;
|
||||
res._v = _v;
|
||||
var i:int, count:int;
|
||||
if (_attributes != null) {
|
||||
count = _attributes.length;
|
||||
res._attributes = new Vector.<Number>(count);
|
||||
for (i = 0; i < count; i++) {
|
||||
res._attributes[i] = _attributes[i];
|
||||
}
|
||||
}
|
||||
if (_jointsIndices != null) {
|
||||
count = _jointsIndices.length;
|
||||
res._jointsIndices = new Vector.<uint>(count);
|
||||
for (i = 0; i < count; i++) {
|
||||
res._jointsIndices[i] = _jointsIndices[i];
|
||||
}
|
||||
}
|
||||
if (_jointsWeights != null) {
|
||||
count = _jointsWeights.length;
|
||||
res._jointsWeights = new Vector.<Number>(count);
|
||||
for (i = 0; i < count; i++) {
|
||||
res._jointsWeights[i] = _jointsWeights[i];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
64
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/View.as
Normal file
64
Alternativa3D8/8.0.0.0/src/alternativa/engine3d/core/View.as
Normal file
@@ -0,0 +1,64 @@
|
||||
package alternativa.engine3d.core {
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
import flash.display.Bitmap3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* Вьюпорт, в который камера отрисовывает графику.
|
||||
* <code>View</code> — это <code>Bitmap3D</code>.
|
||||
* @see alternativa.engine3d.core.Camera3D
|
||||
*/
|
||||
public class View extends Bitmap3D {
|
||||
|
||||
public var backgroundColor:int = 0;
|
||||
public var backgroundAlpha:Number = 1;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var _width:Number = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var _height:Number = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var _antialias:int;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var _depthdtencil:Boolean;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
alternativa3d var cachedPrograms:Object = new Object();
|
||||
|
||||
/**
|
||||
* Создаёт новый вьюпорт.
|
||||
* @param width Ширина вьюпорта.
|
||||
* @param height Высота вьюпорта.
|
||||
*/
|
||||
public function View(width:Number, height:Number, rendermode:String = "AUTO", antialias:uint = 0, depthstencil:Boolean = true) {
|
||||
super(rendermode);
|
||||
setupBackbuffer(width, height, antialias, depthstencil);
|
||||
}
|
||||
|
||||
override public function setupBackbuffer(width:uint, height:uint, antialias:uint, depthstencil:Boolean):void {
|
||||
if (_width != width || _height != height || _antialias != antialias || _depthdtencil != depthstencil) {
|
||||
super.setupBackbuffer(width, height, antialias, depthstencil);
|
||||
_width = width;
|
||||
_height = height;
|
||||
_antialias = antialias;
|
||||
_depthdtencil = depthstencil;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package alternativa.engine3d.core {
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
|
||||
use namespace alternativa3d;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public class Wrapper {
|
||||
|
||||
alternativa3d var next:Wrapper;
|
||||
|
||||
alternativa3d var vertex:Vertex;
|
||||
|
||||
static alternativa3d var collector:Wrapper;
|
||||
|
||||
static alternativa3d function create():Wrapper {
|
||||
if (collector != null) {
|
||||
var res:Wrapper = collector;
|
||||
collector = collector.next;
|
||||
res.next = null;
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Wrapper");
|
||||
return new Wrapper();
|
||||
}
|
||||
}
|
||||
|
||||
alternativa3d function create():Wrapper {
|
||||
if (collector != null) {
|
||||
var res:Wrapper = collector;
|
||||
collector = collector.next;
|
||||
res.next = null;
|
||||
return res;
|
||||
} else {
|
||||
//trace("new Wrapper");
|
||||
return new Wrapper();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 106
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/lights
|
||||
END
|
||||
DirectionalLight.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 126
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/lights/DirectionalLight.as
|
||||
END
|
||||
@@ -0,0 +1,40 @@
|
||||
8
|
||||
|
||||
dir
|
||||
46043
|
||||
http://svndev.alternativaplatform.com/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/lights
|
||||
http://svndev.alternativaplatform.com
|
||||
|
||||
|
||||
|
||||
2010-09-06T09:12:26.928415Z
|
||||
40690
|
||||
andrei
|
||||
|
||||
|
||||
svn:special svn:externals svn:needs-lock
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
d9e2387a-1f3e-40e2-b57f-9df5970a2fa5
|
||||
|
||||
DirectionalLight.as
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-28T04:33:34.000000Z
|
||||
b22aea1db75a93ff9a3af1d303eb419c
|
||||
2010-09-06T09:12:26.928415Z
|
||||
40690
|
||||
andrei
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
8
|
||||
@@ -0,0 +1,217 @@
|
||||
package alternativa.engine3d.lights {
|
||||
|
||||
import __AS3__.vec.Vector;
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.core.Camera3D;
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
import alternativa.engine3d.core.View;
|
||||
import alternativa.engine3d.materials.TextureMaterial;
|
||||
|
||||
import flash.display.IndexBuffer3D;
|
||||
import flash.display.Texture3D;
|
||||
import flash.geom.Matrix3D;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
public class DirectionalLight extends Object3D {
|
||||
|
||||
public var debugMaterial:TextureMaterial;
|
||||
|
||||
public var forceDontRenderToTexture:Boolean = false;
|
||||
|
||||
public var options:Vector.<Number> = Vector.<Number>([0.007, 10000, 1.0, 0]); // Смещение, множитель
|
||||
|
||||
// Матрица перевода в источник света
|
||||
alternativa3d var lightMatrix:Matrix3D = new Matrix3D();
|
||||
alternativa3d var uvMatrix:Matrix3D = new Matrix3D();
|
||||
|
||||
private var near:Number;
|
||||
private var far:Number;
|
||||
|
||||
private var _width:uint;
|
||||
private var _height:uint;
|
||||
|
||||
alternativa3d var numSplits:uint;
|
||||
alternativa3d var currentSplitNear:Number;
|
||||
alternativa3d var currentSplitFar:Number;
|
||||
|
||||
private var shadowMap:Texture3D;
|
||||
|
||||
public function DirectionalLight(width:uint, height:uint, near:Number, far:Number, numSplits:uint = 4) {
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this.near = near;
|
||||
this.far = far;
|
||||
this.numSplits = numSplits;
|
||||
}
|
||||
|
||||
alternativa3d function update(camera:Camera3D, view:View, splitIndex:int):void {
|
||||
if (forceDontRenderToTexture) {
|
||||
return;
|
||||
}
|
||||
shadowMap = view.createTexture(_width, _height, "BGRA", true);
|
||||
if (debugMaterial != null && splitIndex == 0) {
|
||||
debugMaterial.texture3d = shadowMap;
|
||||
}
|
||||
|
||||
// Расчёт матрицы перевода из глобального пространства в камеру
|
||||
composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
cameraMatrix.append(root.cameraMatrix);
|
||||
}
|
||||
cameraMatrix.invert();
|
||||
|
||||
view.setRenderToTexture(shadowMap, true);
|
||||
view.clear(1, 1, 1, 1, 1);
|
||||
|
||||
var cameraWCoeff:Number = camera.view._width/2/camera.focalLength;
|
||||
var cameraHCoeff:Number = camera.view._height/2/camera.focalLength;
|
||||
|
||||
var points:Vector.<Vector3D> = new Vector.<Vector3D>();
|
||||
points[0] = new Vector3D(-cameraWCoeff, -cameraHCoeff, 0);
|
||||
points[1] = new Vector3D(cameraWCoeff, -cameraHCoeff, 0);
|
||||
points[2] = new Vector3D(cameraWCoeff, cameraHCoeff, 0);
|
||||
points[3] = new Vector3D(-cameraWCoeff, cameraHCoeff, 0);
|
||||
var p:Vector3D;
|
||||
var transformed:Vector3D = new Vector3D();
|
||||
|
||||
var currentNear:Number = (camera.nearClipping < near) ? near : camera.nearClipping;
|
||||
var currentFar:Number = (camera.farClipping < far) ? camera.farClipping : far;
|
||||
var scissor:Rectangle = new Rectangle();
|
||||
|
||||
var minLightX:Number = Number.MAX_VALUE, minLightY:Number = Number.MAX_VALUE, minLightZ:Number = Number.MAX_VALUE;
|
||||
var maxLightX:Number = -Number.MAX_VALUE, maxLightY:Number = -Number.MAX_VALUE, maxLightZ:Number = -Number.MAX_VALUE;
|
||||
|
||||
const lambda:Number = 1;
|
||||
var splitNear:Number = lambda*currentNear*Math.pow(currentFar/currentNear, splitIndex/numSplits) + (1 - lambda)*((currentNear + splitIndex/numSplits)*(currentFar - currentNear));
|
||||
var splitFar:Number = lambda*currentNear*Math.pow(currentFar/currentNear, (splitIndex + 1)/numSplits) + (1 - lambda)*((currentNear + (splitIndex + 1)/numSplits)*(currentFar - currentNear));
|
||||
|
||||
currentSplitNear = splitNear;
|
||||
currentSplitFar = splitFar;
|
||||
|
||||
projectionMatrix.identity();
|
||||
projectionMatrix.append(camera.globalMatrix);
|
||||
projectionMatrix.append(cameraMatrix);
|
||||
// Считаем баунд куска в источнике света
|
||||
for (var j:int = 0; j < 8; j++) {
|
||||
if (j < 4) {
|
||||
p = points[j];
|
||||
transformed.x = p.x * splitNear;
|
||||
transformed.y = p.y * splitNear;
|
||||
transformed.z = splitNear;
|
||||
} else {
|
||||
p = points[j - 4];
|
||||
transformed.x = p.x * splitFar;
|
||||
transformed.y = p.y * splitFar;
|
||||
transformed.z = splitFar;
|
||||
}
|
||||
p = projectionMatrix.transformVector(transformed);
|
||||
if (p.x < minLightX) {
|
||||
minLightX = p.x;
|
||||
} else if (p.x > maxLightX) {
|
||||
maxLightX = p.x;
|
||||
}
|
||||
if (p.y < minLightY) {
|
||||
minLightY = p.y;
|
||||
} else if (p.y > maxLightY) {
|
||||
maxLightY = p.y;
|
||||
}
|
||||
if (p.z < minLightZ) {
|
||||
minLightZ = p.z;
|
||||
} else if (p.z > maxLightZ) {
|
||||
maxLightZ = p.z;
|
||||
}
|
||||
}
|
||||
minLightZ = 0;
|
||||
// trace("[Light bounds]", minLightX, maxLightX, minLightY, maxLightY, minLightZ, maxLightZ);
|
||||
|
||||
var pixelW:Number = 1/_width;
|
||||
|
||||
// Считаем матрицу проецирования
|
||||
var rawData:Vector.<Number> = new Vector.<Number>(16);
|
||||
// cameraMatrixData
|
||||
// rawData[0] = 2/(maxLightX - minLightX)/numSplits;
|
||||
rawData[0] = 2/(maxLightX - minLightX);
|
||||
rawData[5] = 2/(maxLightY - minLightY);
|
||||
rawData[10]= 1/(maxLightZ - minLightZ);
|
||||
// rawData[12] = (-0.5 * (maxLightX + minLightX) * rawData[0]) + 2*i/numSplits - 1/numSplits;
|
||||
rawData[12] = (-0.5 * (maxLightX + minLightX) * rawData[0]);
|
||||
rawData[13] = (-0.5 * (maxLightY + minLightY) * rawData[5]);
|
||||
rawData[14]= -minLightZ/(maxLightZ - minLightZ);
|
||||
rawData[15]= 1;
|
||||
projectionMatrix.rawData = rawData;
|
||||
|
||||
rawData[0] = 1/((maxLightX - minLightX));
|
||||
rawData[5] = -1/((maxLightY - minLightY));
|
||||
// rawData[12] = 0.5 - (0.5 * (maxLightX + minLightX) * rawData[0]) + i/numSplits - 0.5/numSplits;
|
||||
rawData[12] = 0.5 - (0.5 * (maxLightX + minLightX) * rawData[0]);
|
||||
rawData[13] = 0.5 - (0.5 * (maxLightY + minLightY) * rawData[5]);
|
||||
uvMatrix = new Matrix3D(rawData);
|
||||
|
||||
lightMatrix.identity();
|
||||
lightMatrix.append(camera.globalMatrix);
|
||||
lightMatrix.append(cameraMatrix);
|
||||
lightMatrix.append(uvMatrix);
|
||||
|
||||
// scissor.x = i * _width/numSplits;
|
||||
// scissor.width = _width/numSplits;
|
||||
// scissor.height = _height;
|
||||
// view.setScissor(scissor);
|
||||
if (root != this && root.visible && !root.isTransparent) {
|
||||
root.composeMatrix();
|
||||
root.cameraMatrix.append(cameraMatrix);
|
||||
root.drawInShadowMap(camera, this);
|
||||
}
|
||||
// splitNear = splitFar;
|
||||
view.flush();
|
||||
view.setRenderToBackbuffer();
|
||||
// view.setScissor(null);
|
||||
}
|
||||
|
||||
alternativa3d function attenuateVertexShader(v4:String, const4x4:uint):String {
|
||||
if (forceDontRenderToTexture) {
|
||||
return "";
|
||||
}
|
||||
var shader:String = "dp4 " + v4 + ".x, va0, vc" + const4x4+ " \n" +
|
||||
"dp4 " + v4 + ".y, va0, vc" + (const4x4 + 1) + " \n" +
|
||||
"dp4 " + v4 + ".z, va0, vc" + (const4x4 + 2) + " \n" +
|
||||
"dp4 " + v4 + ".w, va0, vc" + (const4x4 + 3) + " \n";
|
||||
return shader;
|
||||
}
|
||||
|
||||
alternativa3d function attenuateFragmentShader(result4:String, v4:String, texture:uint, const2:uint):String {
|
||||
if (forceDontRenderToTexture) {
|
||||
return "mov " + result4 + ", fc" + const2 + ".zzzz \n";
|
||||
}
|
||||
// Отображение шедоу мапы
|
||||
// var shader:String = "tex " + result4 + ", " + v4 + ", fs" + texture.toString() + " <2d,clamp,linear> \n" +
|
||||
// "mov " + result4 + ", " + result4 + ".zzzz \n";
|
||||
|
||||
var shader:String = "tex " + result4 + ", " + v4 + ", fs" + texture.toString() + " <2d,clamp,linear> \n" +
|
||||
// var shader:String = "tex " + result4 + ", " + v4 + ", fs" + texture.toString() + " <2d,clamp,nearest> \n" +
|
||||
"add " + result4 + ".z, " + result4 + ".z, fc" + const2.toString() + ".x \n" + // Смещение
|
||||
"sub " + result4 + ".z, " + result4 + ".z, " + v4 + ".z \n" +
|
||||
"mul " + result4 + ".z, " + result4 + ".z, fc" + const2.toString() + ".y \n" +
|
||||
"sat " + result4 + ".z, " + result4 + ".z \n" +
|
||||
"mov " + result4 + ", " + result4 + ".zzzz \n";
|
||||
return shader;
|
||||
}
|
||||
|
||||
alternativa3d function attenuateProgramSetup(view:View, obj:Object3D, const4x4:uint, texture:uint, constF2:uint):void {
|
||||
if (forceDontRenderToTexture) {
|
||||
view.setProgramConstants("FRAGMENT", constF2, 1, options);
|
||||
}
|
||||
var lightMatrix:Matrix3D = obj.cameraMatrix.clone();
|
||||
lightMatrix.append(this.lightMatrix);
|
||||
view.setTexture(texture, shadowMap);
|
||||
view.setProgramConstantsMatrixTransposed("VERTEX", const4x4, lightMatrix);
|
||||
view.setProgramConstants("FRAGMENT", constF2, 1, options);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
package alternativa.engine3d.lights {
|
||||
|
||||
import __AS3__.vec.Vector;
|
||||
|
||||
import alternativa.engine3d.alternativa3d;
|
||||
import alternativa.engine3d.core.Camera3D;
|
||||
import alternativa.engine3d.core.Object3D;
|
||||
import alternativa.engine3d.core.View;
|
||||
import alternativa.engine3d.materials.TextureMaterial;
|
||||
|
||||
import flash.display.IndexBuffer3D;
|
||||
import flash.display.Texture3D;
|
||||
import flash.geom.Matrix3D;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.geom.Vector3D;
|
||||
|
||||
use namespace alternativa3d;
|
||||
public class DirectionalLight extends Object3D {
|
||||
|
||||
public var debugMaterial:TextureMaterial;
|
||||
|
||||
public var forceDontRenderToTexture:Boolean = false;
|
||||
|
||||
public var options:Vector.<Number> = Vector.<Number>([0.007, 10000, 1.0, 0]); // Смещение, множитель
|
||||
|
||||
// Матрица перевода в источник света
|
||||
alternativa3d var lightMatrix:Matrix3D = new Matrix3D();
|
||||
alternativa3d var uvMatrix:Matrix3D = new Matrix3D();
|
||||
|
||||
private var near:Number;
|
||||
private var far:Number;
|
||||
|
||||
private var _width:uint;
|
||||
private var _height:uint;
|
||||
|
||||
alternativa3d var numSplits:uint;
|
||||
alternativa3d var currentSplitNear:Number;
|
||||
alternativa3d var currentSplitFar:Number;
|
||||
|
||||
private var shadowMap:Texture3D;
|
||||
|
||||
public function DirectionalLight(width:uint, height:uint, near:Number, far:Number, numSplits:uint = 4) {
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this.near = near;
|
||||
this.far = far;
|
||||
this.numSplits = numSplits;
|
||||
}
|
||||
|
||||
alternativa3d function update(camera:Camera3D, view:View, splitIndex:int):void {
|
||||
if (forceDontRenderToTexture) {
|
||||
return;
|
||||
}
|
||||
shadowMap = view.createTexture(_width, _height, "BGRA", true);
|
||||
if (debugMaterial != null && splitIndex == 0) {
|
||||
debugMaterial.texture3d = shadowMap;
|
||||
}
|
||||
|
||||
// Расчёт матрицы перевода из глобального пространства в камеру
|
||||
composeMatrix();
|
||||
var root:Object3D = this;
|
||||
while (root._parent != null) {
|
||||
root = root._parent;
|
||||
root.composeMatrix();
|
||||
cameraMatrix.append(root.cameraMatrix);
|
||||
}
|
||||
cameraMatrix.invert();
|
||||
|
||||
view.setRenderToTexture(shadowMap, true);
|
||||
view.clear(1, 1, 1, 1, 1);
|
||||
|
||||
var cameraWCoeff:Number = camera.view._width/2/camera.focalLength;
|
||||
var cameraHCoeff:Number = camera.view._height/2/camera.focalLength;
|
||||
|
||||
var points:Vector.<Vector3D> = new Vector.<Vector3D>();
|
||||
points[0] = new Vector3D(-cameraWCoeff, -cameraHCoeff, 0);
|
||||
points[1] = new Vector3D(cameraWCoeff, -cameraHCoeff, 0);
|
||||
points[2] = new Vector3D(cameraWCoeff, cameraHCoeff, 0);
|
||||
points[3] = new Vector3D(-cameraWCoeff, cameraHCoeff, 0);
|
||||
var p:Vector3D;
|
||||
var transformed:Vector3D = new Vector3D();
|
||||
|
||||
var currentNear:Number = (camera.nearClipping < near) ? near : camera.nearClipping;
|
||||
var currentFar:Number = (camera.farClipping < far) ? camera.farClipping : far;
|
||||
var scissor:Rectangle = new Rectangle();
|
||||
|
||||
var minLightX:Number = Number.MAX_VALUE, minLightY:Number = Number.MAX_VALUE, minLightZ:Number = Number.MAX_VALUE;
|
||||
var maxLightX:Number = -Number.MAX_VALUE, maxLightY:Number = -Number.MAX_VALUE, maxLightZ:Number = -Number.MAX_VALUE;
|
||||
|
||||
const lambda:Number = 1;
|
||||
var splitNear:Number = lambda*currentNear*Math.pow(currentFar/currentNear, splitIndex/numSplits) + (1 - lambda)*((currentNear + splitIndex/numSplits)*(currentFar - currentNear));
|
||||
var splitFar:Number = lambda*currentNear*Math.pow(currentFar/currentNear, (splitIndex + 1)/numSplits) + (1 - lambda)*((currentNear + (splitIndex + 1)/numSplits)*(currentFar - currentNear));
|
||||
|
||||
currentSplitNear = splitNear;
|
||||
currentSplitFar = splitFar;
|
||||
|
||||
projectionMatrix.identity();
|
||||
projectionMatrix.append(camera.globalMatrix);
|
||||
projectionMatrix.append(cameraMatrix);
|
||||
// Считаем баунд куска в источнике света
|
||||
for (var j:int = 0; j < 8; j++) {
|
||||
if (j < 4) {
|
||||
p = points[j];
|
||||
transformed.x = p.x * splitNear;
|
||||
transformed.y = p.y * splitNear;
|
||||
transformed.z = splitNear;
|
||||
} else {
|
||||
p = points[j - 4];
|
||||
transformed.x = p.x * splitFar;
|
||||
transformed.y = p.y * splitFar;
|
||||
transformed.z = splitFar;
|
||||
}
|
||||
p = projectionMatrix.transformVector(transformed);
|
||||
if (p.x < minLightX) {
|
||||
minLightX = p.x;
|
||||
} else if (p.x > maxLightX) {
|
||||
maxLightX = p.x;
|
||||
}
|
||||
if (p.y < minLightY) {
|
||||
minLightY = p.y;
|
||||
} else if (p.y > maxLightY) {
|
||||
maxLightY = p.y;
|
||||
}
|
||||
if (p.z < minLightZ) {
|
||||
minLightZ = p.z;
|
||||
} else if (p.z > maxLightZ) {
|
||||
maxLightZ = p.z;
|
||||
}
|
||||
}
|
||||
minLightZ = 0;
|
||||
// trace("[Light bounds]", minLightX, maxLightX, minLightY, maxLightY, minLightZ, maxLightZ);
|
||||
|
||||
var pixelW:Number = 1/_width;
|
||||
|
||||
// Считаем матрицу проецирования
|
||||
var rawData:Vector.<Number> = new Vector.<Number>(16);
|
||||
// cameraMatrixData
|
||||
// rawData[0] = 2/(maxLightX - minLightX)/numSplits;
|
||||
rawData[0] = 2/(maxLightX - minLightX);
|
||||
rawData[5] = 2/(maxLightY - minLightY);
|
||||
rawData[10]= 1/(maxLightZ - minLightZ);
|
||||
// rawData[12] = (-0.5 * (maxLightX + minLightX) * rawData[0]) + 2*i/numSplits - 1/numSplits;
|
||||
rawData[12] = (-0.5 * (maxLightX + minLightX) * rawData[0]);
|
||||
rawData[13] = (-0.5 * (maxLightY + minLightY) * rawData[5]);
|
||||
rawData[14]= -minLightZ/(maxLightZ - minLightZ);
|
||||
rawData[15]= 1;
|
||||
projectionMatrix.rawData = rawData;
|
||||
|
||||
rawData[0] = 1/((maxLightX - minLightX));
|
||||
rawData[5] = -1/((maxLightY - minLightY));
|
||||
// rawData[12] = 0.5 - (0.5 * (maxLightX + minLightX) * rawData[0]) + i/numSplits - 0.5/numSplits;
|
||||
rawData[12] = 0.5 - (0.5 * (maxLightX + minLightX) * rawData[0]);
|
||||
rawData[13] = 0.5 - (0.5 * (maxLightY + minLightY) * rawData[5]);
|
||||
uvMatrix = new Matrix3D(rawData);
|
||||
|
||||
lightMatrix.identity();
|
||||
lightMatrix.append(camera.globalMatrix);
|
||||
lightMatrix.append(cameraMatrix);
|
||||
lightMatrix.append(uvMatrix);
|
||||
|
||||
// scissor.x = i * _width/numSplits;
|
||||
// scissor.width = _width/numSplits;
|
||||
// scissor.height = _height;
|
||||
// view.setScissor(scissor);
|
||||
if (root != this && root.visible && !root.isTransparent) {
|
||||
root.composeMatrix();
|
||||
root.cameraMatrix.append(cameraMatrix);
|
||||
root.drawInShadowMap(camera, this);
|
||||
}
|
||||
// splitNear = splitFar;
|
||||
view.flush();
|
||||
view.setRenderToBackbuffer();
|
||||
// view.setScissor(null);
|
||||
}
|
||||
|
||||
alternativa3d function attenuateVertexShader(v4:String, const4x4:uint):String {
|
||||
if (forceDontRenderToTexture) {
|
||||
return "";
|
||||
}
|
||||
var shader:String = "dp4 " + v4 + ".x, va0, vc" + const4x4+ " \n" +
|
||||
"dp4 " + v4 + ".y, va0, vc" + (const4x4 + 1) + " \n" +
|
||||
"dp4 " + v4 + ".z, va0, vc" + (const4x4 + 2) + " \n" +
|
||||
"dp4 " + v4 + ".w, va0, vc" + (const4x4 + 3) + " \n";
|
||||
return shader;
|
||||
}
|
||||
|
||||
alternativa3d function attenuateFragmentShader(result4:String, v4:String, texture:uint, const2:uint):String {
|
||||
if (forceDontRenderToTexture) {
|
||||
return "mov " + result4 + ", fc" + const2 + ".zzzz \n";
|
||||
}
|
||||
// Отображение шедоу мапы
|
||||
// var shader:String = "tex " + result4 + ", " + v4 + ", fs" + texture.toString() + " <2d,clamp,linear> \n" +
|
||||
// "mov " + result4 + ", " + result4 + ".zzzz \n";
|
||||
|
||||
var shader:String = "tex " + result4 + ", " + v4 + ", fs" + texture.toString() + " <2d,clamp,linear> \n" +
|
||||
// var shader:String = "tex " + result4 + ", " + v4 + ", fs" + texture.toString() + " <2d,clamp,nearest> \n" +
|
||||
"add " + result4 + ".z, " + result4 + ".z, fc" + const2.toString() + ".x \n" + // Смещение
|
||||
"sub " + result4 + ".z, " + result4 + ".z, " + v4 + ".z \n" +
|
||||
"mul " + result4 + ".z, " + result4 + ".z, fc" + const2.toString() + ".y \n" +
|
||||
"sat " + result4 + ".z, " + result4 + ".z \n" +
|
||||
"mov " + result4 + ", " + result4 + ".zzzz \n";
|
||||
return shader;
|
||||
}
|
||||
|
||||
alternativa3d function attenuateProgramSetup(view:View, obj:Object3D, const4x4:uint, texture:uint, constF2:uint):void {
|
||||
if (forceDontRenderToTexture) {
|
||||
view.setProgramConstants("FRAGMENT", constF2, 1, options);
|
||||
}
|
||||
var lightMatrix:Matrix3D = obj.cameraMatrix.clone();
|
||||
lightMatrix.append(this.lightMatrix);
|
||||
view.setTexture(texture, shadowMap);
|
||||
view.setProgramConstantsMatrixTransposed("VERTEX", const4x4, lightMatrix);
|
||||
view.setProgramConstants("FRAGMENT", constF2, 1, options);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 107
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/loaders
|
||||
END
|
||||
MaterialLoader.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 125
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/loaders/MaterialLoader.as
|
||||
END
|
||||
Parser3DS.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 120
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/loaders/Parser3DS.as
|
||||
END
|
||||
ParserCollada.as
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 124
|
||||
/!svn/ver/40841/platform/clients/fp11/libraries/Alternativa3D/tags/8.0.0.0/src/alternativa/engine3d/loaders/ParserCollada.as
|
||||
END
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user