├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── README.md ├── _config.yml ├── bin ├── assets │ ├── internal │ │ ├── avatar │ │ │ ├── footstep.ogg │ │ │ └── starterAvatars.babylon │ │ ├── particles │ │ │ ├── fire │ │ │ │ ├── flare.png │ │ │ │ └── thumbnail.png │ │ │ ├── rain │ │ │ │ ├── raindrop-1.png │ │ │ │ └── raindrop-2.png │ │ │ └── smoke │ │ │ │ ├── flare.png │ │ │ │ └── thumbnail.png │ │ ├── primitives │ │ │ ├── box │ │ │ │ └── thumbnail.png │ │ │ ├── cone │ │ │ │ └── thumbnail.png │ │ │ ├── cylinder │ │ │ │ └── thumbnail.png │ │ │ ├── disc │ │ │ │ └── thumbnail.png │ │ │ ├── plane │ │ │ │ └── thumbnail.png │ │ │ ├── sphere │ │ │ │ └── thumbnail.png │ │ │ └── torus │ │ │ │ └── thumbnail.png │ │ └── textures │ │ │ ├── no-texture.jpg │ │ │ └── tga-image.jpg │ ├── internalAssets.js │ └── updateAssets.js ├── index.html ├── lib │ └── Oimo.js ├── main.js ├── main.js.LICENSE.txt └── main.js.map ├── changelog.md ├── docs ├── sna.md └── ui.md ├── package-lock.json ├── package.json ├── sat.txt ├── src ├── CameraController.ts ├── Game.ts ├── GrndSpread.ts ├── Vishva.ts ├── VishvaSerialized.ts ├── assets │ ├── internal │ │ ├── avatar │ │ │ ├── footstep.ogg │ │ │ └── starterAvatars.babylon │ │ ├── particles │ │ │ ├── fire │ │ │ │ ├── flare.png │ │ │ │ └── thumbnail.png │ │ │ ├── rain │ │ │ │ ├── raindrop-1.png │ │ │ │ └── raindrop-2.png │ │ │ └── smoke │ │ │ │ ├── flare.png │ │ │ │ └── thumbnail.png │ │ ├── primitives │ │ │ ├── box │ │ │ │ └── thumbnail.png │ │ │ ├── cone │ │ │ │ └── thumbnail.png │ │ │ ├── cylinder │ │ │ │ └── thumbnail.png │ │ │ ├── disc │ │ │ │ └── thumbnail.png │ │ │ ├── plane │ │ │ │ └── thumbnail.png │ │ │ ├── sphere │ │ │ │ └── thumbnail.png │ │ │ └── torus │ │ │ │ └── thumbnail.png │ │ └── textures │ │ │ ├── no-texture.jpg │ │ │ └── tga-image.jpg │ ├── internalAssets.js │ └── updateAssets.js ├── avatar │ └── AvManager.ts ├── d.ts │ └── babylon.dynamicTerrain.d.ts ├── eventing │ ├── EventManager.ts │ └── VEvent.ts ├── gui │ ├── CCML.ts │ ├── CCUI.ts │ ├── ColorPickerFld.ts │ ├── DialogMgr.ts │ ├── EnvironmentML.ts │ ├── EnvironmentUI.ts │ ├── GuiUtils.ts │ ├── HelpML.ts │ ├── InternalAssetsUI.ts │ ├── ItemListUI.ts │ ├── MaterialListUI.ts │ ├── NavBarML.ts │ ├── SettingsML.ts │ ├── SettingsUI.ts │ ├── SnaML.ts │ ├── SnaUI.ts │ ├── SoundML.ts │ ├── SoundUI.ts │ ├── TextureML.ts │ ├── TextureUI.ts │ ├── UIConst.ts │ ├── VishvaGUI.ts │ ├── VishvaML.ts │ ├── colorpicker │ │ ├── colorpicker.themes.css │ │ └── colorpicker.ts │ ├── components │ │ ├── VButton.ts │ │ ├── VDiag.ts │ │ ├── VFileInput.ts │ │ ├── VInputNumber.ts │ │ ├── VInputSelect.ts │ │ ├── VInputText.ts │ │ ├── VInputVector2.ts │ │ ├── VInputVector3.ts │ │ ├── VRange.ts │ │ ├── VTab.ts │ │ ├── VTheme.ts │ │ ├── VTree.ts │ │ └── VTreeDialog.ts │ └── propspanel │ │ ├── AnimationML.ts │ │ ├── AnimationUI.ts │ │ ├── GeneralML.ts │ │ ├── GeneralUI.ts │ │ ├── GrndDimML.ts │ │ ├── GrndDimUI.ts │ │ ├── GrndSPSML.ts │ │ ├── GrndSPSUI.ts │ │ ├── LightUI.ts │ │ ├── LightsML.ts │ │ ├── MaterialML.ts │ │ ├── MaterialUI.ts │ │ ├── ParentChildUI.ts │ │ ├── PhysicsML.ts │ │ ├── PhysicsUI.ts │ │ ├── PropsPanelML.ts │ │ └── PropsPanelUI.ts ├── index.html ├── index.ts ├── lib │ └── Oimo.js ├── misc │ ├── babylon.dynamicTerrain.min.js │ └── perlin.js ├── sna │ ├── ActuatorAnimator.ts │ ├── ActuatorAvAnimator.ts │ ├── ActuatorCloaker.ts │ ├── ActuatorDialog.ts │ ├── ActuatorDisabler.ts │ ├── ActuatorEnabler.ts │ ├── ActuatorLight.ts │ ├── ActuatorMover.ts │ ├── ActuatorRotator.ts │ ├── ActuatorSignalEmitter.ts │ ├── ActuatorSound.ts │ ├── ActuatorTextBar.ts │ ├── SNA.ts │ ├── SensorClick.ts │ ├── SensorContact.ts │ └── SensorTimer.ts ├── style.css ├── util │ ├── AnimUtils.ts │ ├── HREFsearch.ts │ └── Random.ts ├── w3-theme-black.css ├── w3-theme-brown.css ├── w3-theme-dark-grey.css ├── w3-theme-eggplant.css ├── w3-theme-grey.css └── w3.css ├── todo.txt ├── tsconfig.json ├── vishva ├── assets │ └── curated │ │ └── skyboxes │ │ └── desert │ │ ├── desert_nx.jpg │ │ ├── desert_ny.jpg │ │ ├── desert_nz.jpg │ │ ├── desert_px.jpg │ │ ├── desert_py.jpg │ │ ├── desert_pz.jpg │ │ └── thumbnail.png ├── config.js ├── u.bat ├── updateAssets.js └── vishvaFiles.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject 2 | node_modules 3 | *.bat 4 | ig_*.* 5 | ig_* 6 | userAssets.js 7 | vishva/assets/**/* 8 | vishva/worlds/*.js 9 | *.log 10 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "pwa-chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:8080", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.fontFamily": "JetBrains Mono" 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "build", 7 | "problemMatcher": [] 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Note: 2 | 3 | Repo has been renamed from "Vishav.ts" to "Vishva". 4 | Branch names have changed. 5 | Default branch has changed. 6 | "modularize" has been renamed to "master" and is the default branch. 7 | The old master has been renamed to "old-master". 8 | 9 | # Vishva 10 | 11 | ## about 12 | 13 | Vishva - A hindi word for "World" 14 | 15 | A simple live scene editor for [BabylonJS](http://www.babylonjs.com/), a 3D HTML Webgl framework. 16 | 17 | Intro : [http://ssatguru.appspot.com/BabylonJS-Vishva/intro.html](http://ssatguru.appspot.com/BabylonJS-Vishva/intro.html). 18 | 19 | Demo : [https://ssatguru.github.io/VishvaWorlds-KennyLowPoly/bin](https://ssatguru.github.io/VishvaWorlds-KennyLowPoly/bin). 20 | 21 | Documentation : [wiki](https://github.com/ssatguru/Vishva/wiki). 22 | 23 | ## to test, build and run 24 | 25 | make sure you have typescript installed locally or globally 26 | run 27 | 28 | - npm install 29 | this will install any dependencies. 30 | 31 | - npm run test 32 | this will build in memory, start a webpack-dev-server and open browser at http://localhost:8080 33 | if you make any changes to source and save , this will automatically reload your project in the browser. 34 | goto "http://localhost:8080/bin/?world=empty" to open an empty world 35 | 36 | - npm run build 37 | This will create a production build. It will compile,minify and bundle all reuired files into the bin folder. 38 | 39 | - to run , start an http server from the root of the project and goto url "http://localhost:8080/bin/?world=empty" 40 | - url "http://localhost:8080/bin" will also work as he default world in "config.js" is set to "empty" 41 | - the default character jump animations might require some speed adjustment - lower speed , maybe 0.5 instead of 1 42 | 43 | ## built using 44 | 45 | - [BabylonJS](http://www.babylonjs.com/) 46 | - [BabylonJS-CharacterController](https://github.com/ssatguru/BabylonJS-CharacterController) 47 | - [BabylonJS-EditControl](https://github.com/ssatguru/BabylonJS-EditControl) 48 | - [w3-css](https://www.w3schools.com/w3css/) 49 | 50 | ## Notes 51 | 52 | The original version was written in Java and then transpiled to TypeScript/JavaScript using JSweet. 53 | It was originally written in Java, as at that time I wasn't very comfortable with the TypeScript language and ecosystem. 54 | Over time I have become more comfortable with it. 55 | The new version is thus written in TypeScript (based on the initial TypeScript code generated by JSweet). 56 | Porting to Typescript was easy, as JSweet generates human readable TypeScript thus allowing one to switch to TypeScript at any time. 57 | For those interested, the old java version is still available at [https://github.com/ssatguru/Vishva.java](https://github.com/ssatguru/Vishva.java) 58 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /bin/assets/internal/avatar/footstep.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/avatar/footstep.ogg -------------------------------------------------------------------------------- /bin/assets/internal/particles/fire/flare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/particles/fire/flare.png -------------------------------------------------------------------------------- /bin/assets/internal/particles/fire/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/particles/fire/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/particles/rain/raindrop-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/particles/rain/raindrop-1.png -------------------------------------------------------------------------------- /bin/assets/internal/particles/rain/raindrop-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/particles/rain/raindrop-2.png -------------------------------------------------------------------------------- /bin/assets/internal/particles/smoke/flare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/particles/smoke/flare.png -------------------------------------------------------------------------------- /bin/assets/internal/particles/smoke/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/particles/smoke/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/primitives/box/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/primitives/box/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/primitives/cone/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/primitives/cone/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/primitives/cylinder/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/primitives/cylinder/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/primitives/disc/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/primitives/disc/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/primitives/plane/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/primitives/plane/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/primitives/sphere/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/primitives/sphere/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/primitives/torus/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/primitives/torus/thumbnail.png -------------------------------------------------------------------------------- /bin/assets/internal/textures/no-texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/textures/no-texture.jpg -------------------------------------------------------------------------------- /bin/assets/internal/textures/tga-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/bin/assets/internal/textures/tga-image.jpg -------------------------------------------------------------------------------- /bin/assets/internalAssets.js: -------------------------------------------------------------------------------- 1 | internalAssets=[{d:"internal",f:[{d:"avatar",f:["starterAvatars.babylon"]},{d:"particles",f:[{d:"fire",f:["flare.png","thumbnail.png"]},{d:"rain",f:["raindrop-1.png","raindrop-2.png"]},{d:"smoke",f:["flare.png","thumbnail.png"]},{d:"snow",f:[]}]},{d:"primitives",f:[{d:"box",f:["thumbnail.png"]},{d:"cone",f:["thumbnail.png"]},{d:"cylinder",f:["thumbnail.png"]},{d:"disc",f:["thumbnail.png"]},{d:"plane",f:["thumbnail.png"]},{d:"sphere",f:["thumbnail.png"]},{d:"torus",f:["thumbnail.png"]}]},{d:"textures",f:["no-texture.jpg","tga-image.jpg"]}]},"internalAssets.js","u.bat","updateAssets.js","vishvaFiles.js"]; -------------------------------------------------------------------------------- /bin/assets/updateAssets.js: -------------------------------------------------------------------------------- 1 | let fs=require("fs"),varName=process.argv[2],path=process.argv[3],fn=process.argv[4],_tab=" ";function printDir(r,e){let t=fs.readdirSync(r),a=t.length-1,s="";for(let i=0;i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Vishva 18 | 19 | 20 | 21 |
22 |
23 | loading
24 | please wait
25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ### 4/27/2025 0.4.0-alpha.11 2 | - fixed issue of dialog box spilling out of canvas when its content height exceed the canvas height 3 | - when switching avatar and the new avatar root is not a mesh throws a error and prevents switching 4 | - if avatar mesh has one or more children then instead of just making the mesh unpickable make all chilren unpickable too 5 | ### 4/26/2025 0.4.0-alpha.10 6 | - fixed issue of dialog box spilling out of canvas when it is restored after minimizing and moving it around 7 | - fixed SNA ActuatorTextBar. Text would become transparent when the background was skybox 8 | ### 4/25/2025 0.4.0-alpha.9 9 | - fixed universal camera not becoming active due to ambient occlusion issue 10 | - added keys q and e to move universal camera up and down 11 | - added option to disable shadow and serilizing that option during save 12 | - upgraded to bablonjs version 8.4 13 | ### 4/24/2025 0.4.0-alpha.8 14 | - added ambient occlusion 15 | - fixed hemisphere light orientation 16 | ### 4/19/2025 0.4.0-alpha.7 17 | - updated babylonjs to 8.x version 18 | ### 4/13/2025 0.4.0-alpha.5 19 | - added new actuator SignalEmitter 20 | - refactored actuators 21 | ### 9/13/2023 0.4.0-alpha.4 22 | - added two depth renderer for each of the arc and uni cameras. previous fix for unicam not moving when Cascade shadow map used no longer required 23 | ### 9/13/2023 0.4.0-alpha.3 24 | - fix issue of not picking up shadowgenerator when loading saved scene 25 | - added two depth renderer for each of the arc and uni cameras. previous fix for unicam not moving when Cascade shadow map used no longer required 26 | ### 9/13/2023 0.4.0-alpha.2 27 | - fix issue of unicam not moving when Cascade shadow map used 28 | - fix issue of not picking up shadowgenerator when loading saved scene 29 | - unicam speed increases when shft key is pressed 30 | ### 9/13/2023 0.4.0-alpha.1 31 | - azimuth and elevation algorithm changed 32 | ### 9/12/2023 0.4.0-alpha.0 33 | - light direction now set using azimuth and elevation 34 | - shadows now generated using CascadedShadowGenerator 35 | 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vishva", 3 | "version": "0.4.0-alpha.11", 4 | "keywords": [ 5 | "babylonjs", 6 | "editor" 7 | ], 8 | "author": "satguru p srivastava", 9 | "contributors": [], 10 | "dependencies": { 11 | "babylonjs": "^8.4.0", 12 | "babylonjs-charactercontroller": "^0.4.4-alpha.6", 13 | "babylonjs-editcontrol": "^3.3.0", 14 | "babylonjs-gui": "^8.4.0", 15 | "babylonjs-loaders": "^8.4.0", 16 | "babylonjs-materials": "^8.4.0", 17 | "babylonjs-serializers": "^8.4.0", 18 | "cannon": "^0.6.2", 19 | "oimo": "^1.0.9", 20 | "pepjs": "^0.4.3" 21 | }, 22 | "devDependencies": { 23 | "copy-webpack-plugin": "^11.0.0", 24 | "css-loader": "^6.7.2", 25 | "file-loader": "^6.2.0", 26 | "style-loader": "^3.3.1", 27 | "terser-webpack-plugin": "^5.3.6", 28 | "ts-loader": "^9.4.2", 29 | "typescript": "4.9.4", 30 | "uglify-js": "^3.17.4", 31 | "webpack": "^5.75.0", 32 | "webpack-cli": "^5.0.1", 33 | "webpack-dev-server": "^4.11.1" 34 | }, 35 | "scripts": { 36 | "dev": "webpack-dev-server --open", 37 | "build": "webpack --mode production " 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /sat.txt: -------------------------------------------------------------------------------- 1 | 2 | start http-server from root 3 | goto localhost:8080/bin/index.html 4 | this picks up config file from absolute location /vishva 5 | the idea is to run distributable from one folder and the world from another folder 6 | 7 | 8 | 9 | vishva needs 10 | 11 | a) internal assets 12 | these are stored in the build/bin folder. 13 | same place as the index.html file 14 | These are picked up using relative location "assets/..." 15 | 16 | b) user assets 17 | these are stored in the "vishva" folder. 18 | These are thus picked up using absolute location "/vishva/.." 19 | 20 | See index.html and Vishva.ts vBinHome variable. 21 | In index.html note the 22 | 23 | webpack-dev-server is setup to serve build and static content from root "./" 24 | webpack will copy all src/assets folder to bin folder. 25 | 26 | 27 | themes 28 | download themes from 29 | https://www.w3schools.com/w3css/w3css_color_themes.asp 30 | example 31 | w3-theme-eggpant.css 32 | 33 | The css itself isn't used. 34 | Instead the color values fromthe css needs to be copied to sr/gui/components/VTheme.ts 35 | a) create a new class say EggPlantTheme which extends VTheme. 36 | b) copy the 10 foreground and background colors from the css to this class 37 | c) set the CurretTheme to an instance of this new class. 38 | See VTheme.ts for more instructions. -------------------------------------------------------------------------------- /src/CameraController.ts: -------------------------------------------------------------------------------- 1 | import { Scene, Camera, ArcRotateCamera, UniversalCamera, TargetCamera, Vector3, CascadedShadowGenerator, DepthRenderer } from "babylonjs"; 2 | 3 | export class UniCamController { 4 | camera: UniversalCamera; 5 | canvas: HTMLCanvasElement; 6 | active: boolean; 7 | csg: CascadedShadowGenerator; 8 | dr: DepthRenderer; 9 | 10 | oldCam: TargetCamera; 11 | oldDr: DepthRenderer; 12 | scene: Scene; 13 | defaultSpeed: number; 14 | isFast: boolean = false; 15 | 16 | constructor(scene: Scene, canvas: HTMLCanvasElement, csg: CascadedShadowGenerator, oldDr: DepthRenderer) { 17 | 18 | console.log("creating new uni camera"); 19 | 20 | this.scene = scene; 21 | this.canvas = canvas; 22 | this.active = false; 23 | this.csg = csg; 24 | this.oldDr = oldDr; 25 | 26 | this.camera = new UniversalCamera("UniCam", Vector3.Zero(), this.scene); 27 | 28 | this.camera.speed = this.camera.speed / 8; 29 | this.defaultSpeed = this.camera.speed; 30 | this.dr = this.scene.enableDepthRenderer(this.camera); 31 | this.dr.useOnlyInActiveCamera = true; 32 | 33 | scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline("ssaopipeline", this.camera); 34 | 35 | } 36 | 37 | public start() { 38 | if (this.active) return; 39 | this.active = true; 40 | 41 | this.oldCam = this.scene.activeCamera; 42 | this.oldCam.detachControl(); 43 | 44 | this.camera.position = this.oldCam.position; 45 | this.camera.setTarget(this.oldCam.getTarget()); 46 | 47 | this.camera.attachControl(true); 48 | 49 | this.camera.keysLeft = [37, 65]; //left arrow, "a" 50 | this.camera.keysRight = [39, 68];//right arrow,"d" 51 | this.camera.keysUp = [38, 87];//up arrow,"w" 52 | this.camera.keysDown = [40, 83];//down arrow,"s" 53 | this.camera.keysUpward = [33, 81]; //page up,"q" 54 | this.camera.keysDownward = [34, 69]; //page down,"e" 55 | 56 | this.oldDr.enabled = false; 57 | this.dr.enabled = true; 58 | this.csg.setDepthRenderer(this.dr); 59 | 60 | this.scene.activeCamera = this.camera; 61 | 62 | //if we donot do this then this camera doesnot move 63 | this.csg.autoCalcDepthBounds = true; 64 | } 65 | 66 | public stop() { 67 | if (!this.active) return; 68 | this.active = false; 69 | 70 | this.camera.detachControl(); 71 | this.dr.enabled = false; 72 | 73 | this.oldDr.enabled = true; 74 | this.csg.setDepthRenderer(this.oldDr); 75 | this.csg.autoCalcDepthBounds = true; 76 | (this.oldCam).attachControl(true, false, 2); 77 | this.scene.activeCamera = this.oldCam; 78 | } 79 | 80 | public speedUp() { 81 | if (this.isFast) return; 82 | this.isFast = true; 83 | this.camera.speed = this.defaultSpeed * 4; 84 | } 85 | 86 | public slowDown() { 87 | if (!this.isFast) return; 88 | this.isFast = false; 89 | this.camera.speed = this.defaultSpeed; 90 | } 91 | 92 | 93 | 94 | 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/Game.ts: -------------------------------------------------------------------------------- 1 | import { Vishva } from "./Vishva"; 2 | 3 | /** 4 | * Place holder for any game logic 5 | */ 6 | 7 | export class Game { 8 | 9 | constructor(vishva: Vishva) { 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /src/VishvaSerialized.ts: -------------------------------------------------------------------------------- 1 | import { Vector3, AnimationGroup, Scene, Tags, Sound, ISoundOptions } from "babylonjs"; 2 | import { ActionData, ActionMap, CCSettings } from "babylonjs-charactercontroller"; 3 | import { Color4 } from "babylonjs/Maths/math.color"; 4 | import { GrndSpread_Serializeable } from "./GrndSpread"; 5 | import { SNAserialized } from "./sna/SNA"; 6 | import { Vishva } from "./Vishva"; 7 | 8 | export class VishvaSerialized { 9 | //babylon version 10 | public bVer: string; 11 | //vishva version 12 | public vVer: string; 13 | public snas: SNAserialized[]; 14 | public settings: SettingsSerialized; 15 | public guiSettings: Object; 16 | public misc: MiscSerialized; 17 | public grndSpreadArray: GrndSpread_Serializeable[]; 18 | public avSerialized: AvSerialized; 19 | 20 | public constructor(vishva: Vishva) { 21 | this.settings = new SettingsSerialized(); 22 | this.misc = new MiscSerialized(); 23 | this.avSerialized = new AvSerialized(vishva); 24 | 25 | //we donot serialize the sps. 26 | //the sps mesh's doNotSerialize property is set to true when the sps is created 27 | //serializing the sps bloats up the file 28 | //instead we just serialize the sps properties and recreate the sps when the file 29 | //is loaded in future 30 | if (vishva.GrndSpreads != null) { 31 | this.grndSpreadArray = new Array(); 32 | for (let gSPS of vishva.GrndSpreads) { 33 | this.grndSpreadArray.push(gSPS.serialize()); 34 | } 35 | } 36 | 37 | } 38 | } 39 | 40 | export class SettingsSerialized { 41 | 42 | public cameraCollision: boolean = true; 43 | //automatcally open edit menu whenever a mesh is selected 44 | public autoEditMenu: boolean = false; 45 | 46 | 47 | } 48 | 49 | /* 50 | * BABYLONJS values not serialized by BABYLONJS but which we need 51 | */ 52 | export class MiscSerialized { 53 | public activeCameraTarget: Vector3 = Vector3.Zero(); 54 | public skyColor: Color4; 55 | public skyBright: number; 56 | public sceneShadowsEnabled: boolean; 57 | 58 | } 59 | 60 | export class AvSerialized { 61 | public settings: CCSettings; 62 | public actionMap: ActionMap; 63 | 64 | constructor(vishva: Vishva) { 65 | this.settings = vishva.avManager.cc.getSettings(); 66 | if (this.settings.sound) 67 | this.settings.sound = this.settings.sound.serialize(); 68 | this.actionMap = vishva.avManager.cc.getActionMap(); 69 | let keys = Object.keys(this.actionMap); 70 | for (let key of keys) { 71 | let ad: ActionData = this.actionMap[key]; 72 | ad.sound = null; 73 | } 74 | this.serializeAG(); 75 | } 76 | 77 | 78 | public static deSerializeSound(sndObj: Object): Sound { 79 | let sndOptions: ISoundOptions = {}; 80 | sndOptions.autoplay = false; 81 | sndOptions.distanceModel = sndObj["distanceModel"]; 82 | sndOptions.spatialSound = sndObj["spatialSound"]; 83 | sndOptions.maxDistance = sndObj["maxDistance"]; 84 | sndOptions.refDistance = sndObj["refDistance"]; 85 | sndOptions.rolloffFactor = sndObj["rolloffFactor"]; 86 | sndOptions.volume = sndObj["volume"]; 87 | 88 | return new Sound(sndObj["name"], sndObj["name"], Vishva.vishva.scene, null, sndOptions); 89 | } 90 | 91 | //replace any reference to AnimationGroup instance with just the name of the AnimationGroup 92 | //during de-serialization we will use then name and tag to get animationgroup and re reference it 93 | public serializeAG() { 94 | let keys = Object.keys(this.actionMap); 95 | for (let key of keys) { 96 | let ad: ActionData = this.actionMap[key]; 97 | if (ad.ag instanceof AnimationGroup) { 98 | this.actionMap[key]["ag"] = this.actionMap[key]["ag"].name; 99 | } 100 | 101 | } 102 | } 103 | 104 | public static deSerializeAG(scene: Scene, actionMap: ActionMap): ActionMap { 105 | let keys = Object.keys(actionMap); 106 | for (let key of keys) { 107 | let ad: ActionData = actionMap[key]; 108 | if (actionMap[key]["ag"] != null && actionMap[key]["ag"] != "") { 109 | actionMap[key]["ag"] = AvSerialized.findAGbyName(scene, actionMap[key]["ag"]); 110 | } 111 | } 112 | return actionMap; 113 | } 114 | 115 | private static findAGbyTag(scene: Scene, name: string): AnimationGroup { 116 | let ags: AnimationGroup[] = scene.animationGroups; 117 | for (let ag of ags) { 118 | try { 119 | if (Tags.HasTags(ag)) { 120 | if (Tags.MatchesQuery(ag, name)) return ag; 121 | } 122 | } catch (e) { 123 | console.log(e); 124 | } 125 | } 126 | return null; 127 | } 128 | 129 | private static findAGbyName(scene: Scene, name: string): AnimationGroup { 130 | let ags: AnimationGroup[] = scene.animationGroups; 131 | for (let ag of ags) { 132 | if (ag.name == name) return ag; 133 | } 134 | return null; 135 | } 136 | 137 | } 138 | 139 | 140 | -------------------------------------------------------------------------------- /src/assets/internal/avatar/footstep.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/avatar/footstep.ogg -------------------------------------------------------------------------------- /src/assets/internal/particles/fire/flare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/particles/fire/flare.png -------------------------------------------------------------------------------- /src/assets/internal/particles/fire/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/particles/fire/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/particles/rain/raindrop-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/particles/rain/raindrop-1.png -------------------------------------------------------------------------------- /src/assets/internal/particles/rain/raindrop-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/particles/rain/raindrop-2.png -------------------------------------------------------------------------------- /src/assets/internal/particles/smoke/flare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/particles/smoke/flare.png -------------------------------------------------------------------------------- /src/assets/internal/particles/smoke/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/particles/smoke/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/primitives/box/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/primitives/box/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/primitives/cone/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/primitives/cone/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/primitives/cylinder/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/primitives/cylinder/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/primitives/disc/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/primitives/disc/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/primitives/plane/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/primitives/plane/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/primitives/sphere/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/primitives/sphere/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/primitives/torus/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/primitives/torus/thumbnail.png -------------------------------------------------------------------------------- /src/assets/internal/textures/no-texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/textures/no-texture.jpg -------------------------------------------------------------------------------- /src/assets/internal/textures/tga-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssatguru/Vishva/ccdb630924580ee183f6431a92bd8165111932c0/src/assets/internal/textures/tga-image.jpg -------------------------------------------------------------------------------- /src/assets/internalAssets.js: -------------------------------------------------------------------------------- 1 | internalAssets=[ 2 | {"d":"internal", 3 | "f":[ 4 | {"d":"avatar", 5 | "f":[ 6 | "starterAvatars.babylon" 7 | ]}, 8 | {"d":"particles", 9 | "f":[ 10 | {"d":"fire", 11 | "f":[ 12 | "flare.png", 13 | "thumbnail.png" 14 | ]}, 15 | {"d":"rain", 16 | "f":[ 17 | "raindrop-1.png", 18 | "raindrop-2.png" 19 | ]}, 20 | {"d":"smoke", 21 | "f":[ 22 | "flare.png", 23 | "thumbnail.png" 24 | ]}, 25 | {"d":"snow", 26 | "f":[ 27 | ]} 28 | ]}, 29 | {"d":"primitives", 30 | "f":[ 31 | {"d":"box", 32 | "f":[ 33 | "thumbnail.png" 34 | ]}, 35 | {"d":"cone", 36 | "f":[ 37 | "thumbnail.png" 38 | ]}, 39 | {"d":"cylinder", 40 | "f":[ 41 | "thumbnail.png" 42 | ]}, 43 | {"d":"disc", 44 | "f":[ 45 | "thumbnail.png" 46 | ]}, 47 | {"d":"plane", 48 | "f":[ 49 | "thumbnail.png" 50 | ]}, 51 | {"d":"sphere", 52 | "f":[ 53 | "thumbnail.png" 54 | ]}, 55 | {"d":"torus", 56 | "f":[ 57 | "thumbnail.png" 58 | ]} 59 | ]}, 60 | {"d":"textures", 61 | "f":[ 62 | "no-texture.jpg", 63 | "tga-image.jpg" 64 | ]} 65 | ]}, 66 | "internalAssets.js", 67 | "u.bat", 68 | "updateAssets.js", 69 | "vishvaFiles.js" 70 | ] -------------------------------------------------------------------------------- /src/assets/updateAssets.js: -------------------------------------------------------------------------------- 1 | /** 2 | Takes three args 3 | 4 | varName - variable name to use in the output file 5 | path - the path to be scanned for file 6 | fn - name of the output file 7 | 8 | */ 9 | let fs = require('fs'); 10 | 11 | let varName = process.argv[2] 12 | let path = process.argv[3]; 13 | let fn = process.argv[4]; 14 | 15 | let _tab = " "; 16 | 17 | function printDir(path,tab){ 18 | let items = fs.readdirSync(path); 19 | let last=items.length-1; 20 | let line=""; 21 | for(let i = 0;i void)[] = EventManager.eventMap[event]; 14 | if (funcs === undefined) return; 15 | for (let func of funcs) { 16 | func(); 17 | } 18 | } 19 | 20 | public static subscribe(event: string, func: () => void) { 21 | if (EventManager.eventMap[event] === undefined) 22 | EventManager.eventMap[event] = new Array(); 23 | 24 | EventManager.eventMap[event].push(func); 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /src/eventing/VEvent.ts: -------------------------------------------------------------------------------- 1 | export class VEvent { 2 | public static _WORLD_ITEMS_CHANGED: string = "1"; 3 | public static _AVATAR_SWITCHED: string = "2"; 4 | 5 | } -------------------------------------------------------------------------------- /src/gui/CCML.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * .av-m - motion 3 | * .av-as - animation source 4 | * .av-at - animation target 5 | */ 6 | 7 | const settingFormHtml: string = ` 8 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 |
59 | 60 | 61 |
62 | 63 | 64 | 65 | 66 | 67 |
68 | 69 | 70 | 71 |
72 | 73 | 74 | 75 |
76 | `; 77 | const mapFormHTML: string = ` 78 |
79 | 80 |
81 |
motion
82 |
speed
83 |
animation
84 |
rate
85 |
loop
86 | 87 |
88 | 89 |
90 |
range/group
91 |
92 |
93 |
94 |
95 | `; 96 | 97 | export { settingFormHtml, mapFormHTML }; 98 | -------------------------------------------------------------------------------- /src/gui/ColorPickerFld.ts: -------------------------------------------------------------------------------- 1 | import { ColorPicker } from "./colorpicker/colorpicker"; 2 | import { VDiag } from "./components/VDiag"; 3 | import { VInputText } from "./components/VInputText"; 4 | 5 | /** 6 | * adds a two input box and a color dialog box inside the element whose id is passed 7 | */ 8 | export class ColorPickerFld { 9 | 10 | // input box to show or enter the color hex value 11 | // input box to show the color 12 | // the div which would be used to create a dialog box cotaining the color picker 13 | // note width 70%,20% not 70%,30% = 100%- to prevent color box wrapping to next line. firefox is more finicky, had to go from 70,20 to 60,20 14 | // 15 | ih: string = ` 16 |
17 | 18 |
19 | `; 20 | //colorInputValue: HTMLInputElement; 21 | colorInputText: VInputText; 22 | colorInput: HTMLInputElement; 23 | 24 | //vDiag: VDialog; 25 | cpDiag: VDiag = null; 26 | cp: ColorPicker = null; 27 | hexColor: string; 28 | private _chgHandler: (p1: any, p2: any, p3: RGB) => void; 29 | 30 | constructor(title: string, diagSelector: string, initialColor: string, pos: string, f: (p1: any, p2: any, p3: RGB) => void) { 31 | 32 | this._chgHandler = f; 33 | this.hexColor = initialColor; 34 | 35 | let colorEle: HTMLElement = document.getElementById(diagSelector); 36 | colorEle.innerHTML = this.ih; 37 | 38 | this.colorInputText = new VInputText(); 39 | this.colorInputText.setStyle("width:60%;min-width:4em"); 40 | this.colorInputText.setHint("enter color in hex #hhhhhh"); 41 | this.colorInputText.appendTo(colorEle.getElementsByClassName("colorFlds")[0]); 42 | 43 | this.colorInputText.setValue(this.hexColor); 44 | //TODO - check for valid value, allow hsv and rgb too 45 | this.colorInputText.onChange = (color) => { 46 | this.hexColor = color; 47 | this.colorInput.style.backgroundColor = this.hexColor; 48 | if (this.cp != null) this.cp.setHex(this.hexColor); 49 | this._chgHandler(this.hexColor, null, null); 50 | } 51 | 52 | this.colorInput = colorEle.getElementsByClassName("colorInput")[0]; 53 | this.colorInput.style.backgroundColor = this.hexColor; 54 | 55 | let colorPicker: HTMLElement = document.createElement("div"); 56 | colorPicker.style.cssText = "display:grid;grid-template-columns:auto auto;align-items:center;grid-gap:0.75em;padding:0.5em"; 57 | 58 | this.colorInput.onclick = () => { 59 | if (this.cpDiag == null) { 60 | this._createCPdiag(colorPicker, title, pos); 61 | } else { 62 | this.cpDiag.toggle(); 63 | } 64 | this.cp.setHex(this.hexColor); 65 | } 66 | 67 | } 68 | 69 | private _createCPdiag(colorPicker: HTMLElement, title: string, pos: string) { 70 | this.cp = new ColorPicker(colorPicker, (hex: any, hsv: any, rgb: RGB) => { 71 | this.hexColor = hex; 72 | this.colorInput.style.backgroundColor = hex; 73 | this.colorInputText.setValue(hex); 74 | this._chgHandler(hex, hsv, rgb); 75 | }); 76 | this.cpDiag = new VDiag(colorPicker, title, pos, 0, "auto", "19em"); 77 | } 78 | 79 | // public open(hex: string) { 80 | // this.vDiag.open(); 81 | // this.setColor(hex); 82 | // } 83 | 84 | public setColor(hex: string) { 85 | this.hexColor = hex; 86 | // if color picker is open then set the color there too 87 | if (this.cp != null) this.cp.setHex(hex); 88 | this.colorInput.style.backgroundColor = hex; 89 | this.colorInputText.setValue(hex); 90 | } 91 | 92 | public getColor(): string { 93 | return this.hexColor; 94 | } 95 | 96 | } 97 | 98 | class RGB { 99 | r: number; 100 | 101 | g: number; 102 | 103 | b: number; 104 | 105 | constructor() { 106 | this.r = 0; 107 | this.g = 0; 108 | this.b = 0; 109 | } 110 | } 111 | 112 | -------------------------------------------------------------------------------- /src/gui/DialogMgr.ts: -------------------------------------------------------------------------------- 1 | 2 | import { VDiag } from "./components/VDiag"; 3 | 4 | export class DialogMgr { 5 | 6 | public static vdiags: Array = new Array(); 7 | private static _alertDialog: VDiag; 8 | private static _alertDiv: HTMLDivElement; 9 | 10 | public static createAlertDiag() { 11 | if (this._alertDialog == null) { 12 | this._alertDiv = document.createElement("div"); 13 | this._alertDiv.style.textAlign = "center"; 14 | this._alertDiv.style.padding = "1em"; 15 | this._alertDialog = new VDiag(this._alertDiv, "Info", VDiag.center, "", "", "12em"); 16 | } 17 | } 18 | 19 | public static showAlertDiag(msg: string) { 20 | if (this._alertDialog == null) DialogMgr.createAlertDiag(); 21 | this._alertDiv.innerHTML = msg; 22 | this._alertDialog.open(); 23 | } 24 | 25 | } 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/gui/EnvironmentML.ts: -------------------------------------------------------------------------------- 1 | import { VButton } from "./components/VButton"; 2 | 3 | const envHTML: string = ` 4 |
5 | 6 |
sun elevation
7 |
8 | 9 |
sun azimuth
10 |
11 | 12 |
sun brightness
13 |
14 | 15 |
sky brightness
16 |
17 | 18 |
scene brightness
19 |
20 | 21 |
light color
22 |
23 | 24 |
shade
25 |
26 | 27 |
shadows on/off
28 |
29 | 30 |
fog
31 |
32 | 33 |
fog color
34 |
35 | 36 |
ambient color
37 |
38 | 39 |
toggle snow
40 |
41 | 42 |
toggle rainy
43 |
44 | 45 |
fov
46 |
47 | 48 |
sky
49 |
50 | 51 |
sky color
52 |
color
53 | 54 |
sea
55 |
56 | 57 | 58 | 59 |
60 | 61 |
terrain
62 |
63 | 64 |
`; 65 | 66 | let envElement = document.createElement("div"); 67 | envElement.style.visibility = "hidden"; 68 | envElement.innerHTML = envHTML; 69 | VButton.styleThem(envElement.getElementsByTagName("button")); 70 | 71 | export { envElement }; -------------------------------------------------------------------------------- /src/gui/GuiUtils.ts: -------------------------------------------------------------------------------- 1 | import { Vishva } from "../Vishva"; 2 | 3 | export class GuiUtils { 4 | /** 5 | * populates a html select element with options from the passed string array 6 | */ 7 | public static PopulateSelect(selectEle: HTMLSelectElement, options: Array) { 8 | let childs: HTMLCollection = selectEle.children; 9 | let l: number = (childs.length | 0); 10 | for (var i: number = l - 1; i >= 0; i--) { 11 | childs[i].remove(); 12 | } 13 | let optEle: HTMLOptionElement; 14 | for (let option of options) { 15 | optEle = document.createElement("option"); 16 | optEle.value = option; 17 | optEle.innerText = option; 18 | selectEle.appendChild(optEle); 19 | } 20 | } 21 | 22 | public static createDiv(id?: string): HTMLDivElement { 23 | let div: HTMLDivElement = document.createElement("div"); 24 | //div.style.visibility = "hidden"; 25 | if (id != null) div.id = id; 26 | Vishva.gui.appendChild(div); 27 | return div; 28 | } 29 | 30 | public static stopPropagation(inp: HTMLInputElement) { 31 | inp.onkeypress = (e) => { 32 | e.stopPropagation() 33 | } 34 | inp.onkeydown = (e) => { 35 | e.stopPropagation() 36 | } 37 | inp.onkeyup = (e) => { 38 | e.stopPropagation() 39 | } 40 | inp.onchange = (e) => { 41 | e.preventDefault(); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/gui/HelpML.ts: -------------------------------------------------------------------------------- 1 | import { VButton } from "./components/VButton"; 2 | 3 | let hlpHTML = ` 4 |
5 |
Avatar Movement Keys
6 | Click right mouse button on the ground to move the avatar to that position 7 | or use keyboard and mouse as explained below. 8 |
    9 |
  • Turn left, right - press "A,D" or "left,right arrow" key or press and drag left mouse key
  • 10 |
  • Strafe left, right - press "Q,E" key
  • 11 |
  • Go forward, backward - press "W,S" or "up,down arrow" key
  • 12 |
  • Run - press "shift" key while going forward, backward
  • 13 |
  • Jump - press and release "space" key
  • 14 |
15 | 16 |
Camera Movement Keys
17 |
    18 |
  • Normally the camera follows the avatar.
    19 | To move the camera independently of the avatar, press the "ESC" key.
    20 | The avatar will become semi-transparent to indicate it no longer controls the camera.
    21 | Pressing the "A,D,W,S" or arrow kyes will now move the camera instead of the avatar.
    22 | Pressing "SHIFT" and above keys will move the camera faster.
    23 | To switch back to Avatar, press "ESC" key again. 24 |
  • 25 |
26 | 27 |
Item Edit Keys
28 |
    29 |
  • 30 | To select an item press 'ALT' and the mouse LEFT or RIGHT click the item 31 |
      32 |
    • LEFT click will pick the root of that item
    • 33 |
    • RIGHT click will just pick that item
    • 34 |
    35 |
  • 36 |
  • 37 | To select multiple items press 'CTL' and mouse LEFT or RIGHT click each of the items 38 |
      39 |
    • LEFT click will add the item's root and all its childrens to the items already selected
    • 40 |
    • RIGHT click will just add that item to items already selected
    • 41 |
    42 |
  • 43 |
  • To deselect item - press"Esc" key
  • 44 |
  • To move,rotate or scale selected item - press "1,2,or 3" key
  • 45 |
  • To focus (center the camera) on selected item - press "F" key. To focus back on avatar press "Esc" twice.
  • 46 |
  • To zoom in or out of focused item - scroll mouse wheel forward or backward
  • 47 |
  • To pan around focused item - press and drag mouse right key
  • 48 |
49 | 50 |
For more help and source code
51 | https://github.com/ssatguru/Vishva/tree/master 52 | 53 |
54 | `; 55 | 56 | 57 | let hlpElement = document.createElement("div"); 58 | hlpElement.innerHTML = hlpHTML; 59 | VButton.styleThem(hlpElement.getElementsByTagName("button")); 60 | 61 | 62 | export { hlpElement }; -------------------------------------------------------------------------------- /src/gui/ItemListUI.ts: -------------------------------------------------------------------------------- 1 | 2 | import { TransformNode } from "babylonjs"; 3 | import { Vishva } from "../Vishva"; 4 | import { VTreeDialog } from "./components/VTreeDialog"; 5 | import { Node } from "babylonjs"; 6 | import { VDiag } from "./components/VDiag"; 7 | import { EventManager } from "../eventing/EventManager"; 8 | import { VEvent } from "../eventing/VEvent"; 9 | /* 10 | * provides a user interface which list all nodes in the scene 11 | */ 12 | export class ItemListUI { 13 | 14 | private _vishva: Vishva; 15 | private _itemsDiag: VTreeDialog; 16 | 17 | //see search() for an explanation of this 18 | private _donotSearch: boolean = false; 19 | 20 | constructor(vishva: Vishva) { 21 | 22 | this._vishva = vishva; 23 | 24 | this._updateTreeData(); 25 | 26 | this._itemsDiag = new VTreeDialog(this._vishva, "assets in world", VDiag.leftTop1, this.treeData); 27 | this._itemsDiag.addTreeListener((f, p, l) => { 28 | let i: number = f.indexOf(","); 29 | f = f.substring(0, i); 30 | this._donotSearch = true; 31 | this._vishva.selectMesh(f); 32 | }); 33 | this._itemsDiag.addRefreshHandler(() => { 34 | this.refresh(); 35 | return false; 36 | }); 37 | 38 | EventManager.subscribe(VEvent._WORLD_ITEMS_CHANGED, () => { this.onItemsChanged(); }); 39 | } 40 | 41 | public refresh() { 42 | this._refreshNeeded = false; 43 | this._itemsDiag.close(); 44 | this._updateTreeData(); 45 | this._itemsDiag.refresh(this.treeData); 46 | this._itemsDiag.open(); 47 | this._highlightSelected(); 48 | } 49 | 50 | public toggle() { 51 | if (!this._itemsDiag.isOpen()) { 52 | this.open(); 53 | } else { 54 | this._itemsDiag.close(); 55 | } 56 | } 57 | 58 | public open() { 59 | if (this._itemsDiag.isOpen()) return; 60 | if (this._refreshNeeded) { 61 | this.refresh(); 62 | } else { 63 | this._itemsDiag.open(); 64 | this._highlightSelected(); 65 | } 66 | } 67 | 68 | public onOpen(f: () => void) { 69 | this._itemsDiag.onOpen(f); 70 | } 71 | 72 | public isOpen(): boolean { 73 | return this._itemsDiag.isOpen(); 74 | } 75 | 76 | public filter(filter: string) { 77 | this._itemsDiag.filter(filter); 78 | } 79 | 80 | private _refreshNeeded = false; 81 | public onItemsChanged() { 82 | if (this.isOpen()) { 83 | this.refresh(); 84 | } else { 85 | this._refreshNeeded = true; 86 | } 87 | } 88 | 89 | public _highlightSelected = () => { 90 | if (this._vishva.anyMeshSelected()) { 91 | this.search(Number(this._vishva.meshSelected.uniqueId).toString() + ", " + this._vishva.meshSelected.name); 92 | } 93 | 94 | } 95 | 96 | /** 97 | * This search method finds, higlights and scrolls to the item in the list. 98 | * 99 | * Note: 100 | * This search is not done when an item in the itemlist was selected 101 | * 102 | * Explanation: 103 | * Selecting item in world VS selecting item in itemlist 104 | * 105 | * When the user selects an item in the world 106 | * system checks if the item list is open and if open it calls search 107 | * to "find, higlight and scroll" to the item in the list. 108 | * 109 | * When the user selects an item in the item list 110 | * that also results in selecting an item in the world 111 | * which results in a call to this search 112 | * but now we donot want to highlight or scroll 113 | * to the item as the item is already higlighted and in view. 114 | * 115 | * @param filter 116 | */ 117 | public search(filter: string) { 118 | if (this._donotSearch) this._donotSearch = false; 119 | else this._itemsDiag.search(filter); 120 | } 121 | 122 | treeData: Array; 123 | private _updateTreeData() { 124 | this.treeData = new Array(); 125 | 126 | 127 | let nodes: Array = this._vishva.scene.rootNodes; 128 | this._addChildren(nodes, this.treeData); 129 | // let children: Array; 130 | // for (let node of nodes) { 131 | // children = node.getChildren(); 132 | // if (children != null) { 133 | // let obj: object = {}; 134 | // obj["d"] = Number(node.uniqueId).toString() + ", " + node.name; 135 | // obj["f"] = new Array(); 136 | // this.treeData.push(obj); 137 | // this._addChildren(children, obj["f"]); 138 | // } else { 139 | // this.treeData.push(Number(node.uniqueId).toString() + ", " + node.name); 140 | // } 141 | // } 142 | } 143 | 144 | 145 | private _addChildren(children: Array, treeData: Array) { 146 | for (let child of children) { 147 | 148 | if (!(child instanceof TransformNode)) continue; 149 | //if (!(child instanceof Mesh)) continue; 150 | if (child == this._vishva.ground || child == this._vishva.avatar || child == this._vishva.skybox) continue; 151 | if (this._vishva.editControl != null && (child == this._vishva.editControl.getRoot())) continue; 152 | 153 | let childs: Array = child.getChildren(); 154 | if (childs.length > 0) { 155 | let obj: object = {}; 156 | obj["d"] = Number(child.uniqueId).toString() + ", " + child.name; 157 | obj["f"] = new Array(); 158 | treeData.push(obj); 159 | this._addChildren(childs, obj["f"]); 160 | } else { 161 | treeData.push(Number(child.uniqueId).toString() + ", " + child.name); 162 | } 163 | } 164 | } 165 | 166 | } 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /src/gui/MaterialListUI.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Scene, 3 | Material, 4 | MultiMaterial 5 | } from "babylonjs"; 6 | import { VDiag } from "./components/VDiag"; 7 | import { VTreeDialog } from "./components/VTreeDialog"; 8 | 9 | /* 10 | * provides a user interface which list all materials in the scene 11 | */ 12 | export class MaterialListUI { 13 | 14 | 15 | private _scene: Scene; 16 | private _materialsDiag: VTreeDialog; 17 | 18 | 19 | constructor(scene: Scene, matHdlr: (mat: Material) => void) { 20 | this._scene = scene; 21 | this._updateTreeData(); 22 | this._materialsDiag = new VTreeDialog(null, "Materials in Scene", VDiag.center, this.treeData); 23 | this._materialsDiag.addTreeListener((f, p, l) => { 24 | if (!l) return; 25 | let i: number = f.indexOf(","); 26 | f = f.substring(0, i); 27 | let mat; Material; 28 | if (p.indexOf("MultiMaterial") == 0) { 29 | mat = this._getMutliMaterialById(f); 30 | } else { 31 | mat = this._scene.getMaterialByID(f); 32 | } 33 | matHdlr(mat); 34 | }); 35 | this._materialsDiag.addRefreshHandler(() => { 36 | this._materialsDiag.close(); 37 | this._updateTreeData(); 38 | this._materialsDiag.refresh(this.treeData); 39 | this._materialsDiag.open(); 40 | return false; 41 | }); 42 | } 43 | 44 | private _getMutliMaterialById(id: string) { 45 | let mms: Array = this._scene.multiMaterials; 46 | let _multiMaterial: MultiMaterial = null; 47 | for (let mm of mms) { 48 | if (mm.id == id) { 49 | _multiMaterial = mm; 50 | break; 51 | } 52 | } 53 | return _multiMaterial; 54 | } 55 | 56 | public toggle() { 57 | if (!this._materialsDiag.isOpen()) { 58 | this._materialsDiag.open(); 59 | } else { 60 | this._materialsDiag.close(); 61 | } 62 | } 63 | 64 | treeData: Array; 65 | 66 | 67 | private _updateTreeData() { 68 | this.treeData = new Array(); 69 | let mats: Array = this._scene.materials; 70 | for (let mat of mats) { 71 | this.treeData.push(mat.id + ", " + mat.name); 72 | } 73 | 74 | let multiMats: Array = this._scene.multiMaterials; 75 | let obj: object = {}; 76 | obj["d"] = "MultiMaterial"; 77 | let mmIds: Array = new Array(); 78 | for (let multiMat of multiMats) { 79 | mmIds.push(multiMat.id + "," + multiMat.name); 80 | } 81 | obj["f"] = mmIds; 82 | this.treeData.push(obj); 83 | } 84 | 85 | //recursively adds children to the array 86 | private _addChildren(children: Array, treeData: Array) { 87 | for (let child of children) { 88 | if (child instanceof MultiMaterial) { 89 | let childs: Array = child.subMaterials; 90 | let obj: object = {}; 91 | obj["d"] = child.id + ", " + child.name; 92 | obj["f"] = new Array(); 93 | treeData.push(obj); 94 | this._addChildren(childs, obj["f"]); 95 | 96 | } else { 97 | treeData.push(child.id + ", " + child.name); 98 | } 99 | } 100 | 101 | 102 | 103 | } 104 | } -------------------------------------------------------------------------------- /src/gui/NavBarML.ts: -------------------------------------------------------------------------------- 1 | import { Vishva } from "../Vishva"; 2 | import { VButton } from "./components/VButton"; 3 | 4 | 5 | 6 | let navHTML = ` 7 | 41 | 42 | `; 43 | 44 | 45 | let navElement = document.createElement("div"); 46 | navElement.style.zIndex = "999"; 47 | navElement.innerHTML = navHTML; 48 | VButton.styleThem(navElement.getElementsByTagName("button")); 49 | 50 | 51 | export { navElement }; -------------------------------------------------------------------------------- /src/gui/SettingsML.ts: -------------------------------------------------------------------------------- 1 | 2 | const settingHTML: string = ` 3 |
4 |
camera collision
5 |
6 | 7 |
show edit menu on mesh selection
8 |
9 | 10 |
show tooltips
11 |
12 | 13 |
reveal invisibles
14 |
15 | 16 |
show disabled
17 |
18 | 19 |
enable snapper
20 |
21 | 22 | 23 |
24 | `; 25 | 26 | export { settingHTML }; 27 | -------------------------------------------------------------------------------- /src/gui/SettingsUI.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Vishva } from "../Vishva"; 3 | import { VishvaGUI } from "./VishvaGUI"; 4 | import { DialogMgr } from "./DialogMgr"; 5 | import { settingHTML } from "./SettingsML"; 6 | import { VButton } from "./components/VButton"; 7 | import { VDiag } from "./components/VDiag"; 8 | /** 9 | * provide ui to manage world/user settings/preferences 10 | */ 11 | export class SettingsUI { 12 | private _vishva: Vishva; 13 | private _vishvaGUI: VishvaGUI; 14 | 15 | private _settingDiag: VDiag; 16 | private _camCol: HTMLInputElement; 17 | private _autoEditMenu: HTMLInputElement; 18 | private _showToolTips: HTMLInputElement; 19 | public enableToolTips: boolean = true; 20 | private _revealInvis: HTMLInputElement; 21 | private _showDisa: HTMLInputElement; 22 | private _snapper: HTMLInputElement; 23 | 24 | private _redoShadows: HTMLButtonElement; 25 | 26 | //TODO pass property dialog instead of VishvaGUI 27 | constructor(vishvaGUI: VishvaGUI) { 28 | this._vishva = Vishva.vishva; 29 | this._vishvaGUI = vishvaGUI; 30 | this.enableToolTips = vishvaGUI.guiSettings.enableToolTips; 31 | 32 | let div = document.createElement("div"); 33 | Vishva.gui.appendChild(div); 34 | div.innerHTML = settingHTML; 35 | 36 | 37 | let dboSave: HTMLButtonElement = VButton.create("save", "save"); 38 | dboSave.style.margin = "1em"; 39 | dboSave.onclick = (e) => { 40 | 41 | this._vishva.enableCameraCollision(this._camCol.checked); 42 | 43 | this._vishva.enableAutoEditMenu(this._autoEditMenu.checked); 44 | 45 | this._vishvaGUI.guiSettings.enableToolTips = this._showToolTips.checked; 46 | 47 | 48 | if (this._revealInvis.checked) { 49 | this._vishva.revealInvisibles(); 50 | } else { 51 | this._vishva.hideInvisibles(); 52 | } 53 | if (this._showDisa.checked) { 54 | this._vishva.showAllDisabled(); 55 | } else { 56 | this._vishva.hideAllDisabled() 57 | } 58 | 59 | let err: string = this._vishva.snapper(this._snapper.checked); 60 | if (err != null) { 61 | DialogMgr.showAlertDiag(err); 62 | return false; 63 | } 64 | 65 | this._settingDiag.close(); 66 | //DialogMgr.showAlertDiag("Saved"); 67 | //refresh the property dialog in case something changed here 68 | 69 | //TODO pass props dialog 70 | this._vishvaGUI.refreshPropsDiag(); 71 | 72 | 73 | return true; 74 | }; 75 | 76 | let dboCancel: HTMLButtonElement = VButton.create("cancel", "cancel"); 77 | //dboCancel.style.marginTop = "1em"; 78 | dboCancel.style.margin = "1em"; 79 | dboCancel.onclick = (e) => { 80 | this._settingDiag.close(); 81 | return true; 82 | } 83 | div.appendChild(dboSave); 84 | div.appendChild(dboCancel); 85 | 86 | this._camCol = document.getElementById("camCol"); 87 | this._autoEditMenu = document.getElementById("autoEditMenu"); 88 | this._showToolTips = document.getElementById("showToolTips"); 89 | this._revealInvis = document.getElementById("revealInvis"); 90 | this._showDisa = document.getElementById("showDisa"); 91 | this._snapper = document.getElementById("snapper"); 92 | 93 | this._redoShadows = document.getElementById("redoShadow"); 94 | 95 | this._redoShadows.onclick = (e) => { 96 | this._vishva.redoShadows(); 97 | } 98 | 99 | this._updateSettings(); 100 | 101 | this._settingDiag = new VDiag(div, "Settings", VDiag.center, "", "", "24em"); 102 | } 103 | 104 | private _updateSettings() { 105 | 106 | this._camCol.checked = this._vishva.isCameraCollisionOn(); 107 | 108 | this._autoEditMenu.checked = this._vishva.isAutoEditMenuOn(); 109 | 110 | this._showToolTips.checked = this.enableToolTips; 111 | } 112 | 113 | public toggle() { 114 | if (!this._settingDiag.isOpen()) { 115 | this._updateSettings(); 116 | this._settingDiag.open(); 117 | } else { 118 | this._settingDiag.close(); 119 | } 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/gui/SnaML.ts: -------------------------------------------------------------------------------- 1 | import { VButton } from "./components/VButton"; 2 | 3 | const snaHTML: string = ` 4 | 5 |
6 | 7 |
8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 |

16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
NAMESIGNAL
24 |
25 | 26 | 39 | 40 |
41 | 42 | 43 |
44 |
45 |
46 | 47 |
48 |
49 |
50 | `; 51 | 52 | 53 | let snaElement = document.createElement("div"); 54 | snaElement.innerHTML = snaHTML; 55 | // snaElement.style.visibility = "hidden"; 56 | //VButton.styleThem(snaElement.getElementsByTagName("button")); 57 | 58 | export { snaElement }; -------------------------------------------------------------------------------- /src/gui/SoundML.ts: -------------------------------------------------------------------------------- 1 | 2 | const sndFormHtml: string = ` 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | `; 27 | 28 | let sndElement = document.createElement("div"); 29 | sndElement.innerHTML = sndFormHtml; 30 | export { sndElement }; 31 | -------------------------------------------------------------------------------- /src/gui/SoundUI.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Vishva } from "../Vishva"; 3 | import { sndElement } from "./SoundML"; 4 | import { VButton } from "./components/VButton"; 5 | import { VDiag } from "./components/VDiag"; 6 | import { VInputNumber } from "./components/VInputNumber"; 7 | import { VFileInput } from "./components/VFileInput"; 8 | import { VInputSelect } from "./components/VInputSelect"; 9 | import { DialogMgr } from "./DialogMgr"; 10 | import { ISoundOptions, Sound } from "babylonjs"; 11 | 12 | 13 | /** 14 | * provide ui to manage sound 15 | */ 16 | export class SoundUI { 17 | 18 | 19 | private _sndDiag: VDiag; 20 | private _snd: Sound; 21 | 22 | private static instance: SoundUI = null; 23 | 24 | constructor(snd: Sound) { 25 | 26 | this._snd = snd; 27 | 28 | if (SoundUI.instance != null) { 29 | SoundUI.instance.toggle(); 30 | return; 31 | 32 | } 33 | this._buildUI(); 34 | this._updateUI(this._snd); 35 | 36 | let dboSave: HTMLButtonElement = VButton.create("save", "save"); 37 | let dboCancel: HTMLButtonElement = VButton.create("cancel", "cancel"); 38 | 39 | dboSave.style.margin = "1em"; 40 | dboCancel.style.margin = "1em"; 41 | 42 | sndElement.appendChild(dboSave); 43 | sndElement.appendChild(dboCancel); 44 | 45 | dboSave.onclick = (e) => { 46 | if (this._saveSnd()) this._sndDiag.close(); 47 | return true; 48 | }; 49 | 50 | dboCancel.onclick = (e) => { 51 | this._sndDiag.close(); 52 | return true; 53 | } 54 | 55 | this._sndDiag = new VDiag(sndElement, "Sound Settings", VDiag.center, "", "", "12em", false); 56 | this._sndDiag.close(); 57 | 58 | SoundUI.instance = this; 59 | 60 | } 61 | 62 | 63 | public toggle() { 64 | if (!this._sndDiag.isOpen()) { 65 | this._updateUI(this._snd); 66 | this._sndDiag.open(); 67 | } else { 68 | this._sndDiag.close(); 69 | } 70 | } 71 | 72 | 73 | 74 | private _buildUI() { 75 | let form: HTMLFormElement = sndElement.getElementsByClassName("snd-settings")[0]; 76 | 77 | new VFileInput(form.sndFile, null, "Sound files", VDiag.centerBottom, Vishva.userAssets, "\.wav$|\.ogg$", true); 78 | form.attachToMesh.value = true; 79 | new VInputSelect(form.distModel, [{ id: "linear", desc: "linear" }, { id: "exponential", desc: "exponential" }, { id: "inverse", desc: "inverse" }]); 80 | new VInputNumber(form.maxDist, 100); 81 | new VInputNumber(form.rollOff, 1); 82 | new VInputNumber(form.refDist, 1); 83 | new VInputNumber(form.vol, 0.01); 84 | } 85 | 86 | private _updateUI(snd: Sound) { 87 | if (snd == null) return; 88 | let form: HTMLFormElement = sndElement.getElementsByClassName("snd-settings")[0]; 89 | form.sndFile.value = snd.name; 90 | form.maxDist.value = snd.maxDistance; 91 | form.rollOff.value = snd.rolloffFactor; 92 | form.refDist.value = snd.refDistance; 93 | form.distModel.value = snd.distanceModel; 94 | form.vol.value = snd.getVolume(); 95 | 96 | } 97 | 98 | 99 | private _saveSnd(): boolean { 100 | 101 | let sndOptions: ISoundOptions = {}; 102 | 103 | let form: HTMLFormElement = sndElement.getElementsByClassName("snd-settings")[0]; 104 | 105 | if (form["sndFile"].value == "No file chosen") { 106 | DialogMgr.showAlertDiag("No sound file choosen"); 107 | return false; 108 | } 109 | 110 | 111 | sndOptions.autoplay = false; 112 | sndOptions.distanceModel = form["distModel"].value; 113 | sndOptions.loop = false; 114 | sndOptions.maxDistance = Number(form["maxDist"].value); 115 | sndOptions.refDistance = Number(form["refDist"].value); 116 | sndOptions.rolloffFactor = Number(form["rollOff"].value); 117 | sndOptions.volume = Number(form["vol"].value); 118 | sndOptions.spatialSound = true; 119 | 120 | if (this._snd != null) { 121 | this._snd.updateOptions(sndOptions); 122 | } else 123 | this._snd = new Sound(form["sndFile"].value, form["sndFile"].value, Vishva.vishva.scene, null, sndOptions); 124 | 125 | return true; 126 | 127 | } 128 | 129 | public getSound(): Sound { 130 | return this._snd; 131 | } 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/gui/TextureML.ts: -------------------------------------------------------------------------------- 1 | import { VButton } from "./components/VButton"; 2 | 3 | let txtrHTML = ` 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 38 | 41 | 42 | 43 | 46 | 51 | 52 | 53 | 56 | 59 | 60 | 61 | 64 | 67 | 68 |
texture idid
texture typetype
image 17 | no images 18 |
19 | 20 |
24 | image source 25 | /textures/....
Horizontal Scale 31 | 32 |
36 | Vertical Scale 37 | 39 | 40 |
44 | Rotation 45 | 47 | U
48 | V
49 | W 50 |
54 | Horizontal Offset 55 | 57 | 58 |
62 | Vertical Offset 63 | 65 | 66 |
69 |
70 | `; 71 | 72 | let txtrElement = document.createElement("div"); 73 | txtrElement.style.visibility = "hidden"; 74 | txtrElement.innerHTML = txtrHTML; 75 | VButton.styleThem(txtrElement.getElementsByTagName("button")); 76 | 77 | 78 | export { txtrElement }; -------------------------------------------------------------------------------- /src/gui/TextureUI.ts: -------------------------------------------------------------------------------- 1 | import { Vishva } from "../Vishva"; 2 | import { VTreeDialog } from "./components/VTreeDialog"; 3 | import { txtrElement } from "./TextureML"; 4 | import { VDiag } from "./components/VDiag"; 5 | 6 | /** 7 | * Provides a UI to manage texture of a material 8 | */ 9 | export class TextureUI { 10 | 11 | private _vishva: Vishva; 12 | private _textureDiag: VDiag; 13 | private _textureImg: HTMLImageElement; 14 | private _textIDEle: HTMLElement; 15 | private _textType: HTMLElement; 16 | private _textImgSrc: HTMLElement; 17 | //private _textListDiv: HTMLElement; 18 | 19 | private _matHScale: HTMLInputElement; 20 | private _matVScale: HTMLInputElement; 21 | private _matURot: HTMLInputElement; 22 | private _matVRot: HTMLInputElement; 23 | private _matWRot: HTMLInputElement; 24 | private _matHO: HTMLInputElement; 25 | private _matVO: HTMLInputElement; 26 | 27 | private _matID: string; 28 | private _matTextImg: HTMLImageElement; 29 | private _textName: string; 30 | private _textID: string; 31 | 32 | constructor(vishva: Vishva) { 33 | this._vishva = vishva; 34 | 35 | 36 | 37 | document.body.appendChild(txtrElement); 38 | 39 | this._textureDiag = new VDiag("textureDiag", "Texture", VDiag.centerBottom, "auto", "auto", "0", false); 40 | 41 | this._textureImg = document.getElementById("textImg"); 42 | this._textIDEle = document.getElementById("textID"); 43 | this._textType = document.getElementById("textType"); 44 | this._textImgSrc = document.getElementById("textImgSrc"); 45 | this._matHScale = document.getElementById("matHScale"); 46 | this._matHScale.onchange = () => { 47 | this._vishva.setTextHScale(this._textID, Number(this._matHScale.value)); 48 | } 49 | this._matVScale = document.getElementById("matVScale"); 50 | this._matVScale.onchange = () => { 51 | this._vishva.setTextVScale(this._textID, Number(this._matVScale.value)); 52 | } 53 | 54 | this._matURot = document.getElementById("matURot"); 55 | this._matURot.oninput = () => { 56 | this._vishva.setTextRot(this._textID, Number(this._matURot.value), "u"); 57 | } 58 | this._matVRot = document.getElementById("matVRot"); 59 | this._matVRot.oninput = () => { 60 | this._vishva.setTextRot(this._textID, Number(this._matVRot.value), "v"); 61 | } 62 | this._matWRot = document.getElementById("matWRot"); 63 | this._matWRot.oninput = () => { 64 | this._vishva.setTextRot(this._textID, Number(this._matWRot.value), "w"); 65 | } 66 | 67 | this._matHO = document.getElementById("matHO"); 68 | this._matHO.oninput = () => { 69 | this._vishva.setTextHO(this._textID, Number(this._matHO.value)); 70 | } 71 | this._matVO = document.getElementById("matVO"); 72 | this._matVO.oninput = () => { 73 | this._vishva.setTextVO(this._textID, Number(this._matVO.value)); 74 | } 75 | 76 | 77 | let chgTexture: HTMLButtonElement = document.getElementById("changeTexture"); 78 | chgTexture.onclick = () => { 79 | if (this._textListDiag == null) { 80 | this._textListDiag = new VTreeDialog(this._vishva, "select texture", VDiag.center, Vishva.userAssets, "\.jpg$|\.png$|\.tga$|\.bmp$", true); 81 | this._textListDiag.addTreeListener((f, p, l) => { 82 | if (!l) return; 83 | let imgsrc: string = Vishva.vHome + "assets/" + p + f; 84 | this._vishva.setTextURL(this._textID, imgsrc); 85 | this._textName = imgsrc; 86 | this._textImgSrc.innerText = imgsrc; 87 | if (imgsrc.indexOf(".tga") >= 0) { 88 | imgsrc = Vishva.TGA_IMAGE; 89 | } 90 | this._textureImg.src = imgsrc; 91 | this._matTextImg.src = imgsrc; 92 | }); 93 | 94 | this._textListDiag.setModal(true); 95 | } 96 | this._textListDiag.open(); 97 | 98 | } 99 | 100 | } 101 | private _textListDiag: VTreeDialog; 102 | 103 | public update() { 104 | this._matHScale.value = this._vishva.getTextHScale(this._textID); 105 | this._matVScale.value = this._vishva.getTextVScale(this._textID); 106 | this._matWRot.value = this._vishva.getTextRot(this._textID); 107 | this._matHO.value = this._vishva.getTextHO(this._textID); 108 | this._matVO.value = this._vishva.getTextVO(this._textID); 109 | } 110 | 111 | public open() { 112 | this._textureDiag.open(); 113 | } 114 | public isOpen(): boolean { 115 | return this._textureDiag.isOpen(); 116 | } 117 | public close() { 118 | this._textureDiag.close(); 119 | } 120 | 121 | public setParms(textID: string, textName: string, textType: string, matdId: string, matTextImg: HTMLImageElement) { 122 | this._textID = textID; 123 | this._textIDEle.innerText = textID; 124 | this._textName = textName; 125 | this._textImgSrc.innerText = textName; 126 | this._textType.innerText = textType; 127 | this._matID = matdId; 128 | this._matTextImg = matTextImg; 129 | this._textureImg.src = this._matTextImg.src; 130 | 131 | this.update(); 132 | } 133 | } -------------------------------------------------------------------------------- /src/gui/UIConst.ts: -------------------------------------------------------------------------------- 1 | export class UIConst { 2 | public static _diagWidth: number = 480; 3 | public static _diagWidthS: string = "38em"; 4 | public static _buttonHeight: number = 41; 5 | } -------------------------------------------------------------------------------- /src/gui/VishvaML.ts: -------------------------------------------------------------------------------- 1 | import { VButton } from "./components/VButton"; 2 | 3 | const saveHTML: string = ` 4 |
5 |
6 | Your world file is ready for download. 7 |

8 | 9 | Right click here 10 | 11 |
12 | then select "Save link as..." 13 |
14 | to save this file on your computer 15 |
16 |
17 |

18 |
19 | 20 |
21 |
Your asset file is ready for download. 22 |

23 | 24 | Right click here 25 | 26 |
27 | then select "Save link as..." 28 |
29 | to save this file on your computer 30 |
31 |
32 |

33 |
`; 34 | 35 | 36 | let saveElement = document.createElement("div"); 37 | saveElement.innerHTML = saveHTML; 38 | saveElement.style.visibility = "hidden"; 39 | VButton.styleThem(saveElement.getElementsByTagName("button")); 40 | var fragment = new DocumentFragment() 41 | 42 | 43 | export { saveElement }; -------------------------------------------------------------------------------- /src/gui/colorpicker/colorpicker.themes.css: -------------------------------------------------------------------------------- 1 | /* Common stuff */ 2 | .picker-wrapper, 3 | .slide-wrapper { 4 | position: relative; 5 | float: left; 6 | } 7 | 8 | .picker, 9 | .slide { 10 | cursor: pointer; 11 | float: left; 12 | } 13 | 14 | .picker-indicator, 15 | .slide-indicator { 16 | position: absolute; 17 | left: 0; 18 | top: 0; 19 | pointer-events: none; 20 | } 21 | 22 | .slide-wrapper { 23 | margin-left: 0.3em; 24 | } 25 | 26 | .picker { 27 | width: 14em; 28 | height: 14em; 29 | } 30 | .slide { 31 | width: 2em; 32 | height: 14em; 33 | } 34 | 35 | .picker-indicator { 36 | width: 5px; 37 | height: 5px; 38 | border: 1px solid black; 39 | opacity: 0.5; 40 | background-color: white; 41 | pointer-events: none; 42 | } 43 | .slide-indicator { 44 | width: 2em; 45 | height: 10px; 46 | opacity: 0.6; 47 | border: 4px solid black; 48 | background-color: white; 49 | pointer-events: none; 50 | } 51 | -------------------------------------------------------------------------------- /src/gui/components/VButton.ts: -------------------------------------------------------------------------------- 1 | import { Vishva } from "../../Vishva"; 2 | import { VThemes } from "./VTheme"; 3 | 4 | export class VButton { 5 | public static create(id: string, label: string): HTMLButtonElement { 6 | let btn: HTMLButtonElement = document.createElement("BUTTON"); 7 | btn.id = id; 8 | btn.innerHTML = label; 9 | this.styleIt(btn); 10 | return btn; 11 | } 12 | 13 | public static styleIt(btn: HTMLButtonElement) { 14 | btn.classList.add("w3-btn"); 15 | btn.style.color = VThemes.CurrentTheme.lightColors.f; 16 | btn.style.backgroundColor = VThemes.CurrentTheme.lightColors.b; 17 | } 18 | 19 | public static styleThem(btns: HTMLCollectionOf) { 20 | let l = btns.length 21 | for (let i = 0; i < l; i++) { 22 | VButton.styleIt(btns[i]); 23 | } 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/gui/components/VFileInput.ts: -------------------------------------------------------------------------------- 1 | import { Vishva } from "../../Vishva"; 2 | import { DialogMgr } from "../DialogMgr"; 3 | import { VDiag } from "./VDiag"; 4 | import { VTreeDialog } from "./VTreeDialog"; 5 | 6 | /** 7 | * provides a ui to input a file 8 | */ 9 | export class VFileInput { 10 | 11 | 12 | constructor(eID: string | HTMLElement, private value = "", title = "", pos = VDiag.centerBottom, treeContent: Array, filter = "", openAll = true) { 13 | let e: HTMLElement = null; 14 | let ein: HTMLInputElement = null; 15 | let fibL: HTMLLabelElement = null; 16 | const noFile: string = "No file chosen"; 17 | 18 | let fib: HTMLButtonElement = document.createElement("button"); 19 | fib.innerText = "Choose File"; 20 | fib.type = "button"; 21 | 22 | if (eID instanceof HTMLInputElement) { 23 | ein = eID; 24 | ein.value = (value == null) ? noFile : value; 25 | ein.readOnly = true; 26 | let br = document.createElement("br"); 27 | ein.insertAdjacentElement('afterend', br); 28 | br.insertAdjacentElement('afterend', fib); 29 | } else { 30 | if (eID instanceof HTMLElement) { 31 | e = eID; 32 | } else e = document.getElementById(eID); 33 | 34 | fibL = document.createElement("label"); 35 | fibL.textContent = (value == null) ? noFile : value; 36 | e.appendChild(fibL); 37 | e.appendChild(document.createElement("br")); 38 | e.appendChild(fib); 39 | } 40 | 41 | let fiTD: VTreeDialog; 42 | fib.onclick = (e) => { 43 | 44 | fiTD = new VTreeDialog(null, title, pos, treeContent, filter, openAll); 45 | 46 | fiTD.addTreeListener((f, p, l) => { 47 | if (l) { 48 | if (filter.indexOf(f.substring(f.length - 4)) >= 0) { 49 | if (fibL != null) 50 | fibL.textContent = Vishva.vHome + "assets/" + p + f; 51 | else 52 | ein.value = Vishva.vHome + "assets/" + p + f; 53 | //TODO set this value only if "save button clicked 54 | this.value = Vishva.vHome + "assets/" + p + f; 55 | 56 | } 57 | } 58 | }) 59 | 60 | // fiTD.toggle(); 61 | } 62 | 63 | } 64 | 65 | 66 | 67 | public getValue(): string { 68 | return this.value; 69 | } 70 | public setValue(s: string) { 71 | this.value = s; 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/gui/components/VInputNumber.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * provides a ui to input a vector3 value 4 | */ 5 | export class VInputNumber { 6 | 7 | public _e: HTMLInputElement; 8 | public onChange: (n: number) => void; 9 | 10 | constructor(eID: string | HTMLElement, value = 0, readOnly = false) { 11 | 12 | if (eID != null) { 13 | let e: HTMLElement; 14 | if (eID instanceof HTMLInputElement) { 15 | this._e = eID; 16 | } else { 17 | this._e = document.createElement("input"); 18 | this._e.type = "text"; 19 | 20 | if (eID instanceof HTMLElement) { 21 | e = eID; 22 | } else e = document.getElementById(eID); 23 | 24 | e.appendChild(this._e); 25 | } 26 | } else { 27 | this._e = document.createElement("input"); 28 | this._e.type = "text"; 29 | } 30 | 31 | this._e.value = Number(value).toString(); 32 | this._e.style.width = "2em"; 33 | this._e.setAttribute("class", "vinput w3-input"); 34 | 35 | if (readOnly) this._e.readOnly = true; 36 | this._e.onkeypress = (e) => { 37 | e.stopPropagation() 38 | } 39 | this._e.onkeydown = (e) => { 40 | e.stopPropagation() 41 | } 42 | this._e.onkeyup = (e) => { 43 | e.stopPropagation() 44 | } 45 | this._e.onchange = (e) => { 46 | let n: number = Number(this._e.value); 47 | if (isNaN(n)) this._e.value = "0"; 48 | e.preventDefault(); 49 | if (this.onChange != null) { 50 | this.onChange(Number(this._e.value)); 51 | } 52 | } 53 | 54 | 55 | } 56 | 57 | 58 | 59 | public getValue(): number { 60 | let n: number = Number(this._e.value); 61 | if (isNaN(n)) return 0; 62 | else return n; 63 | } 64 | public setValue(n: number) { 65 | this._e.value = Number(n).toFixed(2); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/gui/components/VInputSelect.ts: -------------------------------------------------------------------------------- 1 | import { HtmlElementTexture } from "babylonjs"; 2 | 3 | export class VInputSelect { 4 | 5 | private _e: HTMLSelectElement; 6 | public onSelect: (v: string) => void = null; 7 | 8 | constructor(eId: string | HTMLElement, options: Array<{ id: string, desc: string }>) { 9 | 10 | if (eId instanceof HTMLSelectElement) { 11 | this._e = eId; 12 | } else { 13 | this._e = document.createElement("select"); 14 | let e: HTMLElement = (eId instanceof HTMLElement) ? eId : document.getElementById(eId); 15 | e.appendChild(this._e); 16 | } 17 | 18 | this._e.className = "w3-select"; 19 | this._e.onchange = () => { 20 | if (this.onSelect != null) { 21 | this.onSelect(this._e.value); 22 | } 23 | } 24 | 25 | this.populateSelect(options); 26 | } 27 | 28 | /** 29 | * populates a html select element with options from the passed string array 30 | */ 31 | public populateSelect(options: Array<{ id: string, desc: string }>) { 32 | let childs: HTMLCollection = this._e.children; 33 | let l: number = (childs.length | 0); 34 | for (var i: number = l - 1; i >= 0; i--) { 35 | childs[i].remove(); 36 | } 37 | let optEle: HTMLOptionElement; 38 | for (let option of options) { 39 | optEle = document.createElement("option"); 40 | optEle.value = option.id; 41 | optEle.innerText = option.desc; 42 | this._e.appendChild(optEle); 43 | } 44 | } 45 | 46 | public getValue(): string { 47 | return this._e.value; 48 | } 49 | 50 | public static styleIt(se: HTMLSelectElement) { 51 | se.className = "w3-select"; 52 | se.style.width = "auto"; 53 | 54 | } 55 | 56 | 57 | } -------------------------------------------------------------------------------- /src/gui/components/VInputText.ts: -------------------------------------------------------------------------------- 1 | import { UIConst } from "../UIConst"; 2 | 3 | /** 4 | * provides a ui to input a vector3 value 5 | */ 6 | export class VInputText { 7 | 8 | public _e: HTMLInputElement; 9 | public onChange: (s: string) => void; 10 | 11 | constructor(value = "") { 12 | this._e = document.createElement("input"); 13 | this._e.type = "text"; 14 | this._e.setAttribute("class", "vinput w3-input"); 15 | // this._inE.style.display = "inline-block"; 16 | // this._inE.style.backgroundColor = "#655870"; 17 | // this._inE.style.color = "White" 18 | // this._inE.style.border = "1px solid black" 19 | // this._inE.style.outline = "none" 20 | //this._inE.style.height = UIConst._buttonHeight.toString() + "px"; 21 | // this._inE.style.borderRadius = "10px"; 22 | 23 | this._e.onkeypress = (e) => { 24 | e.stopPropagation() 25 | } 26 | this._e.onkeydown = (e) => { 27 | e.stopPropagation() 28 | } 29 | this._e.onkeyup = (e) => { 30 | e.stopPropagation() 31 | } 32 | this._e.onchange = (e) => { 33 | e.preventDefault(); 34 | if (this.onChange != null) { 35 | this.onChange(this._e.value); 36 | } 37 | } 38 | } 39 | 40 | 41 | 42 | public getValue(): string { 43 | return this._e.value; 44 | } 45 | public setValue(s: string) { 46 | this._e.value = s; 47 | } 48 | 49 | public appendTo(eID: string | HTMLElement) { 50 | let e: HTMLElement; 51 | 52 | if (eID instanceof HTMLElement) { 53 | e = eID; 54 | } else e = document.getElementById(eID); 55 | 56 | e.appendChild(this._e); 57 | } 58 | 59 | public setStyle(style: string) { 60 | this._e.style.cssText = style; 61 | } 62 | 63 | public setHint(hint: string) { 64 | this._e.setAttribute("title", hint); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/gui/components/VInputVector2.ts: -------------------------------------------------------------------------------- 1 | 2 | import {Vector2} from "babylonjs"; 3 | import { VInputNumber } from "./VInputNumber"; 4 | /** 5 | * provides a ui to input a vector2 value 6 | */ 7 | export class VInputVector2 { 8 | 9 | private _v: Vector2; 10 | private _x: VInputNumber; 11 | private _y: VInputNumber; 12 | 13 | constructor(v3eID: string, v?: Vector2, readOnly = false) { 14 | if (v) { 15 | this._v = v.clone(); 16 | } else { 17 | this._v = new Vector2(0, 0); 18 | } 19 | 20 | this._x = new VInputNumber(v3eID, this._v.x, readOnly); 21 | this._x.onChange = (n) => { 22 | this._v.x = n; 23 | } 24 | 25 | this._y = new VInputNumber(v3eID, this._v.y, readOnly); 26 | this._y.onChange = (n) => { 27 | this._v.y = n; 28 | } 29 | 30 | } 31 | 32 | public getValue(): Vector2 { 33 | return this._v; 34 | } 35 | 36 | public setValue(v: Vector2) { 37 | 38 | this._v.x = v.x; 39 | this._v.y = v.y; 40 | 41 | this._x.setValue(v.x); 42 | this._y.setValue(v.y); 43 | 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/gui/components/VInputVector3.ts: -------------------------------------------------------------------------------- 1 | 2 | import {Vector3} from "babylonjs"; 3 | import { VInputNumber } from "./VInputNumber"; 4 | /** 5 | * provides a ui to input a vector3 value 6 | */ 7 | export class VInputVector3 { 8 | 9 | private _v: Vector3; 10 | private _x: VInputNumber; 11 | private _y: VInputNumber; 12 | private _z: VInputNumber; 13 | public onChange: (v3: Vector3) => void; 14 | 15 | constructor(v3eID: string | HTMLElement, v?: Vector3, readOnly = false) { 16 | if (v) { 17 | this._v = v.clone(); 18 | } else { 19 | this._v = new Vector3(0, 0, 0) 20 | } 21 | 22 | this._x = new VInputNumber(v3eID, this._v.x, readOnly); 23 | this._x.onChange = (n) => { 24 | this._v.x = n; 25 | this.doOnChange(); 26 | } 27 | this._y = new VInputNumber(v3eID, this._v.y, readOnly); 28 | this._y.onChange = (n) => { 29 | this._v.y = n; 30 | this.doOnChange(); 31 | } 32 | this._z = new VInputNumber(v3eID, this._v.z, readOnly); 33 | this._z.onChange = (n) => { 34 | this._v.z = n; 35 | this.doOnChange(); 36 | } 37 | } 38 | 39 | private doOnChange() { 40 | if (this.onChange != null) { 41 | this.onChange(this.getValue()); 42 | } 43 | } 44 | 45 | public getValue(): Vector3 { 46 | return this._v; 47 | } 48 | 49 | public setValue(v: Vector3) { 50 | 51 | this._v.x = v.x; 52 | this._v.y = v.y; 53 | this._v.z = v.z; 54 | 55 | this._x.setValue(v.x); 56 | this._y.setValue(v.y); 57 | this._z.setValue(v.z); 58 | 59 | } 60 | 61 | 62 | } -------------------------------------------------------------------------------- /src/gui/components/VRange.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * provides a ui to input a vector3 value 4 | */ 5 | export class VRange { 6 | 7 | 8 | private _e: HTMLInputElement; 9 | private _v: number; 10 | public onChange: (n: number) => void; 11 | 12 | constructor(eID: string, min = 0, max = 1, step = 0.01, value = 0) { 13 | let e: HTMLElement = document.getElementById(eID); 14 | let d: HTMLInputElement = document.createElement("input"); 15 | d.type = "range"; 16 | e.appendChild(d); 17 | 18 | d.min = min.toString(); 19 | d.max = max.toString(); 20 | d.step = step.toString(); 21 | d.value = value.toString(); 22 | 23 | this._e = d; 24 | 25 | } 26 | 27 | 28 | public getValue(): number { 29 | return Number(this._e.value); 30 | } 31 | 32 | public setValue(n: number) { 33 | this._e.value = n.toString(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/gui/components/VTab.ts: -------------------------------------------------------------------------------- 1 | import { DivideBlock } from "babylonjs/Materials/Node/Blocks/divideBlock"; 2 | import { Vishva } from "../../Vishva"; 3 | 4 | export class VTab { 5 | 6 | //
7 | // 8 | //
9 | // 10 | // 11 | // 12 | // .... 13 | //
14 | // 15 | //
16 | //