Merge branch 'master' into feature/update_ice_hostname
80
README.md
|
@ -1,21 +1,21 @@
|
|||
<p align="center"><a href="https://overte.org/"><img src="interface/resources/images/brand-banner-black.svg" alt="Overte" width="350"/></a></p>
|
||||
<h3 align="center"><a href="https://vircadia.com/">Website</a> | <a href="https://discordapp.com/invite/Pvx2vke">Discord</a> | <a href="https://vircadia.com/download-vircadia/">Download</a></h3>
|
||||
<h3 align="center"><a href="https://overte.org/">Website</a> | <a href="https://matrix.to/#/#overte:matrix.org">Matrix</a> | <a href="https://overte.org/#download">Download</a></h3>
|
||||
<p align="center">
|
||||
<a href="https://vircadia.com/contribute"><img alt="GitHub contributors" src="https://img.shields.io/github/contributors/vircadia/vircadia"></a>
|
||||
<a href="https://github.com/sponsors/digisomni"><img alt="GitHub sponsors" src="https://img.shields.io/github/sponsors/digisomni?style=flat&label=github%20sponsors"></a>
|
||||
<a href="https://github.com/vircadia/vircadia/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/vircadia/vircadia"></a>
|
||||
<a href="https://github.com/vircadia/vircadia/network"><img alt="GitHub forks" src="https://img.shields.io/github/forks/vircadia/vircadia"></a>
|
||||
<a href="https://docs.overte.org/en/latest/contribute.html"><img alt="GitHub contributors" src="https://img.shields.io/github/contributors/overte-org/overte"></a>
|
||||
<a href="https://github.com/overte-org/overte/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/overte-org/overte"></a>
|
||||
<a href="https://github.com/overte-org/overte/network"><img alt="GitHub forks" src="https://img.shields.io/github/forks/overte-org/overte"></a>
|
||||
<a href="https://www.apache.org/licenses/LICENSE-2.0"><img alt="Apache 2.0" src="https://img.shields.io/badge/license-Apache--2.0-%230A7BBB?style=flat"></a>
|
||||
<a href="https://discordapp.com/invite/Pvx2vke"><img alt="Discord" src="https://img.shields.io/discord/564926326025224212?style=flat"></a>
|
||||
<a href="https://matrix.to/#/#overte:matrix.org"><img alt="Matrix" src="https://img.shields.io/matrix/overte:matrix.org?label=Matrix%20chat"></a>
|
||||
</p>
|
||||
<h3 align="center">Build Status</h3>
|
||||
<p align="center">
|
||||
<a href="https://github.com/vircadia/vircadia/actions/workflows/master_build.yml"><img alt="Master CI Build" src="https://github.com/vircadia/vircadia/actions/workflows/master_build.yml/badge.svg"></a>
|
||||
<a href="https://github.com/overte-org/overte/actions/workflows/master_build.yml"><img alt="Master CI Build" src="https://github.com/overte-org/overte/actions/workflows/master_build.yml/badge.svg"></a>
|
||||
<a href="https://github.com/overte-org/overte/actions/workflows/master_deploy_apidocs.yml"><img alt="API-docs CI Build & Deploy" src="https://github.com/overte-org/overte/actions/workflows/master_deploy_apidocs.yml/badge.svg"></a>
|
||||
</p>
|
||||
|
||||
### What is this?
|
||||
|
||||
Vircadia™ is a 3D social software project seeking to incrementally bring about a truly free and open metaverse.
|
||||
Overte is a 3D social software project seeking to incrementally bring about a truly free and open metaverse.
|
||||
|
||||
* Desktop and VR use
|
||||
* Hundreds of users simultaneously
|
||||
|
@ -28,73 +28,55 @@ Vircadia™ is a 3D social software project seeking to incrementally bring about
|
|||
|
||||
### Releases
|
||||
|
||||
[View Releases here](https://github.com/vircadia/vircadia/releases/)
|
||||
[View Releases here](https://github.com/overte-org/overte/releases/)
|
||||
|
||||
### How to deploy a Server
|
||||
|
||||
- [For Windows and Linux](https://vircadia.com/deploy-a-server/)
|
||||
- [For Windows and Linux](https://docs.overte.org/en/latest/host.html)
|
||||
|
||||
### Building
|
||||
|
||||
#### How to build the Interface
|
||||
|
||||
- [For Windows](https://github.com/vircadia/vircadia/blob/master/BUILD_WIN.md)
|
||||
- [For Mac](https://github.com/vircadia/vircadia/blob/master/BUILD_OSX.md)
|
||||
- [For Linux](https://github.com/vircadia/vircadia/blob/master/BUILD_LINUX.md)
|
||||
- [For Linux - Vircadia Builder](https://github.com/vircadia/vircadia-builder)
|
||||
- [For Windows](https://github.com/overte-org/overte/blob/master/BUILD_WIN.md)
|
||||
- [For Mac](https://github.com/overte-org/overte/blob/master/BUILD_OSX.md)
|
||||
- [For Linux](https://github.com/overte-org/overte/blob/master/BUILD_LINUX.md)
|
||||
- [For Linux - Vircadia Builder](https://github.com/overte-org/overte-builder)
|
||||
|
||||
#### How to build a Server
|
||||
|
||||
- [For Windows](https://github.com/vircadia/vircadia/blob/master/BUILD_WIN.md)
|
||||
- [For Linux](https://github.com/vircadia/vircadia/blob/master/BUILD_LINUX.md)
|
||||
- [For Linux - Vircadia Builder](https://github.com/vircadia/vircadia-builder)
|
||||
- [For Windows](https://github.com/overte-org/overte/blob/master/BUILD_WIN.md)
|
||||
- [For Linux](https://github.com/overte-org/overte/blob/master/BUILD_LINUX.md)
|
||||
- [For Linux - Vircadia Builder](https://github.com/overte-org/overte-builder)
|
||||
|
||||
#### How to generate an Installer
|
||||
|
||||
- [For Windows - Interface & Server](https://github.com/vircadia/vircadia/blob/master/INSTALLER.md)
|
||||
- [For Mac - Interface](https://github.com/vircadia/vircadia/blob/master/INSTALLER.md#os-x)
|
||||
- [For Windows - Interface & Server](https://github.com/overte-org/overte/blob/master/INSTALLER.md)
|
||||
- [For Mac - Interface](https://github.com/overte-org/overte/blob/master/INSTALLER.md#os-x)
|
||||
- [For Linux - Server .deb - Vircadia Builder](INSTALLER.md#ubuntu-1804--deb)
|
||||
- [For Linux - Interface AppImage - Vircadia Builder](https://github.com/vircadia/vircadia-builder/blob/master/README.md#building-appimages)
|
||||
- [For Linux - Interface AppImage - Vircadia Builder](https://github.com/overte-org/overte-builder/blob/master/README.md#building-appimages)
|
||||
|
||||
### Boot to Metaverse: [The Goal](https://vircadia.com/vision/)
|
||||
### Boot to Metaverse: The Goal
|
||||
|
||||
Having a place to experience adventure, a place to relax with calm breath, that's a world to live in. An engine to support infinite combinations and possibilities of worlds without censorship and interruption, that's metaverse. Finding a way to make infinite realities our reality is the dream.
|
||||
|
||||
### Boot to Metaverse: The Technicals
|
||||
|
||||
Vircadia consists of many projects and codebases with its unifying structure's goal being a decentralized metaverse.
|
||||
Overte consists of many projects and codebases with its unifying structure's goal being a decentralized metaverse.
|
||||
|
||||
- The Interface (Codename Athena) - You are here!
|
||||
- The Server (Codename Athena) - You are also here!
|
||||
- [The Web Interface (Codename Aether)](https://github.com/vircadia/vircadia-web/)
|
||||
- [The Web SDK (Codename Ananke)](https://github.com/vircadia/vircadia-web-sdk/)
|
||||
- [The Metaverse Server (Codename Iamus)](https://github.com/vircadia/Iamus/)
|
||||
- [The Metaverse Server Dashboard (Codename Iamus)](https://github.com/vircadia/project-iamus-dashboard/)
|
||||
- [The Launcher (Codename Pantheon)](https://github.com/vircadia/pantheon-launcher/) - Currently Windows only.
|
||||
- The Interface - You are here!
|
||||
- The Server - You are also here!
|
||||
- [The Metaverse Server (Codename Iamus)](https://github.com/overte/Iamus/)
|
||||
- [The Metaverse Server Dashboard (Codename Iamus)](https://github.com/overte/project-iamus-dashboard/)
|
||||
- [The Launcher (Codename Pantheon)](https://github.com/overte/pantheon-launcher/) - Currently Windows only.
|
||||
|
||||
#### Tools
|
||||
- [Vircadia Builder for Linux](https://github.com/vircadia/vircadia-builder/)
|
||||
- [Overte Builder for Linux](https://github.com/overte-org/overte-builder/)
|
||||
|
||||
#### Documentation
|
||||
- [User Documentation](https://github.com/vircadia/vircadia-docs-sphinx/)
|
||||
- [Developer Documentation](https://github.com/vircadia/vircadia-dev-docs/)
|
||||
- [User Documentation](https://github.com/overte-org/overte-docs-sphinx/)
|
||||
- [Developer Documentation](https://github.com/overte-org/overte-dev-docs/)
|
||||
|
||||
### Contribution
|
||||
|
||||
There are many contributors to Vircadia. Code writers, reviewers, testers, documentation writers, modelers, and general supporters of the project are all integral to its development and success towards its goals. Find out how you can [contribute](https://vircadia.com/contribute)!
|
||||
|
||||
### Support
|
||||
|
||||
You can support the Vircadia project financially through [GitHub Sponsors](https://github.com/sponsors/digisomni/).
|
||||
|
||||
You can also support individual active contributors by visiting each repository, this is the main Vircadia repository's [list of active contributors](https://vircadia.com/contributors-redirector/?redirect=vircadia/vircadia). Click on a contributor's profile to see if they accept donations!
|
||||
|
||||
Keep in mind that Vircadia consists of multiple smaller projects that might have different active contributors. This is a [a non-exhaustive list](https://github.com/vircadia).
|
||||
|
||||
#### Supporters of the Vircadia Project
|
||||
|
||||
One (1) anonymous, three (3) total sponsors through GitHub. ❤️
|
||||
|
||||
| [Daichi Shimabukuro](https://github.com/mshlomd) |
|
||||
| --- |
|
||||
| <p align="center">[<img src="https://avatars.githubusercontent.com/u/4787162?v=4" width="80" alt="Daichi Shimabukuro" />](https://github.com/mshlomd)</p>
|
||||
There are many contributors to Overte. Code writers, reviewers, testers, documentation writers, modellers, and general supporters of the project are all integral to its development and success towards its goals. Find out how you can [contribute](https://docs.overte.org/en/latest/contribute.html)!
|
||||
|
|
|
@ -394,6 +394,12 @@ else()
|
|||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/Fonts"
|
||||
"${RESOURCES_DEV_DIR}/serverless/Fonts"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/Scripts"
|
||||
"${RESOURCES_DEV_DIR}/serverless/Scripts"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${RESOURCES_RCC}"
|
||||
"${INTERFACE_EXEC_DIR}/resources.rcc"
|
||||
|
|
202
interface/resources/serverless/Fonts/LICENSE.txt
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
BIN
interface/resources/serverless/Fonts/Roboto-Bold.ttf
Normal file
BIN
interface/resources/serverless/Fonts/Roboto-BoldItalic.ttf
Normal file
BIN
interface/resources/serverless/Fonts/Roboto-Italic.ttf
Normal file
BIN
interface/resources/serverless/Fonts/Roboto-Regular.ttf
Normal file
BIN
interface/resources/serverless/Images/applications.png
Normal file
After Width: | Height: | Size: 143 KiB |
BIN
interface/resources/serverless/Images/avatar.png
Normal file
After Width: | Height: | Size: 366 KiB |
BIN
interface/resources/serverless/Images/controls.png
Normal file
After Width: | Height: | Size: 584 KiB |
BIN
interface/resources/serverless/Images/tabletAndToolbar.png
Normal file
After Width: | Height: | Size: 340 KiB |
BIN
interface/resources/serverless/Models/avatarStand.fbx
Normal file
3
interface/resources/serverless/Models/avatarStand.fst
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = AVATAR_STAND
|
||||
filename = qrc:///serverless/Models/avatarStand.fbx
|
||||
materialMap = [{"mat::MAIN": {"materials":[{ "name": "MAIN", "albedo": [0.4235294117647059, 1, 0], "roughness": 0.26, "metallic": 1.0, "normalMap": "qrc:///serverless/Textures/concreteNormal512.jpg", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}, {"mat::LIGHT": {"materials":[{ "name": "LIGHT", "albedo": [1, 1, 1], "roughness": 0.5, "metallic": 0.01, "emissive": [1.89, 1.68247, 0.756], "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
BIN
interface/resources/serverless/Models/dome.fbx
Normal file
3
interface/resources/serverless/Models/dome.fst
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = DOME
|
||||
filename = qrc:///serverless/Models/dome.fbx
|
||||
materialMap = [{"mat::FLOOR": {"materials":[{ "name": "FLOOR", "albedo": [0.06 ,0.06 ,0.06], "roughness": 0.32, "metallic": 0.01, "normalMap": "qrc:///serverless/Textures/fundationNormal512.jpg", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}, {"mat::LIGHT": {"materials":[{ "name": "LIGHT", "albedo": [1, 1, 1], "roughness": 0.5, "metallic": 0.01, "emissive": [1.64741, 2.09, 0.713058], "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}, {"mat::STRUCTURE": {"materials":[{ "name": "STRUCTURE", "albedo": [0.7882, 0.9333, 0.6274], "roughness": 0.5, "metallic": 0.1, "albedoMap": "qrc:///serverless/Textures/Concrete15_col-512.jpg", "normalMap": "qrc:///serverless/Textures/concreteNormal512.jpg", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
BIN
interface/resources/serverless/Models/engery-bowl.fbx
Normal file
3
interface/resources/serverless/Models/engery-bowl.fst
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = ENERGY_BOWL
|
||||
filename = qrc:///serverless/Models/engery-bowl.fbx
|
||||
materialMap = [{"mat::MAIN": {"materials":[{ "name": "MAIN", "albedo": [1 ,1 ,1], "albedoMap": "qrc:///serverless/Textures/Metal26_col.jpg","roughness": 0.28, "metallic": 1.0, "normalMap": "qrc:///serverless/Textures/Metal26_nrm.jpg", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
BIN
interface/resources/serverless/Models/standAngle.fbx
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = STAND-ANGLE_APPLICATIONS
|
||||
filename = qrc:///serverless/Models/standAngle.fbx
|
||||
materialMap = [{"mat::IMAGE": {"materials":[{ "name": "IMAGE", "albedo": [1.0 ,1.0 ,1.0], "roughness": 0.2, "metallic": 0.01, "unlit": true, "albedoMap": "qrc:///serverless/Images/applications.png", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
|
@ -0,0 +1,3 @@
|
|||
name = STAND-ANGLE_AVATAR
|
||||
filename = qrc:///serverless/Models/standAngle.fbx
|
||||
materialMap = [{"mat::IMAGE": {"materials":[{ "name": "IMAGE", "albedo": [1.0 ,1.0 ,1.0], "roughness": 0.2, "metallic": 0.01, "unlit": true, "albedoMap": "qrc:///serverless/Images/avatar.png", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
|
@ -0,0 +1,3 @@
|
|||
name = STAND-ANGLE_CONFIG-WIZARD
|
||||
filename = qrc:///serverless/Models/standAngle.fbx
|
||||
materialMap = [{"mat::IMAGE": {"materials":[{ "name": "IMAGE", "albedo": [0 ,0 ,0], "roughness": 1, "metallic": 0.01, "unlit": true, "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
|
@ -0,0 +1,3 @@
|
|||
name = STAND-ANGLE_CONTROLS
|
||||
filename = qrc:///serverless/Models/standAngle.fbx
|
||||
materialMap = [{"mat::IMAGE": {"materials":[{ "name": "IMAGE", "albedo": [1.0 ,1.0 ,1.0], "roughness": 0.2, "metallic": 0.01, "unlit": true, "albedoMap": "qrc:///serverless/Images/controls.png", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
|
@ -0,0 +1,3 @@
|
|||
name = STAND-ANGLE_TABLET-TOOLBAR
|
||||
filename = qrc:///serverless/Models/standAngle.fbx
|
||||
materialMap = [{"mat::IMAGE": {"materials":[{ "name": "IMAGE", "albedo": [1.0 ,1.0 ,1.0], "roughness": 0.2, "metallic": 0.01, "unlit": true, "albedoMap": "qrc:///serverless/Images/tabletAndToolbar.png", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
BIN
interface/resources/serverless/Models/teleporter.fbx
Normal file
3
interface/resources/serverless/Models/teleporter.fst
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = TELEPORTER
|
||||
filename = qrc:///serverless/Models/teleporter.fbx
|
||||
materialMap = [{"mat::EXO": {"materials":[{ "name": "MAIN", "albedo": [0.06, 0.06, 0.06], "roughness": 0.26, "metallic": 1.0, "normalMap": "qrc:///serverless/Textures/concreteNormal512.jpg", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}, {"mat::LIGHT": {"materials":[{ "name": "LIGHT", "albedo": [1, 1, 1], "roughness": 0.5, "metallic": 0.01, "emissive": [1.51466666, 0.879843137, 2.84], "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}, {"mat::ENDO": {"materials":[{ "name": "ENDO", "albedo": [0.85, 0.85, 0.85], "roughness": 0.26, "metallic": 1.0, "normalMap": "qrc:///serverless/Textures/concreteNormal512.jpg", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
BIN
interface/resources/serverless/Models/test_area.fbx
Normal file
3
interface/resources/serverless/Models/test_area.fst
Normal file
|
@ -0,0 +1,3 @@
|
|||
name = QUICK-TEST-AREA
|
||||
filename = qrc:///serverless/Models/test_area.fbx
|
||||
materialMap = [{"mat::FLOOR": {"materials":[{ "name": "FLOOR", "albedo": [0.06 ,0.06 ,0.06], "roughness": 0.32, "metallic": 0.01, "normalMap": "qrc:///serverless/Textures/fundationNormal512.jpg", "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}, {"mat::LIGHT": {"materials":[{ "name": "LIGHT", "albedo": [1, 1, 1], "roughness": 0.5, "metallic": 0.01, "emissive": [1.64741, 2.09, 0.713058], "cullFaceMode": "CULL_NONE", "model": "hifi_pbr"}]}}]
|
|
@ -0,0 +1,99 @@
|
|||
'use strict';
|
||||
//
|
||||
// activator-doppleganger.js
|
||||
//
|
||||
// Created by Alezia Kurdis on February 20th, 2022.
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// This script is display a doppleganger of the user by entering an entity.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
var isActive = false;
|
||||
var thisEntityID;
|
||||
var versioncall = Math.floor(Math.random()*50000);
|
||||
var DopplegangerClass = Script.require('file:///~/serverless/Scripts/doppleganger.js?version=' + versioncall);
|
||||
|
||||
var doppleganger = new DopplegangerClass({
|
||||
avatar: MyAvatar,
|
||||
mirrored: false,
|
||||
autoUpdate: true
|
||||
});
|
||||
|
||||
this.preload = function(entityID) {
|
||||
thisEntityID = entityID;
|
||||
}
|
||||
|
||||
function onDomainChanged() {
|
||||
if (doppleganger.active) {
|
||||
doppleganger.stop('domain_changed');
|
||||
}
|
||||
}
|
||||
|
||||
Window.domainChanged.connect(onDomainChanged);
|
||||
|
||||
Window.domainConnectionRefused.connect(onDomainChanged);
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
if (isActive) {
|
||||
doppleganger.stop();
|
||||
isActive = false;
|
||||
}
|
||||
Window.domainChanged.disconnect(onDomainChanged);
|
||||
Window.domainConnectionRefused.disconnect(onDomainChanged);
|
||||
|
||||
});
|
||||
|
||||
this.enterEntity = function(entityID) {
|
||||
print("ENTERING");
|
||||
startDopplegangerShow(entityID);
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
this.leaveEntity = function(entityID) {
|
||||
print("LEAVING");
|
||||
doppleganger.stop();
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
function startDopplegangerShow(entityID) {
|
||||
var properties = Entities.getEntityProperties(entityID, ["position", "rotation"]);
|
||||
var avatarPosition = MyAvatar.position;
|
||||
var drawPosition = {
|
||||
"x": properties.position.x,
|
||||
"y": avatarPosition.y,
|
||||
"z": properties.position.z
|
||||
};
|
||||
var param = {
|
||||
"position": drawPosition,
|
||||
"orientation": properties.rotation,
|
||||
"autoUpdate": true
|
||||
};
|
||||
doppleganger.start(param);
|
||||
}
|
||||
|
||||
|
||||
MyAvatar.skeletonModelURLChanged.connect(function () {
|
||||
if (isActive) {
|
||||
print("CHANGED WHILE ACTIVE");
|
||||
doppleganger.stop();
|
||||
isActive = false;
|
||||
var timer = Script.setTimeout(function () {
|
||||
startDopplegangerShow(thisEntityID);
|
||||
isActive = true;
|
||||
}, 4000);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// alert the user if there was an error applying their skeletonModelURL
|
||||
doppleganger.addingEntity.connect(function(error, result) {
|
||||
if (doppleganger.active && error) {
|
||||
Window.alert('doppleganger | ' + error + '\n' + doppleganger.skeletonModelURL);
|
||||
}
|
||||
});
|
||||
|
||||
})
|
529
interface/resources/serverless/Scripts/doppleganger.js
Normal file
|
@ -0,0 +1,529 @@
|
|||
"use strict";
|
||||
//======================================
|
||||
// Version 1.1
|
||||
// Addaption to "Local" Entities (since Overlays get deprecated for "Model" type.)
|
||||
// by Alezia Kurdis on February 2020
|
||||
//======================================
|
||||
// Version 1.0
|
||||
// doppleganger.js
|
||||
//
|
||||
// Created by Timothy Dedischew on 04/21/2017.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
//
|
||||
/* global module */
|
||||
// @module doppleganger
|
||||
//
|
||||
// This module contains the `Doppleganger` class implementation for creating an inspectable replica of
|
||||
// an Avatar (as a model directly in front of and facing them). Joint positions and rotations are copied
|
||||
// over in an update thread, so that the model automatically mirrors the Avatar's joint movements.
|
||||
// An Avatar can then for example walk around "themselves" and examine from the back, etc.
|
||||
//
|
||||
// This should be helpful for inspecting your own look and debugging avatars, etc.
|
||||
//
|
||||
// The doppleganger is created as an overlay so that others do not see it -- and this also allows for the
|
||||
// highest possible update rate when keeping joint data in sync.
|
||||
//
|
||||
// NOTE: THIS IS A MODIFIED VERSION SPECIFICALLY FOR THE TUTORIAL.
|
||||
|
||||
module.exports = Doppleganger;
|
||||
|
||||
// @property {bool} - when set true, Script.update will be used instead of setInterval for syncing joint data
|
||||
Doppleganger.USE_SCRIPT_UPDATE = false;
|
||||
|
||||
// @property {int} - the frame rate to target when using setInterval for joint updates
|
||||
Doppleganger.TARGET_FPS = 60;
|
||||
|
||||
// @property {int} - the maximum time in seconds to wait for the model overlay to finish loading
|
||||
Doppleganger.MAX_WAIT_SECS = 10;
|
||||
|
||||
// @function - derive mirrored joint names from a list of regular joint names
|
||||
// @param {Array} - list of joint names to mirror
|
||||
// @return {Array} - list of mirrored joint names (note: entries for non-mirrored joints will be `undefined`)
|
||||
|
||||
var Setarry;
|
||||
|
||||
Doppleganger.getMirroredJointNames = function(jointNames) {
|
||||
return jointNames.map(function(name, i) {
|
||||
if (/Left/.test(name)) {
|
||||
return name.replace('Left', 'Right');
|
||||
}
|
||||
if (/Right/.test(name)) {
|
||||
return name.replace('Right', 'Left');
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
};
|
||||
|
||||
// @class Doppleganger - Creates a new instance of a Doppleganger.
|
||||
// @param {Avatar} [options.avatar=MyAvatar] - Avatar used to retrieve position and joint data.
|
||||
// @param {bool} [options.mirrored=true] - Apply "symmetric mirroring" of Left/Right joints.
|
||||
// @param {bool} [options.autoUpdate=true] - Automatically sync joint data.
|
||||
function Doppleganger(options) {
|
||||
options = options || {};
|
||||
this.avatar = options.avatar || MyAvatar;
|
||||
this.mirrored = 'mirrored' in options ? options.mirrored : false;
|
||||
this.autoUpdate = 'autoUpdate' in options ? options.autoUpdate : true;
|
||||
|
||||
// @public
|
||||
this.active = false; // whether doppleganger is currently being displayed/updated
|
||||
this.entityID = null; // current doppleganger's Entity id
|
||||
this.frame = 0; // current joint update frame
|
||||
|
||||
// @signal - emitted when .active state changes
|
||||
this.activeChanged = signal(function(active, reason) {});
|
||||
// @signal - emitted once model overlay is either loaded or errors out
|
||||
this.addingEntity = signal(function(error, result){});
|
||||
// @signal - emitted each time the model overlay's joint data has been synchronized
|
||||
this.jointsUpdated = signal(function(entityID){});
|
||||
}
|
||||
|
||||
Doppleganger.prototype = {
|
||||
// @public @method - toggles doppleganger on/off
|
||||
toggle: function() {
|
||||
if (this.active) {
|
||||
log('toggling off');
|
||||
this.stop();
|
||||
}else{
|
||||
log('toggling on');
|
||||
this.start();
|
||||
}
|
||||
return this.active;
|
||||
},
|
||||
|
||||
// @public @method - synchronize the joint data between Avatar / doppleganger
|
||||
update: function() {
|
||||
this.frame++;
|
||||
try {
|
||||
if (!this.entityID) {
|
||||
throw new Error('!this.entityID');
|
||||
}
|
||||
|
||||
if (this.avatar.skeletonModelURL !== this.skeletonModelURL) {
|
||||
//return this.stop('avatar_changed');
|
||||
}
|
||||
|
||||
var rotations = this.avatar.getJointRotations();
|
||||
var translations = this.avatar.getJointTranslations();
|
||||
var size = rotations.length;
|
||||
|
||||
|
||||
// note: this mismatch can happen when the avatar's model is actively changing
|
||||
if (size !== translations.length ||
|
||||
(this.jointStateCount && size !== this.jointStateCount)) {
|
||||
log('mismatched joint counts (avatar model likely changed)', size, translations.length, this.jointStateCount);
|
||||
this.stop('avatar_changed_joints');
|
||||
return;
|
||||
}
|
||||
this.jointStateCount = size;
|
||||
|
||||
|
||||
if (this.mirrored) {
|
||||
var mirroredIndexes = this.mirroredIndexes;
|
||||
var outRotations = new Array(size);
|
||||
var outTranslations = new Array(size);
|
||||
for (var i=0; i < size; i++) {
|
||||
var index = mirroredIndexes[i];
|
||||
if (index < 0 || index === false) {
|
||||
index = i;
|
||||
}
|
||||
var rot = rotations[index];
|
||||
var trans = translations[index];
|
||||
trans.x *= -1;
|
||||
rot.y *= -1;
|
||||
rot.z *= -1;
|
||||
outRotations[i] = rot;
|
||||
outTranslations[i] = trans;
|
||||
}
|
||||
rotations = outRotations;
|
||||
translations = outTranslations;
|
||||
}
|
||||
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
jointRotations: rotations,
|
||||
jointTranslations: translations,
|
||||
jointRotationsSet: Setarry,
|
||||
jointTranslationsSet: Setarry
|
||||
});
|
||||
|
||||
this.jointsUpdated(this.entityID);
|
||||
} catch (e) {
|
||||
//log('.update error: '+ e, index);
|
||||
this.stop('update_error');
|
||||
}
|
||||
},
|
||||
|
||||
// @public @method - show the doppleganger (and start the update thread, if options.autoUpdate was specified).
|
||||
// @param {vec3} [options.position=(in front of avatar)] - starting position
|
||||
// @param {quat} [options.orientation=avatar.orientation] - starting orientation
|
||||
start: function(options) {
|
||||
|
||||
|
||||
options = options || {};
|
||||
if (this.entityID) {
|
||||
//log('start() called but entity model already exists', this.entityID);
|
||||
return;
|
||||
}
|
||||
var avatar = this.avatar;
|
||||
if (!avatar.jointNames.length) {
|
||||
return this.stop('joints_unavailable');
|
||||
}
|
||||
|
||||
this.frame = 0;
|
||||
this.position = options.position || Vec3.sum(avatar.position, Quat.getForward(avatar.orientation));
|
||||
this.orientation = options.orientation || avatar.orientation;
|
||||
this.skeletonModelURL = avatar.skeletonModelURL;
|
||||
this.jointStateCount = 0;
|
||||
this.jointNames = avatar.jointNames;
|
||||
this.mirroredNames = Doppleganger.getMirroredJointNames(this.jointNames);
|
||||
//log(this.mirroredNames);
|
||||
this.mirroredIndexes = this.mirroredNames.map(function(name) {
|
||||
return name ? avatar.getJointIndex(name) : false;
|
||||
});
|
||||
//log(this.mirroredIndexes);
|
||||
var prop = {
|
||||
type: "Model",
|
||||
name: 'Doppelganger', //added
|
||||
visible: false, // normally false
|
||||
modelURL: this.skeletonModelURL, //was field: url
|
||||
position: this.position,
|
||||
rotation: this.orientation
|
||||
};
|
||||
|
||||
this.entityID = Entities.addEntity(prop, "local");
|
||||
|
||||
var allJoints = avatar.getJointRotations();
|
||||
var nbrJoints = allJoints.length;
|
||||
Setarry = Array(nbrJoints);
|
||||
for (var i=0; i < nbrJoints; i++) {
|
||||
Setarry[i] = true;
|
||||
}
|
||||
|
||||
this.onAddingEntity = function(error, result) {
|
||||
|
||||
if (error) {
|
||||
return this.stop(error);
|
||||
}
|
||||
log('ModelEntity is ready; # joints == ' + result.jointNames.length);
|
||||
Entities.editEntity(this.entityID, { visible: true });
|
||||
|
||||
this.syncVerticalPosition('LeftFoot');
|
||||
|
||||
if (this.autoUpdate) {
|
||||
this._createUpdateThread();
|
||||
}
|
||||
};
|
||||
this.addingEntity.connect(this, 'onAddingEntity');
|
||||
|
||||
log('doppleganger created; entityID =', this.entityID);
|
||||
|
||||
// trigger clean up (and stop updates) if the overlay gets deleted
|
||||
this.onDeletedEntity = function(uuid) {
|
||||
if (uuid === this.entityID) {
|
||||
log('onDeletedEntity', uuid);
|
||||
this.stop('entity_deleted');
|
||||
}
|
||||
};
|
||||
Entities.deletingEntity.connect(this, 'onDeletedEntity');
|
||||
|
||||
if ('onLoadComplete' in avatar) {
|
||||
// stop the current doppleganger if Avatar loads a different model URL
|
||||
this.onLoadComplete = function() {
|
||||
if (avatar.skeletonModelURL !== this.skeletonModelURL) {
|
||||
//this.stop('avatar_changed_load');
|
||||
}
|
||||
};
|
||||
avatar.onLoadComplete.connect(this, 'onLoadComplete');
|
||||
}
|
||||
|
||||
this.activeChanged(this.active = true, 'start');
|
||||
this._waitForModel(ModelCache.prefetch(this.skeletonModelURL));
|
||||
},
|
||||
|
||||
// @public @method - hide the doppleganger
|
||||
// @param {String} [reason=stop] - the reason stop was called
|
||||
stop: function(reason) {
|
||||
reason = reason || 'stop';
|
||||
if (this.onUpdate) {
|
||||
Script.update.disconnect(this, 'onUpdate');
|
||||
delete this.onUpdate;
|
||||
}
|
||||
if (this._interval) {
|
||||
Script.clearInterval(this._interval);
|
||||
this._interval = undefined;
|
||||
}
|
||||
if (this.onDeletedEntity) {
|
||||
Entities.deletingEntity.disconnect(this, 'onDeletedEntity');
|
||||
delete this.onDeletedEntity;
|
||||
}
|
||||
if (this.onLoadComplete) {
|
||||
this.avatar.onLoadComplete.disconnect(this, 'onLoadComplete');
|
||||
delete this.onLoadComplete;
|
||||
}
|
||||
if (this.onAddingEntity) {
|
||||
this.addingEntity.disconnect(this, 'onAddingEntity');
|
||||
}
|
||||
if (this.entityID) {
|
||||
Entities.deleteEntity(this.entityID);
|
||||
this.entityID = undefined;
|
||||
}
|
||||
if (this.active) {
|
||||
this.activeChanged(this.active = false, reason);
|
||||
} else if (reason) {
|
||||
log('already stopped so not triggering another activeChanged; latest reason was:', reason);
|
||||
}
|
||||
},
|
||||
|
||||
// @public @method - Reposition the doppleganger so it sees "eye to eye" with the Avatar.
|
||||
// @param {String} [byJointName=Hips] - the reference joint used to align the Doppleganger and Avatar
|
||||
syncVerticalPosition: function(byJointName) {
|
||||
byJointName = byJointName || 'Hips';
|
||||
|
||||
var dopplePosition = Entities.getEntityProperties(this.entityID, ["position"]);
|
||||
var doppleJointIndex = Entities.getJointIndex( this.entityID, byJointName );
|
||||
var doppleJointPosition = Vec3.sum(Entities.getAbsoluteJointTranslationInObjectFrame( this.entityID, doppleJointIndex ), dopplePosition);
|
||||
|
||||
//log("Joint Pos = " + JSON.stringify(doppleJointPosition));
|
||||
|
||||
var avatarPosition = this.avatar.position;
|
||||
var avatarJointIndex = this.avatar.getJointIndex(byJointName);
|
||||
var avatarJointPosition = Vec3.sum(this.avatar.getAbsoluteJointTranslationInObjectFrame(avatarJointIndex), avatarPosition);
|
||||
|
||||
//log("AV Joint Pos = " + JSON.stringify(avatarJointPosition));
|
||||
|
||||
dopplePosition.position.y = avatarJointPosition.y - doppleJointPosition.y;
|
||||
this.position = dopplePosition.position;
|
||||
Entities.editEntity(this.entityID, { position: this.position });
|
||||
},
|
||||
|
||||
// @private @method - creates the update thread to synchronize joint data
|
||||
_createUpdateThread: function() {
|
||||
if (Doppleganger.USE_SCRIPT_UPDATE) {
|
||||
log('creating Script.update thread');
|
||||
this.onUpdate = this.update;
|
||||
Script.update.connect(this, 'onUpdate');
|
||||
} else {
|
||||
log('creating Script.setInterval thread @ ~', Doppleganger.TARGET_FPS +'fps');
|
||||
var timeout = 1000 / Doppleganger.TARGET_FPS;
|
||||
this._interval = Script.setInterval(bind(this, 'update'), timeout);
|
||||
}
|
||||
},
|
||||
|
||||
// @private @method - waits for model to load and handles timeouts
|
||||
// @param {ModelResource} resource - a prefetched resource to monitor loading state against
|
||||
_waitForModel: function(resource) {
|
||||
var RECHECK_MS = 50;
|
||||
var id = this.entityID,
|
||||
watchdogTimer = null;
|
||||
|
||||
function waitForJointNames() {
|
||||
var error = null, result = null;
|
||||
if (!watchdogTimer) {
|
||||
error = 'joints_unavailable';
|
||||
} else if (resource.state === Resource.State.FAILED) {
|
||||
error = 'prefetch_failed';
|
||||
} else if (resource.state === Resource.State.FINISHED) {
|
||||
var names = Entities.getJointNames(id);
|
||||
if (Array.isArray(names) && names.length) {
|
||||
result = { entityID: id, jointNames: names };
|
||||
}
|
||||
}
|
||||
if (error || result !== null) {
|
||||
Script.clearInterval(this._interval);
|
||||
this._interval = null;
|
||||
if (watchdogTimer) {
|
||||
Script.clearTimeout(watchdogTimer);
|
||||
}
|
||||
this.addingEntity(error, result);
|
||||
}
|
||||
}
|
||||
watchdogTimer = Script.setTimeout(function() {
|
||||
watchdogTimer = null;
|
||||
}, Doppleganger.MAX_WAIT_SECS * 1000);
|
||||
this._interval = Script.setInterval(bind(this, waitForJointNames), RECHECK_MS);
|
||||
}
|
||||
};
|
||||
|
||||
// @function - bind a function to a `this` context
|
||||
// @param {Object} - the `this` context
|
||||
// @param {Function|String} - function or method name
|
||||
function bind(thiz, method) {
|
||||
method = thiz[method] || method;
|
||||
return function() {
|
||||
return method.apply(thiz, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
// @function - Qt signal polyfill
|
||||
function signal(template) {
|
||||
var callbacks = [];
|
||||
return Object.defineProperties(function() {
|
||||
var args = [].slice.call(arguments);
|
||||
callbacks.forEach(function(obj) {
|
||||
obj.handler.apply(obj.scope, args);
|
||||
});
|
||||
}, {
|
||||
connect: { value: function(scope, handler) {
|
||||
callbacks.push({scope: scope, handler: scope[handler] || handler || scope});
|
||||
}},
|
||||
disconnect: { value: function(scope, handler) {
|
||||
var match = {scope: scope, handler: scope[handler] || handler || scope};
|
||||
callbacks = callbacks.filter(function(obj) {
|
||||
return !(obj.scope === match.scope && obj.handler === match.handler);
|
||||
});
|
||||
}}
|
||||
});
|
||||
}
|
||||
|
||||
// @function - debug logging
|
||||
function log() {
|
||||
//print('doppleganger | ' + [].slice.call(arguments).join(' '));
|
||||
}
|
||||
|
||||
// -- ADVANCED DEBUGGING --
|
||||
// @function - Add debug joint indicators / extra debugging info.
|
||||
// @param {Doppleganger} - existing Doppleganger instance to add controls to
|
||||
//
|
||||
// @note:
|
||||
// * rightclick toggles mirror mode on/off
|
||||
// * shift-rightclick toggles the debug indicators on/off
|
||||
// * clicking on an indicator displays the joint name and mirrored joint name in the debug log.
|
||||
//
|
||||
// Example use:
|
||||
// var doppleganger = new Doppleganger();
|
||||
// Doppleganger.addDebugControls(doppleganger);
|
||||
Doppleganger.addDebugControls = function(doppleganger) {
|
||||
DebugControls.COLOR_DEFAULT = { red: 255, blue: 255, green: 255 };
|
||||
DebugControls.COLOR_SELECTED = { red: 0, blue: 255, green: 0 };
|
||||
|
||||
function DebugControls() {
|
||||
this.enableIndicators = true;
|
||||
this.selectedJointName = null;
|
||||
this.debugEntityIDs = undefined;
|
||||
this.jointSelected = signal(function(result) {});
|
||||
}
|
||||
DebugControls.prototype = {
|
||||
start: function() {
|
||||
if (!this.onMousePressEvent) {
|
||||
this.onMousePressEvent = this._onMousePressEvent;
|
||||
Controller.mousePressEvent.connect(this, 'onMousePressEvent');
|
||||
}
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
this.removeIndicators();
|
||||
if (this.onMousePressEvent) {
|
||||
Controller.mousePressEvent.disconnect(this, 'onMousePressEvent');
|
||||
delete this.onMousePressEvent;
|
||||
}
|
||||
},
|
||||
|
||||
createIndicators: function(jointNames) {
|
||||
this.jointNames = jointNames;
|
||||
return jointNames.map(function(name, i) {
|
||||
return Entities.addEntity({
|
||||
type: "Shape",
|
||||
shape: 'Icosahedron',
|
||||
scale: 0.1,
|
||||
solid: false,
|
||||
alpha: 0.5
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
removeIndicators: function() {
|
||||
if (this.debugEntityIDs) {
|
||||
this.debugEntityIDs.forEach(Entities.deleteEntity);
|
||||
this.debugEntityIDs = undefined;
|
||||
}
|
||||
},
|
||||
|
||||
onJointsUpdated: function(entityID) {
|
||||
if (!this.enableIndicators) {
|
||||
return;
|
||||
}
|
||||
var jointNames = Entities.getJointNames(entityID),
|
||||
jointOrientations = Entities.getEntityProperties(entityID, ['jointRotations']), //was jointOrientations
|
||||
jointPositions = Entities.getEntityProperties(entityID, ['jointTranslations']), //was jointPositions
|
||||
//selectedIndex = jointNames.indexOf(this.selectedJointName);
|
||||
selectedIndex = Entities.getJointIndex( entityID, this.selectedJointName );
|
||||
|
||||
if (!this.debugEntityIDs) {
|
||||
this.debugEntityIDs = this.createIndicators(jointNames);
|
||||
}
|
||||
|
||||
// batch all updates into a single call (using the editOverlays({ id: {props...}, ... }) API)
|
||||
var updatedOverlays = this.debugEntityIDs.reduce(function(updates, id, i) {
|
||||
updates[id] = {
|
||||
position: jointPositions.jointTranslations[i],
|
||||
rotation: jointOrientations.jointRotations[i],
|
||||
color: i === selectedIndex ? DebugControls.COLOR_SELECTED : DebugControls.COLOR_DEFAULT,
|
||||
solid: i === selectedIndex
|
||||
};
|
||||
return updates;
|
||||
}, {});
|
||||
//Entities.editOverlays(updatedOverlays);
|
||||
},
|
||||
|
||||
_onMousePressEvent: function(evt) {
|
||||
if (!evt.isLeftButton || !this.enableIndicators || !this.debugEntityIDs) {
|
||||
return;
|
||||
}
|
||||
var ray = Camera.computePickRay(evt.x, evt.y),
|
||||
hit = Entities.findRayIntersection(ray, true, this.debugEntityIDs);
|
||||
|
||||
hit.jointIndex = this.debugEntityIDs.indexOf(hit.entityID);
|
||||
hit.jointName = this.jointNames[hit.jointIndex];
|
||||
this.jointSelected(hit);
|
||||
}
|
||||
};
|
||||
|
||||
if ('$debugControls' in doppleganger) {
|
||||
throw new Error('only one set of debug controls can be added per doppleganger');
|
||||
}
|
||||
var debugControls = new DebugControls();
|
||||
doppleganger.$debugControls = debugControls;
|
||||
|
||||
function onMousePressEvent(evt) {
|
||||
if (evt.isRightButton) {
|
||||
if (evt.isShifted) {
|
||||
debugControls.enableIndicators = !debugControls.enableIndicators;
|
||||
if (!debugControls.enableIndicators) {
|
||||
debugControls.removeIndicators();
|
||||
}
|
||||
} else {
|
||||
doppleganger.mirrored = !doppleganger.mirrored;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doppleganger.activeChanged.connect(function(active) {
|
||||
if (active) {
|
||||
debugControls.start();
|
||||
doppleganger.jointsUpdated.connect(debugControls, 'onJointsUpdated');
|
||||
Controller.mousePressEvent.connect(onMousePressEvent);
|
||||
} else {
|
||||
Controller.mousePressEvent.disconnect(onMousePressEvent);
|
||||
doppleganger.jointsUpdated.disconnect(debugControls, 'onJointsUpdated');
|
||||
debugControls.stop();
|
||||
}
|
||||
});
|
||||
|
||||
debugControls.jointSelected.connect(function(hit) {
|
||||
debugControls.selectedJointName = hit.jointName;
|
||||
if (hit.jointIndex < 0) {
|
||||
return;
|
||||
}
|
||||
hit.mirroredJointName = Doppleganger.getMirroredJointNames([hit.jointName])[0];
|
||||
log('selected joint:', JSON.stringify(hit, 0, 2));
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(debugControls, 'removeIndicators');
|
||||
|
||||
return doppleganger;
|
||||
};
|
|
@ -1,59 +0,0 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
// 2020 Silverfish.
|
||||
//material sequencer, put on a material entity (server script) to make it iterate through discrete steps of X UV offset.
|
||||
|
||||
/*UserData:
|
||||
{
|
||||
"verticalOffset": 0,
|
||||
"segments": 16,
|
||||
"updateInterval": 250
|
||||
}
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var DEFAULT_VERTICAL_OFFSET = 0.0;
|
||||
var DEFAULT_HORIZONTAL_SPEED = 1;
|
||||
var DEFAULT_UPDATE_INTERVAL = 1000;
|
||||
var DEFAULT_SEGMENTS = 16;
|
||||
|
||||
var self = this;
|
||||
var _entityID;
|
||||
this.preload = function(entityID) {
|
||||
_entityID = entityID;
|
||||
var verticalOffset = DEFAULT_VERTICAL_OFFSET;
|
||||
var updateInterval = DEFAULT_UPDATE_INTERVAL;
|
||||
var moveDistance = 1 / DEFAULT_SEGMENTS;
|
||||
var verticalOffset = DEFAULT_VERTICAL_OFFSET;
|
||||
var oldPosition = 0;
|
||||
var currentPosition = 0;
|
||||
var userData = JSON.parse(Entities.getEntityProperties(_entityID, ["userData"]).userData);
|
||||
if (userData !== undefined) {
|
||||
if (userData.segments !== undefined) {
|
||||
moveDistance = 1 / userData.segments;
|
||||
}
|
||||
if (userData.verticalOffset !== undefined) {
|
||||
verticalOffset = userData.verticalOffset;
|
||||
}
|
||||
if (userData.updateInterval !== undefined) {
|
||||
updateInterval = userData.updateInterval;
|
||||
}
|
||||
}
|
||||
|
||||
self.intervalID = Script.setInterval(function() {
|
||||
if(currentPosition >= 1){
|
||||
currentPosition = 0;
|
||||
oldPosition = 0;
|
||||
}
|
||||
|
||||
Entities.editEntity(_entityID, { materialMappingPos: { x: currentPosition, y: verticalOffset}});
|
||||
// print("current Pos: " + currentPosition);
|
||||
currentPosition = oldPosition + moveDistance;
|
||||
oldPosition = currentPosition;
|
||||
}, updateInterval);
|
||||
};
|
||||
|
||||
this.unload = function() {
|
||||
Script.clearInterval(self.intervalID);
|
||||
}
|
||||
});
|
|
@ -1,182 +0,0 @@
|
|||
//
|
||||
// mirrorClient.js
|
||||
//
|
||||
// Created by Patrick Manalich
|
||||
// Edited by Rebecca Stankus on 8/30/17.
|
||||
// Edited by David Back on 11/17/17.
|
||||
// Edited by Anna Brewer on 7/12/19.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Attach `mirrorClient.js` to a box entity whose z dimension is very small,
|
||||
// and whose x and y dimensions are up to you. See comments in `mirrorReflection.js`
|
||||
// for more information about the mirror on/off zone.
|
||||
|
||||
"use strict";
|
||||
|
||||
(function () { // BEGIN LOCAL SCOPE
|
||||
|
||||
// VARIABLES
|
||||
/* globals utils, Render */
|
||||
var _this = this;
|
||||
var MAX_MIRROR_RESOLUTION_SIDE_PX = 960; // The max pixel resolution of the long side of the mirror
|
||||
var ZERO_ROT = { w: 1, x: 0, y: 0, z: 0 }; // Constant quaternion for a rotation of 0
|
||||
var FAR_CLIP_DISTANCE = 16; // The far clip distance for the spectator camera when the mirror is on
|
||||
var mirrorLocalEntityID = false; // The entity ID of the local entity that displays the mirror reflection
|
||||
var mirrorLocalEntityRunning; // True if mirror local entity is reflecting, false otherwise
|
||||
var mirrorLocalEntityOffset = 0.01; // The distance between the center of the mirror and the mirror local entity
|
||||
var spectatorCameraConfig = Render.getConfig("SecondaryCamera"); // Render configuration for the spectator camera
|
||||
var lastDimensions = { x: 0, y: 0 }; // The previous dimensions of the mirror
|
||||
var previousFarClipDistance; // Store the specator camera's previous far clip distance that we override for the mirror
|
||||
|
||||
// LOCAL FUNCTIONS
|
||||
function isPositionInsideBox(position, boxProperties) {
|
||||
var localPosition = Vec3.multiplyQbyV(Quat.inverse(boxProperties.rotation),
|
||||
Vec3.subtract(MyAvatar.position, boxProperties.position));
|
||||
var halfDimensions = Vec3.multiply(boxProperties.dimensions, 0.5);
|
||||
return -halfDimensions.x <= localPosition.x &&
|
||||
halfDimensions.x >= localPosition.x &&
|
||||
-halfDimensions.y <= localPosition.y &&
|
||||
halfDimensions.y >= localPosition.y &&
|
||||
-halfDimensions.z <= localPosition.z &&
|
||||
halfDimensions.z >= localPosition.z;
|
||||
}
|
||||
|
||||
// When x or y dimensions of the mirror change - reset the resolution of the
|
||||
// spectator camera and edit the mirror local entity to adjust for the new dimensions
|
||||
function updateMirrorDimensions(forceUpdate) {
|
||||
|
||||
if (!mirrorLocalEntityID) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mirrorLocalEntityRunning) {
|
||||
var newDimensions = Entities.getEntityProperties(_this.entityID, 'dimensions').dimensions;
|
||||
|
||||
if (forceUpdate === true || (newDimensions.x != lastDimensions.x || newDimensions.y != lastDimensions.y)) {
|
||||
var mirrorResolution = _this.calculateMirrorResolution(newDimensions);
|
||||
spectatorCameraConfig.resetSizeSpectatorCamera(mirrorResolution.x, mirrorResolution.y);
|
||||
Entities.editEntity(mirrorLocalEntityID, {
|
||||
dimensions: {
|
||||
x: (Math.max(newDimensions.x, newDimensions.y)),
|
||||
y: (Math.max(newDimensions.x, newDimensions.y)),
|
||||
z: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
lastDimensions = newDimensions;
|
||||
}
|
||||
}
|
||||
|
||||
// Takes in an mirror scalar number which is used for the index of "halfDimSigns" that is needed to adjust the mirror
|
||||
// local entity's position. Deletes and re-adds the mirror local entity so the url and position are updated.
|
||||
function createMirrorLocalEntity() {
|
||||
|
||||
if (mirrorLocalEntityID) {
|
||||
Entities.deleteEntity(mirrorLocalEntityID);
|
||||
mirrorLocalEntityID = false;
|
||||
}
|
||||
|
||||
if (mirrorLocalEntityRunning) {
|
||||
mirrorLocalEntityID = Entities.addEntity({
|
||||
type: "Image",
|
||||
name: "mirrorLocalEntity",
|
||||
imageURL: "resource://spectatorCameraFrame",
|
||||
emissive: true,
|
||||
parentID: _this.entityID,
|
||||
alpha: 1,
|
||||
localPosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: mirrorLocalEntityOffset
|
||||
},
|
||||
localRotation: Quat.fromPitchYawRollDegrees(0, 0, 180),
|
||||
isVisibleInSecondaryCamera: false
|
||||
}, "local");
|
||||
|
||||
updateMirrorDimensions(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_this.calculateMirrorResolution = function(entityDimensions) {
|
||||
var mirrorResolutionX, mirrorResolutionY;
|
||||
if (entityDimensions.x > entityDimensions.y) {
|
||||
mirrorResolutionX = MAX_MIRROR_RESOLUTION_SIDE_PX;
|
||||
mirrorResolutionY = Math.round(mirrorResolutionX * entityDimensions.y / entityDimensions.x);
|
||||
} else {
|
||||
mirrorResolutionY = MAX_MIRROR_RESOLUTION_SIDE_PX;
|
||||
mirrorResolutionX = Math.round(mirrorResolutionY * entityDimensions.x / entityDimensions.y);
|
||||
}
|
||||
|
||||
var resolution = {
|
||||
"x": mirrorResolutionX,
|
||||
"y": mirrorResolutionY
|
||||
};
|
||||
|
||||
return resolution;
|
||||
};
|
||||
|
||||
// Sets up spectator camera to render the mirror, calls 'createMirrorLocalEntity' once to set up
|
||||
// mirror local entity, then connects 'updateMirrorDimensions' to update dimension changes
|
||||
_this.mirrorLocalEntityOn = function(onPreload) {
|
||||
if (!mirrorLocalEntityRunning) {
|
||||
if (!spectatorCameraConfig.attachedEntityId) {
|
||||
mirrorLocalEntityRunning = true;
|
||||
spectatorCameraConfig.mirrorProjection = true;
|
||||
spectatorCameraConfig.attachedEntityId = _this.entityID;
|
||||
previousFarClipDistance = spectatorCameraConfig.farClipPlaneDistance;
|
||||
spectatorCameraConfig.farClipPlaneDistance = FAR_CLIP_DISTANCE;
|
||||
var entityProperties = Entities.getEntityProperties(_this.entityID, ['dimensions']);
|
||||
var mirrorEntityDimensions = entityProperties.dimensions;
|
||||
var initialResolution = _this.calculateMirrorResolution(mirrorEntityDimensions);
|
||||
spectatorCameraConfig.resetSizeSpectatorCamera(initialResolution.x, initialResolution.y);
|
||||
spectatorCameraConfig.enableSecondaryCameraRenderConfigs(true);
|
||||
createMirrorLocalEntity();
|
||||
Script.update.connect(updateMirrorDimensions);
|
||||
} else {
|
||||
print("Cannot turn on mirror if spectator camera is already in use");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Resets spectator camera, deletes the mirror local entity, and disconnects 'updateMirrorDimensions'
|
||||
_this.mirrorLocalEntityOff = function() {
|
||||
if (mirrorLocalEntityRunning) {
|
||||
spectatorCameraConfig.enableSecondaryCameraRenderConfigs(false);
|
||||
spectatorCameraConfig.mirrorProjection = false;
|
||||
spectatorCameraConfig.attachedEntityId = null;
|
||||
spectatorCameraConfig.farClipPlaneDistance = previousFarClipDistance;
|
||||
if (mirrorLocalEntityID) {
|
||||
Entities.deleteEntity(mirrorLocalEntityID);
|
||||
mirrorLocalEntityID = false;
|
||||
}
|
||||
Script.update.disconnect(updateMirrorDimensions);
|
||||
mirrorLocalEntityRunning = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ENTITY FUNCTIONS
|
||||
_this.preload = function(entityID) {
|
||||
_this.entityID = entityID;
|
||||
mirrorlocalEntityRunning = false;
|
||||
|
||||
// If avatar is already inside the mirror zone at the time preload is called then turn on the mirror
|
||||
var children = Entities.getChildrenIDs(_this.entityID);
|
||||
var childZero = Entities.getEntityProperties(children[0]);
|
||||
if (isPositionInsideBox(MyAvatar.position, {
|
||||
position: childZero.position,
|
||||
rotation: childZero.rotation,
|
||||
dimensions: childZero.dimensions
|
||||
})) {
|
||||
_this.mirrorLocalEntityOn(true);
|
||||
}
|
||||
};
|
||||
|
||||
// Turn off mirror on unload
|
||||
_this.unload = function(entityID) {
|
||||
_this.mirrorLocalEntityOff();
|
||||
};
|
||||
});
|
|
@ -1,32 +0,0 @@
|
|||
//
|
||||
// mirrorReflection.js
|
||||
//
|
||||
// Created by Rebecca Stankus on 8/30/17.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Attach `mirrorReflection.js` to a zone entity that is parented to
|
||||
// the box entity whose Script is `mirrorClient.js`.
|
||||
// When a user enters this zone, the mirror will turn on.
|
||||
// When a user leaves this zone, the mirror will turn off.
|
||||
|
||||
(function () {
|
||||
var mirrorID, reflectionAreaID;
|
||||
// get id of reflection area and mirror
|
||||
this.preload = function(entityID) {
|
||||
reflectionAreaID = entityID;
|
||||
mirrorID = Entities.getEntityProperties(reflectionAreaID, 'parentID').parentID;
|
||||
};
|
||||
|
||||
// when avatar enters reflection area, begin reflecting
|
||||
this.enterEntity = function(entityID){
|
||||
Entities.callEntityMethod(mirrorID, 'mirrorLocalEntityOn');
|
||||
};
|
||||
|
||||
// when avatar leaves reflection area, stop reflecting
|
||||
this.leaveEntity = function (entityID) {
|
||||
Entities.callEntityMethod(mirrorID, 'mirrorLocalEntityOff');
|
||||
};
|
||||
});
|
490
interface/resources/serverless/Scripts/wizard.html
Normal file
|
@ -0,0 +1,490 @@
|
|||
<!DOCTYPE html>
|
||||
<!--
|
||||
//
|
||||
// wizard.html
|
||||
//
|
||||
// Created by Alezia Kurdis based on a concept from Kalila L. on February 18th 2022
|
||||
// Copyright 2022 Overte. e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Quick Configuration</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Roboto'
|
||||
src: url('file:///~/serverless/Fonts/Roboto-Regular.ttf') format('truetype')
|
||||
font-weight: normal
|
||||
font-style: normal
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto'
|
||||
src: url('file:///~/serverless/Fonts/Roboto-Bold.ttf') format('truetype')
|
||||
font-weight: bold
|
||||
font-style: normal
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('file:///~/serverless/Fonts/Roboto-Italic.ttf');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
src: url('file:///~/serverless/Fonts/Roboto-BoldItalic.ttf');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
html, body {
|
||||
font-family: Roboto;
|
||||
font-size:140%;
|
||||
color:#ffffff;
|
||||
margin:2%;
|
||||
padding:0%;
|
||||
width:96%;
|
||||
height:90%;
|
||||
background-color:#433952;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: Roboto;
|
||||
color:#ffffff;
|
||||
font-size:200%;
|
||||
}
|
||||
|
||||
table.maintable {
|
||||
width:100%;
|
||||
height:95%;
|
||||
border-collapse:collapse;
|
||||
padding:2%;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.pagetable {
|
||||
width:100%;
|
||||
height:100%;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
|
||||
div.page {
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.activeBtn {
|
||||
font-family: Roboto;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
background: #0033ff;
|
||||
background-image: linear-gradient(to bottom, #0033ff, #002259);
|
||||
border-radius: 18px;
|
||||
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.5);
|
||||
color: #ffffff;
|
||||
border: 0px;
|
||||
padding: 10px 20px 10px 20px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.activeBtn:hover {
|
||||
font-family: Roboto;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
background: #0599fc;
|
||||
background-image: linear-gradient(to bottom, #0599fc, #003670);
|
||||
text-decoration: none;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.completeBtn {
|
||||
font-family: Roboto;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
background: #00ff00;
|
||||
background-image: linear-gradient(to bottom, #00ff00, #003600);
|
||||
border-radius: 18px;
|
||||
border: 0px;
|
||||
box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.5);
|
||||
color: #ffffff;
|
||||
padding: 10px 20px 10px 20px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.completeBtn:hover {
|
||||
font-family: Roboto;
|
||||
font-size: 140%;
|
||||
font-weight: bold;
|
||||
background: #59ffc2;
|
||||
background-image: linear-gradient(to bottom, #59ffc2, #196144);
|
||||
text-decoration: none;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.displayName {
|
||||
font-family: Roboto;
|
||||
font-size: 130%;
|
||||
font-weight: bold;
|
||||
color:#0000ff;
|
||||
}
|
||||
|
||||
.choice {
|
||||
font-family: Roboto;
|
||||
font-size: 130%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.green {
|
||||
color:#00ba1c;
|
||||
}
|
||||
|
||||
|
||||
.orange {
|
||||
color:#ff9900;
|
||||
}
|
||||
|
||||
.red {
|
||||
color:#ff0000;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
color:#ffff00;
|
||||
}
|
||||
|
||||
.blue {
|
||||
color:#0096db;
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
height:35px;
|
||||
width:35px;
|
||||
}
|
||||
|
||||
.stepper-wrapper {
|
||||
margin-top: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.stepper-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.stepper-item::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
border-bottom: 2px solid #ccc;
|
||||
width: 100%;
|
||||
top: 20px;
|
||||
left: -50%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.stepper-item::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
border-bottom: 2px solid #ccc;
|
||||
width: 100%;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.stepper-item .step-counter {
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: #ccc;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.stepper-item.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stepper-item.completed .step-counter {
|
||||
background-color: #4bb543;
|
||||
}
|
||||
|
||||
.stepper-item.completed::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
border-bottom: 2px solid #4bb543;
|
||||
width: 100%;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.stepper-item:first-child::before {
|
||||
content: none;
|
||||
}
|
||||
.stepper-item:last-child::after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
#flowStatusBar {
|
||||
background-color: #26202e;
|
||||
border-radius: 3%;
|
||||
padding: 1%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table class="maintable">
|
||||
<tr>
|
||||
<td style="height:10%;">
|
||||
<div id='flowStatusBar'></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="height:90%;">
|
||||
<div id='page1' class='page'>
|
||||
<table class="pagetable">
|
||||
<tr>
|
||||
<td colspan='2' style="height:25%;">
|
||||
<h1>Welcome to Overte!</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' style="height:65%;">
|
||||
Let's get you setup to experience the virtual world. <br/>
|
||||
First, we need to select some performance and graphics quality options. <br/><br/>
|
||||
Press <b style="color: #2e89ff;">Continue</b> when you are ready.<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align = 'left' style="height:10%;">
|
||||
|
||||
</td>
|
||||
<td align='right' style="height:10%;">
|
||||
<button class = 'activeBtn' onClick="movetoPage(2);">Continue ›</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id='page2' class='page'>
|
||||
<table class="pagetable">
|
||||
<tr>
|
||||
<td colspan='2' style="height:25%;">
|
||||
<h1>Quality</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' style="height:65%;">
|
||||
What level of visual quality would you like?<br/>
|
||||
<b>Remember! If you do not have a powerful computer,<br/>you may want to set this to low or medium at most.</b>
|
||||
<br/><br/>
|
||||
<div> <input type="radio" name="performancePreset" value = "1" onClick="performancePreset = 1;"> <strong class="choice orange">Very Low Quality</strong> Slow Laptop / Very Slow Computer</div>
|
||||
<div> <input type="radio" name="performancePreset" value = "2" onClick="performancePreset = 2;"> <strong class="choice yellow">Low Quality</strong> Average Laptop / Slow Computer</div>
|
||||
<div> <input type="radio" name="performancePreset" value = "3" onClick="performancePreset = 3;"> <strong class="choice green">Medium Quality</strong> Average Computer - <b><i class='green'>Recommended</i></b></div>
|
||||
<div> <input type="radio" name="performancePreset" value = "4" onClick="performancePreset = 4;"> <strong class="choice blue">High Quality</strong> Gaming Computer</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align = 'left' style="height:10%;">
|
||||
<button class = 'activeBtn' onClick="movetoPage(1);">‹ Back</button>
|
||||
</td>
|
||||
<td align = 'right' style="height:10%;">
|
||||
<button class = 'activeBtn' onClick="movetoPage(3);">Continue ›</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id='page3' class='page'>
|
||||
<table class="pagetable">
|
||||
<tr>
|
||||
<td colspan='2' style="height:25%;">
|
||||
<h1>Performance</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' style="height:65%;">
|
||||
Do you want a smooth experience <i>(high refresh rate)</i><br/>or do you want to conserve power and resources <i>(low refresh rate)</i> on your computer?<br/>
|
||||
<b><i>Note: This does not apply to virtual reality headsets.</i></b>
|
||||
<br/><br/>
|
||||
<div class="text-h5"> <input type="radio" name="refreshRateProfile" value = "0" onClick="refreshRateProfile = 0;"> <strong class="choice orange">Not Smooth (20 Hz)</strong> Conserve Power</div>
|
||||
<div class="text-h5"> <input type="radio" name="refreshRateProfile" value = "1" onClick="refreshRateProfile = 1;"> <strong class="choice yellow">Smooth (30 Hz)</strong> Use Average Resources</div>
|
||||
<div class="text-h5"> <input type="radio" name="refreshRateProfile" value = "2" onClick="refreshRateProfile = 2;"> <strong class="choice green">Very Smooth (60 Hz)</strong> Use Maximum Resources - <b><i class='green'>Recommended</i></b></div>
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align = 'left' style="height:10%;">
|
||||
<button class = 'activeBtn' onClick="movetoPage(2);">‹ Back</button>
|
||||
</td>
|
||||
<td align = 'right' style="height:10%;">
|
||||
<button class = 'activeBtn' onClick="movetoPage(4);">Continue ›</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id='page4' class='page'>
|
||||
<table class="pagetable">
|
||||
<tr>
|
||||
<td colspan='2' style="height:25%;">
|
||||
<h1>Display Name</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' style="height:65%;">
|
||||
What should people call you?<br/>
|
||||
This is simply a nickname, it will be shown in place of your username (if you have one).
|
||||
<br/><br/>
|
||||
NAME: <input class = 'displayName' type = "text" id='displayName' size='40' onChange = "displayName = this.value;">
|
||||
<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align = 'left' style="height:10%;">
|
||||
<button class = 'activeBtn' onClick="movetoPage(3);">‹ Back</button>
|
||||
</td>
|
||||
<td align = 'right' style="height:10%;">
|
||||
<button class = 'activeBtn' onClick="movetoPage(5);">Continue ›</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id='page5' class='page'>
|
||||
<table class="pagetable">
|
||||
<tr>
|
||||
<td colspan='2' style="height:25%;">
|
||||
<h1>All done!</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='2' style="height:65%;">
|
||||
Now you're almost ready to go!<br/>
|
||||
Press <b style="color: #1ee62e;">Complete</b> to save your setup.<br/>
|
||||
Then take a look at the other information kiosks after completing this wizard.<br/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align = 'left' style="height:10%;">
|
||||
<button class = 'activeBtn' onClick="movetoPage(4);">‹ Back</button>
|
||||
</td>
|
||||
<td align = 'right' style="height:10%;">
|
||||
<button class = 'completeBtn' onClick = "completion();">Complete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<script>
|
||||
var performancePreset;
|
||||
var refreshRateProfile;
|
||||
var displayName = "";
|
||||
|
||||
EventBridge.scriptEventReceived.connect(function (message) {
|
||||
var messageJSON = JSON.parse(message);
|
||||
if (messageJSON.command === "script-to-web-initialize") {
|
||||
performancePreset = messageJSON.data.performancePreset;
|
||||
refreshRateProfile = messageJSON.data.refreshRateProfile;
|
||||
displayName = messageJSON.data.displayName;
|
||||
|
||||
document.getElementById("displayName").value = displayName;
|
||||
|
||||
var radioButtons = document.getElementsByName("performancePreset");
|
||||
for (var j = 0; j < radioButtons.length; j++) {
|
||||
if ((j + 1) === performancePreset) {
|
||||
radioButtons[j].checked = true;
|
||||
} else {
|
||||
radioButtons[j].checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
radioButtons = document.getElementsByName("refreshRateProfile");
|
||||
for (j = 0; j < radioButtons.length; j++) {
|
||||
if (j === refreshRateProfile) {
|
||||
radioButtons[j].checked = true;
|
||||
} else {
|
||||
radioButtons[j].checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function completion() {
|
||||
var completionMessage = {
|
||||
"command": "complete-wizard",
|
||||
"data": {
|
||||
"performancePreset": performancePreset,
|
||||
"refreshRateProfile": refreshRateProfile,
|
||||
"displayName": displayName
|
||||
}
|
||||
};
|
||||
EventBridge.emitWebEvent(JSON.stringify(completionMessage));
|
||||
}
|
||||
|
||||
function movetoPage(pageNo) {
|
||||
for (var i=1; i < 6; i++) {
|
||||
if (pageNo === i) {
|
||||
document.getElementById("page" + i.toString()).style.display = "block";
|
||||
document.getElementById("page" + i.toString()).style.width = "100%";
|
||||
} else {
|
||||
document.getElementById("page" + i.toString()).style.width = "0%";
|
||||
document.getElementById("page" + i.toString()).style.display = "none";
|
||||
}
|
||||
}
|
||||
drawProgressBar(pageNo);
|
||||
}
|
||||
|
||||
function drawProgressBar(pageNo) {
|
||||
var title = ["", "Welcome","Quality","Performance","Display Name","Completion"];
|
||||
var bar = '<div class="stepper-wrapper">';
|
||||
|
||||
for (var i=1;i < 6;i++) {
|
||||
if (i < pageNo) {
|
||||
bar = bar + '<div class="stepper-item completed">';
|
||||
} else {
|
||||
if (1 === pageNo) {
|
||||
bar = bar + '<div class="stepper-item active">';
|
||||
} else {
|
||||
bar = bar + '<div class="stepper-item">';
|
||||
}
|
||||
}
|
||||
|
||||
bar = bar + '<div class="step-counter">' + i + '</div>';
|
||||
bar = bar + '<div class="step-name">' + title[i] + '</div>';
|
||||
bar = bar + "</div>";
|
||||
}
|
||||
|
||||
bar = bar + "</div>";
|
||||
document.getElementById("flowStatusBar").innerHTML = bar;
|
||||
}
|
||||
|
||||
|
||||
movetoPage(1);
|
||||
|
||||
var goSignal = {"command": "first-run-wizard-ready"};
|
||||
EventBridge.emitWebEvent(JSON.stringify(goSignal));
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +1,10 @@
|
|||
'use strict';
|
||||
|
||||
//
|
||||
// wizardLoader.js
|
||||
//
|
||||
// Created by Kalila L. on Feb 19 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// This script is used to load the onboarding wizard at the location of the entity it's on.
|
||||
//
|
||||
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
|
||||
(function() {
|
||||
var CONFIG_WIZARD_WEB_URL = 'https://cdn-1.vircadia.com/us-e-1/DomainContent/Tutorial/Apps/configWizard/dist/index.html';
|
||||
var CONFIG_WIZARD_URL = "file:///~/serverless/Scripts/wizard.html?v=" + Math.floor(Math.random() * 65000);
|
||||
|
||||
var loaderEntityID;
|
||||
var configWizardEntityID;
|
||||
|
@ -22,20 +22,20 @@
|
|||
if (sendingEntityID === configWizardEntityID) {
|
||||
var eventJSON = JSON.parse(event);
|
||||
|
||||
if (eventJSON.command === 'first-run-wizard-ready') {
|
||||
if (eventJSON.command === "first-run-wizard-ready") {
|
||||
var objectToSend = {
|
||||
command: 'script-to-web-initialize',
|
||||
data: {
|
||||
performancePreset: Performance.getPerformancePreset(),
|
||||
refreshRateProfile: Performance.getRefreshRateProfile(),
|
||||
displayName: MyAvatar.displayName
|
||||
"command": "script-to-web-initialize",
|
||||
"data": {
|
||||
"performancePreset": Performance.getPerformancePreset(),
|
||||
"refreshRateProfile": Performance.getRefreshRateProfile(),
|
||||
"displayName": MyAvatar.displayName
|
||||
}
|
||||
};
|
||||
|
||||
Entities.emitScriptEvent(configWizardEntityID, JSON.stringify(objectToSend));
|
||||
}
|
||||
|
||||
if (eventJSON.command === 'complete-wizard') {
|
||||
if (eventJSON.command === "complete-wizard") {
|
||||
Performance.setPerformancePreset(eventJSON.data.performancePreset);
|
||||
Performance.setRefreshRateProfile(eventJSON.data.refreshRateProfile);
|
||||
MyAvatar.displayName = eventJSON.data.displayName;
|
||||
|
@ -48,21 +48,25 @@
|
|||
|
||||
this.preload = function (entityID) {
|
||||
loaderEntityID = entityID;
|
||||
var loaderEntityProps = Entities.getEntityProperties(loaderEntityID, ['position', 'rotation']);
|
||||
|
||||
configWizardEntityID = Entities.addEntity({
|
||||
type: 'Web',
|
||||
sourceUrl: CONFIG_WIZARD_WEB_URL,
|
||||
maxFPS: 60,
|
||||
dpi: 20,
|
||||
useBackground: false,
|
||||
grab: {
|
||||
grabbable: false
|
||||
"type": "Web",
|
||||
"parentID": loaderEntityID,
|
||||
"sourceUrl": CONFIG_WIZARD_URL,
|
||||
"maxFPS": 60,
|
||||
"dpi": 19,
|
||||
"useBackground": true,
|
||||
"grab": {
|
||||
"grabbable": false
|
||||
},
|
||||
position: loaderEntityProps.position,
|
||||
rotation: loaderEntityProps.rotation,
|
||||
dimensions: { x: 1.4, y: 0.75, z: 0 }
|
||||
}, 'local');
|
||||
"localPosition": {
|
||||
"x": 0,
|
||||
"y": 1.121,
|
||||
"z": 0.33
|
||||
},
|
||||
"localRotation": Quat.fromVec3Degrees({"x": -58, "y": 0, "z": 0}),
|
||||
"dimensions": { x: 2.6, y: 1.3, z: 0 }
|
||||
}, "local");
|
||||
|
||||
Entities.webEventReceived.connect(onWebAppEventReceived);
|
||||
}
|
||||
|
|
BIN
interface/resources/serverless/Sounds/dreamscape192.mp3
Normal file
BIN
interface/resources/serverless/Textures/Concrete15_col-512.jpg
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
interface/resources/serverless/Textures/Metal26_col.jpg
Normal file
After Width: | Height: | Size: 352 KiB |
BIN
interface/resources/serverless/Textures/Metal26_nrm.jpg
Normal file
After Width: | Height: | Size: 147 KiB |
BIN
interface/resources/serverless/Textures/concreteNormal512.jpg
Normal file
After Width: | Height: | Size: 198 KiB |
BIN
interface/resources/serverless/Textures/fundationNormal512.jpg
Normal file
After Width: | Height: | Size: 175 KiB |
Before Width: | Height: | Size: 870 KiB |
BIN
interface/resources/serverless/Textures/galaxySkybox.jpg
Normal file
After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 5.1 MiB |
Before Width: | Height: | Size: 14 KiB |
|
@ -6,7 +6,6 @@
|
|||
},
|
||||
"Entities": [
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
|
@ -14,33 +13,18 @@
|
|||
},
|
||||
"created": "2018-09-25T18:44:28Z",
|
||||
"dimensions": {
|
||||
"blue": 8.645400047302246,
|
||||
"green": 0.20000000298023224,
|
||||
"red": 20.025121688842773,
|
||||
"x": 20.025121688842773,
|
||||
"y": 0.20000000298023224,
|
||||
"z": 8.645400047302246
|
||||
},
|
||||
"id": "{eac57ccf-1e81-4d74-80f1-f17f23fc2f2c}",
|
||||
"lastEdited": 1537901430334573,
|
||||
"lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}",
|
||||
"locked": true,
|
||||
"name": "ceiling",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 4.846520900726318,
|
||||
"green": 2.912982940673828,
|
||||
"red": 6.00444221496582,
|
||||
"x": 6.00444221496582,
|
||||
"y": 2.912982940673828,
|
||||
"z": 4.846520900726318
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 21.812576293945312,
|
||||
"x": -4.901845932006836,
|
||||
"y": -7.993305206298828,
|
||||
"z": -6.059767246246338
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.970295786857605,
|
||||
"x": 0,
|
||||
|
@ -49,11 +33,12 @@
|
|||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"grab": {
|
||||
"grabbable": false
|
||||
},
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
|
@ -61,33 +46,18 @@
|
|||
},
|
||||
"created": "2018-09-25T18:44:28Z",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"y": 3.580313205718994,
|
||||
"z": 11.117486953735352
|
||||
},
|
||||
"id": "{54609e9e-f729-46fc-ac06-78d44ee6b6fe}",
|
||||
"lastEdited": 1537901430334887,
|
||||
"lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}",
|
||||
"locked": true,
|
||||
"name": "backWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 5.268576622009277,
|
||||
"green": 1.0066027641296387,
|
||||
"red": 6.358620643615723,
|
||||
"x": 6.358620643615723,
|
||||
"y": 1.0066027641296387,
|
||||
"z": 5.268576622009277
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": 0.5178766250610352,
|
||||
"y": -4.834141254425049,
|
||||
"z": -0.5721673965454102
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9662165641784668,
|
||||
"x": -4.57763671875e-05,
|
||||
|
@ -96,11 +66,12 @@
|
|||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"grab": {
|
||||
"grabbable": false
|
||||
},
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
|
@ -108,33 +79,18 @@
|
|||
},
|
||||
"created": "2018-09-25T18:44:28Z",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"y": 3.580313205718994,
|
||||
"z": 11.117486953735352
|
||||
},
|
||||
"id": "{c9352a54-b2cd-4c0f-a898-7e79c01404d0}",
|
||||
"lastEdited": 1537901430334652,
|
||||
"lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}",
|
||||
"locked": true,
|
||||
"name": "frontWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 2.662257671356201,
|
||||
"green": 1.0063786506652832,
|
||||
"red": 1.7517199516296387,
|
||||
"x": 1.7517199516296387,
|
||||
"y": 1.0063786506652832,
|
||||
"z": 2.662257671356201
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": -4.089024066925049,
|
||||
"y": -4.834365367889404,
|
||||
"z": -3.1784863471984863
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.9666743278503418,
|
||||
"x": -4.57763671875e-05,
|
||||
|
@ -143,11 +99,12 @@
|
|||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"grab": {
|
||||
"grabbable": false
|
||||
},
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
|
@ -155,33 +112,18 @@
|
|||
},
|
||||
"created": "2018-09-25T18:44:28Z",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"y": 3.580313205718994,
|
||||
"z": 11.117486953735352
|
||||
},
|
||||
"id": "{c4b7a530-ec5b-47fc-be60-eed22f96799d}",
|
||||
"lastEdited": 1537901430334730,
|
||||
"lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}",
|
||||
"locked": true,
|
||||
"name": "rightWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 0,
|
||||
"green": 1.0061144828796387,
|
||||
"red": 5.229935646057129,
|
||||
"x": 5.229935646057129,
|
||||
"y": 1.0061144828796387,
|
||||
"z": 0
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": -0.6108083724975586,
|
||||
"y": -4.834629535675049,
|
||||
"z": -5.8407440185546875
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8637980222702026,
|
||||
"x": -4.57763671875e-05,
|
||||
|
@ -190,39 +132,25 @@
|
|||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"grab": {
|
||||
"grabbable": false
|
||||
},
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"created": "2018-09-25T18:44:28Z",
|
||||
"dimensions": {
|
||||
"blue": 14.40000057220459,
|
||||
"green": 14.40000057220459,
|
||||
"red": 14.40000057220459,
|
||||
"x": 14.40000057220459,
|
||||
"y": 14.40000057220459,
|
||||
"z": 14.40000057220459
|
||||
},
|
||||
"id": "{351ddd1e-79b3-4be7-8784-aca29bd65193}",
|
||||
"lastEdited": 1537901430334210,
|
||||
"lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}",
|
||||
"locked": true,
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 2.3440732955932617,
|
||||
"green": 1.6162219047546387,
|
||||
"red": 2.1396677494049072,
|
||||
"x": 2.1396677494049072,
|
||||
"y": 1.6162219047546387,
|
||||
"z": 2.3440732955932617
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 24.9415340423584,
|
||||
"x": -10.331099510192871,
|
||||
"y": -10.854545593261719,
|
||||
"z": -10.126693725585938
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8697794675827026,
|
||||
"x": -1.52587890625e-05,
|
||||
|
@ -232,10 +160,11 @@
|
|||
"shapeType": "box",
|
||||
"skyboxMode": "enabled",
|
||||
"type": "Zone",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
"grab": {
|
||||
"grabbable": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
|
@ -243,33 +172,18 @@
|
|||
},
|
||||
"created": "2018-09-25T18:44:28Z",
|
||||
"dimensions": {
|
||||
"blue": 6.9401350021362305,
|
||||
"green": 0.04553089290857315,
|
||||
"red": 7.004304885864258,
|
||||
"x": 7.004304885864258,
|
||||
"y": 0.04553089290857315,
|
||||
"z": 6.9401350021362305
|
||||
},
|
||||
"id": "{81c13ed1-1873-4f21-adea-5112a0fdacd1}",
|
||||
"lastEdited": 1537901430334808,
|
||||
"lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}",
|
||||
"locked": true,
|
||||
"name": "floor",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 3.6175529956817627,
|
||||
"green": 0,
|
||||
"red": 4.367232322692871,
|
||||
"x": 4.367232322692871,
|
||||
"y": 0,
|
||||
"z": 3.6175529956817627
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 9.860417366027832,
|
||||
"x": -0.5629763603210449,
|
||||
"y": -4.930208683013916,
|
||||
"z": -1.3126556873321533
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8660253882408142,
|
||||
"x": -1.5922749298624694e-05,
|
||||
|
@ -278,53 +192,12 @@
|
|||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"grab": {
|
||||
"grabbable": false
|
||||
},
|
||||
"visible": false
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"created": "2018-09-25T18:44:28Z",
|
||||
"dimensions": {
|
||||
"blue": 6.9401350021362305,
|
||||
"green": 0.04553089290857315,
|
||||
"red": 7.004304885864258,
|
||||
"x": 7.004304885864258,
|
||||
"y": 0.04553089290857315,
|
||||
"z": 6.9401350021362305
|
||||
},
|
||||
"id": "{5582179a-fb69-4678-af0c-c8e6d890839a}",
|
||||
"lastEdited": 1537901430334966,
|
||||
"lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}",
|
||||
"locked": true,
|
||||
"modelURL": "https://cdn-1.vircadia.com/eu-c-1/vircadia-content/alexia/LoadingScreens/floor.fbx",
|
||||
"name": "floorModel",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 3.6175529956817627,
|
||||
"green": 0,
|
||||
"red": 4.367232322692871,
|
||||
"x": 4.367232322692871,
|
||||
"y": 0,
|
||||
"z": 3.6175529956817627
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 9.860417366027832,
|
||||
"x": -0.5629763603210449,
|
||||
"y": -4.930208683013916,
|
||||
"z": -1.3126556873321533
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8660253882408142,
|
||||
"x": -1.5922749298624694e-05,
|
||||
"y": 0.5,
|
||||
"z": -4.572480611386709e-05
|
||||
},
|
||||
"shapeType": "simple-hull",
|
||||
"type": "Model",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
|
||||
},
|
||||
{
|
||||
"clientOnly": false,
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
|
@ -332,33 +205,18 @@
|
|||
},
|
||||
"created": "2018-09-25T18:44:28Z",
|
||||
"dimensions": {
|
||||
"blue": 11.117486953735352,
|
||||
"green": 3.580313205718994,
|
||||
"red": 0.20000000298023224,
|
||||
"x": 0.20000000298023224,
|
||||
"y": 3.580313205718994,
|
||||
"z": 11.117486953735352
|
||||
},
|
||||
"id": "{366ec0b9-5106-4172-a9f6-2143f6c279aa}",
|
||||
"lastEdited": 1537901430334307,
|
||||
"lastEditedBy": "{69540019-db48-4375-86c8-ac1a4a90d043}",
|
||||
"locked": true,
|
||||
"name": "leftWall",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"blue": 6.1806135177612305,
|
||||
"green": 1.0066027641296387,
|
||||
"red": 1.7338871955871582,
|
||||
"x": 1.7338871955871582,
|
||||
"y": 1.0066027641296387,
|
||||
"z": 6.1806135177612305
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 11.681488037109375,
|
||||
"x": -4.106856822967529,
|
||||
"y": -4.834141254425049,
|
||||
"z": 0.33986949920654297
|
||||
},
|
||||
"rotation": {
|
||||
"w": 0.8637980222702026,
|
||||
"x": -4.57763671875e-05,
|
||||
|
@ -367,7 +225,9 @@
|
|||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"userData": "{\"grabbableKey\":{\"grabbable\":false}}",
|
||||
"grab": {
|
||||
"grabbable": false
|
||||
},
|
||||
"visible": false
|
||||
}
|
||||
],
|
||||
|
|