rindy пре 7 година
комит
2d1536269c
100 измењених фајлова са 1385992 додато и 0 уклоњено
  1. 21 0
      .gitignore
  2. 10 0
      .jsbeautifyrc
  3. 30 0
      index.html
  4. 5980 0
      package-lock.json
  5. 26 0
      package.json
  6. 11 0
      src/Base/ComponentBase.ts
  7. 26 0
      src/Base/SystemBase.ts
  8. 126 0
      src/Components/ModelComponent.ts
  9. 61 0
      src/Components/ParticleComponent.ts
  10. 102 0
      src/Components/TitleComponent.ts
  11. 39 0
      src/Context.ts
  12. 175 0
      src/Models/Models/Information.ts
  13. 91 0
      src/Models/Models/index.ts
  14. 59 0
      src/Models/Pivots/index.ts
  15. 167 0
      src/Models/Scenes/index.ts
  16. 55 0
      src/Models/Submodels/AISLE_INSIDE.ts
  17. 49 0
      src/Models/Submodels/END.ts
  18. 34 0
      src/Models/Submodels/HUILING_INSIDE.ts
  19. 54 0
      src/Models/Submodels/INTRO.ts
  20. 54 0
      src/Models/Submodels/LIUBEI_INSIDE.ts
  21. 116 0
      src/Models/Submodels/PATH_AISLE_TO_LIUBEI.ts
  22. 112 0
      src/Models/Submodels/PATH_HUILING_TO_END.ts
  23. 136 0
      src/Models/Submodels/PATH_INTRO_TO_TANGBEI.ts
  24. 140 0
      src/Models/Submodels/PATH_LIUBEI_TO_ZHUGELIANG.ts
  25. 112 0
      src/Models/Submodels/PATH_TANGBEI_TO_AISLE.ts
  26. 34 0
      src/Models/Submodels/PATH_ZHUGELIANG_TO_HUILING.ts
  27. 55 0
      src/Models/Submodels/TANGBEI.ts
  28. 94 0
      src/Models/Submodels/ZHUGELIANG_INSIDE.ts
  29. 9 0
      src/Models/index.ts
  30. 1 0
      src/Resources/Particles.ts
  31. 290 0
      src/Shaders/index.ts
  32. 13 0
      src/System/DataSystem.ts
  33. 51 0
      src/System/InputSystem.ts
  34. 148 0
      src/System/ResourceSystem.ts
  35. 89 0
      src/System/ScenesSystem.ts
  36. 7 0
      src/Utils/UUID.ts
  37. 1 0
      src/global.d.ts
  38. 39 0
      src/index.ts
  39. 17 0
      static/libs/TweenMax.min.js
  40. 11 0
      static/libs/css/animate.css
  41. 4 0
      static/libs/jquery.min.js
  42. 282 0
      static/libs/threejs/DragControls.js
  43. 793 0
      static/libs/threejs/OBJLoader.js
  44. 1039 0
      static/libs/threejs/OrbitControls.js
  45. 259 0
      static/libs/threejs/ctm/CTMLoader.js
  46. 19 0
      static/libs/threejs/ctm/CTMWorker.js
  47. 658 0
      static/libs/threejs/ctm/ctm.js
  48. 517 0
      static/libs/threejs/ctm/lzma.js
  49. 1 0
      static/libs/threejs/dat.gui.css
  50. 13 0
      static/libs/threejs/dat.gui.min.js
  51. 521 0
      static/libs/threejs/draco/DRACOLoader.js
  52. 32 0
      static/libs/threejs/draco/draco_decoder.js
  53. BIN
      static/libs/threejs/draco/draco_decoder.wasm
  54. 5 0
      static/libs/threejs/stats.min.js
  55. 47349 0
      static/libs/threejs/three.js
  56. 949 0
      static/libs/threejs/three.min.js
  57. 46939 0
      static/libs/threejs/three.module.js
  58. BIN
      static/models/KongMingDian - 副本.jpg
  59. BIN
      static/models/KongMingDian.jpg
  60. 517895 0
      static/models/KongMingDian.obj
  61. BIN
      static/models/KongMingDian_2048.jpg
  62. BIN
      static/models/KongMingDian_512.jpg
  63. BIN
      static/models/LiuBeiDian - 副本.jpg
  64. BIN
      static/models/LiuBeiDian.jpg
  65. 374989 0
      static/models/LiuBeiDian.obj
  66. BIN
      static/models/LiuBeiDian_2048.jpg
  67. BIN
      static/models/LiuBeiDian_512.jpg
  68. BIN
      static/models/TangBei - 副本.jpg
  69. BIN
      static/models/TangBei.jpg
  70. 123286 0
      static/models/TangBei.obj
  71. BIN
      static/models/TangBei_2048.jpg
  72. BIN
      static/models/TangBei_512.jpg
  73. BIN
      static/models/WenChenLang - 副本.jpg
  74. BIN
      static/models/WenChenLang.jpg
  75. 261775 0
      static/models/WenChenLang.obj
  76. BIN
      static/models/WenChenLang_2048.jpg
  77. BIN
      static/models/WenChenLang_512.jpg
  78. 1 0
      static/points/all2(1)_lod10.json
  79. 1 0
      static/points/all2(2)_lod10.json
  80. 1 0
      static/points/all_lod10.json
  81. 1 0
      static/points/di(1)_lod10.json
  82. 1 0
      static/points/di(2)_lod10.json
  83. 1 0
      static/points/di_lod10.json
  84. 1 0
      static/points/fileNames.txt
  85. 1 0
      static/points/point_0.json
  86. 1 0
      static/points/point_1.json
  87. 1 0
      static/points/point_10.json
  88. 1 0
      static/points/point_100.json
  89. 1 0
      static/points/point_101.json
  90. 1 0
      static/points/point_102.json
  91. 1 0
      static/points/point_103.json
  92. 1 0
      static/points/point_104.json
  93. 1 0
      static/points/point_105.json
  94. 1 0
      static/points/point_106.json
  95. 1 0
      static/points/point_107.json
  96. 1 0
      static/points/point_108.json
  97. 1 0
      static/points/point_109.json
  98. 1 0
      static/points/point_11.json
  99. 1 0
      static/points/point_110.json
  100. 0 0
      static/points/point_111.json

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+.DS_Store
+node_modules
+dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw*

Разлика између датотеке није приказан због своје велике величине
+ 10 - 0
.jsbeautifyrc


Разлика између датотеке није приказан због своје велике величине
+ 30 - 0
index.html


Разлика између датотеке није приказан због своје велике величине
+ 5980 - 0
package-lock.json


+ 26 - 0
package.json

@@ -0,0 +1,26 @@
+{
+  "name": "webgl-components",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "dev": "webpack-dev-server --hot --inline --mode=development",
+    "build": "webpack  --mode=production"
+  },
+  "author": "rindy",
+  "license": "MIT",
+  "dependencies": {
+    "core-js": "^2.6.3"
+  },
+  "devDependencies": {
+    "@types/three": "^0.93.15",
+    "clean-webpack-plugin": "^1.0.1",
+    "copy-webpack-plugin": "^4.6.0",
+    "html-webpack-plugin": "^3.2.0",
+    "ts-loader": "^5.3.3",
+    "typescript": "^3.2.4",
+    "webpack": "^4.29.0",
+    "webpack-cli": "^3.2.1",
+    "webpack-dev-server": "^3.1.14"
+  }
+}

+ 11 - 0
src/Base/ComponentBase.ts

@@ -0,0 +1,11 @@
+import { root, Context } from '../Context'
+import { EventDispatcher } from 'three';
+
+abstract class ComponentBase extends EventDispatcher {
+    /**
+     * 系统管理上下文
+     */
+    root: Context = root;
+}
+
+export default ComponentBase

+ 26 - 0
src/Base/SystemBase.ts

@@ -0,0 +1,26 @@
+import { root, Context } from '../Context'
+import { EventDispatcher } from 'three';
+
+abstract class SystemBase extends EventDispatcher {
+    /**
+     * 系统名称
+     */
+    name: string;
+    /**
+     * 系统管理上下文
+     */
+    root: Context = root;
+    constructor(name: string) {
+        super()
+        this.name = name
+    }
+
+    /**
+     * 空的渲染方法,需要时再子类中实现
+     */
+    update() { 
+        
+    }
+}
+
+export default SystemBase

+ 126 - 0
src/Components/ModelComponent.ts

@@ -0,0 +1,126 @@
+import * as THREE from "three";
+import shaders from '../Shaders/index'
+import ScenesSystem from "../System/ScenesSystem";
+import ComponentBase from "../Base/ComponentBase";
+
+
+export interface IFile {
+    name: string
+    buffer?: ArrayBuffer
+    uv?: ArrayLike<number>
+    normal?: ArrayLike<number>
+    position?: ArrayLike<number>
+}
+
+export interface IModel {
+    name: string
+    transform: {
+        translation: THREE.Vector3
+    }
+}
+
+export class Model extends THREE.Mesh {
+    name: string
+    positionV: THREE.Vector3
+    material: THREE.ShaderMaterial
+    showProgress: number
+    hideProgress: number
+    private fade: number
+    private visibility: boolean
+    private static shaderMaterial = new THREE.ShaderMaterial({
+        uniforms: {
+            opacity: { value: 0.5 },
+            u_alphatest: { value: 1 },
+            map: { value: undefined }
+        },
+        vertexShader: shaders.mesh.vs,
+        fragmentShader: shaders.mesh.fs,
+        transparent: true,
+        side: THREE.DoubleSide
+    })
+    constructor(model: IModel) {
+        super()
+
+        this.name = model.name
+        this.material = Model.shaderMaterial.clone()
+        this.positionV = new THREE.Vector3().copy(model.transform.translation);
+        this.showProgress = 0
+        this.hideProgress = 0
+        this.fade = 1
+        this.visibility = true
+        this.frustumCulled = false
+    }
+
+    // public setVisible( visibility:boolean ) {
+
+    //     this.visibility = visibility;
+    // }
+
+
+    // public update( camera: THREE.Camera ) {
+
+    //     let distance = camera.position.distanceTo( this.positionV );  
+
+    //     this.fade = THREE.Math.clamp( this.fade + (this.visibility ? 0.016 / 2 : -0.016 / 2 ), 0, 1 );
+    //     this.material.uniforms["u_alphatest"].value = this.fade;
+    //     this.visible = (distance < 30 && this.fade != 0);
+    // }
+}
+
+/**
+ * 模型组件
+ */
+export class Component extends ComponentBase {
+    private models: Map<string, Model> = new Map<string, Model>();
+    private static bufferGeometry = new THREE.BufferGeometry()
+    private static texture = new THREE.Texture()
+    get list() {
+        return Array.from(this.models.values())
+    }
+
+    add(model: IModel) {
+        if (!model.name) {
+            throw new Error('title.name is require')
+        }
+        this.models.set(model.name, new Model(model))
+    }
+
+    get(name: string): Model {
+        return this.models.get(name)
+    }
+    setObj(file: IFile) {
+
+        const model = this.get(file.name)
+        const geometry = Component.bufferGeometry.clone()
+
+        geometry.addAttribute('normal', new THREE.BufferAttribute(new Float32Array(file.normal), 3, false))
+        geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(file.position), 3, false))
+        geometry.addAttribute('uv', new THREE.BufferAttribute(new Float32Array(file.uv), 2, false))
+        model.geometry = geometry
+        this.root.get<ScenesSystem>(ScenesSystem.name).scene.add(model)
+    }
+    setTexture(file: IFile) {
+
+        const material = this.get(file.name).material
+        const texture = Component.texture.clone()
+        
+        const blob = new Blob([file.buffer]);
+        const data = URL.createObjectURL(blob)
+        const img = new Image();
+
+        img.src = data;
+        img.onload = () => {
+            texture.image = img
+            texture.format = THREE.RGBFormat;
+            texture.needsUpdate = true;
+            material.uniforms.map.value = texture;
+            material.needsUpdate = true
+        }
+    }
+}
+
+/**
+ * 模型组件实例
+ */
+export const ModelComponent = new Component()
+

+ 61 - 0
src/Components/ParticleComponent.ts

@@ -0,0 +1,61 @@
+import ComponentBase from '../Base/ComponentBase'
+import ScenesSystem from '../System/ScenesSystem'
+import * as THREE from "three";
+import shaders from '../Shaders/index'
+
+
+export interface IData {
+    positions: ArrayBuffer
+    ranking: ArrayBuffer
+}
+
+/**
+ * 粒子组件
+ */
+export class Component extends ComponentBase {
+    private material: THREE.ShaderMaterial
+    private static group: THREE.Group
+    constructor() {
+        super()
+        this.material = new THREE.ShaderMaterial({
+            uniforms: {
+                _Time: { value: 0 },
+                _Progress: { value: 1 },
+                meshShowProgress: { value: 1 },
+                WIND_AMP: { value: 50 }
+            },
+            vertexShader: shaders.pointClound.vs,
+            fragmentShader: shaders.pointClound.fs,
+        })
+    }
+    add(data: IData) {
+
+        if(!Component.group){
+            Component.group = new THREE.Group()
+            this.root.get<ScenesSystem>("ScenesSystem").scene.add(Component.group)
+        }
+
+        const geometry = new THREE.BufferGeometry();
+        geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(data.positions), 3));
+        geometry.addAttribute('aRanking', new THREE.BufferAttribute(new Float32Array(data.ranking), 1));
+
+        Component.group.add(new THREE.Points(geometry, this.material))
+    }
+    update() {
+        this.material.uniforms._Time.value += 0.003;
+    }
+
+    setProgress(value: number) {
+        this.material.uniforms._Progress.value = value;
+    }
+
+    fade(value: number) {
+        this.material.uniforms.meshShowProgress.value = value;
+    }
+}
+
+/**
+ * 粒子组件实例
+ */
+export const ParticleComponent = new Component()
+

+ 102 - 0
src/Components/TitleComponent.ts

@@ -0,0 +1,102 @@
+import * as THREE from "three";
+import shaders from '../Shaders/index'
+
+export interface IFile {
+    type: string
+    name: string
+    format: string
+    buffer: ArrayBuffer
+}
+
+export interface ITitle {
+    name: string,
+    position: THREE.Vector3
+    showProgress: number
+    hideProgress: number
+}
+
+export class Title {
+    name: string
+    position: THREE.Vector3
+    showProgress: number
+    hideProgress: number
+    material:THREE.ShaderMaterial
+
+    constructor(title: ITitle) {
+        this.name = title.name
+        this.position = new THREE.Vector3().copy(title.position)
+        this.showProgress = title.showProgress
+        this.hideProgress = title.hideProgress
+        this.material = new THREE.ShaderMaterial({
+            uniforms: {
+				_Aspect: { value: window.innerWidth / window.innerHeight },
+				_TitleAspect: { value: 0.5 },
+				_TitleScale: { value: 0.5 },
+				_Center: { },
+				_Texture: {  },
+				_Mask: {  },		
+				_Fade: { value: 0.5},
+				_FrameCounter: { value: 0 },
+            },
+            premultipliedAlpha : true,
+            transparent: true,
+			vertexShader: shaders.title.vs,
+            fragmentShader: shaders.title.fs,
+        });
+    }
+
+    animate( progress ) {
+        const i = progress > this.showProgress && progress < this.hideProgress;
+        this.material.uniforms["_FrameCounter"].value += i ? 0.5 : 0;
+        this.material.uniforms["_FrameCounter"].value > 148 && (this.material.uniforms["_FrameCounter"].value = 0);
+	}
+}
+
+/**
+ * 模型标题组件
+ */
+export class Component {
+    private titles: Map<string, Title> = new Map<string, Title>();
+    get list() {
+        return Array.from(this.titles.values())
+    }
+
+    add(title: ITitle) {
+        if (!title.name) {
+            throw new Error('title.name is require')
+        }
+        this.titles.set(title.name, new Title(title))
+    }
+
+    get(name: string): Title {
+        return this.titles.get(name)
+    }
+    
+    setTexture(file: IFile) {
+        const material = this.get(file.name).material
+        const texture = new THREE.Texture()
+
+        const blob = new Blob([file.buffer]);
+        const data = URL.createObjectURL(blob)
+        const img = new Image();
+
+        img.src = data;
+        img.onload = ()=>{
+            document.body.appendChild(img)
+            texture.image = img
+            texture.format = THREE.RGBAFormat;
+            texture.needsUpdate = true;
+            if(file.type == 'image'){
+                material.uniforms["_Texture"].value = img;
+            }else{
+                material.uniforms["_Mask"].value = img;
+            }
+        }
+    }
+}
+
+/**
+ * 模型标题组件实例
+ */
+export const TitleComponent = new Component()
+

+ 39 - 0
src/Context.ts

@@ -0,0 +1,39 @@
+import SystemBase from './Base/SystemBase'
+
+/**
+ * 系统管理类
+ */
+class Context {
+    /**
+     * 字典集合
+     */
+    private readonly systems: Map<string, any> = new Map<string, any>();
+    /**
+     * 缓存集合
+     */
+    readonly list: Array<SystemBase> = new Array<SystemBase>();
+
+    get<T>(name: string): T {
+        return this.systems.get(name);
+    }
+
+    add(system: SystemBase) {
+        if (this.systems.has(system.name)) {
+            return
+        }
+
+        this.systems.set(system.name, system)
+        this.list.push(system);
+        return this;
+    }
+    remove(name: string) {
+        this.systems.delete(name)
+        const index = this.list.findIndex(c => c.name == name);
+        if (index !== -1) {
+            this.list.splice(index, index)
+        }
+    }
+}
+
+export { Context };
+export const root = new Context()

+ 175 - 0
src/Models/Models/Information.ts

@@ -0,0 +1,175 @@
+let spaces = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
+let smodel = 'static/4DModel/Model.html'
+
+/**
+ * 唐碑
+ */
+export const TangBei = {
+    title: '唐碑',
+    description: '走进大门,重重殿宇庄严肃穆,浓荫丛中伫立着六通石碑,<br>在东侧碑廊内,唐代《蜀汉丞相诸葛武候祠堂碑》,由唐<br>朝著名宰相裴度所撰,著名书法家柳公权之兄柳公绰所书,<br>蜀中名匠鲁建所刻,后人盛赞“武侯之功德、裴度之文章、<br>柳公绰之书法”,故被称为"三绝碑"。',
+    hotspots: [{
+        type: 'image',
+        title: '唐碑“三绝碑”',
+        audio: 'audio/hots/TangBei.wav',
+        resource: [{
+            src: 'pictures/tb/1.png',
+            title: '唐碑“三绝碑”',
+            description: [
+                spaces + '唐“三绝碑”,原名《蜀丞相诸葛武候祠堂碑》。碑身通高3.67m,碑文分序和铭两部分,正书共22行,每行约',
+                '50字。碑文称赞诸葛亮有“事君之节、开国之才、立身之道、治人之术”四大政治功德,并以前代名相姜尚、管仲、',
+                '萧何、张良等人相喻,盛赞诸葛亮的文韬武略。',
+                spaces + '由唐朝著名宰相裴度所撰,著名书法家柳公权之兄柳公绰所书。后人盛赞“武侯之功德,裴度之文章、柳公绰',
+                '之书法”,故又称此碑为"三绝碑"。'
+            ].join('<br>')
+        }, {
+            src: smodel + '?m=tangbei',
+            type: 'model',
+            title: '指尖文物',
+            description: [
+                spaces + '现实参观中,普通观众无法全方位看到文物,只能通过导游或者语音解说,无法真正感触文物。通过三维技',
+                '术,获得文物更多的表面形貌信息,可达到微米级,广泛应用于文物防伪、鉴定、保存和展示。',
+                spaces + '当智能技术遇到历史知识,当互动体验碰撞古老文化,厚重的文物开始焕发着年轻的光彩。现在,只需动动',
+                '手指点击鼠标,即可720度浏览文物。以数字化的方式去表现和承载文物本体,为参观者创造一个不受时空约束',
+                '的虚拟文物展。'
+            ].join('<br>')
+        }]
+    }]
+}
+
+/**
+ * 文臣廊
+ */
+export const WenChengLang = {
+    map: 'mini-map/wcl.png',
+    title: '文臣廊',
+    description: '蜀国的重要人物都有塑像。其中,刘备、诸葛亮、关羽和张飞,<br>都有专殿,其余的重要文官与武将,则分别塑在文武廊。东边<br>是文臣廊,西边是武将廊。左右两廊各有文臣武将14位,合计<br>共28位。',
+    hotspots: [{
+        type: 'image',
+        title: '文臣廊',
+        resource: [{
+            src: 'pictures/wcl/1.png',
+            title: '文臣廊',
+            description: [
+                spaces + '文臣武将廊前后与二门、刘备殿相接,使刘备殿前的建筑构成一个完整的四合院。塑像均为清代泥塑,其人物',
+                '形象基本上是由文学作品中或戏剧舞台上的形象而来,服装也基本上是明清时期的戏服。每一尊塑像前都刻有一通',
+                '小碑,介绍身后人物的生平事迹。',
+                spaces + '文臣廊位于刘备殿前东面的廊庑中,共14尊塑像,主要塑制蜀汉一朝的文官,有庞统、简雍、吕凯、傅肜、费',
+                '祎、董和、邓芝、陈震、蒋琬、董允、秦宓、杨洪、马良、程畿。'
+            ].join('<br>')
+        }]
+    }]
+}
+
+/**
+ * 刘备殿
+ */
+export const LiuBeiDian = {
+    map: 'mini-map/lbd.png',
+    title: '汉昭烈庙',
+    description: '汉昭烈帝是刘备的谥号。由于刘备是蜀汉的开国皇帝,建立了<br>蜀汉政权,弘毅宽厚,知人待士,百折不挠,终成帝业,因此<br>用“昭”字赞扬他的品德。同时歌颂他对汉朝的忠诚,生前以汉<br>室宗亲自称,并以恢复汉室为己任,“有功安民”、“秉德遵业”,<br>所以用“烈”字赞扬他一生的功绩。',
+    audio: '',
+    hotspots: [{
+        type: 'image',
+        position: { x: 0, y: 0 },
+        title: '刘备像',
+        audio: 'audio/hots/HanZhaoLieMiao_LiuBeiXiang.wav',
+        resource: [{
+            src: 'pictures/lbd/2.png',
+            title: '刘备像',
+            description: [
+                spaces + '刘备塑像位于汉昭烈庙殿正中,像高3米,全身贴金,冠冕九旈,双手执圭。塑像塑于康熙十一年(公元1672',
+                '年),距今已有300多年,塑像从容大度,很有福相,与史书记载刘备的耳大臂长、身材高大相符。',
+                spaces + '刘备,字玄德,涿县人,乃西汉中山靖王刘胜之后。一生历经黄巾之乱、讨伐董卓、群雄割据、赤壁大战等汉',
+                '末历史阶段,转战南北37年,不避艰险终于公元221年,开创蜀汉王朝,称帝登基。'
+            ].join('<br>')
+        }, {
+            src: smodel + '?m=liubei',
+            type: 'model',
+            title: '指尖文物',
+            description: [
+                spaces + '现实参观中,普通观众无法全方位看到文物,只能通过导游或者语音解说,无法真正感触文物。通过三维技',
+                '术,获得文物更多的表面形貌信息,可达到微米级,广泛应用于文物防伪、鉴定、保存和展示。',
+                spaces + '当智能技术遇到历史知识,当互动体验碰撞古老文化,厚重的文物开始焕发着年轻的光彩。现在,只需动动',
+                '手指点击鼠标,即可720度浏览文物。以数字化的方式去表现和承载文物本体,为参观者创造一个不受时空约束',
+                '的虚拟文物展。'
+            ].join('<br>')
+        }]
+    }]
+}
+
+/**
+ * 诸葛亮殿
+ */
+export const KongMingDian = {
+    map: 'mini-map/zgld.png',
+    title: '武侯祠',
+    description: '经刘备殿,拾阶而下,就是武侯祠。为什么要低数个台阶呢?<br>这是当时封建社会君尊臣卑等级观念的体现。过厅正中门楣悬<br>挂“武侯祠”横匾,武侯祠是纪念三国时蜀汉丞相武乡侯诸葛亮<br>的祠堂,诸葛亮生前封“武乡侯”,死后谥号“忠武”,故纪念他<br>的祠堂称作“武侯祠”。',
+    audio: '',
+    hotspots: [{
+        type: 'image',
+        position: { x: 0, y: 0 },
+        title: '“名垂宇宙”匾额',
+        audio: 'audio/hots/WuHouCi_MingChuiYuZhou.wav',
+        resource: [{
+            src: 'pictures/lbd/3.png',
+            title: '“名垂宇宙”匾额',
+            description: [
+                spaces + '“名垂宇宙”四字横匾,出自杜甫《咏怀古迹五首》之五:“诸葛大名垂宇宙,宗臣遗像肃清高。”由清康熙十',
+                '七皇子爱新觉罗·允礼题写。意在赞扬诸葛亮一生丰功伟绩,千古流传,世人皆知。'
+            ].join('<br>')
+        }]
+    },
+    {
+        type: 'image',
+        position: { x: 0, y: 0 },
+        title: '攻心联',
+        audio: 'audio/hots/WuHouCi_GongXinLian.wav',
+        resource: [{
+            src: 'pictures/lbd/4.png',
+            title: '攻心联',
+            description: [
+                spaces + '“能攻心则反侧自消,从古知兵非好战;不审势即宽严皆误,后来治蜀要深思。”的联文,为清人赵藩撰书,',
+                '是颇负盛名的一幅对联。',
+                spaces + '上联说,诸葛亮在打仗中能用“攻心”战术,南征时对孟获七擒七纵,使其心悦诚服,以此称赞诸葛亮是真正',
+                '懂得用兵打仗,而不是好战的军事家。下联称颂诸葛亮能审时度势,制定出宽严得宜的政治法度,收到良好效果,',
+                '提醒后人在治蜀、治国时借鉴前人的经验教训,要特别注意“攻心”和“审势”。'
+            ].join('<br>')
+        }]
+    },
+    {
+        type: 'image',
+        title: '诸葛亮像',
+        position: { x: 0, y: 0 },
+        audio: 'audio/hots/WuHouCi_ZhuGeLiangXiang.wav',
+        resource: [{
+            src: 'pictures/zgld/1.jpg',
+            title: '诸葛亮像',
+            description: [
+                spaces + '诸葛亮(181年-234年),字孔明,号卧龙,徐州琅琊阳都(今山东临沂市沂南县)人 ,三国时期蜀国丞相。',
+                spaces + '诸葛亮塑像神态从容,头戴纶巾,手执羽扇,神情超凡脱俗,高2米余。一代贤相风范展露无余。蜀汉章武元年(221年),刘备在成都建立',
+                '蜀汉政权,诸葛亮被任命为丞相,主持朝政。蜀汉后主刘禅继位,诸葛亮被封为武乡侯,领益州牧。勤勉谨慎,大小政事必亲自处理,赏罚严明,',
+                '终因积劳成疾,于蜀汉建兴十二年(234年)病逝于五丈原(今陕西宝鸡岐山境内),享年54岁。刘禅追封其为忠武侯,后世常以武侯尊称诸葛亮。'
+            ].join('<br>')
+        },
+        {
+            src: smodel + '?m=kongming',
+            type: 'model',
+            title: '指尖文物',
+            description: [
+                spaces + '现实参观中,普通观众无法全方位看到文物,只能通过导游或者语音解说,无法真正感触文物。通过三维技',
+                '术,获得文物更多的表面形貌信息,可达到微米级,广泛应用于文物防伪、鉴定、保存和展示。',
+                spaces + '当智能技术遇到历史知识,当互动体验碰撞古老文化,厚重的文物开始焕发着年轻的光彩。现在,只需动动',
+                '手指点击鼠标,即可720度浏览文物。以数字化的方式去表现和承载文物本体,为参观者创造一个不受时空约束',
+                '的虚拟文物展。'
+            ].join('<br>')
+        }]
+    }]
+}
+
+/**
+ * 惠陵
+ */
+export const HuiLing = {
+    title: '惠陵',
+    description: '《三国志·先主传》记载:“八月,葬惠陵”。据《谥法》,<br>“爱民好与,曰‘惠’”,故名刘备墓称“惠陵”。而按照汉制,<br>有陵必有庙,所以在同时期,就有了汉昭烈庙诞生。<br>《三国志》记载,陵墓中还合葬有刘备的甘、吴二位夫人。<br>至今保存完好。'
+}

+ 91 - 0
src/Models/Models/index.ts

@@ -0,0 +1,91 @@
+export default [
+    {
+        "name": "TangBei",
+        "transform": {
+            "translation": {
+                "x": 48.773,
+                "y": 2.483,
+                "z": 47.041
+            }
+        },
+        "title": {
+            "position":{
+                "x": 50.813,
+                "y": 4.374,
+                "z": 46.979
+            },
+            "showProgress": 0.5,
+            "hideProgress": 0.9
+        }
+    },
+    {
+        "name": "WenChenLang",
+        "transform": {
+            "translation": {
+                "x": 54.13,
+                "y": 0.68,
+                "z": 13.62
+            }
+        },
+        "title": {
+            "position":{
+                "x": 54.241,
+                "y": 5.055,
+                "z": 25.131
+            },
+            "showProgress": 0.5,
+            "hideProgress": 0.9
+        }
+    },
+    {
+        "name": "LiuBeiDian",
+        "transform": {
+            "translation": {
+                "x": 38.77,
+                "y": 1.26,
+                "z": -5.64
+            }
+        },
+        "title": {
+            "position":{
+                "x": 40.896,
+                "y": 8.539,
+                "z": 9.428
+            },
+            "showProgress": 0.5,
+            "hideProgress": 0.9
+        }
+    },
+    {
+        "name": "KongMingDian",
+        "transform": {
+            "translation": {
+                "x": 37.14,
+                "y": 0.94,
+                "z": -21.75
+            }
+        },
+        "title": {
+            "position":{
+                "x": 40.896,
+                "y": 8.352,
+                "z": -22.627
+            },
+            "showProgress": 0.5,
+            "hideProgress": 0.9
+        }
+    },
+    {
+        "name": "HuiLing",
+        "title": {
+            "position":{
+                "x": -6.765,
+                "y": 5.365,
+                "z": 16.361
+            },
+            "showProgress": 0.5,
+            "hideProgress": 0.9
+        },
+        "hide": true,
+    }
+]

+ 59 - 0
src/Models/Pivots/index.ts

@@ -0,0 +1,59 @@
+export default [
+    {
+        "name": "1",
+        "center": {
+            "x": 38.297,
+            "y": 0,
+            "z": 28.417
+        },
+        "radius": 75
+    }, {
+        "name": "PATH_INTRO_TO_TANGBEI",
+        "center": {
+            "x": 50.695,
+            "y": 1.544,
+            "z": 46.979
+        },
+        "radius": 28
+    }, {
+        "name": "PATH_TANGBEI_TO_AISLE",
+        "center": {
+            "x": 51.642,
+            "y": 2.601,
+            "z": 25.156
+        },
+        "radius": 27.3
+    }, {
+        "name": "PATH_AISLE_TO_LIUBEI",
+        "center": {
+            "x": 40.887,
+            "y": 2.285,
+            "z": 18.251
+        },
+        "radius": 7.5
+    }, {
+        "name": "PATH_LIUBEI_TO_ZHUGELIANG",
+        "center": {
+            "x": 41.021,
+            "y": 2.402,
+            "z": -17.814
+        },
+        "radius": 44
+    }, {
+        "name": "PATH_ZHUGELIANG_TO_HUILING",
+        "center": {
+            "x": -6.739,
+            "y": 2.976,
+            "z": 3.493
+        },
+        "radius": 52.9
+    }, {
+        "name": "PATH_HUILING_TO_END",
+        "center": {
+            "x": 38.29,
+            "y": 0,
+            "z": 28.417
+        },
+        "radius": 75
+    }
+]

+ 167 - 0
src/Models/Scenes/index.ts

@@ -0,0 +1,167 @@
+export default [
+    {	
+        "name":"WenChenLang",
+        "transform" : {
+            "translation": { 
+                "x": 54.13279,
+                "y": 0.688, 
+                "z": 13.62904
+            },
+            "rotation": {
+                "x": -90,
+                "y": 0,
+                "z": 0
+            },
+            "scale": {
+                "x": 0.536,
+                "y": 0.536,
+                "z": 0.536
+            }
+        },
+        // "aabb":{						------World
+        // 	"min": {
+        // 		"x": 44.66787338256836,
+        // 		"y": 0.2514230012893677,
+        // 		"z": 12.171180725097656
+        // 	},
+        // 	"max": {
+        // 		"x": 56.23558807373047,
+        // 		"y": 4.385062217712402,
+        // 		"z": 38.949649810791016
+        // 	},
+        // 	"center": {
+        // 		"x": 50.451730728149414,
+        // 		"y": 2.318242609500885,
+        // 		"z": 25.560415267944336
+        // 	}			
+        // },
+        "aabb":{								
+            "min": {
+                "x": -17.582199096679688,
+                "y": -47.26810073852539,
+                "z": -0.8813999891281128
+            },
+            "max": {
+                "x": 3.99429988861084,
+                "y": 2.6800999641418457,
+                "z": 6.828800201416016
+            },
+            "center": {
+                "x": -6.793949604034424,
+                "y": -22.294000387191772,
+                "z": 2.9737001061439514
+            }			
+        },
+        "begin": 10
+    },
+    {	
+        "name":"LiuBeiDian",
+        "transform" : {
+            "translation": { 
+                "x": 34.671, 
+                "y": 1.283, 
+                "z": 8.816
+            },
+            "rotation": {
+                "x": -90,
+                "y": 90,
+                "z": 0
+            },
+            "scale": {
+                "x": 0.536,
+                "y": 0.536,
+                "z": 0.536
+            }
+        },
+        // "aabb":{			--World
+        // 	"min": {
+        // 		"x": 29.66207504272461,
+        // 		"y": 0.20507800579071045,
+        // 		"z": -0.6785339713096619
+        // 	},
+        // 	"max": {
+        // 		"x": 52.69260787963867,
+        // 		"y": 7.728504180908203,
+        // 		"z": 22.582073211669922
+        // 	},
+        // 	"center": {
+        // 		"x": 41.17734146118164,
+        // 		"y": 3.966791093349457,
+        // 		"z": 10.95176962018013
+        // 	}
+        // },
+        "aabb":{
+            "min": {
+                "x": -26.479000091552734,
+                "y": -34.4452018737793,
+                "z": -1.9549000263214111
+            },
+            "max": {
+                "x": 18.420900344848633,
+                "y": 10.010600090026855,
+                "z": 12.56760025024414
+            },
+            "center": {
+                "x": -4.029049873352051,
+                "y": -12.21730089187622,
+                "z": 5.306350111961365
+            }
+        },
+        "begin": 45
+    },
+    {	
+        "name":"KongMingDian",
+        "transform" : {
+            "translation": { 
+                "x": 37.06914, 
+                "y": 0.91266,
+                "z": -22.09541
+            },
+            "rotation": {
+                "x": -90,
+                "y": 180,
+                "z": 0
+            },
+            "scale": {
+                "x": 0.51503,
+                "y": 0.51503,
+                "z": 0.51503
+            }
+        },
+        // "aabb":{
+        // 	"min": {
+        // 		"x": 32.05473709106445,
+        // 		"y": 0.31529200077056885,
+        // 		"z": -28.37198257446289
+        // 	},
+        // 	"max": {
+        // 		"x": 49.984928131103516,
+        // 		"y": 8.299442291259766,
+        // 		"z": -13.952247619628906
+        // 	},
+        // 	"center": {
+        // 		"x": 41.019832611083984,
+        // 		"y": 4.307367146015167,
+        // 		"z": -21.1621150970459
+        // 	}
+        // },
+        "aabb":{
+            "min": {
+                "x": -23.5851993560791,
+                "y": -10.233400344848633,
+                "z": -0.9203000068664551
+            },
+            "max": {
+                "x": 8.523699760437012,
+                "y": 15.58899974822998,
+                "z": 13.3774995803833
+            },
+            "center": {
+                "x": -7.530749797821045,
+                "y": 2.677799701690674,
+                "z": 6.228599786758423
+            }
+        },
+        "begin": 18
+    },
+]

+ 55 - 0
src/Models/Submodels/AISLE_INSIDE.ts

@@ -0,0 +1,55 @@
+export default {
+    "name": "AISLE_INSIDE",
+    "showMeshProgress": 2,
+    "autoMove": false,
+    "path": [],
+    "hotspots": [
+        {
+            "id": 1541646366852,
+            "name": "CameraStart",
+            "pos": {
+                "x": 46.351681,
+                "y": 2.888945,
+                "z": 26.77313
+            },
+            "pivot": {
+                "x": 51.642,
+                "y": 2.601,
+                "z": 25.156
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        },
+        {
+            "id": 1542146352117,
+            "name": "文臣廊",
+            "pos": {
+                "x": 54.159,
+                "y": 1.857,
+                "z": 23.656
+            },
+            "pivot": {
+                "x": 54.159,
+                "y": 1.857,
+                "z": 23.656
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": false,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 0,
+        "y": 0,
+        "z": 0
+    }
+}

+ 49 - 0
src/Models/Submodels/END.ts

@@ -0,0 +1,49 @@
+export default {
+    "name": "END",
+    "showMeshProgress": 2,
+    "autoMove": false,
+    "path": [],
+    "hotspots": [
+        {
+            "id": 1542104690660,
+            "name": "CameraStart",
+            "pos": {
+                "x": 6.31044361179698,
+                "y": 34.75922629080932,
+                "z": 78.98643855692728
+            },
+            "pivot": {
+                "x": 38.29,
+                "y": 0,
+                "z": 28.417
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }, {
+            "id": 1542104702248,
+            "name": "CameraEnd",
+            "pos": {
+                "x": 8.57,
+                "y": 35.361,
+                "z": 81.279
+            },
+            "pivot": {
+                "x": 38.29,
+                "y": 0,
+                "z": 28.417
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": false,
+            "fullOrbit": false
+        }
+    ]
+}

+ 34 - 0
src/Models/Submodels/HUILING_INSIDE.ts

@@ -0,0 +1,34 @@
+export default {
+    "name": "HUILING_INSIDE",
+    "showMeshProgress": 2,
+    "autoMove": false,
+    "path": [],
+    "hotspots": [
+        {
+            "id": 1541646366853,
+            "name": "CameraStart",
+            "pos": {
+                "x":1.8838180000000007,
+                "y":10.068521000000002,
+                "z":39.43291499999998
+            },
+            "pivot": {
+                "x": -6.739,
+                "y": 2.976,
+                "z": 3.493
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 0,
+        "y": 0,
+        "z": 0
+    }
+}

+ 54 - 0
src/Models/Submodels/INTRO.ts

@@ -0,0 +1,54 @@
+export default {
+    "name": "INTRO",
+    "showMeshProgress": 2,
+    "autoMove": false,
+    "path": [],
+    "hotspots": [
+        {
+            "id": 1541646366853,
+            "name": "CameraStart",
+            "pos": {
+                "x": 74.508682,
+                "y": 47.853424,
+                "z": 38.315075
+            },
+            "pivot": {
+                "x": 38.297,
+                "y": 0,
+                "z": 28.417
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }, {
+            "id": 1541646366853,
+            "name": "CameraEnd",
+            "pos": {
+                "x": 70.00389791699219,
+                "y": 43.434971709960934,
+                "z": 44.08098499511719
+            },
+            "pivot": {
+                "x": 38.297,
+                "y": 0,
+                "z": 28.417
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 0,
+        "y": 0,
+        "z": 0
+    }
+}

+ 54 - 0
src/Models/Submodels/LIUBEI_INSIDE.ts

@@ -0,0 +1,54 @@
+export default {
+    "name": "LIUBEI_INSIDE",
+    "showMeshProgress": 2,
+    "autoMove": false,
+    "path": [],
+    "hotspots": [
+        {
+            "id": 1541646366852,
+            "name": "CameraStart",
+            "pos": {
+                "x": 41.084231411348,
+                "y": 1.6083176777959998,
+                "z": 21.959288360004
+            },
+            "pivot": {
+                "x": 40.887,
+                "y": 2.285,
+                "z": 18.251
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }, {
+            "id": 1542147796540,
+            "name": "刘备像",
+            "pos": {
+                "x": 41.579,
+                "y": 2.657,
+                "z": 9.211
+            },
+            "pivot": {
+                "x": 41.579,
+                "y": 2.657,
+                "z": 9.211
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": false,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 0,
+        "y": 0,
+        "z": 0
+    }
+}

+ 116 - 0
src/Models/Submodels/PATH_AISLE_TO_LIUBEI.ts

@@ -0,0 +1,116 @@
+export default {
+    "name": "PATH_AISLE_TO_LIUBEI",
+    "showMeshProgress": 0.6,
+    "autoMove": false,
+    "path": [
+        {
+            "x": 46.351681,
+            "y": 2.888945,
+            "z": 26.77313
+        }, {
+            "x": 45.48257319615912,
+            "y": 3.201889792866941,
+            "z": 26.7226634170096
+        }, {
+            "x": 44.537251853223594,
+            "y": 3.5626861083676267,
+            "z": 26.698079459533606
+        }, {
+            "x": 43.55382374074074,
+            "y": 3.9474081851851848,
+            "z": 26.686436814814815
+        }, {
+            "x": 42.57039562825789,
+            "y": 4.332130262002743,
+            "z": 26.674794170096018
+        }, {
+            "x": 41.625074285322356,
+            "y": 4.692926577503429,
+            "z": 26.650210212620024
+        }, {
+            "x": 40.75596648148147,
+            "y": 5.00587137037037,
+            "z": 26.59974362962963
+        }, {
+            "x": 40.00117898628257,
+            "y": 5.247038879286694,
+            "z": 26.510453108367624
+        }, {
+            "x": 39.39881856927297,
+            "y": 5.392503342935527,
+            "z": 26.369397336076815
+        }, {
+            "x": 38.986992,
+            "y": 5.418339,
+            "z": 26.163635
+        }, {
+            "x": 38.791103791495196,
+            "y": 5.3085953429355275,
+            "z": 25.884538558299038
+        }, {
+            "x": 38.78574943072702,
+            "y": 5.079222879286693,
+            "z": 25.54073555281207
+        }, {
+            "x": 38.93282214814815,
+            "y": 4.7541473703703705,
+            "z": 25.145167296296293
+        }, {
+            "x": 39.194215174211244,
+            "y": 4.3572945775034295,
+            "z": 24.71077510150892
+        }, {
+            "x": 39.53182173936899,
+            "y": 3.9125902620027437,
+            "z": 24.25050028120713
+        }, {
+            "x": 39.907535074074076,
+            "y": 3.443960185185185,
+            "z": 23.777284148148144
+        }, {
+            "x": 40.28324840877914,
+            "y": 2.975330108367628,
+            "z": 23.30406801508916
+        }, {
+            "x": 40.62085497393689,
+            "y": 2.530625792866942,
+            "z": 22.843793194787377
+        }, {
+            "x": 40.88224799999999,
+            "y": 2.133773000000001,
+            "z": 22.409400999999995
+        }, {
+            "x": 41.084231411348,
+            "y": 1.6083176777959998,
+            "z": 21.959288360004
+        }
+    ],
+    "hotspots": [
+        {
+            "id": 1542099436585,
+            "name": "CameraStart",
+            "pos": {
+                "x": 46.351681,
+                "y": 2.888945,
+                "z": 26.77313
+            },
+            "pivot": {
+                "x": 46.225084929922225,
+                "y": 2.9343423532693933,
+                "z": 26.765501460345718
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 40.887,
+        "y": 2.285,
+        "z": 18.251
+    }
+}

+ 112 - 0
src/Models/Submodels/PATH_HUILING_TO_END.ts

@@ -0,0 +1,112 @@
+export default {
+    "name": "PATH_HUILING_TO_END",
+    "showMeshProgress": 2,
+    "autoMove": false,
+    "path": [
+        {
+            "x": -6.883818,
+            "y": 1.532833,
+            "z": 39.432915
+        }, {
+            "x": -7.426323499314129,
+            "y": 4.689869846364882,
+            "z": 41.78966789026063
+        }, {
+            "x": -8.157735080932783,
+            "y": 8.019181128943757,
+            "z": 44.15072928257888
+        }, {
+            "x": -8.983599703703703,
+            "y": 11.434629629629628,
+            "z": 46.51394492592593
+        }, {
+            "x": -9.80946432647462,
+            "y": 14.850078130315497,
+            "z": 48.87716056927298
+        }, {
+            "x": -10.540875908093277,
+            "y": 18.17938941289437,
+            "z": 51.23822196159122
+        }, {
+            "x": -11.083381407407405,
+            "y": 21.33642625925925,
+            "z": 53.59497485185186
+        }, {
+            "x": -11.342527783264742,
+            "y": 24.23505145130315,
+            "z": 55.945264989026064
+        }, {
+            "x": -11.223861994513028,
+            "y": 26.789127770919055,
+            "z": 58.286938122085054
+        }, {
+            "x": -10.632931,
+            "y": 28.912518,
+            "z": 60.61784
+        }, {
+            "x": -9.506766105624141,
+            "y": 30.547797326474623,
+            "z": 62.93653445541839
+        }, {
+            "x": -7.908336005486965,
+            "y": 31.752390562414263,
+            "z": 65.24445765569273
+        }, {
+            "x": -5.932093740740742,
+            "y": 32.61243492592593,
+            "z": 67.54376385185186
+        }, {
+            "x": -3.6724923525377227,
+            "y": 33.2140676351166,
+            "z": 69.83660729492456
+        }, {
+            "x": -1.2239848820301766,
+            "y": 33.64342590809328,
+            "z": 72.12514223593965
+        }, {
+            "x": 1.3189756296296324,
+            "y": 33.986646962962965,
+            "z": 74.41152292592592
+        }, {
+            "x": 3.861936141289437,
+            "y": 34.32986801783265,
+            "z": 76.6979036159122
+        }, {
+            "x": 6.31044361179698,
+            "y": 34.75922629080932,
+            "z": 78.98643855692728
+        }, {
+            "x": 8.570045,
+            "y": 35.360859000000005,
+            "z": 81.279282
+        }
+    ],
+    "hotspots": [
+        {
+            "id": 1542099436593,
+            "name": "CameraStart",
+            "pos": {
+                "x": -6.883818,
+                "y": 1.532833,
+                "z": 39.432915
+            },
+            "pivot": {
+                "x": -6.970099925658142,
+                "y": 2.045236661643554,
+                "z": 39.8168090763932
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 38.29,
+        "y": 0,
+        "z": 28.417
+    }
+}

+ 136 - 0
src/Models/Submodels/PATH_INTRO_TO_TANGBEI.ts

@@ -0,0 +1,136 @@
+export default {
+    "name": "PATH_INTRO_TO_TANGBEI",
+    "showMeshProgress": 0.8,
+    "autoMove": false,
+    "path": [
+        {
+            "x": 74.508682,
+            "y": 47.853424,
+            "z": 38.315075
+        }, {
+            "x": 70.00389791699219,
+            "y": 43.434971709960934,
+            "z": 44.08098499511719
+        }, {
+            "x": 65.2135381796875,
+            "y": 38.7255611484375,
+            "z": 50.4705848046875
+        }, {
+            "x": 60.30894818066405,
+            "y": 33.89976727832031,
+            "z": 57.10966054003906
+        }, {
+            "x": 55.4614733125,
+            "y": 29.1321650625,
+            "z": 63.62399831250001
+        }, {
+            "x": 50.84245896777344,
+            "y": 24.597329463867183,
+            "z": 69.63938423339843
+        }, {
+            "x": 46.6232505390625,
+            "y": 20.469835445312498,
+            "z": 74.78160441406251
+        }, {
+            "x": 42.97519341894531,
+            "y": 16.924257969726558,
+            "z": 78.67644496582032
+        }, {
+            "x": 40.069633,
+            "y": 14.135172,
+            "z": 80.949692
+        }, {
+            "x": 37.927531749023444,
+            "y": 12.23784589453125,
+            "z": 81.26606153320313
+        }, {
+            "x": 36.3946874921875,
+            "y": 11.123989937500001,
+            "z": 79.83825460937501
+        }, {
+            "x": 35.37969866113282,
+            "y": 10.60284198046875,
+            "z": 77.11403488085936
+        }, {
+            "x": 34.7911636875,
+            "y": 10.483639875000001,
+            "z": 73.54116599999999
+        }, {
+            "x": 34.53768100292969,
+            "y": 10.575621472656248,
+            "z": 69.56741161914061
+        }, {
+            "x": 34.52784903906251,
+            "y": 10.688024624999995,
+            "z": 65.640535390625
+        }, {
+            "x": 34.67026622753907,
+            "y": 10.63008718359375,
+            "z": 62.20830096679688
+        }, {
+            "x": 34.873531,
+            "y": 10.211047,
+            "z": 59.718472
+        }, {
+            "x": 35.276611935546875,
+            "y": 9.507400098632814,
+            "z": 58.032974721679686
+        }, {
+            "x": 36.026116109374996,
+            "y": 8.733608726562503,
+            "z": 56.6661930859375
+        }, {
+            "x": 37.04209969726563,
+            "y": 7.905860069335939,
+            "z": 55.544577329101564
+        }, {
+            "x": 38.24461887500001,
+            "y": 7.0403413125,
+            "z": 54.5945776875
+        }, {
+            "x": 39.55372981835938,
+            "y": 6.153239641601562,
+            "z": 53.742644397460936
+        }, {
+            "x": 40.889488703125004,
+            "y": 5.260742242187499,
+            "z": 52.91522769531249
+        }, {
+            "x": 42.17195170507813,
+            "y": 4.379036299804686,
+            "z": 52.03877781738281
+        }, {
+            "x": 45.773,
+            "y": 1.544,
+            "z": 46.979
+        }
+    ],
+    "hotspots": [
+        {
+            "id": 1542099436579,
+            "name": "CameraStart",
+            "pos": {
+                "x": 74.508682,
+                "y": 47.853424,
+                "z": 38.315075
+            },
+            "pivot": {
+                "x": 73.95684965052791,
+                "y": 47.31223915257222,
+                "z": 39.01968363504926
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 50.695,
+        "y": 1.544,
+        "z": 46.979
+    }
+}

+ 140 - 0
src/Models/Submodels/PATH_LIUBEI_TO_ZHUGELIANG.ts

@@ -0,0 +1,140 @@
+export default {
+    "name": "PATH_LIUBEI_TO_ZHUGELIANG",
+    "showMeshProgress": 0.7,
+    "autoMove": false,
+    "path": [
+        {
+            "x": 40.882248,
+            "y": 2.133773,
+            "z": 22.409401
+        }, {
+            "x": 40.4251571328125,
+            "y": 3.7002535634765623,
+            "z": 22.076480648437503
+        }, {
+            "x": 39.93560181249999,
+            "y": 5.370066539062501,
+            "z": 21.832945687499997
+        }, {
+            "x": 39.4330607109375,
+            "y": 7.081212479492187,
+            "z": 21.625164882812502
+        }, {
+            "x": 38.9370125,
+            "y": 8.7716919375,
+            "z": 21.399507
+        }, {
+            "x": 38.4669358515625,
+            "y": 10.379505465820312,
+            "z": 21.1023408046875
+        }, {
+            "x": 38.04230943750001,
+            "y": 11.8426536171875,
+            "z": 20.680035062500004
+        }, {
+            "x": 37.68261192968751,
+            "y": 13.099136944335935,
+            "z": 20.0789585390625
+        }, {
+            "x": 37.407322,
+            "y": 14.086956,
+            "z": 19.24548
+        }, {
+            "x": 37.20478717285156,
+            "y": 14.855358325195313,
+            "z": 18.184002593749998
+        }, {
+            "x": 37.051462414062506,
+            "y": 15.4844971015625,
+            "z": 16.94749075
+        }, {
+            "x": 36.94898755761719,
+            "y": 15.958731342773437,
+            "z": 15.55515515625
+        }, {
+            "x": 36.8990024375,
+            "y": 16.2624200625,
+            "z": 14.0262065
+        }, {
+            "x": 36.903146887695314,
+            "y": 16.379922274414064,
+            "z": 12.379855468750002
+        }, {
+            "x": 36.9630607421875,
+            "y": 16.295596992187498,
+            "z": 10.63531275
+        }, {
+            "x": 37.08038383496094,
+            "y": 15.993803229492187,
+            "z": 8.811789031250003
+        }, {
+            "x": 37.256756,
+            "y": 15.4589,
+            "z": 6.928495
+        }, {
+            "x": 37.51599557714844,
+            "y": 14.608127291015625,
+            "z": 4.9356680078125
+        }, {
+            "x": 37.8667486796875,
+            "y": 13.420912703125001,
+            "z": 2.7936853124999996
+        }, {
+            "x": 38.28789680175781,
+            "y": 11.974896669921874,
+            "z": 0.536967460937499
+        }, {
+            "x": 38.758321437499994,
+            "y": 10.347719624999998,
+            "z": -1.800065000000001
+        }, {
+            "x": 39.256904081054685,
+            "y": 8.617022001953124,
+            "z": -4.182991523437502
+        }, {
+            "x": 39.762526226562485,
+            "y": 6.860444234374995,
+            "z": -6.577391562500002
+        }, {
+            "x": 40.25406936816405,
+            "y": 5.1556267558593705,
+            "z": -8.9488445703125
+        }, {
+            "x": 40.710415,
+            "y": 3.580209999999994,
+            "z": -11.26293
+        }, {
+            "x": 41.362623417169495,
+            "y": 1.9776937175944997,
+            "z": -13.687319630000498
+        }
+    ],
+    "hotspots": [
+        {
+            "id": 1542099436587,
+            "name": "CameraStart",
+            "pos": {
+                "x": 40.882248,
+                "y": 2.133773,
+                "z": 22.409401
+            },
+            "pivot": {
+                "x": 40.75052798702049,
+                "y": 2.585423175338073,
+                "z": 22.310083203468743
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 41.021,
+        "y": 2.402,
+        "z": -17.814
+    }
+}

+ 112 - 0
src/Models/Submodels/PATH_TANGBEI_TO_AISLE.ts

@@ -0,0 +1,112 @@
+export default {
+    "name": "PATH_TANGBEI_TO_AISLE",
+    "showMeshProgress": 0.7,
+    "autoMove": false,
+    "path": [
+        {
+            "x": 43.321175,
+            "y": 3.524309,
+            "z": 51.039745
+        }, {
+            "x": 42.5945645308642,
+            "y": 4.206025155006859,
+            "z": 50.860961382716056
+        }, {
+            "x": 41.74728369135802,
+            "y": 4.984417375857339,
+            "z": 50.839844506172845
+        }, {
+            "x": 40.839667666666664,
+            "y": 5.811147629629629,
+            "z": 50.897561
+        }, {
+            "x": 39.932051641975306,
+            "y": 6.637877883401921,
+            "z": 50.95527749382717
+        }, {
+            "x": 39.08477080246912,
+            "y": 7.416270104252402,
+            "z": 50.93416061728396
+        }, {
+            "x": 38.35816033333332,
+            "y": 8.09798625925926,
+            "z": 50.75537700000001
+        }, {
+            "x": 37.81255541975308,
+            "y": 8.634688315500686,
+            "z": 50.34009327160495
+        }, {
+            "x": 37.508291246913565,
+            "y": 8.978038240054872,
+            "z": 49.60947606172841
+        }, {
+            "x": 37.505703,
+            "y": 9.079698,
+            "z": 48.484692
+        }, {
+            "x": 37.845014135802465,
+            "y": 8.90744224005487,
+            "z": 46.91318550617284
+        }, {
+            "x": 38.48600119753086,
+            "y": 8.493496315500686,
+            "z": 44.94751216049383
+        }, {
+            "x": 39.368329,
+            "y": 7.886198259259261,
+            "z": 42.66650533333334
+        }, {
+            "x": 40.43166235802469,
+            "y": 7.1338861042524,
+            "z": 40.148998395061724
+        }, {
+            "x": 41.61566608641976,
+            "y": 6.284897883401921,
+            "z": 37.473824716049386
+        }, {
+            "x": 42.860005,
+            "y": 5.387571629629629,
+            "z": 34.719817666666664
+        }, {
+            "x": 44.10434391358026,
+            "y": 4.49024537585734,
+            "z": 31.96581061728395
+        }, {
+            "x": 45.28834764197532,
+            "y": 3.6412571550068584,
+            "z": 29.290636938271597
+        }, {
+            "x": 46.351681,
+            "y": 2.888945,
+            "z": 26.77313
+        }
+    ],
+    "hotspots": [
+        {
+            "id": 1542099436582,
+            "name": "CameraStart",
+            "pos": {
+                "x": 43.321175,
+                "y": 3.524309,
+                "z": 51.039745
+            },
+            "pivot": {
+                "x": 43.07845408287015,
+                "y": 3.752665168493936,
+                "z": 50.97286359503466
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 51.642,
+        "y": 2.601,
+        "z": 25.156
+    }
+}

Разлика између датотеке није приказан због своје велике величине
+ 34 - 0
src/Models/Submodels/PATH_ZHUGELIANG_TO_HUILING.ts


+ 55 - 0
src/Models/Submodels/TANGBEI.ts

@@ -0,0 +1,55 @@
+export default {
+    "name": "TANGBEI",
+    "showMeshProgress": 2,
+    "autoMove": false,
+    "path": [],
+    "hotspots": [
+        {
+            "id": 1542100605299,
+            "name": "CameraStart",
+            "pos": {
+                "x": 45.773,
+                "y": 1.544,
+                "z": 46.979
+            },
+            "pivot": {
+                "x": 50.695,
+                "y": 1.544,
+                "z": 46.979
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        },
+        {
+            "id": 1542147796539,
+            "name": "唐碑“三绝碑”",
+            "pos": {
+                "x": 49.047,
+                "y": 1.634,
+                "z": 47.561
+            },
+            "pivot": {
+                "x": 49.047,
+                "y": 1.634,
+                "z": 47.561
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": false,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 0,
+        "y": 0,
+        "z": 0
+    }
+}

+ 94 - 0
src/Models/Submodels/ZHUGELIANG_INSIDE.ts

@@ -0,0 +1,94 @@
+export default {
+    "name": "ZHUGELIANG_INSIDE",
+    "showMeshProgress": 2,
+    "autoMove": false,
+    "path": [],
+    "hotspots": [
+        {
+            "id": 1541646366853,
+            "name": "CameraStart",
+            "pos": {
+                "x": 41.362623417169495,
+                "y": 1.9776937175944997,
+                "z": -13.687319630000498
+            },
+            "pivot": {
+                "x": 41.021,
+                "y": 2.402,
+                "z": -17.814
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": true,
+            "fullOrbit": false
+        }, {
+            "id": 1542147796541,
+            "name": "诸葛亮像",
+            "pos": {
+                "x": 41.713,
+                "y": 2.04,
+                "z": -23.605
+            },
+            "pivot": {
+                "x": 41.713,
+                "y": 2.04,
+                "z": -23.605
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": false,
+            "fullOrbit": false
+        }, {
+            "id": 1541646366853,
+            "name": "攻心联",
+            "pos": {
+                "x": 42.93,
+                "y": 3.015,
+                "z": -19.636
+            },
+            "pivot": {
+                "x": 42.93,
+                "y": 3.015,
+                "z": -19.636
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": false,
+            "fullOrbit": false
+        }, {
+            "id": 1541646366856,
+            "name": "“名垂宇宙”匾额",
+            "pos": {
+                "x": 42.032,
+                "y": 3.358,
+                "z": -19.046
+            },
+            "pivot": {
+                "x": 42.032,
+                "y": 3.358,
+                "z": -19.046
+            },
+            "up": {
+                "x": 0,
+                "y": 1,
+                "z": 0
+            },
+            "cameraStartPosition": false,
+            "fullOrbit": false
+        }
+    ],
+    "focus": {
+        "x": 0,
+        "y": 0,
+        "z": 0
+    }
+}

+ 9 - 0
src/Models/index.ts

@@ -0,0 +1,9 @@
+import models from './Models/index'
+
+export default {
+    data: [],
+    pivots: [],
+    titles: [],
+    scenes: [],
+    models
+}

Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
src/Resources/Particles.ts


+ 290 - 0
src/Shaders/index.ts

@@ -0,0 +1,290 @@
+export default {
+    pointClound: {
+        vs: `
+          uniform float _Progress;
+          uniform float _Time;
+          uniform float meshShowProgress;
+          
+          #define PI2 6.2831
+          uniform float WIND_AMP;
+          
+          vec3 hash33(vec3 p3) {
+              p3 = fract(p3 * vec3(.1031, .1030, .0973));
+              p3 += dot(p3, p3.yxz+19.19);
+              return fract((p3.xxy + p3.yxx)*p3.zyx);
+          }
+          
+          const mat4 m = mat4( 0.00,  0.80,  0.60, -0.4,
+                              -0.80,  0.36, -0.48, -0.5,
+                              -0.60, -0.48,  0.64,  0.2,
+                              0.40,  0.30,  0.20,  0.4);
+          
+          vec3 octaves(vec4 p) {
+              vec4 q = m * p;
+              vec4 f  = 0.5000*sin( q );
+              q = m*q*2.01;
+              f += 0.2500*sin( q );
+              q = m*q*2.02;
+              f += 0.1250*sin( q );
+              q = m*q*2.03;
+              f += 0.0625*sin( q );
+              return f.xyz;
+          }
+          
+          void introEffect(inout vec3 P, float random)
+          {			
+              
+              vec3 Pw = P;
+              vec3 noise = octaves(vec4(vec3(random * 40.-20.), _Time * .2 + random * PI2 * 10.));
+          
+              float nprogress = min(1., _Progress * 1.1);
+          
+              float p = smoothstep( .5*random + .5, .5*random, nprogress);
+  
+          
+              P = mix(P, Pw, p * .65) + noise * (WIND_AMP * p);
+          
+              float yprogress = min(1., _Progress * 2.);
+              P.y *= max(0.01, smoothstep(random, 1., yprogress));
+          }
+  
+          
+          uniform float _FogHeightStrength;
+          uniform float _BaseFog;
+          
+          
+          #define POINT_COLOR vec3(51./255., 34./255., 17./255.)
+          #define FOG_COLOR vec3(244./255., 226./255., 202./255.)
+  
+          attribute float aRanking;
+          attribute vec3 aPos;
+          
+          varying highp vec3 vColor;
+  
+  
+          void main(void) {
+              
+              vec4 pos = vec4(position, 1.0);
+                      
+              introEffect(pos.xyz, aRanking);
+              
+              float show = 0.0;
+              show = 1.0 - clamp( 0.9, 0.0,pow( smoothstep( 20.0, 60.0, length(pos.xyz - cameraPosition) ), 0.6 ) );
+              show *= meshShowProgress;
+              
+              if( aRanking > show )
+              {
+                  gl_Position = vec4(100.,0.,0.,1.0);
+              }
+              else
+              {
+                  gl_Position = projectionMatrix * modelViewMatrix * pos;
+              }
+              gl_PointSize = max(1.0, 0.2 / gl_Position.w );
+              
+              
+              vec3 rd = pos.xyz - cameraPosition;
+              float d = length(rd) ;
+              rd *= (1./d);
+              float fog = d/150.0 + 0.2; //_BaseFog * (1.0-exp( -d*rd.y*_FogHeightStrength )) /rd.y;
+              vColor.xyz =  mix(POINT_COLOR, FOG_COLOR, min(fog, 1.));
+              //vColor.xyz = POINT_COLOR;
+              
+          }
+          `,
+
+
+        fs: `
+          #ifdef GL_ES
+              precision mediump float;
+          #endif
+  
+          varying float aFog;
+  
+          varying highp vec3 vColor;
+  
+          void main(void) {
+              gl_FragColor = vec4(vColor, 1.);
+          }
+          `
+
+    },
+    title: {
+
+        vs: `
+          uniform float _Aspect;
+          uniform float _TitleAspect;		
+          uniform float _TitleScale;
+          uniform vec3 _Center;
+          
+          varying highp vec2 vUV;
+          
+          void main(void) {
+              vec4 pos = vec4( _Center, 1.0);
+          
+              pos = projectionMatrix * viewMatrix * pos;
+          
+          #ifdef NO_ANIMATION
+              vec2 offset = (uv-.5) * vec2(1., _TitleAspect * _Aspect) * (1000. / pos.w);
+              offset *= _TitleScale;
+          #else
+              vec2 offset = (uv-.5) * vec2(1., _TitleAspect * _Aspect) * 5.;
+          #endif
+          
+              if (pos.w < 0. || length(pos.xy) > 4. * pos.w) {
+                  offset *= 0.;
+              }
+          
+              pos.xy += offset;
+          
+              gl_Position = pos;
+          
+              vUV = uv;
+          }
+  
+          `,
+
+        fs: `
+          
+              #ifdef GL_ES
+                  precision mediump float;
+              #endif
+              
+              uniform sampler2D _Texture;
+              uniform sampler2D _Mask;
+              
+              uniform float _Fade;
+              uniform float _FrameCounter;
+              
+              varying highp vec2 vUV;
+              
+              
+              void main(void) {
+                  
+              #ifdef NO_ANIMATION
+                  vec4 data = texture2D(_Texture, vUV);
+                  vec3 col = data.rgb;
+                  float alpha = data.a;
+              
+                  alpha *= _Fade;
+              
+              //	if( alpha == 0. ) discard;
+              
+                  gl_FragColor = vec4(col * alpha, alpha);
+              #else
+                  float alpha = texture2D(_Texture, vUV).a;
+                  float delta = _FrameCounter / 255.;
+                  vec2 colorGrad = texture2D(_Mask, vUV).rb;
+              
+                  bool filled = delta >= colorGrad.x;
+                  bool erased = colorGrad.y >= 0.0 && colorGrad.y <= delta;
+              
+                  alpha *= (filled && !erased ? 1.0 : 0.0);
+              
+              //	if( alpha == 0. ) discard;
+              //	vec3 col = vec3(31./255., 12./255., 1./255.);
+              
+                  gl_FragColor = vec4(alpha);
+              
+                  
+                  
+              #endif
+              
+              }
+          `
+
+    },
+    mesh: {
+
+        vs: `
+          
+              varying vec2 vUv;
+              
+              void main(void) {	
+                  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0);
+                  gl_PointSize = 0.1;
+                  vUv = uv;;
+                  
+              }
+          `,
+
+        fs: `
+              uniform sampler2D map;
+              uniform float u_alphatest;
+              uniform float opacity;
+              varying vec2 vUv;
+              
+              float hash12(vec2 p) {
+                  vec3 p3  = fract(vec3(p.xyx) * 443.8975);
+                  p3 += dot(p3, p3.yzx + 1.5);
+                  return fract((p3.x + p3.y) * p3.z);
+              }
+              
+              
+              void main(void) {			
+                  if(u_alphatest < 1. && hash12(vUv) > u_alphatest) {
+                      discard;
+                  }
+                  vec4 diffuse = texture2D(map,vUv);    	
+                  gl_FragColor = vec4(diffuse.rgb, opacity);
+              }
+          `
+    },
+    pathRibbonPaint: {
+
+        vs: `
+          //pos, progress
+          attribute vec4 aData;
+          attribute vec2 aUV0;
+          
+          #define aPos aData.xyz
+          #define aDistance aData.w
+          
+          uniform mat4 _ViewProjection;
+          uniform vec3 _CamPos;
+          uniform float _MaxDist;
+          uniform float _Fade;
+          
+          uniform float _FogHeightStrength;
+          uniform float _BaseFog;
+          
+          varying vec2 vUV;
+          varying float vFade;
+          varying float vFog;
+          
+          void main(void) {
+  
+              gl_Position = projectionMatrix * modelViewMatrix * vec4(aPos, 1.0);		
+              vUV = uv;
+              vFade = smoothstep(0., 0.1, aDistance) * smoothstep(1., 0.9, aDistance) * _Fade;
+          
+          
+              vec3 rd = aPos.xyz - cameraPosition;
+              float d = length(rd) ;
+              rd *= (1./d);
+              vFade *= 1. - min(1., _BaseFog * (1.0-exp( -d*rd.y*_FogHeightStrength )) /rd.y);
+          }
+      `,
+        fs: `
+          #ifdef GL_ES
+              precision mediump float;
+          #endif
+          
+          #define ORANGE vec4(238./255., 140./255., 0., 1.)
+          
+          uniform sampler2D _Texture;
+          
+          varying vec2 vUV;
+          varying float vFade;
+          
+          void main(void) {
+              
+               
+              float alpha = texture2D(_Texture, vUV).r * vFade;		
+              
+              gl_FragColor = vec4( ORANGE.rgb, alpha );			 
+          }
+      `
+
+    },
+}

+ 13 - 0
src/System/DataSystem.ts

@@ -0,0 +1,13 @@
+import SystemBase from '../Base/SystemBase'
+
+class CameraSystem extends SystemBase {
+    constructor(){
+        super(CameraSystem.name)
+    }
+
+    protected ctx() {
+        return this;
+    }
+}
+
+export default CameraSystem

+ 51 - 0
src/System/InputSystem.ts

@@ -0,0 +1,51 @@
+import SystemBase from '../Base/SystemBase'
+
+
+class InputSystem extends SystemBase {
+    private downX:number = -1;
+    private downY:number = -1;
+    private delay: number = 300;
+    private timestamp: number = 0;
+    constructor() {
+        super(InputSystem.name)
+        this.init()
+        console.log(this)
+    }
+
+    protected ctx() {
+        return this;
+    }
+
+    private init() {
+        document.addEventListener('mousedown', this.mousedown.bind(this));
+        document.addEventListener('mouseup', this.mouseup.bind(this));
+        document.addEventListener('mousemove', this.mousemove.bind(this));
+    }
+
+    private mousedown(e: MouseEvent) {
+        this.downX = e.clientX
+        this.downY = e.clientY
+        this.dispatchEvent({ type: 'mousedown', event: e })
+        this.timestamp = Date.now();
+    }
+
+    private mouseup(e: MouseEvent) {
+        this.dispatchEvent({ type: 'mouseup', event: e })
+        if (Date.now() - this.timestamp < this.delay) {
+            // 模拟点击事件
+            this.dispatchEvent({ type: 'click', event: e })
+        }
+
+        this.downX = -1
+        this.downY = -1
+    }
+
+    private mousemove(e: MouseEvent) {
+        this.dispatchEvent({ type: 'mousemove', event: e })
+        if(this.downX>-1 || this.downY>-1){
+            this.dispatchEvent({ type: 'mousedrag', event: e })
+        }
+    }
+}
+
+export default InputSystem

+ 148 - 0
src/System/ResourceSystem.ts

@@ -0,0 +1,148 @@
+import SystemBase from '../Base/SystemBase'
+import particles from '../Resources/Particles'
+import models from '../Models/index';
+import {
+    IModel,
+    ModelComponent
+} from '../Components/ModelComponent'
+import {
+    ITitle,
+    TitleComponent
+} from '../Components/TitleComponent'
+import { ParticleComponent } from "../Components/ParticleComponent";
+import * as THREE from 'three';
+
+/**
+ * 资源系统
+ */
+class ResourceSystem extends SystemBase {
+    models: any = models
+    worker: Worker
+    constructor() {
+        super(ResourceSystem.name)
+        var d = document.createElement("div")
+        var s = document.createElement('span');
+        var p = document.createElement("p");
+        d.style.position = 'absolute';
+        d.style.top = '8px'
+        d.style.left = '50%'
+        d.style.width = '500px'
+        d.style.height = '30px';
+        d.style.transform = 'translateX(-50%)'
+        d.style.textAlign = 'center'
+        document.body.appendChild(d);
+        s.style.position = 'absolute';
+        s.style.left = '50%'
+        s.style.height = '30px'
+        d.appendChild(s);
+        p.style.background = '#ccc'
+        p.style.height = '30px'
+        p.style.lineHeight = '30px'
+        p.style.textAlign = 'center'
+        p.style.margin = '0px';
+        p.style.width = '0'
+        d.appendChild(p)
+
+        this.worker = new Worker('workers/loaders.js')
+        this.worker.onmessage = e => {
+            switch (e.data.cmd) {
+                case 'progress':
+                    p.style.width = e.data.progress + '%'
+                    s.textContent = e.data.progress + '%'
+                    //this.dispatchEvent({ type: 'progress', progress: e.data.progress })
+                    break
+                case 'loadParticles':
+                    ParticleComponent.add(e.data.file)
+                    break;
+                case 'loadTitles':
+                    TitleComponent.setTexture(e.data.file)
+                    break;
+                case 'loadModels':
+                    ModelComponent.setObj(e.data.file)
+                    break;
+                case 'loadModelsTexture':
+                    ModelComponent.setTexture(e.data.file)
+                    break;
+            }
+        }
+    }
+
+    /**
+     * 加载所有资源
+     */
+    load() {
+
+        this.loadParticles()
+        this.loadModels()
+        this.loadTitles()
+
+        return this;
+    }
+
+    /**
+     * 加载粒子效果
+     */
+    private loadParticles() {
+        particles.sort(() => Math.random() > .5 ? -1 : 1)
+        this.worker.postMessage({ cmd: 'loadParticles', files: particles.slice(0, Math.floor(particles.length * 0.5)) })
+    }
+
+    /**
+     * 加载模型标题
+     */
+    private loadTitles() {
+        this.models.models.forEach((model: { name: string; title: ITitle; }) => {
+            TitleComponent.add({
+                name: model.name,
+                ...model.title
+            })
+        });
+
+        this.worker.postMessage({
+            cmd: 'loadTitles',
+            files: TitleComponent.list.map(c => {
+                return { name: c.name, image: c.name, mask: c.name + '.mask' }
+            })
+        })
+    }
+
+    /**
+     * 加载模型
+     */
+    private loadModels() {
+        this.models.models.filter((m: { hide: boolean; }) => !m.hide).forEach((model) => {
+            ModelComponent.add({
+                name: model.name,
+                transform: model.transform
+            })
+        });
+        const names = ModelComponent.list.map(mode => mode.name)
+        this.worker.postMessage({ cmd: 'loadModels', files: names })
+        this.worker.postMessage({ cmd: 'loadModelsTexture', files: names, size: 2048 })
+
+        // const dracoLoader = new THREE.DRACOLoader();
+
+        // dracoLoader.load(`static/model/${model.name}.drc`, (geometry: any) => {
+
+        //     geometry.computeVertexNormals();
+
+        //     var mesh = new THREE.Mesh(geometry);
+        //     mesh.material = material
+        //     mesh.position.set(0, 0, i * 10)
+
+        //     group.add(mesh)
+
+        //     if (i == models.length - 1) {
+        //         this.scene.add(group)
+        //     }
+
+        //     //this.scene.add( mesh );
+
+        //     // Release decoder resources.
+        //     //THREE.DRACOLoader.releaseDecoderModule();
+
+        // });
+    }
+}
+
+export default ResourceSystem

+ 89 - 0
src/System/ScenesSystem.ts

@@ -0,0 +1,89 @@
+import SystemBase from '../Base/SystemBase'
+import {ParticleComponent} from '../Components/ParticleComponent'
+
+import * as THREE from 'three';
+
+/**
+ * 场景系统
+ */
+class ScenesSystem extends SystemBase {
+    scene!: THREE.Scene
+    canvas!: HTMLCanvasElement
+    camera!: THREE.PerspectiveCamera
+    renderer!: THREE.WebGLRenderer
+    private stats: any;
+    private canvasWidth = 0
+    private canvasHeight = 0
+    constructor() {
+        super(ScenesSystem.name)
+    }
+
+    init(canvas: HTMLCanvasElement) {
+        if (this.canvas) {
+            return
+        }
+
+        this.canvasWidth = innerWidth
+        this.canvasHeight = innerHeight
+
+        this.canvas = canvas
+        this.scene = new THREE.Scene()
+        this.scene.add(new THREE.GridHelper(1000, 100))
+        this.scene.add(new THREE.AxesHelper(1000))
+
+        this.camera = new THREE.PerspectiveCamera(70, this.canvasWidth / this.canvasHeight, 1, 1000)
+        //设置摄像机的位置,并让其指向场景的中心(0,0,0)
+        this.camera.position.x = -30;
+        this.camera.position.y = 40;
+        this.camera.position.z = 30;
+        this.camera.lookAt(this.scene.position);
+
+        this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas })
+        this.renderer.setSize(this.canvasWidth, this.canvasHeight);
+
+        window['orb'] = new THREE.OrbitControls(this.camera, this.renderer.domElement);
+
+        this.scene.background = new THREE.CubeTextureLoader()
+            .setPath('skybox/')
+            .load([
+                'px.jpg',
+                'nx.jpg',
+                'py.jpg',
+                'ny.jpg',
+                'pz.jpg',
+                'nz.jpg'
+            ]);
+
+        // 性能控件
+        this.stats = new Stats();
+        this.stats.dom.style.position = 'absolute';
+        this.stats.dom.style.left = '8px';
+        this.stats.dom.style.top = '8px';
+        this.stats.dom.style.zIndex = 'initial';
+        this.renderer.domElement.parentNode.appendChild(this.stats.dom);
+
+
+        window.addEventListener('resize', this.resize.bind(this))
+    }
+
+    update() {
+        ParticleComponent.update()
+        this.stats.update()
+        this.renderer.render(this.scene, this.camera);
+    }
+
+    private resize() {
+        if (!this.canvas) {
+            return
+        }
+
+        this.canvasWidth = innerWidth
+        this.canvasHeight = innerHeight
+
+        this.camera.aspect = this.canvasWidth / this.canvasHeight ;
+        this.camera.updateProjectionMatrix();
+        this.renderer.setSize(this.canvasWidth, this.canvasHeight );
+    }
+}
+
+export default ScenesSystem

+ 7 - 0
src/Utils/UUID.ts

@@ -0,0 +1,7 @@
+function S4() {
+    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
+}
+
+export default function(){
+    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
+}

+ 1 - 0
src/global.d.ts

@@ -0,0 +1 @@
+declare function Stats(): void;

+ 39 - 0
src/index.ts

@@ -0,0 +1,39 @@
+import 'core-js'
+import { root, Context } from './Context'
+import InputSystem from './System/InputSystem'
+import ScenesSystem from './System/ScenesSystem'
+import ResourceSystem from './System/ResourceSystem'
+
+class WCS {
+    root: Context = root 
+    private timer: number = 0    
+    constructor() {
+        this.root.add(new InputSystem())
+        this.root.add(new ScenesSystem())
+        this.root.add(new ResourceSystem())
+        this.bind(document.querySelector('canvas')).start()
+        
+         this.root.get<ResourceSystem>(ResourceSystem.name).load()
+    }
+
+    private update() {
+        this.root.list.forEach(system => system.update())
+        this.timer = requestAnimationFrame(this.update.bind(this))
+    }
+
+    bind(canvas:HTMLCanvasElement){
+        this.root.get<ScenesSystem>(ScenesSystem.name).init(canvas)
+        return this;
+    }
+
+    start() {
+        this.update()
+    }
+
+    stop() {
+        cancelAnimationFrame(this.timer)
+    }
+
+}
+
+export default new WCS()

Разлика између датотеке није приказан због своје велике величине
+ 17 - 0
static/libs/TweenMax.min.js


Разлика између датотеке није приказан због своје велике величине
+ 11 - 0
static/libs/css/animate.css


Разлика између датотеке није приказан због своје велике величине
+ 4 - 0
static/libs/jquery.min.js


+ 282 - 0
static/libs/threejs/DragControls.js

@@ -0,0 +1,282 @@
+/*
+ * @author zz85 / https://github.com/zz85
+ * @author mrdoob / http://mrdoob.com
+ * Running this will allow you to drag three.js objects around the screen.
+ */
+
+THREE.DragControls = function ( _objects, _camera, _domElement ) {
+
+	if ( _objects instanceof THREE.Camera ) {
+
+		console.warn( 'THREE.DragControls: Constructor now expects ( objects, camera, domElement )' );
+		var temp = _objects; _objects = _camera; _camera = temp;
+
+	}
+
+	var _plane = new THREE.Plane();
+	var _raycaster = new THREE.Raycaster();
+
+	var _mouse = new THREE.Vector2();
+	var _offset = new THREE.Vector3();
+	var _intersection = new THREE.Vector3();
+
+	var _selected = null, _hovered = null;
+
+	//
+
+	var scope = this;
+
+	function activate() {
+
+		_domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
+		_domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
+		_domElement.addEventListener( 'mouseup', onDocumentMouseCancel, false );
+		_domElement.addEventListener( 'mouseleave', onDocumentMouseCancel, false );
+		_domElement.addEventListener( 'touchmove', onDocumentTouchMove, false );
+		_domElement.addEventListener( 'touchstart', onDocumentTouchStart, false );
+		_domElement.addEventListener( 'touchend', onDocumentTouchEnd, false );
+
+	}
+
+	function deactivate() {
+
+		_domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
+		_domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false );
+		_domElement.removeEventListener( 'mouseup', onDocumentMouseCancel, false );
+		_domElement.removeEventListener( 'mouseleave', onDocumentMouseCancel, false );
+		_domElement.removeEventListener( 'touchmove', onDocumentTouchMove, false );
+		_domElement.removeEventListener( 'touchstart', onDocumentTouchStart, false );
+		_domElement.removeEventListener( 'touchend', onDocumentTouchEnd, false );
+
+	}
+
+	function dispose() {
+
+		deactivate();
+
+	}
+
+	function onDocumentMouseMove( event ) {
+
+		event.preventDefault();
+
+		var rect = _domElement.getBoundingClientRect();
+
+		_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
+		_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;
+
+		_raycaster.setFromCamera( _mouse, _camera );
+
+		if ( _selected && scope.enabled ) {
+
+			if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
+
+				_selected.position.copy( _intersection.sub( _offset ) );
+
+			}
+
+			scope.dispatchEvent( { type: 'drag', object: _selected } );
+
+			return;
+
+		}
+
+		_raycaster.setFromCamera( _mouse, _camera );
+
+		var intersects = _raycaster.intersectObjects( _objects );
+
+		if ( intersects.length > 0 ) {
+
+			var object = intersects[ 0 ].object;
+
+			_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), object.position );
+
+			if ( _hovered !== object ) {
+
+				scope.dispatchEvent( { type: 'hoveron', object: object } );
+
+				_domElement.style.cursor = 'pointer';
+				_hovered = object;
+
+			}
+
+		} else {
+
+			if ( _hovered !== null ) {
+
+				scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
+
+				_domElement.style.cursor = 'auto';
+				_hovered = null;
+
+			}
+
+		}
+
+	}
+
+	function onDocumentMouseDown( event ) {
+
+		event.preventDefault();
+
+		_raycaster.setFromCamera( _mouse, _camera );
+
+		var intersects = _raycaster.intersectObjects( _objects );
+
+		if ( intersects.length > 0 ) {
+
+			_selected = intersects[ 0 ].object;
+
+			if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
+
+				_offset.copy( _intersection ).sub( _selected.position );
+
+			}
+
+			_domElement.style.cursor = 'move';
+
+			scope.dispatchEvent( { type: 'dragstart', object: _selected } );
+
+		}
+
+
+	}
+
+	function onDocumentMouseCancel( event ) {
+
+		event.preventDefault();
+
+		if ( _selected ) {
+
+			scope.dispatchEvent( { type: 'dragend', object: _selected } );
+
+			_selected = null;
+
+		}
+
+		_domElement.style.cursor = _hovered ? 'pointer' : 'auto';
+
+	}
+
+	function onDocumentTouchMove( event ) {
+
+		event.preventDefault();
+		event = event.changedTouches[ 0 ];
+
+		var rect = _domElement.getBoundingClientRect();
+
+		_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
+		_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;
+
+		_raycaster.setFromCamera( _mouse, _camera );
+
+		if ( _selected && scope.enabled ) {
+
+			if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
+
+				_selected.position.copy( _intersection.sub( _offset ) );
+
+			}
+
+			scope.dispatchEvent( { type: 'drag', object: _selected } );
+
+			return;
+
+		}
+
+	}
+
+	function onDocumentTouchStart( event ) {
+
+		event.preventDefault();
+		event = event.changedTouches[ 0 ];
+
+		var rect = _domElement.getBoundingClientRect();
+
+		_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
+		_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;
+
+		_raycaster.setFromCamera( _mouse, _camera );
+
+		var intersects = _raycaster.intersectObjects( _objects );
+
+		if ( intersects.length > 0 ) {
+
+			_selected = intersects[ 0 ].object;
+
+			_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _selected.position );
+
+			if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
+
+				_offset.copy( _intersection ).sub( _selected.position );
+
+			}
+
+			_domElement.style.cursor = 'move';
+
+			scope.dispatchEvent( { type: 'dragstart', object: _selected } );
+
+		}
+
+
+	}
+
+	function onDocumentTouchEnd( event ) {
+
+		event.preventDefault();
+
+		if ( _selected ) {
+
+			scope.dispatchEvent( { type: 'dragend', object: _selected } );
+
+			_selected = null;
+
+		}
+
+		_domElement.style.cursor = 'auto';
+
+	}
+
+	activate();
+
+	// API
+
+	this.enabled = true;
+
+	this.activate = activate;
+	this.deactivate = deactivate;
+	this.dispose = dispose;
+
+	// Backward compatibility
+
+	this.setObjects = function () {
+
+		console.error( 'THREE.DragControls: setObjects() has been removed.' );
+
+	};
+
+	this.on = function ( type, listener ) {
+
+		console.warn( 'THREE.DragControls: on() has been deprecated. Use addEventListener() instead.' );
+		scope.addEventListener( type, listener );
+
+	};
+
+	this.off = function ( type, listener ) {
+
+		console.warn( 'THREE.DragControls: off() has been deprecated. Use removeEventListener() instead.' );
+		scope.removeEventListener( type, listener );
+
+	};
+
+	this.notify = function ( type ) {
+
+		console.error( 'THREE.DragControls: notify() has been deprecated. Use dispatchEvent() instead.' );
+		scope.dispatchEvent( { type: type } );
+
+	};
+
+};
+
+THREE.DragControls.prototype = Object.create( THREE.EventDispatcher.prototype );
+THREE.DragControls.prototype.constructor = THREE.DragControls;

+ 793 - 0
static/libs/threejs/OBJLoader.js

@@ -0,0 +1,793 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+THREE.OBJLoader = ( function () {
+
+	// o object_name | g group_name
+	var object_pattern = /^[og]\s*(.+)?/;
+	// mtllib file_reference
+	var material_library_pattern = /^mtllib /;
+	// usemtl material_name
+	var material_use_pattern = /^usemtl /;
+
+	function ParserState() {
+
+		var state = {
+			objects: [],
+			object: {},
+
+			vertices: [],
+			normals: [],
+			colors: [],
+			uvs: [],
+
+			materialLibraries: [],
+
+			startObject: function ( name, fromDeclaration ) {
+
+				// If the current object (initial from reset) is not from a g/o declaration in the parsed
+				// file. We need to use it for the first parsed g/o to keep things in sync.
+				if ( this.object && this.object.fromDeclaration === false ) {
+
+					this.object.name = name;
+					this.object.fromDeclaration = ( fromDeclaration !== false );
+					return;
+
+				}
+
+				var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
+
+				if ( this.object && typeof this.object._finalize === 'function' ) {
+
+					this.object._finalize( true );
+
+				}
+
+				this.object = {
+					name: name || '',
+					fromDeclaration: ( fromDeclaration !== false ),
+
+					geometry: {
+						vertices: [],
+						normals: [],
+						colors: [],
+						uvs: []
+					},
+					materials: [],
+					smooth: true,
+
+					startMaterial: function ( name, libraries ) {
+
+						var previous = this._finalize( false );
+
+						// New usemtl declaration overwrites an inherited material, except if faces were declared
+						// after the material, then it must be preserved for proper MultiMaterial continuation.
+						if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
+
+							this.materials.splice( previous.index, 1 );
+
+						}
+
+						var material = {
+							index: this.materials.length,
+							name: name || '',
+							mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
+							smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
+							groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
+							groupEnd: - 1,
+							groupCount: - 1,
+							inherited: false,
+
+							clone: function ( index ) {
+
+								var cloned = {
+									index: ( typeof index === 'number' ? index : this.index ),
+									name: this.name,
+									mtllib: this.mtllib,
+									smooth: this.smooth,
+									groupStart: 0,
+									groupEnd: - 1,
+									groupCount: - 1,
+									inherited: false
+								};
+								cloned.clone = this.clone.bind( cloned );
+								return cloned;
+
+							}
+						};
+
+						this.materials.push( material );
+
+						return material;
+
+					},
+
+					currentMaterial: function () {
+
+						if ( this.materials.length > 0 ) {
+
+							return this.materials[ this.materials.length - 1 ];
+
+						}
+
+						return undefined;
+
+					},
+
+					_finalize: function ( end ) {
+
+						var lastMultiMaterial = this.currentMaterial();
+						if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
+
+							lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
+							lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
+							lastMultiMaterial.inherited = false;
+
+						}
+
+						// Ignore objects tail materials if no face declarations followed them before a new o/g started.
+						if ( end && this.materials.length > 1 ) {
+
+							for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) {
+
+								if ( this.materials[ mi ].groupCount <= 0 ) {
+
+									this.materials.splice( mi, 1 );
+
+								}
+
+							}
+
+						}
+
+						// Guarantee at least one empty material, this makes the creation later more straight forward.
+						if ( end && this.materials.length === 0 ) {
+
+							this.materials.push( {
+								name: '',
+								smooth: this.smooth
+							} );
+
+						}
+
+						return lastMultiMaterial;
+
+					}
+				};
+
+				// Inherit previous objects material.
+				// Spec tells us that a declared material must be set to all objects until a new material is declared.
+				// If a usemtl declaration is encountered while this new object is being parsed, it will
+				// overwrite the inherited material. Exception being that there was already face declarations
+				// to the inherited material, then it will be preserved for proper MultiMaterial continuation.
+
+				if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
+
+					var declared = previousMaterial.clone( 0 );
+					declared.inherited = true;
+					this.object.materials.push( declared );
+
+				}
+
+				this.objects.push( this.object );
+
+			},
+
+			finalize: function () {
+
+				if ( this.object && typeof this.object._finalize === 'function' ) {
+
+					this.object._finalize( true );
+
+				}
+
+			},
+
+			parseVertexIndex: function ( value, len ) {
+
+				var index = parseInt( value, 10 );
+				return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
+
+			},
+
+			parseNormalIndex: function ( value, len ) {
+
+				var index = parseInt( value, 10 );
+				return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
+
+			},
+
+			parseUVIndex: function ( value, len ) {
+
+				var index = parseInt( value, 10 );
+				return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
+
+			},
+
+			addVertex: function ( a, b, c ) {
+
+				var src = this.vertices;
+				var dst = this.object.geometry.vertices;
+
+				dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
+				dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
+				dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
+
+			},
+
+			addVertexPoint: function ( a ) {
+
+				var src = this.vertices;
+				var dst = this.object.geometry.vertices;
+
+				dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
+
+			},
+
+			addVertexLine: function ( a ) {
+
+				var src = this.vertices;
+				var dst = this.object.geometry.vertices;
+
+				dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
+
+			},
+
+			addNormal: function ( a, b, c ) {
+
+				var src = this.normals;
+				var dst = this.object.geometry.normals;
+
+				dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
+				dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
+				dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
+
+			},
+
+			addColor: function ( a, b, c ) {
+
+				var src = this.colors;
+				var dst = this.object.geometry.colors;
+
+				dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
+				dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
+				dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
+
+			},
+
+			addUV: function ( a, b, c ) {
+
+				var src = this.uvs;
+				var dst = this.object.geometry.uvs;
+
+				dst.push( src[ a + 0 ], src[ a + 1 ] );
+				dst.push( src[ b + 0 ], src[ b + 1 ] );
+				dst.push( src[ c + 0 ], src[ c + 1 ] );
+
+			},
+
+			addUVLine: function ( a ) {
+
+				var src = this.uvs;
+				var dst = this.object.geometry.uvs;
+
+				dst.push( src[ a + 0 ], src[ a + 1 ] );
+
+			},
+
+			addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
+
+				var vLen = this.vertices.length;
+
+				var ia = this.parseVertexIndex( a, vLen );
+				var ib = this.parseVertexIndex( b, vLen );
+				var ic = this.parseVertexIndex( c, vLen );
+
+				this.addVertex( ia, ib, ic );
+
+				if ( ua !== undefined && ua !== '' ) {
+
+					var uvLen = this.uvs.length;
+					ia = this.parseUVIndex( ua, uvLen );
+					ib = this.parseUVIndex( ub, uvLen );
+					ic = this.parseUVIndex( uc, uvLen );
+					this.addUV( ia, ib, ic );
+
+				}
+
+				if ( na !== undefined && na !== '' ) {
+
+					// Normals are many times the same. If so, skip function call and parseInt.
+					var nLen = this.normals.length;
+					ia = this.parseNormalIndex( na, nLen );
+
+					ib = na === nb ? ia : this.parseNormalIndex( nb, nLen );
+					ic = na === nc ? ia : this.parseNormalIndex( nc, nLen );
+
+					this.addNormal( ia, ib, ic );
+
+				}
+
+				if ( this.colors.length > 0 ) {
+
+					this.addColor( ia, ib, ic );
+
+				}
+
+			},
+
+			addPointGeometry: function ( vertices ) {
+
+				this.object.geometry.type = 'Points';
+
+				var vLen = this.vertices.length;
+
+				for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
+
+					this.addVertexPoint( this.parseVertexIndex( vertices[ vi ], vLen ) );
+
+				}
+
+			},
+
+			addLineGeometry: function ( vertices, uvs ) {
+
+				this.object.geometry.type = 'Line';
+
+				var vLen = this.vertices.length;
+				var uvLen = this.uvs.length;
+
+				for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
+
+					this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
+
+				}
+
+				for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
+
+					this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
+
+				}
+
+			}
+
+		};
+
+		state.startObject( '', false );
+
+		return state;
+
+	}
+
+	//
+
+	function OBJLoader( manager ) {
+
+		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+
+		this.materials = null;
+
+	}
+
+	OBJLoader.prototype = {
+
+		constructor: OBJLoader,
+
+		load: function ( url, onLoad, onProgress, onError ) {
+
+			var scope = this;
+
+			var loader = new THREE.FileLoader( scope.manager );
+			loader.setPath( this.path );
+			loader.load( url, function ( text ) {
+
+				onLoad( scope.parse( text ) );
+
+			}, onProgress, onError );
+
+		},
+
+		setPath: function ( value ) {
+
+			this.path = value;
+
+			return this;
+
+		},
+
+		setMaterials: function ( materials ) {
+
+			this.materials = materials;
+
+			return this;
+
+		},
+
+		parse: function ( text ) {
+
+			console.time( 'OBJLoader' );
+
+			var state = new ParserState();
+
+			if ( text.indexOf( '\r\n' ) !== - 1 ) {
+
+				// This is faster than String.split with regex that splits on both
+				text = text.replace( /\r\n/g, '\n' );
+
+			}
+
+			if ( text.indexOf( '\\\n' ) !== - 1 ) {
+
+				// join lines separated by a line continuation character (\)
+				text = text.replace( /\\\n/g, '' );
+
+			}
+
+			var lines = text.split( '\n' );
+			var line = '', lineFirstChar = '';
+			var lineLength = 0;
+			var result = [];
+
+			// Faster to just trim left side of the line. Use if available.
+			var trimLeft = ( typeof ''.trimLeft === 'function' );
+
+			for ( var i = 0, l = lines.length; i < l; i ++ ) {
+
+				line = lines[ i ];
+
+				line = trimLeft ? line.trimLeft() : line.trim();
+
+				lineLength = line.length;
+
+				if ( lineLength === 0 ) continue;
+
+				lineFirstChar = line.charAt( 0 );
+
+				// @todo invoke passed in handler if any
+				if ( lineFirstChar === '#' ) continue;
+
+				if ( lineFirstChar === 'v' ) {
+
+					var data = line.split( /\s+/ );
+
+					switch ( data[ 0 ] ) {
+
+						case 'v':
+							state.vertices.push(
+								parseFloat( data[ 1 ] ),
+								parseFloat( data[ 2 ] ),
+								parseFloat( data[ 3 ] )
+							);
+							if ( data.length === 8 ) {
+
+								state.colors.push(
+									parseFloat( data[ 4 ] ),
+									parseFloat( data[ 5 ] ),
+									parseFloat( data[ 6 ] )
+
+								);
+
+							}
+							break;
+						case 'vn':
+							state.normals.push(
+								parseFloat( data[ 1 ] ),
+								parseFloat( data[ 2 ] ),
+								parseFloat( data[ 3 ] )
+							);
+							break;
+						case 'vt':
+							state.uvs.push(
+								parseFloat( data[ 1 ] ),
+								parseFloat( data[ 2 ] )
+							);
+							break;
+
+					}
+
+				} else if ( lineFirstChar === 'f' ) {
+
+					var lineData = line.substr( 1 ).trim();
+					var vertexData = lineData.split( /\s+/ );
+					var faceVertices = [];
+
+					// Parse the face vertex data into an easy to work with format
+
+					for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) {
+
+						var vertex = vertexData[ j ];
+
+						if ( vertex.length > 0 ) {
+
+							var vertexParts = vertex.split( '/' );
+							faceVertices.push( vertexParts );
+
+						}
+
+					}
+
+					// Draw an edge between the first vertex and all subsequent vertices to form an n-gon
+
+					var v1 = faceVertices[ 0 ];
+
+					for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
+
+						var v2 = faceVertices[ j ];
+						var v3 = faceVertices[ j + 1 ];
+
+						state.addFace(
+							v1[ 0 ], v2[ 0 ], v3[ 0 ],
+							v1[ 1 ], v2[ 1 ], v3[ 1 ],
+							v1[ 2 ], v2[ 2 ], v3[ 2 ]
+						);
+
+					}
+
+				} else if ( lineFirstChar === 'l' ) {
+
+					var lineParts = line.substring( 1 ).trim().split( " " );
+					var lineVertices = [], lineUVs = [];
+
+					if ( line.indexOf( "/" ) === - 1 ) {
+
+						lineVertices = lineParts;
+
+					} else {
+
+						for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
+
+							var parts = lineParts[ li ].split( "/" );
+
+							if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
+							if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
+
+						}
+
+					}
+					state.addLineGeometry( lineVertices, lineUVs );
+
+				} else if ( lineFirstChar === 'p' ) {
+
+					var lineData = line.substr( 1 ).trim();
+					var pointData = lineData.split( " " );
+
+					state.addPointGeometry( pointData );
+
+				} else if ( ( result = object_pattern.exec( line ) ) !== null ) {
+
+					// o object_name
+					// or
+					// g group_name
+
+					// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
+					// var name = result[ 0 ].substr( 1 ).trim();
+					var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
+
+					state.startObject( name );
+
+				} else if ( material_use_pattern.test( line ) ) {
+
+					// material
+
+					state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
+
+				} else if ( material_library_pattern.test( line ) ) {
+
+					// mtl file
+
+					state.materialLibraries.push( line.substring( 7 ).trim() );
+
+				} else if ( lineFirstChar === 's' ) {
+
+					result = line.split( ' ' );
+
+					// smooth shading
+
+					// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
+					// but does not define a usemtl for each face set.
+					// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
+					// This requires some care to not create extra material on each smooth value for "normal" obj files.
+					// where explicit usemtl defines geometry groups.
+					// Example asset: examples/models/obj/cerberus/Cerberus.obj
+
+					/*
+					 * http://paulbourke.net/dataformats/obj/
+					 * or
+					 * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
+					 *
+					 * From chapter "Grouping" Syntax explanation "s group_number":
+					 * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
+					 * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
+					 * surfaces, smoothing groups are either turned on or off; there is no difference between values greater
+					 * than 0."
+					 */
+					if ( result.length > 1 ) {
+
+						var value = result[ 1 ].trim().toLowerCase();
+						state.object.smooth = ( value !== '0' && value !== 'off' );
+
+					} else {
+
+						// ZBrush can produce "s" lines #11707
+						state.object.smooth = true;
+
+					}
+					var material = state.object.currentMaterial();
+					if ( material ) material.smooth = state.object.smooth;
+
+				} else {
+
+					// Handle null terminated files without exception
+					if ( line === '\0' ) continue;
+
+					throw new Error( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
+
+				}
+
+			}
+
+			state.finalize();
+
+			var container = new THREE.Group();
+			container.materialLibraries = [].concat( state.materialLibraries );
+
+			for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
+
+				var object = state.objects[ i ];
+				var geometry = object.geometry;
+				var materials = object.materials;
+				var isLine = ( geometry.type === 'Line' );
+				var isPoints = ( geometry.type === 'Points' );
+				var hasVertexColors = false;
+
+				// Skip o/g line declarations that did not follow with any faces
+				if ( geometry.vertices.length === 0 ) continue;
+
+				var buffergeometry = new THREE.BufferGeometry();
+
+				buffergeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) );
+
+				if ( geometry.normals.length > 0 ) {
+
+					buffergeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) );
+
+				} else {
+
+					buffergeometry.computeVertexNormals();
+
+				}
+
+				if ( geometry.colors.length > 0 ) {
+
+					hasVertexColors = true;
+					buffergeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) );
+
+				}
+
+				if ( geometry.uvs.length > 0 ) {
+
+					buffergeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) );
+
+				}
+
+				// Create materials
+
+				var createdMaterials = [];
+
+				for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
+
+					var sourceMaterial = materials[ mi ];
+					var material = undefined;
+
+					if ( this.materials !== null ) {
+
+						material = this.materials.create( sourceMaterial.name );
+
+						// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
+						if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
+
+							var materialLine = new THREE.LineBasicMaterial();
+							materialLine.copy( material );
+							materialLine.lights = false; // TOFIX
+							material = materialLine;
+
+						} else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) {
+
+							var materialPoints = new THREE.PointsMaterial( { size: 10, sizeAttenuation: false } );
+							materialLine.copy( material );
+							material = materialPoints;
+
+						}
+
+					}
+
+					if ( ! material ) {
+
+						if ( isLine ) {
+
+							material = new THREE.LineBasicMaterial();
+
+						} else if ( isPoints ) {
+
+							material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
+
+						} else {
+
+							material = new THREE.MeshPhongMaterial();
+
+						}
+
+						material.name = sourceMaterial.name;
+
+					}
+
+					material.flatShading = sourceMaterial.smooth ? false : true;
+					material.vertexColors = hasVertexColors ? THREE.VertexColors : THREE.NoColors;
+
+					createdMaterials.push( material );
+
+				}
+
+				// Create mesh
+
+				var mesh;
+
+				if ( createdMaterials.length > 1 ) {
+
+					for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
+
+						var sourceMaterial = materials[ mi ];
+						buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
+
+					}
+
+					if ( isLine ) {
+
+						mesh = new THREE.LineSegments( buffergeometry, createdMaterials );
+
+					} else if ( isPoints ) {
+
+						mesh = new THREE.Points( buffergeometry, createdMaterials );
+
+					} else {
+
+						mesh = new THREE.Mesh( buffergeometry, createdMaterials );
+
+					}
+
+				} else {
+
+					if ( isLine ) {
+
+						mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] );
+
+					} else if ( isPoints ) {
+
+						mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] );
+
+					} else {
+
+						mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] );
+
+					}
+
+				}
+
+				mesh.name = object.name;
+
+				container.add( mesh );
+
+			}
+
+			console.timeEnd( 'OBJLoader' );
+
+			return container;
+
+		}
+
+	};
+
+	return OBJLoader;
+
+} )();

Разлика између датотеке није приказан због своје велике величине
+ 1039 - 0
static/libs/threejs/OrbitControls.js


+ 259 - 0
static/libs/threejs/ctm/CTMLoader.js

@@ -0,0 +1,259 @@
+/**
+ * Loader for CTM encoded models generated by OpenCTM tools:
+ *	http://openctm.sourceforge.net/
+ *
+ * Uses js-openctm library by Juan Mellado
+ *	http://code.google.com/p/js-openctm/
+ *
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+THREE.CTMLoader = function () {
+
+	THREE.Loader.call( this );
+
+};
+
+THREE.CTMLoader.prototype = Object.create( THREE.Loader.prototype );
+THREE.CTMLoader.prototype.constructor = THREE.CTMLoader;
+
+// Load multiple CTM parts defined in JSON
+
+THREE.CTMLoader.prototype.loadParts = function ( url, callback, parameters ) {
+
+	parameters = parameters || {};
+
+	var scope = this;
+
+	var xhr = new XMLHttpRequest();
+
+	var basePath = parameters.basePath ? parameters.basePath : THREE.LoaderUtils.extractUrlBase( url );
+
+	xhr.onreadystatechange = function () {
+
+		if ( xhr.readyState === 4 ) {
+
+			if ( xhr.status === 200 || xhr.status === 0 ) {
+
+				var jsonObject = JSON.parse( xhr.responseText );
+
+				var materials = [], geometries = [], counter = 0;
+
+				function callbackFinal( geometry ) {
+
+					counter += 1;
+
+					geometries.push( geometry );
+
+					if ( counter === jsonObject.offsets.length ) {
+
+						callback( geometries, materials );
+
+					}
+
+				}
+
+
+				// init materials
+
+				for ( var i = 0; i < jsonObject.materials.length; i ++ ) {
+
+					materials[ i ] = scope.createMaterial( jsonObject.materials[ i ], basePath );
+
+				}
+
+				// load joined CTM file
+
+				var partUrl = basePath + jsonObject.data;
+				var parametersPart = { useWorker: parameters.useWorker, worker: parameters.worker, offsets: jsonObject.offsets };
+				scope.load( partUrl, callbackFinal, parametersPart );
+
+			}
+
+		}
+
+	};
+
+	xhr.open( "GET", url, true );
+	xhr.setRequestHeader( "Content-Type", "text/plain" );
+	xhr.send( null );
+
+};
+
+// Load CTMLoader compressed models
+//	- parameters
+//		- url (required)
+//		- callback (required)
+
+THREE.CTMLoader.prototype.load = function ( url, callback, parameters ) {
+
+	parameters = parameters || {};
+
+	var scope = this;
+
+	var offsets = parameters.offsets !== undefined ? parameters.offsets : [ 0 ];
+
+	var xhr = new XMLHttpRequest(),
+		callbackProgress = null;
+
+	var length = 0;
+
+	xhr.onreadystatechange = function () {
+
+		if ( xhr.readyState === 4 ) {
+
+			if ( xhr.status === 200 || xhr.status === 0 ) {
+
+				var binaryData = new Uint8Array( xhr.response );
+
+				var s = Date.now();
+
+				if ( parameters.useWorker ) {
+
+					var worker = parameters.worker || new Worker( 'static/public/threejs/ctm/CTMWorker.js' );
+
+					worker.onmessage = function ( event ) {
+
+						var files = event.data;
+
+						for ( var i = 0; i < files.length; i ++ ) {
+
+							var ctmFile = files[ i ];
+
+							var e1 = Date.now();
+							// console.log( "CTM data parse time [worker]: " + (e1-s) + " ms" );
+
+							scope.createModel( ctmFile, callback );
+
+							var e = Date.now();
+							console.log( "model load time [worker]: " + ( e - e1 ) + " ms, total: " + ( e - s ) );
+
+						}
+
+
+					};
+
+					worker.postMessage( { "data": binaryData, "offsets": offsets }, [ binaryData.buffer ] );
+
+				} else {
+
+					for ( var i = 0; i < offsets.length; i ++ ) {
+
+						var stream = new CTM.Stream( binaryData );
+						stream.offset = offsets[ i ];
+
+						var ctmFile = new CTM.File( stream );
+
+						scope.createModel( ctmFile, callback );
+
+					}
+
+					//var e = Date.now();
+					//console.log( "CTM data parse time [inline]: " + (e-s) + " ms" );
+
+				}
+
+			} else {
+
+				console.error( "Couldn't load [" + url + "] [" + xhr.status + "]" );
+
+			}
+
+		} else if ( xhr.readyState === 3 ) {
+
+			if ( callbackProgress ) {
+
+				if ( length === 0 ) {
+
+					length = xhr.getResponseHeader( "Content-Length" );
+
+				}
+
+				callbackProgress( { total: length, loaded: xhr.responseText.length } );
+
+			}
+
+		} else if ( xhr.readyState === 2 ) {
+
+			length = xhr.getResponseHeader( "Content-Length" );
+
+		}
+
+	};
+
+	xhr.open( "GET", url, true );
+	xhr.responseType = "arraybuffer";
+
+	xhr.send( null );
+
+};
+
+
+THREE.CTMLoader.prototype.createModel = function ( file, callback ) {
+
+	var Model = function () {
+
+		THREE.BufferGeometry.call( this );
+
+		this.materials = [];
+
+		var indices = file.body.indices;
+		var positions = file.body.vertices;
+		var normals = file.body.normals;
+
+		var uvs, colors;
+
+		var uvMaps = file.body.uvMaps;
+
+		if ( uvMaps !== undefined && uvMaps.length > 0 ) {
+
+			uvs = uvMaps[ 0 ].uv;
+
+		}
+
+		var attrMaps = file.body.attrMaps;
+
+		if ( attrMaps !== undefined && attrMaps.length > 0 && attrMaps[ 0 ].name === 'Color' ) {
+
+			colors = attrMaps[ 0 ].attr;
+
+		}
+
+		this.setIndex( new THREE.BufferAttribute( indices, 1 ) );
+		this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
+
+		if ( normals !== undefined ) {
+
+			this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
+
+		}
+
+		if ( uvs !== undefined ) {
+
+			this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
+
+		}
+
+		if ( colors !== undefined ) {
+
+			this.addAttribute( 'color', new THREE.BufferAttribute( colors, 4 ) );
+
+		}
+
+	};
+
+	Model.prototype = Object.create( THREE.BufferGeometry.prototype );
+	Model.prototype.constructor = Model;
+
+	var geometry = new Model();
+
+	// compute vertex normals if not present in the CTM model
+	if ( geometry.attributes.normal === undefined ) {
+
+		geometry.computeVertexNormals();
+
+	}
+
+	callback( geometry );
+
+};

+ 19 - 0
static/libs/threejs/ctm/CTMWorker.js

@@ -0,0 +1,19 @@
+importScripts( "lzma.js", "ctm.js" );
+
+self.onmessage = function ( event ) {
+
+	var files = [];
+
+	for ( var i = 0; i < event.data.offsets.length; i ++ ) {
+
+		var stream = new CTM.Stream( event.data.data );
+		stream.offset = event.data.offsets[ i ];
+
+		files[ i ] = new CTM.File( stream, [ event.data.data.buffer ] );
+
+	}
+
+	self.postMessage( files );
+	self.close();
+
+};

+ 658 - 0
static/libs/threejs/ctm/ctm.js

@@ -0,0 +1,658 @@
+/*
+Copyright (c) 2011 Juan Mellado
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/*
+References:
+- "OpenCTM: The Open Compressed Triangle Mesh file format" by Marcus Geelnard
+  http://openctm.sourceforge.net/
+*/
+
+var CTM = CTM || {};
+
+// browserify support
+if ( typeof module === 'object' ) {
+
+	module.exports = CTM;
+
+}
+
+CTM.CompressionMethod = {
+  RAW: 0x00574152,
+  MG1: 0x0031474d,
+  MG2: 0x0032474d
+};
+
+CTM.Flags = {
+  NORMALS: 0x00000001
+};
+
+CTM.File = function(stream) {
+	this.load(stream);
+};
+
+CTM.File.prototype.load = function(stream) {
+	this.header = new CTM.FileHeader(stream);
+
+	this.body = new CTM.FileBody(this.header);
+
+	this.getReader().read(stream, this.body);
+};
+
+CTM.File.prototype.getReader = function() {
+	var reader;
+
+	switch (this.header.compressionMethod){
+		case CTM.CompressionMethod.RAW:
+			reader = new CTM.ReaderRAW();
+			break;
+		case CTM.CompressionMethod.MG1:
+			reader = new CTM.ReaderMG1();
+			break;
+		case CTM.CompressionMethod.MG2:
+			reader = new CTM.ReaderMG2();
+			break;
+	}
+
+	return reader;
+};
+
+CTM.FileHeader = function(stream) {
+	stream.readInt32(); //magic "OCTM"
+	this.fileFormat = stream.readInt32();
+	this.compressionMethod = stream.readInt32();
+	this.vertexCount = stream.readInt32();
+	this.triangleCount = stream.readInt32();
+	this.uvMapCount = stream.readInt32();
+	this.attrMapCount = stream.readInt32();
+	this.flags = stream.readInt32();
+	this.comment = stream.readString();
+};
+
+CTM.FileHeader.prototype.hasNormals = function() {
+	return this.flags & CTM.Flags.NORMALS;
+};
+
+CTM.FileBody = function(header) {
+	var i = header.triangleCount * 3,
+      v = header.vertexCount * 3,
+      n = header.hasNormals() ? header.vertexCount * 3 : 0,
+      u = header.vertexCount * 2,
+      a = header.vertexCount * 4,
+      j = 0;
+
+	var data = new ArrayBuffer(
+    (i + v + n + (u * header.uvMapCount) + (a * header.attrMapCount) ) * 4);
+
+	this.indices = new Uint32Array(data, 0, i);
+
+	this.vertices = new Float32Array(data, i * 4, v);
+
+	if ( header.hasNormals() ) {
+		this.normals = new Float32Array(data, (i + v) * 4, n);
+	}
+
+	if (header.uvMapCount) {
+		this.uvMaps = [];
+		for (j = 0; j < header.uvMapCount; ++ j) {
+			this.uvMaps[j] = { uv: new Float32Array(data,
+        (i + v + n + (j * u) ) * 4, u) };
+		}
+	}
+
+	if (header.attrMapCount) {
+		this.attrMaps = [];
+		for (j = 0; j < header.attrMapCount; ++ j) {
+			this.attrMaps[j] = { attr: new Float32Array(data,
+        (i + v + n + (u * header.uvMapCount) + (j * a) ) * 4, a) };
+		}
+	}
+};
+
+CTM.FileMG2Header = function(stream) {
+	stream.readInt32(); //magic "MG2H"
+	this.vertexPrecision = stream.readFloat32();
+	this.normalPrecision = stream.readFloat32();
+	this.lowerBoundx = stream.readFloat32();
+	this.lowerBoundy = stream.readFloat32();
+	this.lowerBoundz = stream.readFloat32();
+	this.higherBoundx = stream.readFloat32();
+	this.higherBoundy = stream.readFloat32();
+	this.higherBoundz = stream.readFloat32();
+	this.divx = stream.readInt32();
+	this.divy = stream.readInt32();
+	this.divz = stream.readInt32();
+
+	this.sizex = (this.higherBoundx - this.lowerBoundx) / this.divx;
+	this.sizey = (this.higherBoundy - this.lowerBoundy) / this.divy;
+	this.sizez = (this.higherBoundz - this.lowerBoundz) / this.divz;
+};
+
+CTM.ReaderRAW = function() {
+};
+
+CTM.ReaderRAW.prototype.read = function(stream, body) {
+	this.readIndices(stream, body.indices);
+	this.readVertices(stream, body.vertices);
+
+	if (body.normals) {
+		this.readNormals(stream, body.normals);
+	}
+	if (body.uvMaps) {
+		this.readUVMaps(stream, body.uvMaps);
+	}
+	if (body.attrMaps) {
+		this.readAttrMaps(stream, body.attrMaps);
+	}
+};
+
+CTM.ReaderRAW.prototype.readIndices = function(stream, indices) {
+	stream.readInt32(); //magic "INDX"
+	stream.readArrayInt32(indices);
+};
+
+CTM.ReaderRAW.prototype.readVertices = function(stream, vertices) {
+	stream.readInt32(); //magic "VERT"
+	stream.readArrayFloat32(vertices);
+};
+
+CTM.ReaderRAW.prototype.readNormals = function(stream, normals) {
+	stream.readInt32(); //magic "NORM"
+	stream.readArrayFloat32(normals);
+};
+
+CTM.ReaderRAW.prototype.readUVMaps = function(stream, uvMaps) {
+	var i = 0;
+	for (; i < uvMaps.length; ++ i) {
+		stream.readInt32(); //magic "TEXC"
+
+		uvMaps[i].name = stream.readString();
+		uvMaps[i].filename = stream.readString();
+		stream.readArrayFloat32(uvMaps[i].uv);
+	}
+};
+
+CTM.ReaderRAW.prototype.readAttrMaps = function(stream, attrMaps) {
+	var i = 0;
+	for (; i < attrMaps.length; ++ i) {
+		stream.readInt32(); //magic "ATTR"
+
+		attrMaps[i].name = stream.readString();
+		stream.readArrayFloat32(attrMaps[i].attr);
+	}
+};
+
+CTM.ReaderMG1 = function() {
+};
+
+CTM.ReaderMG1.prototype.read = function(stream, body) {
+	this.readIndices(stream, body.indices);
+	this.readVertices(stream, body.vertices);
+
+	if (body.normals) {
+		this.readNormals(stream, body.normals);
+	}
+	if (body.uvMaps) {
+		this.readUVMaps(stream, body.uvMaps);
+	}
+	if (body.attrMaps) {
+		this.readAttrMaps(stream, body.attrMaps);
+	}
+};
+
+CTM.ReaderMG1.prototype.readIndices = function(stream, indices) {
+	stream.readInt32(); //magic "INDX"
+	stream.readInt32(); //packed size
+
+	var interleaved = new CTM.InterleavedStream(indices, 3);
+	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+
+	CTM.restoreIndices(indices, indices.length);
+};
+
+CTM.ReaderMG1.prototype.readVertices = function(stream, vertices) {
+	stream.readInt32(); //magic "VERT"
+	stream.readInt32(); //packed size
+
+	var interleaved = new CTM.InterleavedStream(vertices, 1);
+	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+};
+
+CTM.ReaderMG1.prototype.readNormals = function(stream, normals) {
+	stream.readInt32(); //magic "NORM"
+	stream.readInt32(); //packed size
+
+	var interleaved = new CTM.InterleavedStream(normals, 3);
+	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+};
+
+CTM.ReaderMG1.prototype.readUVMaps = function(stream, uvMaps) {
+	var i = 0;
+	for (; i < uvMaps.length; ++ i) {
+		stream.readInt32(); //magic "TEXC"
+
+		uvMaps[i].name = stream.readString();
+		uvMaps[i].filename = stream.readString();
+
+		stream.readInt32(); //packed size
+
+		var interleaved = new CTM.InterleavedStream(uvMaps[i].uv, 2);
+		LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+	}
+};
+
+CTM.ReaderMG1.prototype.readAttrMaps = function(stream, attrMaps) {
+	var i = 0;
+	for (; i < attrMaps.length; ++ i) {
+		stream.readInt32(); //magic "ATTR"
+
+		attrMaps[i].name = stream.readString();
+
+		stream.readInt32(); //packed size
+
+		var interleaved = new CTM.InterleavedStream(attrMaps[i].attr, 4);
+		LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+	}
+};
+
+CTM.ReaderMG2 = function() {
+};
+
+CTM.ReaderMG2.prototype.read = function(stream, body) {
+	this.MG2Header = new CTM.FileMG2Header(stream);
+
+	this.readVertices(stream, body.vertices);
+	this.readIndices(stream, body.indices);
+
+	if (body.normals) {
+		this.readNormals(stream, body);
+	}
+	if (body.uvMaps) {
+		this.readUVMaps(stream, body.uvMaps);
+	}
+	if (body.attrMaps) {
+		this.readAttrMaps(stream, body.attrMaps);
+	}
+};
+
+CTM.ReaderMG2.prototype.readVertices = function(stream, vertices) {
+	stream.readInt32(); //magic "VERT"
+	stream.readInt32(); //packed size
+
+	var interleaved = new CTM.InterleavedStream(vertices, 3);
+	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+
+	var gridIndices = this.readGridIndices(stream, vertices);
+
+	CTM.restoreVertices(vertices, this.MG2Header, gridIndices, this.MG2Header.vertexPrecision);
+};
+
+CTM.ReaderMG2.prototype.readGridIndices = function(stream, vertices) {
+	stream.readInt32(); //magic "GIDX"
+	stream.readInt32(); //packed size
+
+	var gridIndices = new Uint32Array(vertices.length / 3);
+
+	var interleaved = new CTM.InterleavedStream(gridIndices, 1);
+	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+
+	CTM.restoreGridIndices(gridIndices, gridIndices.length);
+
+	return gridIndices;
+};
+
+CTM.ReaderMG2.prototype.readIndices = function(stream, indices) {
+	stream.readInt32(); //magic "INDX"
+	stream.readInt32(); //packed size
+
+	var interleaved = new CTM.InterleavedStream(indices, 3);
+	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+
+	CTM.restoreIndices(indices, indices.length);
+};
+
+CTM.ReaderMG2.prototype.readNormals = function(stream, body) {
+	stream.readInt32(); //magic "NORM"
+	stream.readInt32(); //packed size
+
+	var interleaved = new CTM.InterleavedStream(body.normals, 3);
+	LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+
+	var smooth = CTM.calcSmoothNormals(body.indices, body.vertices);
+
+	CTM.restoreNormals(body.normals, smooth, this.MG2Header.normalPrecision);
+};
+
+CTM.ReaderMG2.prototype.readUVMaps = function(stream, uvMaps) {
+	var i = 0;
+	for (; i < uvMaps.length; ++ i) {
+		stream.readInt32(); //magic "TEXC"
+
+		uvMaps[i].name = stream.readString();
+		uvMaps[i].filename = stream.readString();
+
+		var precision = stream.readFloat32();
+
+		stream.readInt32(); //packed size
+
+		var interleaved = new CTM.InterleavedStream(uvMaps[i].uv, 2);
+		LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+
+		CTM.restoreMap(uvMaps[i].uv, 2, precision);
+	}
+};
+
+CTM.ReaderMG2.prototype.readAttrMaps = function(stream, attrMaps) {
+	var i = 0;
+	for (; i < attrMaps.length; ++ i) {
+		stream.readInt32(); //magic "ATTR"
+
+		attrMaps[i].name = stream.readString();
+
+		var precision = stream.readFloat32();
+
+		stream.readInt32(); //packed size
+
+		var interleaved = new CTM.InterleavedStream(attrMaps[i].attr, 4);
+		LZMA.decompress(stream, stream, interleaved, interleaved.data.length);
+
+		CTM.restoreMap(attrMaps[i].attr, 4, precision);
+	}
+};
+
+CTM.restoreIndices = function(indices, len) {
+	var i = 3;
+	if (len > 0) {
+		indices[2] += indices[0];
+		indices[1] += indices[0];
+	}
+	for (; i < len; i += 3) {
+		indices[i] += indices[i - 3];
+
+		if (indices[i] === indices[i - 3]) {
+			indices[i + 1] += indices[i - 2];
+		}else {
+			indices[i + 1] += indices[i];
+		}
+
+		indices[i + 2] += indices[i];
+	}
+};
+
+CTM.restoreGridIndices = function(gridIndices, len) {
+	var i = 1;
+	for (; i < len; ++ i) {
+		gridIndices[i] += gridIndices[i - 1];
+	}
+};
+
+CTM.restoreVertices = function(vertices, grid, gridIndices, precision) {
+	var gridIdx, delta, x, y, z,
+      intVertices = new Uint32Array(vertices.buffer, vertices.byteOffset, vertices.length),
+      ydiv = grid.divx, zdiv = ydiv * grid.divy,
+      prevGridIdx = 0x7fffffff, prevDelta = 0,
+      i = 0, j = 0, len = gridIndices.length;
+
+	for (; i < len; j += 3) {
+		x = gridIdx = gridIndices[i ++];
+
+		z = ~~(x / zdiv);
+		x -= ~~(z * zdiv);
+		y = ~~(x / ydiv);
+		x -= ~~(y * ydiv);
+
+		delta = intVertices[j];
+		if (gridIdx === prevGridIdx) {
+			delta += prevDelta;
+		}
+
+		vertices[j]     = grid.lowerBoundx +
+      x * grid.sizex + precision * delta;
+		vertices[j + 1] = grid.lowerBoundy +
+      y * grid.sizey + precision * intVertices[j + 1];
+		vertices[j + 2] = grid.lowerBoundz +
+      z * grid.sizez + precision * intVertices[j + 2];
+
+		prevGridIdx = gridIdx;
+		prevDelta = delta;
+	}
+};
+
+CTM.restoreNormals = function(normals, smooth, precision) {
+	var ro, phi, theta, sinPhi,
+      nx, ny, nz, by, bz, len,
+      intNormals = new Uint32Array(normals.buffer, normals.byteOffset, normals.length),
+      i = 0, k = normals.length,
+      PI_DIV_2 = 3.141592653589793238462643 * 0.5;
+
+	for (; i < k; i += 3) {
+		ro = intNormals[i] * precision;
+		phi = intNormals[i + 1];
+
+		if (phi === 0) {
+			normals[i]     = smooth[i]     * ro;
+			normals[i + 1] = smooth[i + 1] * ro;
+			normals[i + 2] = smooth[i + 2] * ro;
+		}else {
+
+			if (phi <= 4) {
+				theta = (intNormals[i + 2] - 2) * PI_DIV_2;
+			}else {
+				theta = ( (intNormals[i + 2] * 4 / phi) - 2) * PI_DIV_2;
+			}
+
+			phi *= precision * PI_DIV_2;
+			sinPhi = ro * Math.sin(phi);
+
+			nx = sinPhi * Math.cos(theta);
+			ny = sinPhi * Math.sin(theta);
+			nz = ro * Math.cos(phi);
+
+			bz = smooth[i + 1];
+			by = smooth[i] - smooth[i + 2];
+
+			len = Math.sqrt(2 * bz * bz + by * by);
+			if (len > 1e-20) {
+				by /= len;
+				bz /= len;
+			}
+
+			normals[i] = smooth[i] * nz + (smooth[i + 1] * bz - smooth[i + 2] * by) * ny - bz * nx;
+			normals[i + 1] = smooth[i + 1] * nz - (smooth[i + 2] + smooth[i]) * bz  * ny + by * nx;
+			normals[i + 2] = smooth[i + 2] * nz + (smooth[i] * by + smooth[i + 1] * bz) * ny + bz * nx;
+		}
+	}
+};
+
+CTM.restoreMap = function(map, count, precision) {
+	var delta, value,
+      intMap = new Uint32Array(map.buffer, map.byteOffset, map.length),
+      i = 0, j, len = map.length;
+
+	for (; i < count; ++ i) {
+		delta = 0;
+
+		for (j = i; j < len; j += count) {
+			value = intMap[j];
+
+			delta += value & 1 ? -( (value + 1) >> 1) : value >> 1;
+
+			map[j] = delta * precision;
+		}
+	}
+};
+
+CTM.calcSmoothNormals = function(indices, vertices) {
+	var smooth = new Float32Array(vertices.length),
+      indx, indy, indz, nx, ny, nz,
+      v1x, v1y, v1z, v2x, v2y, v2z, len,
+      i, k;
+
+	for (i = 0, k = indices.length; i < k;) {
+		indx = indices[i ++] * 3;
+		indy = indices[i ++] * 3;
+		indz = indices[i ++] * 3;
+
+		v1x = vertices[indy]     - vertices[indx];
+		v2x = vertices[indz]     - vertices[indx];
+		v1y = vertices[indy + 1] - vertices[indx + 1];
+		v2y = vertices[indz + 1] - vertices[indx + 1];
+		v1z = vertices[indy + 2] - vertices[indx + 2];
+		v2z = vertices[indz + 2] - vertices[indx + 2];
+
+		nx = v1y * v2z - v1z * v2y;
+		ny = v1z * v2x - v1x * v2z;
+		nz = v1x * v2y - v1y * v2x;
+
+		len = Math.sqrt(nx * nx + ny * ny + nz * nz);
+		if (len > 1e-10) {
+			nx /= len;
+			ny /= len;
+			nz /= len;
+		}
+
+		smooth[indx]     += nx;
+		smooth[indx + 1] += ny;
+		smooth[indx + 2] += nz;
+		smooth[indy]     += nx;
+		smooth[indy + 1] += ny;
+		smooth[indy + 2] += nz;
+		smooth[indz]     += nx;
+		smooth[indz + 1] += ny;
+		smooth[indz + 2] += nz;
+	}
+
+	for (i = 0, k = smooth.length; i < k; i += 3) {
+		len = Math.sqrt(smooth[i] * smooth[i] +
+      smooth[i + 1] * smooth[i + 1] +
+      smooth[i + 2] * smooth[i + 2]);
+
+		if (len > 1e-10) {
+			smooth[i]     /= len;
+			smooth[i + 1] /= len;
+			smooth[i + 2] /= len;
+		}
+	}
+
+	return smooth;
+};
+
+CTM.isLittleEndian = (function() {
+	var buffer = new ArrayBuffer(2),
+      bytes = new Uint8Array(buffer),
+      ints = new Uint16Array(buffer);
+
+	bytes[0] = 1;
+
+	return ints[0] === 1;
+}());
+
+CTM.InterleavedStream = function(data, count) {
+	this.data = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
+	this.offset = CTM.isLittleEndian ? 3 : 0;
+	this.count = count * 4;
+	this.len = this.data.length;
+};
+
+CTM.InterleavedStream.prototype.writeByte = function(value) {
+	this.data[this.offset] = value;
+
+	this.offset += this.count;
+	if (this.offset >= this.len) {
+
+		this.offset -= this.len - 4;
+		if (this.offset >= this.count) {
+
+			this.offset -= this.count + (CTM.isLittleEndian ? 1 : -1);
+		}
+	}
+};
+
+CTM.Stream = function(data) {
+	this.data = data;
+	this.offset = 0;
+};
+
+CTM.Stream.prototype.TWO_POW_MINUS23 = Math.pow(2, -23);
+
+CTM.Stream.prototype.TWO_POW_MINUS126 = Math.pow(2, -126);
+
+CTM.Stream.prototype.readByte = function() {
+	return this.data[this.offset ++] & 0xff;
+};
+
+CTM.Stream.prototype.readInt32 = function() {
+	var i = this.readByte();
+	i |= this.readByte() << 8;
+	i |= this.readByte() << 16;
+	return i | (this.readByte() << 24);
+};
+
+CTM.Stream.prototype.readFloat32 = function() {
+	var m = this.readByte();
+	m += this.readByte() << 8;
+
+	var b1 = this.readByte();
+	var b2 = this.readByte();
+
+	m += (b1 & 0x7f) << 16;
+	var e = ( (b2 & 0x7f) << 1) | ( (b1 & 0x80) >>> 7);
+	var s = b2 & 0x80 ? -1 : 1;
+
+	if (e === 255) {
+		return m !== 0 ? NaN : s * Infinity;
+	}
+	if (e > 0) {
+		return s * (1 + (m * this.TWO_POW_MINUS23) ) * Math.pow(2, e - 127);
+	}
+	if (m !== 0) {
+		return s * m * this.TWO_POW_MINUS126;
+	}
+	return s * 0;
+};
+
+CTM.Stream.prototype.readString = function() {
+	var len = this.readInt32();
+
+	this.offset += len;
+
+	return String.fromCharCode.apply(null, this.data.subarray(this.offset - len, this.offset));
+};
+
+CTM.Stream.prototype.readArrayInt32 = function(array) {
+	var i = 0, len = array.length;
+
+	while (i < len) {
+		array[i ++] = this.readInt32();
+	}
+
+	return array;
+};
+
+CTM.Stream.prototype.readArrayFloat32 = function(array) {
+	var i = 0, len = array.length;
+
+	while (i < len) {
+		array[i ++] = this.readFloat32();
+	}
+
+	return array;
+};

+ 517 - 0
static/libs/threejs/ctm/lzma.js

@@ -0,0 +1,517 @@
+
+var LZMA = LZMA || {};
+
+// browserify support
+if ( typeof module === 'object' ) {
+
+	module.exports = LZMA;
+
+}
+
+LZMA.OutWindow = function() {
+	this._windowSize = 0;
+};
+
+LZMA.OutWindow.prototype.create = function(windowSize) {
+	if ( (!this._buffer) || (this._windowSize !== windowSize) ) {
+		this._buffer = [];
+	}
+	this._windowSize = windowSize;
+	this._pos = 0;
+	this._streamPos = 0;
+};
+
+LZMA.OutWindow.prototype.flush = function() {
+	var size = this._pos - this._streamPos;
+	if (size !== 0) {
+		while (size --) {
+			this._stream.writeByte(this._buffer[this._streamPos ++]);
+		}
+		if (this._pos >= this._windowSize) {
+			this._pos = 0;
+		}
+		this._streamPos = this._pos;
+	}
+};
+
+LZMA.OutWindow.prototype.releaseStream = function() {
+	this.flush();
+	this._stream = null;
+};
+
+LZMA.OutWindow.prototype.setStream = function(stream) {
+	this.releaseStream();
+	this._stream = stream;
+};
+
+LZMA.OutWindow.prototype.init = function(solid) {
+	if (!solid) {
+		this._streamPos = 0;
+		this._pos = 0;
+	}
+};
+
+LZMA.OutWindow.prototype.copyBlock = function(distance, len) {
+	var pos = this._pos - distance - 1;
+	if (pos < 0) {
+		pos += this._windowSize;
+	}
+	while (len --) {
+		if (pos >= this._windowSize) {
+			pos = 0;
+		}
+		this._buffer[this._pos ++] = this._buffer[pos ++];
+		if (this._pos >= this._windowSize) {
+			this.flush();
+		}
+	}
+};
+
+LZMA.OutWindow.prototype.putByte = function(b) {
+	this._buffer[this._pos ++] = b;
+	if (this._pos >= this._windowSize) {
+		this.flush();
+	}
+};
+
+LZMA.OutWindow.prototype.getByte = function(distance) {
+	var pos = this._pos - distance - 1;
+	if (pos < 0) {
+		pos += this._windowSize;
+	}
+	return this._buffer[pos];
+};
+
+LZMA.RangeDecoder = function() {
+};
+
+LZMA.RangeDecoder.prototype.setStream = function(stream) {
+	this._stream = stream;
+};
+
+LZMA.RangeDecoder.prototype.releaseStream = function() {
+	this._stream = null;
+};
+
+LZMA.RangeDecoder.prototype.init = function() {
+	var i = 5;
+
+	this._code = 0;
+	this._range = -1;
+  
+	while (i --) {
+		this._code = (this._code << 8) | this._stream.readByte();
+	}
+};
+
+LZMA.RangeDecoder.prototype.decodeDirectBits = function(numTotalBits) {
+	var result = 0, i = numTotalBits, t;
+
+	while (i --) {
+		this._range >>>= 1;
+		t = (this._code - this._range) >>> 31;
+		this._code -= this._range & (t - 1);
+		result = (result << 1) | (1 - t);
+
+		if ( (this._range & 0xff000000) === 0) {
+			this._code = (this._code << 8) | this._stream.readByte();
+			this._range <<= 8;
+		}
+	}
+
+	return result;
+};
+
+LZMA.RangeDecoder.prototype.decodeBit = function(probs, index) {
+	var prob = probs[index],
+      newBound = (this._range >>> 11) * prob;
+
+	if ( (this._code ^ 0x80000000) < (newBound ^ 0x80000000) ) {
+		this._range = newBound;
+		probs[index] += (2048 - prob) >>> 5;
+		if ( (this._range & 0xff000000) === 0) {
+			this._code = (this._code << 8) | this._stream.readByte();
+			this._range <<= 8;
+		}
+		return 0;
+	}
+
+	this._range -= newBound;
+	this._code -= newBound;
+	probs[index] -= prob >>> 5;
+	if ( (this._range & 0xff000000) === 0) {
+		this._code = (this._code << 8) | this._stream.readByte();
+		this._range <<= 8;
+	}
+	return 1;
+};
+
+LZMA.initBitModels = function(probs, len) {
+	while (len --) {
+		probs[len] = 1024;
+	}
+};
+
+LZMA.BitTreeDecoder = function(numBitLevels) {
+	this._models = [];
+	this._numBitLevels = numBitLevels;
+};
+
+LZMA.BitTreeDecoder.prototype.init = function() {
+	LZMA.initBitModels(this._models, 1 << this._numBitLevels);
+};
+
+LZMA.BitTreeDecoder.prototype.decode = function(rangeDecoder) {
+	var m = 1, i = this._numBitLevels;
+
+	while (i --) {
+		m = (m << 1) | rangeDecoder.decodeBit(this._models, m);
+	}
+	return m - (1 << this._numBitLevels);
+};
+
+LZMA.BitTreeDecoder.prototype.reverseDecode = function(rangeDecoder) {
+	var m = 1, symbol = 0, i = 0, bit;
+
+	for (; i < this._numBitLevels; ++ i) {
+		bit = rangeDecoder.decodeBit(this._models, m);
+		m = (m << 1) | bit;
+		symbol |= bit << i;
+	}
+	return symbol;
+};
+
+LZMA.reverseDecode2 = function(models, startIndex, rangeDecoder, numBitLevels) {
+	var m = 1, symbol = 0, i = 0, bit;
+
+	for (; i < numBitLevels; ++ i) {
+		bit = rangeDecoder.decodeBit(models, startIndex + m);
+		m = (m << 1) | bit;
+		symbol |= bit << i;
+	}
+	return symbol;
+};
+
+LZMA.LenDecoder = function() {
+	this._choice = [];
+	this._lowCoder = [];
+	this._midCoder = [];
+	this._highCoder = new LZMA.BitTreeDecoder(8);
+	this._numPosStates = 0;
+};
+
+LZMA.LenDecoder.prototype.create = function(numPosStates) {
+	for (; this._numPosStates < numPosStates; ++ this._numPosStates) {
+		this._lowCoder[this._numPosStates] = new LZMA.BitTreeDecoder(3);
+		this._midCoder[this._numPosStates] = new LZMA.BitTreeDecoder(3);
+	}
+};
+
+LZMA.LenDecoder.prototype.init = function() {
+	var i = this._numPosStates;
+	LZMA.initBitModels(this._choice, 2);
+	while (i --) {
+		this._lowCoder[i].init();
+		this._midCoder[i].init();
+	}
+	this._highCoder.init();
+};
+
+LZMA.LenDecoder.prototype.decode = function(rangeDecoder, posState) {
+	if (rangeDecoder.decodeBit(this._choice, 0) === 0) {
+		return this._lowCoder[posState].decode(rangeDecoder);
+	}
+	if (rangeDecoder.decodeBit(this._choice, 1) === 0) {
+		return 8 + this._midCoder[posState].decode(rangeDecoder);
+	}
+	return 16 + this._highCoder.decode(rangeDecoder);
+};
+
+LZMA.Decoder2 = function() {
+	this._decoders = [];
+};
+
+LZMA.Decoder2.prototype.init = function() {
+	LZMA.initBitModels(this._decoders, 0x300);
+};
+
+LZMA.Decoder2.prototype.decodeNormal = function(rangeDecoder) {
+	var symbol = 1;
+
+	do {
+		symbol = (symbol << 1) | rangeDecoder.decodeBit(this._decoders, symbol);
+	}while (symbol < 0x100);
+
+	return symbol & 0xff;
+};
+
+LZMA.Decoder2.prototype.decodeWithMatchByte = function(rangeDecoder, matchByte) {
+	var symbol = 1, matchBit, bit;
+
+	do {
+		matchBit = (matchByte >> 7) & 1;
+		matchByte <<= 1;
+		bit = rangeDecoder.decodeBit(this._decoders, ( (1 + matchBit) << 8) + symbol);
+		symbol = (symbol << 1) | bit;
+		if (matchBit !== bit) {
+			while (symbol < 0x100) {
+				symbol = (symbol << 1) | rangeDecoder.decodeBit(this._decoders, symbol);
+			}
+			break;
+		}
+	}while (symbol < 0x100);
+
+	return symbol & 0xff;
+};
+
+LZMA.LiteralDecoder = function() {
+};
+
+LZMA.LiteralDecoder.prototype.create = function(numPosBits, numPrevBits) {
+	var i;
+
+	if (this._coders
+    && (this._numPrevBits === numPrevBits)
+    && (this._numPosBits === numPosBits) ) {
+		return;
+	}
+	this._numPosBits = numPosBits;
+	this._posMask = (1 << numPosBits) - 1;
+	this._numPrevBits = numPrevBits;
+
+	this._coders = [];
+
+	i = 1 << (this._numPrevBits + this._numPosBits);
+	while (i --) {
+		this._coders[i] = new LZMA.Decoder2();
+	}
+};
+
+LZMA.LiteralDecoder.prototype.init = function() {
+	var i = 1 << (this._numPrevBits + this._numPosBits);
+	while (i --) {
+		this._coders[i].init();
+	}
+};
+
+LZMA.LiteralDecoder.prototype.getDecoder = function(pos, prevByte) {
+	return this._coders[( (pos & this._posMask) << this._numPrevBits)
+    + ( (prevByte & 0xff) >>> (8 - this._numPrevBits) )];
+};
+
+LZMA.Decoder = function() {
+	this._outWindow = new LZMA.OutWindow();
+	this._rangeDecoder = new LZMA.RangeDecoder();
+	this._isMatchDecoders = [];
+	this._isRepDecoders = [];
+	this._isRepG0Decoders = [];
+	this._isRepG1Decoders = [];
+	this._isRepG2Decoders = [];
+	this._isRep0LongDecoders = [];
+	this._posSlotDecoder = [];
+	this._posDecoders = [];
+	this._posAlignDecoder = new LZMA.BitTreeDecoder(4);
+	this._lenDecoder = new LZMA.LenDecoder();
+	this._repLenDecoder = new LZMA.LenDecoder();
+	this._literalDecoder = new LZMA.LiteralDecoder();
+	this._dictionarySize = -1;
+	this._dictionarySizeCheck = -1;
+
+	this._posSlotDecoder[0] = new LZMA.BitTreeDecoder(6);
+	this._posSlotDecoder[1] = new LZMA.BitTreeDecoder(6);
+	this._posSlotDecoder[2] = new LZMA.BitTreeDecoder(6);
+	this._posSlotDecoder[3] = new LZMA.BitTreeDecoder(6);
+};
+
+LZMA.Decoder.prototype.setDictionarySize = function(dictionarySize) {
+	if (dictionarySize < 0) {
+		return false;
+	}
+	if (this._dictionarySize !== dictionarySize) {
+		this._dictionarySize = dictionarySize;
+		this._dictionarySizeCheck = Math.max(this._dictionarySize, 1);
+		this._outWindow.create( Math.max(this._dictionarySizeCheck, 4096) );
+	}
+	return true;
+};
+
+LZMA.Decoder.prototype.setLcLpPb = function(lc, lp, pb) {
+	var numPosStates = 1 << pb;
+
+	if (lc > 8 || lp > 4 || pb > 4) {
+		return false;
+	}
+
+	this._literalDecoder.create(lp, lc);
+
+	this._lenDecoder.create(numPosStates);
+	this._repLenDecoder.create(numPosStates);
+	this._posStateMask = numPosStates - 1;
+
+	return true;
+};
+
+LZMA.Decoder.prototype.init = function() {
+	var i = 4;
+
+	this._outWindow.init(false);
+
+	LZMA.initBitModels(this._isMatchDecoders, 192);
+	LZMA.initBitModels(this._isRep0LongDecoders, 192);
+	LZMA.initBitModels(this._isRepDecoders, 12);
+	LZMA.initBitModels(this._isRepG0Decoders, 12);
+	LZMA.initBitModels(this._isRepG1Decoders, 12);
+	LZMA.initBitModels(this._isRepG2Decoders, 12);
+	LZMA.initBitModels(this._posDecoders, 114);
+
+	this._literalDecoder.init();
+
+	while (i --) {
+		this._posSlotDecoder[i].init();
+	}
+
+	this._lenDecoder.init();
+	this._repLenDecoder.init();
+	this._posAlignDecoder.init();
+	this._rangeDecoder.init();
+};
+
+LZMA.Decoder.prototype.decode = function(inStream, outStream, outSize) {
+	var state = 0, rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0, nowPos64 = 0, prevByte = 0,
+      posState, decoder2, len, distance, posSlot, numDirectBits;
+
+	this._rangeDecoder.setStream(inStream);
+	this._outWindow.setStream(outStream);
+
+	this.init();
+
+	while (outSize < 0 || nowPos64 < outSize) {
+		posState = nowPos64 & this._posStateMask;
+
+		if (this._rangeDecoder.decodeBit(this._isMatchDecoders, (state << 4) + posState) === 0) {
+			decoder2 = this._literalDecoder.getDecoder(nowPos64 ++, prevByte);
+
+			if (state >= 7) {
+				prevByte = decoder2.decodeWithMatchByte(this._rangeDecoder, this._outWindow.getByte(rep0) );
+			}else {
+				prevByte = decoder2.decodeNormal(this._rangeDecoder);
+			}
+			this._outWindow.putByte(prevByte);
+
+			state = state < 4 ? 0 : state - (state < 10 ? 3 : 6);
+
+		}else {
+
+			if (this._rangeDecoder.decodeBit(this._isRepDecoders, state) === 1) {
+				len = 0;
+				if (this._rangeDecoder.decodeBit(this._isRepG0Decoders, state) === 0) {
+					if (this._rangeDecoder.decodeBit(this._isRep0LongDecoders, (state << 4) + posState) === 0) {
+						state = state < 7 ? 9 : 11;
+						len = 1;
+					}
+				}else {
+					if (this._rangeDecoder.decodeBit(this._isRepG1Decoders, state) === 0) {
+						distance = rep1;
+					}else {
+						if (this._rangeDecoder.decodeBit(this._isRepG2Decoders, state) === 0) {
+							distance = rep2;
+						}else {
+							distance = rep3;
+							rep3 = rep2;
+						}
+						rep2 = rep1;
+					}
+					rep1 = rep0;
+					rep0 = distance;
+				}
+				if (len === 0) {
+					len = 2 + this._repLenDecoder.decode(this._rangeDecoder, posState);
+					state = state < 7 ? 8 : 11;
+				}
+			}else {
+				rep3 = rep2;
+				rep2 = rep1;
+				rep1 = rep0;
+
+				len = 2 + this._lenDecoder.decode(this._rangeDecoder, posState);
+				state = state < 7 ? 7 : 10;
+
+				posSlot = this._posSlotDecoder[len <= 5 ? len - 2 : 3].decode(this._rangeDecoder);
+				if (posSlot >= 4) {
+
+					numDirectBits = (posSlot >> 1) - 1;
+					rep0 = (2 | (posSlot & 1) ) << numDirectBits;
+
+					if (posSlot < 14) {
+						rep0 += LZMA.reverseDecode2(this._posDecoders,
+                rep0 - posSlot - 1, this._rangeDecoder, numDirectBits);
+					}else {
+						rep0 += this._rangeDecoder.decodeDirectBits(numDirectBits - 4) << 4;
+						rep0 += this._posAlignDecoder.reverseDecode(this._rangeDecoder);
+						if (rep0 < 0) {
+							if (rep0 === -1) {
+								break;
+							}
+							return false;
+						}
+					}
+				}else {
+					rep0 = posSlot;
+				}
+			}
+
+			if (rep0 >= nowPos64 || rep0 >= this._dictionarySizeCheck) {
+				return false;
+			}
+
+			this._outWindow.copyBlock(rep0, len);
+			nowPos64 += len;
+			prevByte = this._outWindow.getByte(0);
+		}
+	}
+
+	this._outWindow.flush();
+	this._outWindow.releaseStream();
+	this._rangeDecoder.releaseStream();
+
+	return true;
+};
+
+LZMA.Decoder.prototype.setDecoderProperties = function(properties) {
+	var value, lc, lp, pb, dictionarySize;
+
+	if (properties.size < 5) {
+		return false;
+	}
+
+	value = properties.readByte();
+	lc = value % 9;
+	value = ~~(value / 9);
+	lp = value % 5;
+	pb = ~~(value / 5);
+
+	if ( !this.setLcLpPb(lc, lp, pb) ) {
+		return false;
+	}
+
+	dictionarySize = properties.readByte();
+	dictionarySize |= properties.readByte() << 8;
+	dictionarySize |= properties.readByte() << 16;
+	dictionarySize += properties.readByte() * 16777216;
+
+	return this.setDictionarySize(dictionarySize);
+};
+
+LZMA.decompress = function(properties, inStream, outStream, outSize) {
+	var decoder = new LZMA.Decoder();
+
+	if ( !decoder.setDecoderProperties(properties) ) {
+		throw "Incorrect stream properties";
+	}
+
+	if ( !decoder.decode(inStream, outStream, outSize) ) {
+		throw "Error in data stream";
+	}
+
+	return true;
+};

Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/libs/threejs/dat.gui.css


Разлика између датотеке није приказан због своје велике величине
+ 13 - 0
static/libs/threejs/dat.gui.min.js


+ 521 - 0
static/libs/threejs/draco/DRACOLoader.js

@@ -0,0 +1,521 @@
+// Copyright 2016 The Draco Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+'use strict';
+
+/**
+ * @param {THREE.LoadingManager} manager
+ */
+THREE.DRACOLoader = function(manager) {
+    this.timeLoaded = 0;
+    this.manager = manager || THREE.DefaultLoadingManager;
+    this.materials = null;
+    this.verbosity = 0;
+    this.attributeOptions = {};
+    this.drawMode = THREE.TrianglesDrawMode;
+    // Native Draco attribute type to Three.JS attribute type.
+    this.nativeAttributeMap = {
+      'position' : 'POSITION',
+      'normal' : 'NORMAL',
+      'color' : 'COLOR',
+      'uv' : 'TEX_COORD'
+    };
+};
+
+THREE.DRACOLoader.prototype = {
+
+    constructor: THREE.DRACOLoader,
+
+    load: function(url, onLoad, onProgress, onError) {
+        var scope = this;
+        var loader = new THREE.FileLoader(scope.manager);
+        loader.setPath(this.path);
+        loader.setResponseType('arraybuffer');
+        loader.load(url, function(blob) {
+            scope.decodeDracoFile(blob, onLoad);
+        }, onProgress, onError);
+    },
+
+    setPath: function(value) {
+        this.path = value;
+        return this;
+    },
+
+    setVerbosity: function(level) {
+        this.verbosity = level;
+        return this;
+    },
+
+    /**
+     *  Sets desired mode for generated geometry indices.
+     *  Can be either:
+     *      THREE.TrianglesDrawMode
+     *      THREE.TriangleStripDrawMode
+     */
+    setDrawMode: function(drawMode) {
+        this.drawMode = drawMode;
+        return this;
+    },
+
+    /**
+     * Skips dequantization for a specific attribute.
+     * |attributeName| is the THREE.js name of the given attribute type.
+     * The only currently supported |attributeName| is 'position', more may be
+     * added in future.
+     */
+    setSkipDequantization: function(attributeName, skip) {
+        var skipDequantization = true;
+        if (typeof skip !== 'undefined')
+          skipDequantization = skip;
+        this.getAttributeOptions(attributeName).skipDequantization =
+            skipDequantization;
+        return this;
+    },
+
+    /**
+     * Decompresses a Draco buffer. Names of attributes (for ID and type maps)
+     * must be one of the supported three.js types, including: position, color,
+     * normal, uv, uv2, skinIndex, skinWeight.
+     *
+     * @param {ArrayBuffer} rawBuffer
+     * @param {Function} callback
+     * @param {Object|undefined} attributeUniqueIdMap Provides a pre-defined ID
+     *     for each attribute in the geometry to be decoded. If given,
+     *     `attributeTypeMap` is required and `nativeAttributeMap` will be
+     *     ignored.
+     * @param {Object|undefined} attributeTypeMap Provides a predefined data
+     *     type (as a typed array constructor) for each attribute in the
+     *     geometry to be decoded.
+     */
+    decodeDracoFile: function(rawBuffer, callback, attributeUniqueIdMap,
+                              attributeTypeMap) {
+      var scope = this;
+      THREE.DRACOLoader.getDecoderModule()
+          .then( function ( module ) {
+            scope.decodeDracoFileInternal( rawBuffer, module.decoder, callback,
+              attributeUniqueIdMap, attributeTypeMap);
+          });
+    },
+
+    decodeDracoFileInternal: function(rawBuffer, dracoDecoder, callback,
+                                      attributeUniqueIdMap, attributeTypeMap) {
+      /*
+       * Here is how to use Draco Javascript decoder and get the geometry.
+       */
+      var buffer = new dracoDecoder.DecoderBuffer();
+      buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);
+      var decoder = new dracoDecoder.Decoder();
+
+      /*
+       * Determine what type is this file: mesh or point cloud.
+       */
+      var geometryType = decoder.GetEncodedGeometryType(buffer);
+      if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
+        if (this.verbosity > 0) {
+          console.log('Loaded a mesh.');
+        }
+      } else if (geometryType == dracoDecoder.POINT_CLOUD) {
+        if (this.verbosity > 0) {
+          console.log('Loaded a point cloud.');
+        }
+      } else {
+        var errorMsg = 'THREE.DRACOLoader: Unknown geometry type.';
+        console.error(errorMsg);
+        throw new Error(errorMsg);
+      }
+      callback(this.convertDracoGeometryTo3JS(dracoDecoder, decoder,
+          geometryType, buffer, attributeUniqueIdMap, attributeTypeMap));
+    },
+
+    addAttributeToGeometry: function(dracoDecoder, decoder, dracoGeometry,
+                                     attributeName, attributeType, attribute,
+                                     geometry, geometryBuffer) {
+      if (attribute.ptr === 0) {
+        var errorMsg = 'THREE.DRACOLoader: No attribute ' + attributeName;
+        console.error(errorMsg);
+        throw new Error(errorMsg);
+      }
+
+      var numComponents = attribute.num_components();
+      var numPoints = dracoGeometry.num_points();
+      var numValues = numPoints * numComponents;
+      var attributeData;
+      var TypedBufferAttribute;
+
+      switch ( attributeType ) {
+
+        case Float32Array:
+          attributeData = new dracoDecoder.DracoFloat32Array();
+          decoder.GetAttributeFloatForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Float32Array( numValues );
+          TypedBufferAttribute = THREE.Float32BufferAttribute;
+          break;
+
+        case Int8Array:
+          attributeData = new dracoDecoder.DracoInt8Array();
+          decoder.GetAttributeInt8ForAllPoints(
+            dracoGeometry, attribute, attributeData );
+          geometryBuffer[ attributeName ] = new Int8Array( numValues );
+          TypedBufferAttribute = THREE.Int8BufferAttribute;
+          break;
+
+        case Int16Array:
+          attributeData = new dracoDecoder.DracoInt16Array();
+          decoder.GetAttributeInt16ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Int16Array( numValues );
+          TypedBufferAttribute = THREE.Int16BufferAttribute;
+          break;
+
+        case Int32Array:
+          attributeData = new dracoDecoder.DracoInt32Array();
+          decoder.GetAttributeInt32ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Int32Array( numValues );
+          TypedBufferAttribute = THREE.Int32BufferAttribute;
+          break;
+
+        case Uint8Array:
+          attributeData = new dracoDecoder.DracoUInt8Array();
+          decoder.GetAttributeUInt8ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Uint8Array( numValues );
+          TypedBufferAttribute = THREE.Uint8BufferAttribute;
+          break;
+
+        case Uint16Array:
+          attributeData = new dracoDecoder.DracoUInt16Array();
+          decoder.GetAttributeUInt16ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Uint16Array( numValues );
+          TypedBufferAttribute = THREE.Uint16BufferAttribute;
+          break;
+
+        case Uint32Array:
+          attributeData = new dracoDecoder.DracoUInt32Array();
+          decoder.GetAttributeUInt32ForAllPoints(
+            dracoGeometry, attribute, attributeData);
+          geometryBuffer[ attributeName ] = new Uint32Array( numValues );
+          TypedBufferAttribute = THREE.Uint32BufferAttribute;
+          break;
+
+        default:
+          var errorMsg = 'THREE.DRACOLoader: Unexpected attribute type.';
+          console.error( errorMsg );
+          throw new Error( errorMsg );
+
+      }
+
+      // Copy data from decoder.
+      for (var i = 0; i < numValues; i++) {
+        geometryBuffer[attributeName][i] = attributeData.GetValue(i);
+      }
+      // Add attribute to THREEJS geometry for rendering.
+      geometry.addAttribute(attributeName,
+          new TypedBufferAttribute(geometryBuffer[attributeName],
+            numComponents));
+      dracoDecoder.destroy(attributeData);
+    },
+
+    convertDracoGeometryTo3JS: function(dracoDecoder, decoder, geometryType,
+                                        buffer, attributeUniqueIdMap,
+                                        attributeTypeMap) {
+        // TODO: Should not assume native Draco attribute IDs apply.
+        if (this.getAttributeOptions('position').skipDequantization === true) {
+          decoder.SkipAttributeTransform(dracoDecoder.POSITION);
+        }
+        var dracoGeometry;
+        var decodingStatus;
+        var start_time = performance.now();
+        if (geometryType === dracoDecoder.TRIANGULAR_MESH) {
+          dracoGeometry = new dracoDecoder.Mesh();
+          decodingStatus = decoder.DecodeBufferToMesh(buffer, dracoGeometry);
+        } else {
+          dracoGeometry = new dracoDecoder.PointCloud();
+          decodingStatus =
+              decoder.DecodeBufferToPointCloud(buffer, dracoGeometry);
+        }
+        if (!decodingStatus.ok() || dracoGeometry.ptr == 0) {
+          var errorMsg = 'THREE.DRACOLoader: Decoding failed: ';
+          errorMsg += decodingStatus.error_msg();
+          console.error(errorMsg);
+          dracoDecoder.destroy(decoder);
+          dracoDecoder.destroy(dracoGeometry);
+          throw new Error(errorMsg);
+        }
+
+        var decode_end = performance.now();
+        dracoDecoder.destroy(buffer);
+        /*
+         * Example on how to retrieve mesh and attributes.
+         */
+        var numFaces;
+        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
+          numFaces = dracoGeometry.num_faces();
+          if (this.verbosity > 0) {
+            console.log('Number of faces loaded: ' + numFaces.toString());
+          }
+        } else {
+          numFaces = 0;
+        }
+
+        var numPoints = dracoGeometry.num_points();
+        var numAttributes = dracoGeometry.num_attributes();
+        if (this.verbosity > 0) {
+          console.log('Number of points loaded: ' + numPoints.toString());
+          console.log('Number of attributes loaded: ' +
+              numAttributes.toString());
+        }
+
+        // Verify if there is position attribute.
+        // TODO: Should not assume native Draco attribute IDs apply.
+        var posAttId = decoder.GetAttributeId(dracoGeometry,
+                                              dracoDecoder.POSITION);
+        if (posAttId == -1) {
+          var errorMsg = 'THREE.DRACOLoader: No position attribute found.';
+          console.error(errorMsg);
+          dracoDecoder.destroy(decoder);
+          dracoDecoder.destroy(dracoGeometry);
+          throw new Error(errorMsg);
+        }
+        var posAttribute = decoder.GetAttribute(dracoGeometry, posAttId);
+
+        // Structure for converting to THREEJS geometry later.
+        var geometryBuffer = {};
+        // Import data to Three JS geometry.
+        var geometry = new THREE.BufferGeometry();
+
+        // Do not use both the native attribute map and a provided (e.g. glTF) map.
+        if ( attributeUniqueIdMap ) {
+
+          // Add attributes of user specified unique id. E.g. GLTF models.
+          for (var attributeName in attributeUniqueIdMap) {
+            var attributeType = attributeTypeMap[attributeName];
+            var attributeId = attributeUniqueIdMap[attributeName];
+            var attribute = decoder.GetAttributeByUniqueId(dracoGeometry,
+                                                           attributeId);
+            this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry,
+                attributeName, attributeType, attribute, geometry, geometryBuffer);
+          }
+
+        } else {
+
+          // Add native Draco attribute type to geometry.
+          for (var attributeName in this.nativeAttributeMap) {
+            var attId = decoder.GetAttributeId(dracoGeometry,
+                dracoDecoder[this.nativeAttributeMap[attributeName]]);
+            if (attId !== -1) {
+              if (this.verbosity > 0) {
+                console.log('Loaded ' + attributeName + ' attribute.');
+              }
+              var attribute = decoder.GetAttribute(dracoGeometry, attId);
+              this.addAttributeToGeometry(dracoDecoder, decoder, dracoGeometry,
+                  attributeName, Float32Array, attribute, geometry, geometryBuffer);
+            }
+          }
+
+        }
+
+        // For mesh, we need to generate the faces.
+        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
+          if (this.drawMode === THREE.TriangleStripDrawMode) {
+            var stripsArray = new dracoDecoder.DracoInt32Array();
+            var numStrips = decoder.GetTriangleStripsFromMesh(
+                dracoGeometry, stripsArray);
+            geometryBuffer.indices = new Uint32Array(stripsArray.size());
+            for (var i = 0; i < stripsArray.size(); ++i) {
+              geometryBuffer.indices[i] = stripsArray.GetValue(i);
+            }
+            dracoDecoder.destroy(stripsArray);
+          } else {
+            var numIndices = numFaces * 3;
+            geometryBuffer.indices = new Uint32Array(numIndices);
+            var ia = new dracoDecoder.DracoInt32Array();
+            for (var i = 0; i < numFaces; ++i) {
+              decoder.GetFaceFromMesh(dracoGeometry, i, ia);
+              var index = i * 3;
+              geometryBuffer.indices[index] = ia.GetValue(0);
+              geometryBuffer.indices[index + 1] = ia.GetValue(1);
+              geometryBuffer.indices[index + 2] = ia.GetValue(2);
+            }
+            dracoDecoder.destroy(ia);
+         }
+        }
+
+        geometry.drawMode = this.drawMode;
+        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
+          geometry.setIndex(new(geometryBuffer.indices.length > 65535 ?
+                THREE.Uint32BufferAttribute : THREE.Uint16BufferAttribute)
+              (geometryBuffer.indices, 1));
+        }
+
+        // TODO: Should not assume native Draco attribute IDs apply.
+        // TODO: Can other attribute types be quantized?
+        var posTransform = new dracoDecoder.AttributeQuantizationTransform();
+        if (posTransform.InitFromAttribute(posAttribute)) {
+          // Quantized attribute. Store the quantization parameters into the
+          // THREE.js attribute.
+          geometry.attributes['position'].isQuantized = true;
+          geometry.attributes['position'].maxRange = posTransform.range();
+          geometry.attributes['position'].numQuantizationBits =
+              posTransform.quantization_bits();
+          geometry.attributes['position'].minValues = new Float32Array(3);
+          for (var i = 0; i < 3; ++i) {
+            geometry.attributes['position'].minValues[i] =
+                posTransform.min_value(i);
+          }
+        }
+        dracoDecoder.destroy(posTransform);
+        dracoDecoder.destroy(decoder);
+        dracoDecoder.destroy(dracoGeometry);
+
+        this.decode_time = decode_end - start_time;
+        this.import_time = performance.now() - decode_end;
+
+        if (this.verbosity > 0) {
+          console.log('Decode time: ' + this.decode_time);
+          console.log('Import time: ' + this.import_time);
+        }
+        return geometry;
+    },
+
+    isVersionSupported: function(version, callback) {
+        THREE.DRACOLoader.getDecoderModule()
+            .then( function ( module ) {
+              callback( module.decoder.isVersionSupported( version ) );
+            });
+    },
+
+    getAttributeOptions: function(attributeName) {
+        if (typeof this.attributeOptions[attributeName] === 'undefined')
+          this.attributeOptions[attributeName] = {};
+        return this.attributeOptions[attributeName];
+    }
+};
+
+THREE.DRACOLoader.decoderPath = './';
+THREE.DRACOLoader.decoderConfig = {};
+THREE.DRACOLoader.decoderModulePromise = null;
+
+/**
+ * Sets the base path for decoder source files.
+ * @param {string} path
+ */
+THREE.DRACOLoader.setDecoderPath = function ( path ) {
+  THREE.DRACOLoader.decoderPath = path;
+};
+
+/**
+ * Sets decoder configuration and releases singleton decoder module. Module
+ * will be recreated with the next decoding call.
+ * @param {Object} config
+ */
+THREE.DRACOLoader.setDecoderConfig = function ( config ) {
+  var wasmBinary = THREE.DRACOLoader.decoderConfig.wasmBinary;
+  THREE.DRACOLoader.decoderConfig = config || {};
+  THREE.DRACOLoader.releaseDecoderModule();
+
+  // Reuse WASM binary.
+  if ( wasmBinary ) THREE.DRACOLoader.decoderConfig.wasmBinary = wasmBinary;
+};
+
+/**
+ * Releases the singleton DracoDecoderModule instance. Module will be recreated
+ * with the next decoding call.
+ */
+THREE.DRACOLoader.releaseDecoderModule = function () {
+  THREE.DRACOLoader.decoderModulePromise = null;
+};
+
+/**
+ * Gets WebAssembly or asm.js singleton instance of DracoDecoderModule
+ * after testing for browser support. Returns Promise that resolves when
+ * module is available.
+ * @return {Promise<{decoder: DracoDecoderModule}>}
+ */
+THREE.DRACOLoader.getDecoderModule = function () {
+  var scope = this;
+  var path = THREE.DRACOLoader.decoderPath;
+  var config = THREE.DRACOLoader.decoderConfig;
+  var promise = THREE.DRACOLoader.decoderModulePromise;
+
+  if ( promise ) return promise;
+
+  // Load source files.
+  if ( typeof DracoDecoderModule !== 'undefined' ) {
+    // Loaded externally.
+    promise = Promise.resolve();
+  } else if ( typeof WebAssembly !== 'object' || config.type === 'js' ) {
+    // Load with asm.js.
+    promise = THREE.DRACOLoader._loadScript( path + 'draco_decoder.js' );
+  } else {
+    // Load with WebAssembly.
+    config.wasmBinaryFile = path + 'draco_decoder.wasm';
+    promise = THREE.DRACOLoader._loadScript( path + 'draco_wasm_wrapper.js' )
+        .then( function () {
+          return THREE.DRACOLoader._loadArrayBuffer( config.wasmBinaryFile );
+        } )
+        .then( function ( wasmBinary ) {
+          config.wasmBinary = wasmBinary;
+        } );
+  }
+
+  // Wait for source files, then create and return a decoder.
+  promise = promise.then( function () {
+    return new Promise( function ( resolve ) {
+      config.onModuleLoaded = function ( decoder ) {
+        scope.timeLoaded = performance.now();
+        // Module is Promise-like. Wrap before resolving to avoid loop.
+        resolve( { decoder: decoder } );
+      };
+      DracoDecoderModule( config );
+    } );
+  } );
+
+  THREE.DRACOLoader.decoderModulePromise = promise;
+  return promise;
+};
+
+/**
+ * @param {string} src
+ * @return {Promise}
+ */
+THREE.DRACOLoader._loadScript = function ( src ) {
+  var prevScript = document.getElementById( 'decoder_script' );
+  if ( prevScript !== null ) {
+    prevScript.parentNode.removeChild( prevScript );
+  }
+  var head = document.getElementsByTagName( 'head' )[ 0 ];
+  var script = document.createElement( 'script' );
+  script.id = 'decoder_script';
+  script.type = 'text/javascript';
+  script.src = src;
+  return new Promise( function ( resolve ) {
+    script.onload = resolve;
+    head.appendChild( script );
+  });
+};
+
+/**
+ * @param {string} src
+ * @return {Promise}
+ */
+THREE.DRACOLoader._loadArrayBuffer = function ( src ) {
+  var loader = new THREE.FileLoader();
+  loader.setResponseType( 'arraybuffer' );
+  return new Promise( function( resolve, reject ) {
+    loader.load( src, resolve, undefined, reject );
+  });
+};

Разлика између датотеке није приказан због своје велике величине
+ 32 - 0
static/libs/threejs/draco/draco_decoder.js


BIN
static/libs/threejs/draco/draco_decoder.wasm


Разлика између датотеке није приказан због своје велике величине
+ 5 - 0
static/libs/threejs/stats.min.js


Разлика између датотеке није приказан због своје велике величине
+ 47349 - 0
static/libs/threejs/three.js


Разлика између датотеке није приказан због своје велике величине
+ 949 - 0
static/libs/threejs/three.min.js


Разлика између датотеке није приказан због своје велике величине
+ 46939 - 0
static/libs/threejs/three.module.js


BIN
static/models/KongMingDian - 副本.jpg


BIN
static/models/KongMingDian.jpg


Разлика између датотеке није приказан због своје велике величине
+ 517895 - 0
static/models/KongMingDian.obj


BIN
static/models/KongMingDian_2048.jpg


BIN
static/models/KongMingDian_512.jpg


BIN
static/models/LiuBeiDian - 副本.jpg


BIN
static/models/LiuBeiDian.jpg


Разлика између датотеке није приказан због своје велике величине
+ 374989 - 0
static/models/LiuBeiDian.obj


BIN
static/models/LiuBeiDian_2048.jpg


BIN
static/models/LiuBeiDian_512.jpg


BIN
static/models/TangBei - 副本.jpg


BIN
static/models/TangBei.jpg


Разлика између датотеке није приказан због своје велике величине
+ 123286 - 0
static/models/TangBei.obj


BIN
static/models/TangBei_2048.jpg


BIN
static/models/TangBei_512.jpg


BIN
static/models/WenChenLang - 副本.jpg


BIN
static/models/WenChenLang.jpg


Разлика између датотеке није приказан због своје велике величине
+ 261775 - 0
static/models/WenChenLang.obj


BIN
static/models/WenChenLang_2048.jpg


BIN
static/models/WenChenLang_512.jpg


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/all2(1)_lod10.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/all2(2)_lod10.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/all_lod10.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/di(1)_lod10.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/di(2)_lod10.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/di_lod10.json


+ 1 - 0
static/points/fileNames.txt

@@ -0,0 +1 @@
+["all_lod10.json","all2(1)_lod10.json","all2(2)_lod10.json","di(1)_lod10.json","di(2)_lod10.json","di_lod10.json"]

Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_0.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_1.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_10.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_100.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_101.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_102.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_103.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_104.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_105.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_106.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_107.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_108.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_109.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_11.json


Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
static/points/point_110.json


+ 0 - 0
static/points/point_111.json


Неке датотеке нису приказане због велике количине промена