more versions added

This commit is contained in:
Tubix
2024-10-05 12:11:16 +01:00
parent 413f563f33
commit c32c7e8c34
7661 changed files with 1343635 additions and 0 deletions

BIN
Alternativa3D8/.DS_Store vendored Normal file

Binary file not shown.

BIN
Alternativa3D8/8.0.0.0/.DS_Store vendored Normal file

Binary file not shown.

View 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>

View 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>

View 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>

View 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

View 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

View File

@@ -0,0 +1 @@
8

View File

@@ -0,0 +1,3 @@
#Wed Jul 07 06:01:58 YEKST 2010
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@@ -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

Binary file not shown.

View 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

View 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

View File

@@ -0,0 +1 @@
8

View 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>

View 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>

View 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>

View 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>

View 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

View 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

View File

@@ -0,0 +1 @@
8

View File

@@ -0,0 +1 @@

View 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

Binary file not shown.

View 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

View 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

View File

@@ -0,0 +1 @@
8

View 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

View 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

View File

@@ -0,0 +1 @@
8

View File

@@ -0,0 +1,14 @@
package alternativa {
/**
* Класс содержит информацию о версии библиотеки.
* Также используется для интеграции библиотеки в среду разработки Adobe Flash.
*/
public class Alternativa3D {
/**
* Версия библиотеки в формате: поколение.feature-версия.fix-версия
*/
public static const version:String = "8.0.0";
}
}

View File

@@ -0,0 +1,14 @@
package alternativa {
/**
* Класс содержит информацию о версии библиотеки.
* Также используется для интеграции библиотеки в среду разработки Adobe Flash.
*/
public class Alternativa3D {
/**
* Версия библиотеки в формате: поколение.feature-версия.fix-версия
*/
public static const version:String = "8.0.0";
}
}

View File

@@ -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

View 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

View File

@@ -0,0 +1 @@
8

View File

@@ -0,0 +1,3 @@
package alternativa.engine3d {
public namespace alternativa3d = "http://alternativaplatform.com/en/alternativa3d";
}

View File

@@ -0,0 +1,3 @@
package alternativa.engine3d {
public namespace alternativa3d = "http://alternativaplatform.com/en/alternativa3d";
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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];
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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];
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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];
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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];
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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 + "]]";
}
}
}

View File

@@ -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 + "]";
}
}
}

View File

@@ -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 + "]";
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 + "]]";
}
}
}

View File

@@ -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 + "]";
}
}
}

View File

@@ -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 + "]";
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
8

View 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";
}
}
}

View 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;
}
}
}

View 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;
}
}*/
}
}

View File

@@ -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;
}
}
}
}
}
}

View File

@@ -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;
}
}

View 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;
}
}
}

View 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;
}
}
}
}

View File

@@ -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();
}
}
}
}

View 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";
}
}
}

View 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;
}
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}*/
}
}

View File

@@ -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;
}
}
}
}
}
}

View File

@@ -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;
}
}

View 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;
}
}
}

View 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;
}
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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