Merge remote-tracking branch 'refs/remotes/JulianGro/master'
Conflicts: .github/workflows/pr_build.yml
|
@ -32,7 +32,7 @@ file(REMOVE_RECURSE "${CMAKE_CURRENT_BINARY_DIR}/_env")
|
|||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_env")
|
||||
|
||||
# Base URL for externally downloaded files
|
||||
set(EXTERNAL_BUILD_ASSETS "https://athena-public.s3.amazonaws.com")
|
||||
set(EXTERNAL_BUILD_ASSETS "https://build-deps.overte.org")
|
||||
|
||||
if( DEFINED ENV{EXTERNAL_BUILD_ASSETS} )
|
||||
set(EXTERNAL_BUILD_ASSETS "$ENV{EXTERNAL_BUILD_ASSETS}")
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<p align="center"><a href="https://overte.org/"><img src="interface/resources/images/brand-banner-black.svg" alt="Overte" width="350"/></a></p>
|
||||
<p align="center"><a href="https://overte.org/"><picture><source srcset="interface/resources/images/brand-banner.svg" alt="Overte" width="350" media="(prefers-color-scheme: dark)"><img src="interface/resources/images/brand-banner-black.svg" alt="Overte" width="350"></picture></a></p>
|
||||
|
||||
<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://docs.overte.org/en/latest/contribute.html"><img alt="GitHub contributors" src="https://img.shields.io/github/contributors/overte-org/overte"></a>
|
||||
|
|
|
@ -107,6 +107,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid");
|
||||
parser.addOption(parentPIDOption);
|
||||
|
||||
const QCommandLineOption logOption("logOptions", "Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald", "options");
|
||||
parser.addOption(logOption);
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
std::cout << parser.errorText().toStdString() << std::endl; // Avoid Qt log spam
|
||||
parser.showHelp();
|
||||
|
@ -123,6 +126,16 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
// We want to configure the logging system as early as possible
|
||||
auto &logHandler = LogHandler::getInstance();
|
||||
if (parser.isSet(logOption)) {
|
||||
if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) {
|
||||
QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp()
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
const QVariantMap argumentVariantMap = HifiConfigVariantMap::mergeCLParametersWithJSONConfig(arguments());
|
||||
|
||||
unsigned int numForks = 0;
|
||||
|
|
|
@ -11,7 +11,7 @@ if (POLICY CMP0042)
|
|||
endif ()
|
||||
|
||||
if (POLICY CMP0074)
|
||||
cmake_policy(SET CMP0074 OLD)
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
endif ()
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
|
45
cmake/modules/FindJournald.cmake
Normal file
|
@ -0,0 +1,45 @@
|
|||
# - Try to find Journald library.
|
||||
# Once done this will define
|
||||
#
|
||||
# JOURNALD_FOUND - system has Journald
|
||||
# JOURNALD_INCLUDE_DIR - the Journald include directory
|
||||
# JOURNALD_LIBRARIES - Link these to use Journald
|
||||
# JOURNALD_DEFINITIONS - Compiler switches required for using Journald
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
#
|
||||
|
||||
# Copyright (c) 2015 David Edmundson
|
||||
#
|
||||
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_JOURNALD QUIET systemd)
|
||||
|
||||
set(JOURNALD_FOUND ${PC_JOURNALD_FOUND})
|
||||
set(JOURNALD_DEFINITIONS ${PC_JOURNALD_CFLAGS_OTHER})
|
||||
|
||||
find_path(JOURNALD_INCLUDE_DIR NAMES systemd/sd-journal.h
|
||||
PATHS
|
||||
${PC_JOURNALD_INCLUDEDIR}
|
||||
${PC_JOURNALD_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_library(JOURNALD_LIBRARY NAMES systemd
|
||||
PATHS
|
||||
${PC_JOURNALD_LIBDIR}
|
||||
${PC_JOURNALD_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
set(JOURNALD_LIBRARIES ${JOURNALD_LIBRARY})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Journald DEFAULT_MSG JOURNALD_LIBRARY JOURNALD_INCLUDE_DIR)
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(Journald PROPERTIES URL https://github.com/systemd
|
||||
DESCRIPTION "Systemd logging daemon")
|
||||
|
||||
# show the JOURNALD_INCLUDE_DIR and JOURNALD_LIBRARY variables only in the advanced view
|
||||
mark_as_advanced(JOURNALD_INCLUDE_DIR JOURNALD_LIBRARY)
|
|
@ -1,11 +1,11 @@
|
|||
include(vcpkg_common_functions)
|
||||
|
||||
set(VERSION 1.2.11)
|
||||
set(VERSION 1.2.12)
|
||||
|
||||
vcpkg_download_distfile(ARCHIVE_FILE
|
||||
URLS "http://www.zlib.net/zlib-${VERSION}.tar.gz" "https://downloads.sourceforge.net/project/libpng/zlib/${VERSION}/zlib-${VERSION}.tar.gz"
|
||||
FILENAME "zlib1211.tar.gz"
|
||||
SHA512 73fd3fff4adeccd4894084c15ddac89890cd10ef105dd5e1835e1e9bbb6a49ff229713bd197d203edfa17c2727700fce65a2a235f07568212d820dca88b528ae
|
||||
URLS "http://www.zlib.net/zlib-${VERSION}.tar.xz" "https://downloads.sourceforge.net/project/libpng/zlib/${VERSION}/zlib-${VERSION}.tar.xz" "https://build-deps.overte.org/dependencies/zlib-${VERSION}.tar.xz"
|
||||
FILENAME "zlib1212.tar.xz"
|
||||
SHA512 12940e81e988f7661da52fa20bdc333314ae86a621fdb748804a20840b065a1d6d984430f2d41f3a057de0effc6ff9bcf42f9ee9510b88219085f59cbbd082bd
|
||||
)
|
||||
|
||||
vcpkg_extract_source_archive_ex(
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"name": "automatic_networking",
|
||||
"label": "Automatic Networking",
|
||||
"help": "This defines how other nodes in the Metaverse will be able to reach your domain-server.<br/>If you don't want to deal with any network settings, use full automatic networking.",
|
||||
"default": "disabled",
|
||||
"default": "full",
|
||||
"type": "select",
|
||||
"options": [
|
||||
{
|
||||
|
|
|
@ -414,6 +414,9 @@ void DomainServer::parseCommandLine(int argc, char* argv[]) {
|
|||
const QCommandLineOption parentPIDOption(PARENT_PID_OPTION, "PID of the parent process", "parent-pid");
|
||||
parser.addOption(parentPIDOption);
|
||||
|
||||
const QCommandLineOption logOption("logOptions", "Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald", "options");
|
||||
parser.addOption(logOption);
|
||||
|
||||
|
||||
QStringList arguments;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
|
@ -436,6 +439,16 @@ void DomainServer::parseCommandLine(int argc, char* argv[]) {
|
|||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
// We want to configure the logging system as early as possible
|
||||
auto &logHandler = LogHandler::getInstance();
|
||||
if (parser.isSet(logOption)) {
|
||||
if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) {
|
||||
QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp()
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.isSet(iceServerAddressOption)) {
|
||||
// parse the IP and port combination for this target
|
||||
QString hostnamePortString = parser.value(iceServerAddressOption);
|
||||
|
|
|
@ -134,7 +134,7 @@ endif()
|
|||
return
|
||||
|
||||
if 'Windows' == system:
|
||||
self.qtUrl = self.assets_url + '/dependencies/vcpkg/qt5-install-5.15.2-windows.tar.gz'
|
||||
self.qtUrl = self.assets_url + '/dependencies/qt5/qt5-install-5.15.5-qtwebengine-5.15.11-2022.08.01-kde_9480de754ec97f4b63c2b5176672903f80e3f22ff59d3acf0ddd8c68f58c1ed8-windows-x86_64.tar.xz'
|
||||
elif 'Darwin' == system:
|
||||
self.qtUrl = self.assets_url + '/dependencies/vcpkg/qt5-install-5.15.2-macos.tar.gz'
|
||||
elif 'Linux' == system:
|
||||
|
@ -146,7 +146,7 @@ endif()
|
|||
u_minor = int( distro.minor_version() )
|
||||
if distro.id() == 'ubuntu' or distro.id() == 'linuxmint':
|
||||
if (distro.id() == 'ubuntu' and u_major == 18) or distro.id() == 'linuxmint' and u_major == 19:
|
||||
self.qtUrl = self.assets_url + '/dependencies/vcpkg/qt5-install-5.15.2-ubuntu-18.04-amd64.tar.xz'
|
||||
self.qtUrl = self.assets_url + '/dependencies/qt5/qt5-install-5.15.5-2022.07.17-kde_ea4efc067b47c11b1aac61668afd8578a6834f5b-ubuntu-18.04-amd64.tar.xz'
|
||||
elif (distro.id() == 'ubuntu' and u_major > 18) or (distro.id() == 'linuxmint' and u_major > 19):
|
||||
self.__no_qt_package_error()
|
||||
else:
|
||||
|
@ -205,7 +205,7 @@ endif()
|
|||
|
||||
def installQt(self):
|
||||
if not os.path.isdir(self.fullPath):
|
||||
print ('Downloading Qt from AWS')
|
||||
print ('Downloading Qt package')
|
||||
print('Extracting ' + self.qtUrl + ' to ' + self.path)
|
||||
hifi_utils.downloadAndExtract(self.qtUrl, self.path)
|
||||
else:
|
||||
|
|
|
@ -46,7 +46,7 @@ class Singleton:
|
|||
self.fh = None
|
||||
# print is horked here so write directly to stdout.
|
||||
with open(1, mode="w", closefd=False) as _stdout:
|
||||
_stdout.write("Couldn't aquire lock, retrying in 10 seconds\n")
|
||||
_stdout.write(f"Couldn't aquire lock {self.path}, retrying in 10 seconds\n")
|
||||
_stdout.flush()
|
||||
time.sleep(10)
|
||||
return self
|
||||
|
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 7.9 KiB |
|
@ -27,7 +27,7 @@ Item {
|
|||
width: parent.width
|
||||
|
||||
property string title: "Controls"
|
||||
property var openVRDevices: ["HTC Vive", "Valve Index", "Valve HMD", "Valve"]
|
||||
property var openVRDevices: ["HTC Vive", "Valve Index", "Valve HMD", "Valve", "WindowsMR"]
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
|
|
|
@ -1045,8 +1045,8 @@ Flickable {
|
|||
var hmdDesktopPosition = settings["hmdDesktopTracking"];
|
||||
var eyeTrackingEnabled = settings["eyeTrackingEnabled"];
|
||||
|
||||
armCircumference.realValue = settings.armCircumference;
|
||||
shoulderWidth.realValue = settings.shoulderWidth;
|
||||
armCircumference.realValue = settings["armCircumference"];
|
||||
shoulderWidth.realValue = settings["shoulderWidth"];
|
||||
|
||||
if (HmdHead) {
|
||||
headBox.checked = true;
|
||||
|
|
After Width: | Height: | Size: 4.5 MiB |
After Width: | Height: | Size: 4.9 MiB |
After Width: | Height: | Size: 4.6 MiB |
After Width: | Height: | Size: 3.5 MiB |
BIN
interface/resources/serverless/Textures/floor_l.png
Normal file
After Width: | Height: | Size: 3.2 MiB |
After Width: | Height: | Size: 4 MiB |
BIN
interface/resources/serverless/Textures/ground_grass_gen_05.png
Normal file
After Width: | Height: | Size: 2.6 MiB |
BIN
interface/resources/serverless/Textures/wall_l.png
Normal file
After Width: | Height: | Size: 3.5 MiB |
|
@ -306,7 +306,7 @@ static const uint32_t MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4;
|
|||
// we will never drop below the 'min' value
|
||||
static const int MIN_PROCESSING_THREAD_POOL_SIZE = 2;
|
||||
|
||||
static const QString SNAPSHOT_EXTENSION = ".jpg";
|
||||
static const QString SNAPSHOT_EXTENSION = ".png";
|
||||
static const QString JPG_EXTENSION = ".jpg";
|
||||
static const QString PNG_EXTENSION = ".png";
|
||||
static const QString SVO_EXTENSION = ".svo";
|
||||
|
@ -3212,7 +3212,7 @@ void Application::showLoginScreen() {
|
|||
#endif
|
||||
}
|
||||
|
||||
static const QUrl AUTHORIZED_EXTERNAL_QML_SOURCE { "https://cdn.vircadia.com/community-apps/applications" };
|
||||
static const QUrl AUTHORIZED_EXTERNAL_QML_SOURCE { "https://more.overte.org/applications" };
|
||||
|
||||
void Application::initializeUi() {
|
||||
|
||||
|
|
|
@ -2089,7 +2089,7 @@ void MyAvatar::loadData() {
|
|||
setDriveGear3(firstRunVal.get() ? DEFAULT_GEAR_3 : _driveGear3Setting.get());
|
||||
setDriveGear4(firstRunVal.get() ? DEFAULT_GEAR_4 : _driveGear4Setting.get());
|
||||
setDriveGear5(firstRunVal.get() ? DEFAULT_GEAR_5 : _driveGear5Setting.get());
|
||||
setControlSchemeIndex(firstRunVal.get() ? LocomotionControlsMode::CONTROLS_DEFAULT : _controlSchemeIndexSetting.get());
|
||||
setControlSchemeIndex(firstRunVal.get() ? LocomotionControlsMode::CONTROLS_ANALOG : _controlSchemeIndexSetting.get());
|
||||
setAnalogWalkSpeed(firstRunVal.get() ? ANALOG_AVATAR_MAX_WALKING_SPEED : _analogWalkSpeedSetting.get());
|
||||
setAnalogPlusWalkSpeed(firstRunVal.get() ? ANALOG_PLUS_AVATAR_MAX_WALKING_SPEED : _analogPlusWalkSpeedSetting.get());
|
||||
setFlyingEnabled(getFlyingEnabled());
|
||||
|
|
|
@ -2763,7 +2763,7 @@ private:
|
|||
float _driveGear3 { DEFAULT_GEAR_3 };
|
||||
float _driveGear4 { DEFAULT_GEAR_4 };
|
||||
float _driveGear5 { DEFAULT_GEAR_5 };
|
||||
int _controlSchemeIndex { CONTROLS_DEFAULT };
|
||||
int _controlSchemeIndex { CONTROLS_ANALOG };
|
||||
int _movementReference{ 0 };
|
||||
|
||||
glm::vec3 _thrust { 0.0f }; // impulse accumulator for outside sources
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
#include "InterfaceLogging.h"
|
||||
#include "UserActivityLogger.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include "Profile.h"
|
||||
#include "LogHandler.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <Windows.h>
|
||||
|
@ -45,7 +45,7 @@ int main(int argc, const char* argv[]) {
|
|||
auto format = getDefaultOpenGLSurfaceFormat();
|
||||
// Deal with some weirdness in the chromium context sharing on Mac.
|
||||
// The primary share context needs to be 3.2, so that the Chromium will
|
||||
// succeed in it's creation of it's command stub contexts.
|
||||
// succeed in it's creation of it's command stub contexts.
|
||||
format.setVersion(3, 2);
|
||||
// This appears to resolve the issues with corrupted fonts on OSX. No
|
||||
// idea why.
|
||||
|
@ -54,8 +54,8 @@ int main(int argc, const char* argv[]) {
|
|||
QSurfaceFormat::setDefaultFormat(format);
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
// Check the minimum version of
|
||||
#if defined(Q_OS_WIN)
|
||||
// Check the minimum version of
|
||||
if (gl::getAvailableVersion() < gl::getRequiredVersion()) {
|
||||
MessageBoxA(nullptr, "Interface requires OpenGL 4.1 or higher", "Unsupported", MB_OK);
|
||||
return -1;
|
||||
|
@ -64,6 +64,9 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
setupHifiApplication(BuildInfo::INTERFACE_NAME);
|
||||
|
||||
// Journald by default in user applications is probably a bit too modern still.
|
||||
LogHandler::getInstance().setShouldUseJournald(false);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("Overte -- A free/libre and open-source metaverse client");
|
||||
QCommandLineOption helpOption = parser.addHelpOption();
|
||||
|
@ -161,7 +164,7 @@ int main(int argc, const char* argv[]) {
|
|||
"url"
|
||||
);
|
||||
QCommandLineOption replaceAvatarURLOption(
|
||||
"replace-avatar-url",
|
||||
"replaceAvatarURL",
|
||||
"Replaces the avatar U.R.L. When used with --avatarURL, this takes precedence.",
|
||||
"url"
|
||||
);
|
||||
|
@ -237,6 +240,11 @@ int main(int argc, const char* argv[]) {
|
|||
"fast-heartbeat",
|
||||
"Change stats polling interval from 10000ms to 1000ms."
|
||||
);
|
||||
QCommandLineOption logOption(
|
||||
"logOptions",
|
||||
"Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald",
|
||||
"options"
|
||||
);
|
||||
// "--qmljsdebugger", which appears in output from "--help-all".
|
||||
// Those below don't seem to be optional.
|
||||
// --ignore-gpu-blacklist
|
||||
|
@ -277,6 +285,7 @@ int main(int argc, const char* argv[]) {
|
|||
parser.addOption(testResultsLocationOption);
|
||||
parser.addOption(quitWhenFinishedOption);
|
||||
parser.addOption(fastHeartbeatOption);
|
||||
parser.addOption(logOption);
|
||||
|
||||
QString applicationPath;
|
||||
// A temporary application instance is needed to get the location of the running executable
|
||||
|
@ -299,6 +308,16 @@ int main(int argc, const char* argv[]) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// We want to configure the logging system as early as possible
|
||||
auto &logHandler = LogHandler::getInstance();
|
||||
if (parser.isSet(logOption)) {
|
||||
if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) {
|
||||
QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp()
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// Act on arguments for early termination.
|
||||
if (parser.isSet(versionOption)) {
|
||||
parser.showVersion();
|
||||
|
@ -356,7 +375,7 @@ int main(int argc, const char* argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
// Early check for --traceFile argument
|
||||
// Early check for --traceFile argument
|
||||
auto tracer = DependencyManager::set<tracing::Tracer>();
|
||||
const char * traceFile = nullptr;
|
||||
float traceDuration = 0.0f;
|
||||
|
@ -370,7 +389,7 @@ int main(int argc, const char* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PROFILE_SYNC_BEGIN(startup, "main startup", "");
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
|
@ -378,8 +397,8 @@ int main(int argc, const char* argv[]) {
|
|||
#endif
|
||||
|
||||
#if defined(USE_GLES) && defined(Q_OS_WIN)
|
||||
// When using GLES on Windows, we can't create normal GL context in Qt, so
|
||||
// we force Qt to use angle. This will cause the QML to be unable to be used
|
||||
// When using GLES on Windows, we can't create normal GL context in Qt, so
|
||||
// we force Qt to use angle. This will cause the QML to be unable to be used
|
||||
// in the output window, so QML should be disabled.
|
||||
qputenv("QT_ANGLE_PLATFORM", "d3d11");
|
||||
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||
|
@ -550,7 +569,7 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
// Extend argv to enable WebGL rendering
|
||||
std::vector<const char*> argvExtended(&argv[0], &argv[argc]);
|
||||
argvExtended.push_back("--ignore-gpu-blacklist");
|
||||
argvExtended.push_back("--ignore-gpu-blocklist");
|
||||
#ifdef Q_OS_ANDROID
|
||||
argvExtended.push_back("--suppress-settings-reset");
|
||||
#endif
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
#include "Snapshot.h"
|
||||
#include "SnapshotUploader.h"
|
||||
|
||||
// filename format: overte-snap-by-%username%-on-%date%_%time%_@-%location%.jpg
|
||||
// filename format: overte-snap-by-%username%-on-%date%_%time%_@-%location%.png
|
||||
// %1 <= username, %2 <= date and time, %3 <= current location
|
||||
const QString FILENAME_PATH_FORMAT = "overte-snap-by-%1-on-%2.jpg";
|
||||
const QString FILENAME_PATH_FORMAT = "overte-snap-by-%1-on-%2.png";
|
||||
const QString DATETIME_FORMAT = "yyyy-MM-dd_hh-mm-ss";
|
||||
const QString SNAPSHOTS_DIRECTORY = "Snapshots";
|
||||
const QString URL = "overte_url";
|
||||
|
@ -385,11 +385,19 @@ QFile* Snapshot::savedFileForSnapshot(QImage& shot,
|
|||
imageQuality = 50;
|
||||
}
|
||||
} else {
|
||||
filename = userSelectedFilename + ".jpg";
|
||||
filename = userSelectedFilename + ".png";
|
||||
imageQuality = 50;
|
||||
}
|
||||
} else {
|
||||
filename = FILENAME_PATH_FORMAT.arg(username, now.toString(DATETIME_FORMAT));
|
||||
QFileInfo snapshotFileInfo(filename);
|
||||
QString filenameSuffix = snapshotFileInfo.suffix();
|
||||
filenameSuffix = filenameSuffix.toLower();
|
||||
if (filenameSuffix == "png") {
|
||||
imageQuality = 50;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!isTemporary) {
|
||||
// If user has requested specific path then use it, else use the application value
|
||||
|
|
|
@ -45,6 +45,7 @@ void SnapshotAnimated::saveSnapshotAnimated(QString pathStill, float aspectRatio
|
|||
SnapshotAnimated::snapshotStillPath = pathStill;
|
||||
SnapshotAnimated::snapshotAnimatedPath = pathStill;
|
||||
SnapshotAnimated::snapshotAnimatedPath.replace("jpg", "gif");
|
||||
SnapshotAnimated::snapshotAnimatedPath.replace("png", "gif");
|
||||
|
||||
// Ensure the snapshot timer is Precise (attempted millisecond precision)
|
||||
SnapshotAnimated::snapshotAnimatedTimer->setTimerType(Qt::PreciseTimer);
|
||||
|
@ -148,7 +149,7 @@ void SnapshotAnimated::processFrames() {
|
|||
GifEnd(&(SnapshotAnimated::snapshotAnimatedGifWriter));
|
||||
|
||||
SnapshotAnimated::clearTempVariables();
|
||||
|
||||
|
||||
// Update the "Share" dialog with the processed GIF.
|
||||
emit SnapshotAnimated::snapshotAnimatedDM->processingGifCompleted(SnapshotAnimated::snapshotAnimatedPath);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
//
|
||||
// Created by Stephen Birarda on 1/16/14.
|
||||
// Copyright 2014 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
|
||||
|
@ -196,7 +197,7 @@ QList<FormData> HTTPConnection::parseFormData() const {
|
|||
qWarning() << "Missing end boundary." << _address;
|
||||
return data;
|
||||
}
|
||||
datum.second = QByteArray::fromRawData(_requestContent->content().data() + buffer.pos(),
|
||||
datum.second = QByteArray(_requestContent->content().data() + buffer.pos(),
|
||||
idx - buffer.pos());
|
||||
data.append(datum);
|
||||
buffer.seek(idx + end.length());
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
//
|
||||
// Created by Seth Alves on 5/19/15.
|
||||
// Copyright 2015 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
|
||||
|
@ -197,13 +198,17 @@ bool isEdged(PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle) {
|
|||
|
||||
void RenderablePolyVoxEntityItem::setVoxelData(const QByteArray& voxelData) {
|
||||
// accept compressed voxel information from the entity-server
|
||||
bool changed = false;
|
||||
withWriteLock([&] {
|
||||
if (_voxelData != voxelData) {
|
||||
_voxelData = voxelData;
|
||||
_voxelDataDirty = true;
|
||||
startUpdates();
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
startUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) {
|
||||
|
@ -248,6 +253,9 @@ bool RenderablePolyVoxEntityItem::setVoxel(const ivec3& v, uint8_t toValue) {
|
|||
withWriteLock([&] {
|
||||
result = setVoxelInternal(v, toValue);
|
||||
});
|
||||
if (result) {
|
||||
startUpdates();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -272,11 +280,10 @@ QByteArray RenderablePolyVoxEntityItem::volDataToArray(quint16 voxelXSize, quint
|
|||
withReadLock([&] {
|
||||
if (isEdged()) {
|
||||
low += 1;
|
||||
voxelSize += 2;
|
||||
}
|
||||
|
||||
loop3(low, voxelSize, [&](const ivec3& v){
|
||||
result[index++] = _volData->getVoxelAt(v.x, v.y, v.z);
|
||||
loop3(ivec3(0), voxelSize, [&](const ivec3& v){
|
||||
result[index++] = _volData->getVoxelAt(v.x + low.x, v.y + low.y, v.z + low.z);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -294,10 +301,12 @@ bool RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
|
|||
result |= setVoxelInternal(v, toValue);
|
||||
});
|
||||
});
|
||||
if (result) {
|
||||
startUpdates();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool RenderablePolyVoxEntityItem::setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) {
|
||||
bool result = false;
|
||||
if (_locked) {
|
||||
|
@ -316,11 +325,12 @@ bool RenderablePolyVoxEntityItem::setCuboid(const glm::vec3& lowPosition, const
|
|||
result |= setVoxelInternal(v, toValue);
|
||||
});
|
||||
});
|
||||
if (result) {
|
||||
startUpdates();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RenderablePolyVoxEntityItem::setVoxelInVolume(const vec3& position, uint8_t toValue) {
|
||||
if (_locked) {
|
||||
return false;
|
||||
|
@ -350,6 +360,9 @@ bool RenderablePolyVoxEntityItem::setSphereInVolume(const vec3& center, float ra
|
|||
}
|
||||
});
|
||||
});
|
||||
if (result) {
|
||||
startUpdates();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -407,6 +420,9 @@ bool RenderablePolyVoxEntityItem::setSphere(const vec3& centerWorldCoords, float
|
|||
// }
|
||||
});
|
||||
});
|
||||
if (result) {
|
||||
startUpdates();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -452,6 +468,9 @@ bool RenderablePolyVoxEntityItem::setCapsule(const vec3& startWorldCoords, const
|
|||
}
|
||||
});
|
||||
});
|
||||
if (result) {
|
||||
startUpdates();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -718,7 +737,7 @@ void RenderablePolyVoxEntityItem::changeUpdates(bool value) {
|
|||
EntitySimulationPointer simulation = entityTree->getSimulation();
|
||||
if (simulation) {
|
||||
_updateNeeded = value;
|
||||
_flags |= Simulation::DIRTY_UPDATEABLE;
|
||||
markDirtyFlags(Simulation::DIRTY_UPDATEABLE);
|
||||
simulation->changeEntity(getThisPointer());
|
||||
}
|
||||
}
|
||||
|
@ -972,9 +991,7 @@ bool RenderablePolyVoxEntityItem::setVoxelInternal(const ivec3& v, uint8_t toVal
|
|||
setVoxelMarkNeighbors(v.x, v.y, v.z, toValue);
|
||||
}
|
||||
_volDataDirty = true;
|
||||
startUpdates();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1025,6 +1042,7 @@ void RenderablePolyVoxEntityItem::uncompressVolumeData() {
|
|||
entity->setVoxelsFromData(QByteArray(1, 0), 1, 1, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
int rawSize = voxelXSize * voxelYSize * voxelZSize;
|
||||
|
||||
QByteArray compressedData;
|
||||
|
@ -1047,14 +1065,23 @@ void RenderablePolyVoxEntityItem::uncompressVolumeData() {
|
|||
void RenderablePolyVoxEntityItem::setVoxelsFromData(QByteArray uncompressedData,
|
||||
quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) {
|
||||
// this accepts the payload from uncompressVolumeData
|
||||
ivec3 low{ 0 };
|
||||
bool result = false;
|
||||
|
||||
withWriteLock([&] {
|
||||
if (isEdged()) {
|
||||
low += 1;
|
||||
}
|
||||
loop3(ivec3(0), ivec3(voxelXSize, voxelYSize, voxelZSize), [&](const ivec3& v) {
|
||||
int uncompressedIndex = (v.z * voxelYSize * voxelXSize) + (v.y * voxelZSize) + v.x;
|
||||
setVoxelInternal(v, uncompressedData[uncompressedIndex]);
|
||||
int uncompressedIndex = (v.z * (voxelYSize) * (voxelXSize)) + (v.y * (voxelZSize)) + v.x;
|
||||
result |= setVoxelInternal(v, uncompressedData[uncompressedIndex]);
|
||||
});
|
||||
|
||||
_state = PolyVoxState::UncompressingFinished;
|
||||
});
|
||||
if (result) {
|
||||
startUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// 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
|
||||
|
@ -1292,6 +1293,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* type: "PolyVox",
|
||||
* position: position,
|
||||
* dimensions: { x: 2, y: 2, z: 2 },
|
||||
* voxelVolumeSize: { x: 16, y: 16, z: 16 },
|
||||
* voxelSurfaceStyle: 2,
|
||||
* xTextureURL: texture,
|
||||
* yTextureURL: texture,
|
||||
* zTextureURL: texture,
|
||||
|
|
|
@ -353,7 +353,7 @@ std::pair<gpu::TexturePointer, glm::ivec2> processImage(std::shared_ptr<QIODevic
|
|||
// Validate that the image loaded
|
||||
if (imageWidth == 0 || imageHeight == 0 || image.getFormat() == Image::Format_Invalid) {
|
||||
QString reason(image.getFormat() == Image::Format_Invalid ? "(Invalid Format)" : "(Size is invalid)");
|
||||
qCWarning(imagelogging) << "Failed to load:" << qPrintable(reason);
|
||||
qCWarning(imagelogging) << "Failed to load" << QString::fromStdString(filename) << ":" << qPrintable(reason);
|
||||
return { nullptr, { imageWidth, imageHeight } };
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ void KTXCache::initialize() {
|
|||
|
||||
|
||||
std::unique_ptr<File> KTXCache::createFile(Metadata&& metadata, const std::string& filepath) {
|
||||
qCInfo(file_cache) << "Wrote KTX" << metadata.key.c_str();
|
||||
qCDebug(file_cache) << "Wrote KTX" << metadata.key.c_str();
|
||||
return FileCache::createFile(std::move(metadata), filepath);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,16 @@ if (APPLE)
|
|||
target_link_libraries(${TARGET_NAME} ${FRAMEWORK_IOKIT} ${CORE_FOUNDATION} ${OpenGL})
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
find_package(Journald)
|
||||
|
||||
if (${JOURNALD_FOUND})
|
||||
target_link_libraries(${TARGET_NAME} ${JOURNALD_LIBRARIES})
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${JOURNALD_INCLUDE_DIR})
|
||||
target_compile_definitions(${TARGET_NAME} PUBLIC HAS_JOURNALD)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_zlib()
|
||||
target_nsight()
|
||||
target_json()
|
||||
|
|
28
libraries/shared/src/Breakpoint.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Breakpoint.h
|
||||
//
|
||||
//
|
||||
// Created by Dale Glass on 5/6/2022
|
||||
// Copyright 2022 Dale Glass
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
// Software defined breakpoints, for aiding in debugging
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#include <csignal>
|
||||
#define BREAKPOINT raise(SIGINT);
|
||||
#elif defined(__clang__)
|
||||
#define BREAKPOINT __builtin_trap();
|
||||
#elif _MSC_VER && !__INTEL_COMPILER
|
||||
#include <intrin.h>
|
||||
#define BREAKPOINT __debugbreak();
|
||||
#else
|
||||
#include "CrashHelpers.h"
|
||||
#define BREAKPOINT crash::nullDeref();
|
||||
#endif
|
|
@ -11,6 +11,7 @@
|
|||
//
|
||||
|
||||
#include "LogHandler.h"
|
||||
#include "Breakpoint.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
|
@ -29,6 +30,12 @@
|
|||
#include <QtCore/QThread>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QRecursiveMutex>
|
||||
#include <vector>
|
||||
|
||||
#ifdef HAS_JOURNALD
|
||||
#include <systemd/sd-journal.h>
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
QRecursiveMutex LogHandler::_mutex;
|
||||
|
||||
|
@ -50,27 +57,11 @@ LogHandler::LogHandler() {
|
|||
}
|
||||
#endif
|
||||
|
||||
auto optionList = logOptions.split(",");
|
||||
#ifdef HAS_JOURNALD
|
||||
_useJournald = true;
|
||||
#endif
|
||||
|
||||
for (auto option : optionList) {
|
||||
option = option.trimmed();
|
||||
|
||||
if (option == "color") {
|
||||
_useColor = true;
|
||||
} else if (option == "nocolor") {
|
||||
_useColor = false;
|
||||
} else if (option == "process_id") {
|
||||
_shouldOutputProcessID = true;
|
||||
} else if (option == "thread_id") {
|
||||
_shouldOutputThreadID = true;
|
||||
} else if (option == "milliseconds") {
|
||||
_shouldDisplayMilliseconds = true;
|
||||
} else if (option == "keep_repeats") {
|
||||
_keepRepeats = true;
|
||||
} else if (option != "") {
|
||||
fprintf(stdout, "Unrecognized option in VIRCADIA_LOG_OPTIONS: '%s'\n", option.toUtf8().constData());
|
||||
}
|
||||
}
|
||||
parseOptions(logOptions, "VIRCADIA_LOG_OPTIONS");
|
||||
}
|
||||
|
||||
const char* stringForLogType(LogMsgType msgType) {
|
||||
|
@ -115,12 +106,53 @@ const char* colorReset() {
|
|||
return "\u001b[0m";
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAS_JOURNALD
|
||||
void addString(std::vector<struct iovec>&list, const QByteArray &str) {
|
||||
auto data = str.constData();
|
||||
struct iovec iov{(void*)data, strlen(data)};
|
||||
list.emplace_back(iov);
|
||||
}
|
||||
#endif
|
||||
|
||||
// the following will produce 11/18 13:55:36
|
||||
const QString DATE_STRING_FORMAT = "MM/dd hh:mm:ss";
|
||||
|
||||
// the following will produce 11/18 13:55:36.999
|
||||
const QString DATE_STRING_FORMAT_WITH_MILLISECONDS = "MM/dd hh:mm:ss.zzz";
|
||||
|
||||
bool LogHandler::parseOptions(const QString& logOptions, const QString& paramName) {
|
||||
QMutexLocker lock(&_mutex);
|
||||
auto optionList = logOptions.split(",");
|
||||
|
||||
for (auto option : optionList) {
|
||||
option = option.trimmed();
|
||||
|
||||
if (option == "color") {
|
||||
_useColor = true;
|
||||
} else if (option == "nocolor") {
|
||||
_useColor = false;
|
||||
} else if (option == "process_id") {
|
||||
_shouldOutputProcessID = true;
|
||||
} else if (option == "thread_id") {
|
||||
_shouldOutputThreadID = true;
|
||||
} else if (option == "milliseconds") {
|
||||
_shouldDisplayMilliseconds = true;
|
||||
} else if (option == "keep_repeats") {
|
||||
_keepRepeats = true;
|
||||
} else if (option == "journald") {
|
||||
_useJournald = true;
|
||||
} else if (option == "nojournald") {
|
||||
_useJournald = false;
|
||||
} else if (option != "") {
|
||||
fprintf(stderr, "Unrecognized option in %s: '%s'\n", paramName.toUtf8().constData(), option.toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogHandler::setTargetName(const QString& targetName) {
|
||||
QMutexLocker lock(&_mutex);
|
||||
_targetName = targetName;
|
||||
|
@ -141,6 +173,24 @@ void LogHandler::setShouldDisplayMilliseconds(bool shouldDisplayMilliseconds) {
|
|||
_shouldDisplayMilliseconds = shouldDisplayMilliseconds;
|
||||
}
|
||||
|
||||
void LogHandler::setShouldUseJournald(bool shouldUseJournald) {
|
||||
QMutexLocker lock(&_mutex);
|
||||
#ifdef HAS_JOURNALD
|
||||
_useJournald = shouldUseJournald;
|
||||
#else
|
||||
if (shouldUseJournald) {
|
||||
fprintf(stderr, "Journald is not supported on this system or was not compiled in.\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LogHandler::isJournaldAvailable() const {
|
||||
#ifdef HAS_JOURNALD
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogHandler::flushRepeatedMessages() {
|
||||
QMutexLocker lock(&_mutex);
|
||||
|
@ -162,6 +212,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
|
|||
if (message.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QMutexLocker lock(&_mutex);
|
||||
|
||||
// log prefix is in the following format
|
||||
|
@ -195,32 +246,100 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont
|
|||
}
|
||||
}
|
||||
|
||||
// This is returned from this function and wanted by the LogEntityServer,
|
||||
// so we have to have it even when using journald.
|
||||
QString logMessage = QString("%1 %2\n").arg(prefixString, message.split('\n').join('\n' + prefixString + " "));
|
||||
|
||||
const char* color = "";
|
||||
const char* resetColor = "";
|
||||
|
||||
if (_useColor) {
|
||||
color = colorForLogType(type);
|
||||
resetColor = colorReset();
|
||||
}
|
||||
|
||||
if (_keepRepeats || _previousMessage != message) {
|
||||
if (_repeatCount > 0) {
|
||||
fprintf(stdout, "[Previous message was repeated %i times]\n", _repeatCount);
|
||||
if ( _useJournald ) {
|
||||
#ifdef HAS_JOURNALD
|
||||
int priority = LOG_NOTICE;
|
||||
switch(type) {
|
||||
case LogMsgType::LogFatal: priority = LOG_EMERG; break;
|
||||
case LogMsgType::LogCritical: priority = LOG_CRIT; break;
|
||||
case LogMsgType::LogWarning: priority = LOG_WARNING; break;
|
||||
case LogMsgType::LogInfo: priority = LOG_INFO; break;
|
||||
case LogMsgType::LogDebug: priority = LOG_DEBUG; break;
|
||||
case LogMsgType::LogSuppressed: priority = LOG_DEBUG; break;
|
||||
default:
|
||||
fprintf(stderr, "Unrecognized log type: %i\n", (int)type);
|
||||
}
|
||||
|
||||
fprintf(stdout, "%s%s%s", color, qPrintable(logMessage), resetColor);
|
||||
_repeatCount = 0;
|
||||
QByteArray sd_file = QString("CODE_FILE=%1").arg(context.file).toUtf8();
|
||||
QByteArray sd_line = QString("CODE_LINE=%1").arg(context.line).toUtf8();
|
||||
|
||||
QByteArray sd_message = QString("MESSAGE=%1").arg(message).toUtf8();
|
||||
QByteArray sd_priority = QString("PRIORITY=%1").arg(priority).toUtf8();
|
||||
QByteArray sd_category = QString("CATEGORY=%1").arg(context.category).toUtf8();
|
||||
QByteArray sd_tid = QString("TID=%1").arg((qlonglong)QThread::currentThreadId()).toUtf8();
|
||||
QByteArray sd_target = QString("COMPONENT=%1").arg(_targetName).toUtf8();
|
||||
|
||||
std::vector<struct iovec> fields;
|
||||
addString(fields, sd_message);
|
||||
addString(fields, sd_priority);
|
||||
addString(fields, sd_category);
|
||||
addString(fields, sd_tid);
|
||||
|
||||
if (!_targetName.isEmpty()) {
|
||||
addString(fields, sd_target);
|
||||
}
|
||||
|
||||
int retval = sd_journal_sendv_with_location(sd_file.constData(),
|
||||
sd_line.constData(),
|
||||
context.function == NULL ? "(unknown)" : context.function,
|
||||
fields.data(),
|
||||
fields.size());
|
||||
|
||||
if ( retval != 0 ) {
|
||||
fprintf(stderr, "Failed to log message, error %i: ", retval);
|
||||
fprintf(stderr, "file=%s, line=%i, func=%s, prio=%i, msg=%s\n",
|
||||
context.file,
|
||||
context.line,
|
||||
context.function,
|
||||
priority,
|
||||
message.toUtf8().constData()
|
||||
);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
_repeatCount++;
|
||||
const char* color = "";
|
||||
const char* resetColor = "";
|
||||
|
||||
if (_useColor) {
|
||||
color = colorForLogType(type);
|
||||
resetColor = colorReset();
|
||||
}
|
||||
|
||||
if (_keepRepeats || _previousMessage != message) {
|
||||
if (_repeatCount > 0) {
|
||||
fprintf(stdout, "[Previous message was repeated %i times]\n", _repeatCount);
|
||||
}
|
||||
|
||||
fprintf(stdout, "%s%s%s", color, qPrintable(logMessage), resetColor);
|
||||
_repeatCount = 0;
|
||||
} else {
|
||||
_repeatCount++;
|
||||
}
|
||||
|
||||
_previousMessage = message;
|
||||
#ifdef Q_OS_WIN
|
||||
// On windows, this will output log lines into the Visual Studio "output" tab
|
||||
OutputDebugStringA(qPrintable(logMessage));
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( !_breakMessages.empty() ) {
|
||||
for(const auto &str : _breakMessages) {
|
||||
if (logMessage.contains(str)) {
|
||||
BREAKPOINT
|
||||
}
|
||||
}
|
||||
}
|
||||
_previousMessage = message;
|
||||
#ifdef Q_OS_WIN
|
||||
// On windows, this will output log lines into the Visual Studio "output" tab
|
||||
OutputDebugStringA(qPrintable(logMessage));
|
||||
#endif
|
||||
|
||||
return logMessage;
|
||||
}
|
||||
|
||||
|
@ -262,3 +381,9 @@ void LogHandler::printRepeatedMessage(int messageID, LogMsgType type, const QMes
|
|||
|
||||
++_repeatedMessageRecords[messageID].repeatCount;
|
||||
}
|
||||
|
||||
|
||||
void LogHandler::breakOnMessage(const char *message) {
|
||||
QMutexLocker lock(&_mutex);
|
||||
LogHandler::getInstance()._breakMessages.append(QString::fromUtf8(message));
|
||||
}
|
||||
|
|
|
@ -31,24 +31,105 @@ enum LogMsgType {
|
|||
LogSuppressed = 100
|
||||
};
|
||||
|
||||
/// Handles custom message handling and sending of stats/logs to Logstash instance
|
||||
///
|
||||
|
||||
/**
|
||||
* @brief Handles custom message handling and sending of stats/logs to Logstash instance
|
||||
*
|
||||
*/
|
||||
class LogHandler : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Returns the one instance of the LogHandler object
|
||||
*
|
||||
* @return LogHandler&
|
||||
*/
|
||||
static LogHandler& getInstance();
|
||||
|
||||
/// sets the target name to output via the verboseMessageHandler, called once before logging begins
|
||||
/// \param targetName the desired target name to output in logs
|
||||
/**
|
||||
* @brief Parse logging options
|
||||
*
|
||||
* This parses the logging settings in the environment variable, or from the commandline
|
||||
*
|
||||
* @param options Option list
|
||||
* @param paramName Name of the log option, for error reporting.
|
||||
* @return true Option list was parsed successfully
|
||||
* @return false There was an error
|
||||
*/
|
||||
bool parseOptions(const QString& options, const QString ¶mName);
|
||||
|
||||
/**
|
||||
* @brief Set the name of the component that's producing log output
|
||||
*
|
||||
* For instance, "assignment-client", "audio-mixer", etc.
|
||||
* Called once before logging begins
|
||||
*
|
||||
* @param targetName the desired target name to output in logs
|
||||
*/
|
||||
void setTargetName(const QString& targetName);
|
||||
|
||||
/**
|
||||
* @brief Set whether to output the process ID
|
||||
*
|
||||
* @note This has no effect when logging with journald, the PID is always logged
|
||||
*
|
||||
* @param shouldOutputProcessID Whether to output the PID
|
||||
*/
|
||||
void setShouldOutputProcessID(bool shouldOutputProcessID);
|
||||
|
||||
/**
|
||||
* @brief Set whether to output the thread ID
|
||||
*
|
||||
* @param shouldOutputThreadID
|
||||
*/
|
||||
void setShouldOutputThreadID(bool shouldOutputThreadID);
|
||||
|
||||
/**
|
||||
* @brief Set whether to display timestamps with milliseconds
|
||||
*
|
||||
* @param shouldDisplayMilliseconds
|
||||
*/
|
||||
void setShouldDisplayMilliseconds(bool shouldDisplayMilliseconds);
|
||||
|
||||
/**
|
||||
* @brief Set whether to use Journald, if it's available
|
||||
*
|
||||
* @param shouldUseJournald Whether to use journald
|
||||
*/
|
||||
void setShouldUseJournald(bool shouldUseJournald);
|
||||
|
||||
/**
|
||||
* @brief Whether Journald is available on this version/system.
|
||||
*
|
||||
* Support is available depending on compile options and only on Linux.
|
||||
*
|
||||
* @return true Journald is available
|
||||
* @return false Journald is not available
|
||||
*/
|
||||
bool isJournaldAvailable() const;
|
||||
|
||||
/**
|
||||
* @brief Process a log message
|
||||
*
|
||||
* This writes it to a file, logs it to the console, or sends it to journald.
|
||||
*
|
||||
* @param type Log message type
|
||||
* @param context Context of the log message (source file, line, function)
|
||||
* @param message Log message
|
||||
* @return QString The log message's text with added severity and timestamp
|
||||
*/
|
||||
QString printMessage(LogMsgType type, const QMessageLogContext& context, const QString &message);
|
||||
|
||||
/// a qtMessageHandler that can be hooked up to a target that links to Qt
|
||||
/// prints various process, message type, and time information
|
||||
/**
|
||||
* @brief A qtMessageHandler that can be hooked up to a target that links to Qt
|
||||
*
|
||||
* Prints various process, message type, and time information
|
||||
*
|
||||
* @param type Log message type
|
||||
* @param context Context of the log message (source file, line, function)
|
||||
* @param message Log message
|
||||
*/
|
||||
static void verboseMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &message);
|
||||
|
||||
int newRepeatedMessageID();
|
||||
|
@ -56,6 +137,27 @@ public:
|
|||
|
||||
void setupRepeatedMessageFlusher();
|
||||
|
||||
/**
|
||||
* @brief Break when a message that contains the specified string is logged
|
||||
*
|
||||
* This is a function intended to be invoked from inside a debugger. It should be of help when it's hard to put a breakpoint
|
||||
* on the generating line because it comes from inlined code, or the interesting text is generated at runtime.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* @code {.cpp}
|
||||
* LogHandler::breakOnMessage("No instance available for");
|
||||
* @endcode
|
||||
*
|
||||
* Then the debugger should be triggered as soon as a message containing that string is logged. Backtracking
|
||||
* through the call stack should lead back to the source.
|
||||
*
|
||||
* @note Support for creating a breakpoint in software is compiler and OS specific. If there's no support for
|
||||
* creating a breakpoint on the current compiler/OS, then an abort will be triggered instead.
|
||||
*
|
||||
* @param str Text to match
|
||||
*/
|
||||
static void breakOnMessage(const char *str);
|
||||
private:
|
||||
LogHandler();
|
||||
~LogHandler() = default;
|
||||
|
@ -68,6 +170,7 @@ private:
|
|||
bool _shouldDisplayMilliseconds { false };
|
||||
bool _useColor { false };
|
||||
bool _keepRepeats { false };
|
||||
bool _useJournald { false };
|
||||
|
||||
QString _previousMessage;
|
||||
int _repeatCount { 0 };
|
||||
|
@ -79,6 +182,8 @@ private:
|
|||
QString repeatString;
|
||||
};
|
||||
std::vector<RepeatedMessageRecord> _repeatedMessageRecords;
|
||||
|
||||
QStringList _breakMessages;
|
||||
static QRecursiveMutex _mutex;
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// Persist toolbar by HRS 6/11/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// This script allows you to edit entities with a new UI/UX for mouse and trackpad based editing
|
||||
//
|
||||
|
@ -11,7 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EntityListTool, Vec3, SelectionManager,
|
||||
/* global Script, SelectionDisplay, LightOverlayManager, CameraManager, Grid, GridTool, EditTools, EditVoxels, EntityListTool, Vec3, SelectionManager,
|
||||
Overlays, OverlayWebWindow, UserActivityLogger, Settings, Entities, Tablet, Toolbars, Messages, Menu, Camera,
|
||||
progressDialog, tooltip, MyAvatar, Quat, Controller, Clipboard, HMD, UndoStack, OverlaySystemWindow,
|
||||
keyUpEventFromUIWindow:true */
|
||||
|
@ -36,7 +37,9 @@ Script.include([
|
|||
"entityList/entityList.js",
|
||||
"entitySelectionTool/entitySelectionTool.js",
|
||||
"audioFeedback/audioFeedback.js",
|
||||
"modules/brokenURLReport.js"
|
||||
"modules/brokenURLReport.js",
|
||||
"editModes/editModes.js",
|
||||
"editModes/editVoxels.js"
|
||||
]);
|
||||
|
||||
var CreateWindow = Script.require('./modules/createWindow.js');
|
||||
|
@ -126,6 +129,16 @@ var gridTool = new GridTool({
|
|||
});
|
||||
gridTool.setVisible(false);
|
||||
|
||||
var editTools = new EditTools({
|
||||
createToolsWindow: createToolsWindow,
|
||||
});
|
||||
|
||||
var editVoxels = new EditVoxels();
|
||||
editVoxels.editTools = editTools;
|
||||
|
||||
editTools.addListener(editVoxels.updateEditSettings);
|
||||
editTools.addListener(selectionManager.updateEditSettings);
|
||||
|
||||
var entityShapeVisualizerSessionName = "SHAPE_VISUALIZER_" + Uuid.generate();
|
||||
|
||||
var EntityShapeVisualizer = Script.require('./modules/entityShapeVisualizer.js');
|
||||
|
@ -750,6 +763,92 @@ var toolBar = (function () {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleNewPolyVoxDialogResult(result) {
|
||||
if (result) {
|
||||
var initialShape = result.initialShapeIndex;
|
||||
var volumeSizeX = parseInt(result.volumeSizeX);
|
||||
var volumeSizeY = parseInt(result.volumeSizeY);
|
||||
var volumeSizeZ = parseInt(result.volumeSizeZ);
|
||||
var voxelSurfaceStyle = parseInt(result.surfaceStyleIndex);
|
||||
var voxelPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: volumeSizeZ * -1.6 }));
|
||||
|
||||
var polyVoxID = createNewEntity({
|
||||
type: "PolyVox",
|
||||
name: "terrain",
|
||||
dimensions: {
|
||||
x: volumeSizeX,
|
||||
y: volumeSizeY,
|
||||
z: volumeSizeZ
|
||||
},
|
||||
voxelVolumeSize: {
|
||||
x: volumeSizeX,
|
||||
y: volumeSizeY,
|
||||
z: volumeSizeZ
|
||||
},
|
||||
xTextureURL: result.xTextureURL,
|
||||
yTextureURL: result.yTextureURL,
|
||||
zTextureURL: result.zTextureURL,
|
||||
voxelSurfaceStyle: voxelSurfaceStyle,
|
||||
collisionless: !(result.collisions),
|
||||
grab: {
|
||||
grabbable: result.grabbable
|
||||
},
|
||||
});
|
||||
|
||||
Entities.editEntity(polyVoxID, {
|
||||
position: voxelPosition
|
||||
});
|
||||
|
||||
if (polyVoxID){
|
||||
switch (initialShape) {
|
||||
case 0:
|
||||
Entities.setVoxelsInCuboid(polyVoxID, {
|
||||
x: Math.round(volumeSizeX / 4),
|
||||
y: Math.round(volumeSizeY / 4),
|
||||
z: Math.round(volumeSizeZ / 4)
|
||||
}, {
|
||||
x: Math.round(volumeSizeX / 2.0),
|
||||
y: Math.round(volumeSizeY / 2.0),
|
||||
z: Math.round(volumeSizeZ / 2.0)
|
||||
}, 255);
|
||||
break;
|
||||
// Plane 1/4
|
||||
case 1:
|
||||
Entities.setVoxelsInCuboid(polyVoxID, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}, {
|
||||
x: volumeSizeX,
|
||||
y: Math.round(volumeSizeY / 4),
|
||||
z: volumeSizeZ
|
||||
}, 255);
|
||||
break;
|
||||
// Plane 3/4
|
||||
case 2:
|
||||
Entities.setVoxelsInCuboid(polyVoxID, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}, {
|
||||
x: volumeSizeX,
|
||||
y: Math.round(3 * volumeSizeY / 4),
|
||||
z: volumeSizeZ
|
||||
}, 255);
|
||||
break;
|
||||
// Single voxel at center
|
||||
case 3:
|
||||
Entities.setVoxel(polyVoxID, {
|
||||
x: Math.round(volumeSizeX / 2),
|
||||
y: Math.round(volumeSizeY / 2),
|
||||
z: Math.round(volumeSizeZ / 2)
|
||||
}, 255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleNewMaterialDialogResult(result) {
|
||||
if (result) {
|
||||
|
@ -806,6 +905,13 @@ var toolBar = (function () {
|
|||
case "newMaterialDialogCancel":
|
||||
closeExistingDialogWindow();
|
||||
break;
|
||||
case "newPolyVoxDialogAdd":
|
||||
handleNewPolyVoxDialogResult(message.params);
|
||||
closeExistingDialogWindow();
|
||||
break;
|
||||
case "newPolyVoxDialogCancel":
|
||||
closeExistingDialogWindow();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -912,6 +1018,10 @@ var toolBar = (function () {
|
|||
closeExistingDialogWindow();
|
||||
var qmlPath = Script.resolvePath("qml/New" + entityType + "Window.qml");
|
||||
var DIALOG_WINDOW_SIZE = { x: 500, y: 300 };
|
||||
if( entityType === "PolyVox" ){
|
||||
DIALOG_WINDOW_SIZE.x = 600;
|
||||
DIALOG_WINDOW_SIZE.y = 500;
|
||||
}
|
||||
dialogWindow = Desktop.createWindow(qmlPath, {
|
||||
title: "New " + entityType + " Entity",
|
||||
additionalFlags: Desktop.ALWAYS_ON_TOP | Desktop.CLOSE_BUTTON_HIDES,
|
||||
|
@ -971,6 +1081,8 @@ var toolBar = (function () {
|
|||
|
||||
addButton("newMaterialButton", createNewEntityDialogButtonCallback("Material"));
|
||||
|
||||
addButton("newPolyVoxButton", createNewEntityDialogButtonCallback("PolyVox"));
|
||||
|
||||
var deactivateCreateIfDesktopWindowsHidden = function() {
|
||||
if (!shouldUseEditTabletApp() && !entityListTool.isVisible() && !createToolsWindow.isVisible()) {
|
||||
that.setActive(false);
|
||||
|
@ -1016,6 +1128,8 @@ var toolBar = (function () {
|
|||
isActive = active;
|
||||
activeButton.editProperties({isActive: isActive});
|
||||
undoHistory.setEnabled(isActive);
|
||||
|
||||
editVoxels.setActive(active);
|
||||
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
||||
|
@ -1369,7 +1483,7 @@ function mouseClickEvent(event) {
|
|||
var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) &&
|
||||
(allowSmallModels || angularSize > MIN_ANGULAR_SIZE);
|
||||
|
||||
if (0 < x && sizeOK) {
|
||||
if (0 < x && sizeOK && selectionManager.editEnabled) {
|
||||
selectedEntityID = foundEntity;
|
||||
orientation = MyAvatar.orientation;
|
||||
intersection = rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));
|
||||
|
|
181
scripts/system/create/editModes/editModes.js
Normal file
|
@ -0,0 +1,181 @@
|
|||
//
|
||||
// editModes.js
|
||||
//
|
||||
// Created by Karol Suprynowicz on 2022.05.15.
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// Partially based on gridTool.js
|
||||
// Created by Ryan Huffman on 6 Nov 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// This script implements a class for managing different edit modes
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
EditTools = function(options) {
|
||||
var that = {};
|
||||
|
||||
var createAppMode = "object";
|
||||
var voxelEditMode = "single";
|
||||
var voxelSphereSize = 0.3;
|
||||
var voxelEditDynamics = "click";
|
||||
var voxelRemove = false;
|
||||
var voxelPointerMode = "laser";
|
||||
var voxelBrushLength = 0.5;
|
||||
var listeners = [];
|
||||
|
||||
var createToolsWindow = options.createToolsWindow;
|
||||
|
||||
that.emitUpdate = function() {
|
||||
var dataString = JSON.stringify({
|
||||
createAppMode : createAppMode,
|
||||
voxelEditMode : voxelEditMode,
|
||||
voxelSphereSize : voxelSphereSize,
|
||||
voxelEditDynamics : voxelEditDynamics,
|
||||
voxelRemove : voxelRemove,
|
||||
voxelPointerMode : voxelPointerMode,
|
||||
voxelBrushLength : voxelBrushLength,
|
||||
});
|
||||
webView.emitScriptEvent(dataString);
|
||||
createToolsWindow.emitScriptEvent(dataString);
|
||||
};
|
||||
|
||||
that.getCreateAppMode = function() {
|
||||
return createAppMode;
|
||||
}
|
||||
|
||||
that.setCreateAppMode = function(value) {
|
||||
createAppMode = value;
|
||||
that.emitUpdate();
|
||||
}
|
||||
|
||||
that.getVoxelEditMode = function() {
|
||||
return voxelEditMode;
|
||||
}
|
||||
|
||||
that.setVoxelEditMode = function(value) {
|
||||
voxelEditMode = value;
|
||||
that.emitUpdate();
|
||||
}
|
||||
|
||||
that.getVoxelSphereSize = function() {
|
||||
return voxelSphereSize;
|
||||
}
|
||||
|
||||
that.setVoxelSphereSize = function(value) {
|
||||
voxelSphereSize = value;
|
||||
that.emitUpdate();
|
||||
}
|
||||
|
||||
that.getVoxelEditDynamics = function() {
|
||||
return voxelEditDynamics;
|
||||
}
|
||||
|
||||
that.setVoxelEditDynamics = function(value) {
|
||||
voxelEditDynamics = value;
|
||||
that.emitUpdate();
|
||||
}
|
||||
|
||||
that.getVoxelRemove = function() {
|
||||
return voxelRemove;
|
||||
}
|
||||
|
||||
that.setVoxelRemove = function(value) {
|
||||
voxelRemove = value;
|
||||
that.emitUpdate();
|
||||
}
|
||||
|
||||
that.getVoxelPointerMode = function() {
|
||||
return voxelPointerMode;
|
||||
}
|
||||
|
||||
that.setVoxelPointerMode = function(value) {
|
||||
voxelPointerMode = value;
|
||||
that.emitUpdate();
|
||||
}
|
||||
|
||||
that.getVoxelBrushLength = function() {
|
||||
return voxelBrushLength;
|
||||
}
|
||||
|
||||
that.setVoxelBrushLength = function(value) {
|
||||
voxelBrushLength = value;
|
||||
that.emitUpdate();
|
||||
}
|
||||
|
||||
that.update = function(data) {
|
||||
if (data.type !== "update-edit-tools") {
|
||||
return;
|
||||
}
|
||||
|
||||
print(JSON.stringify(data));
|
||||
|
||||
var needsUpdate = false;
|
||||
|
||||
if (data.createAppMode) {
|
||||
createAppMode = data.createAppMode;
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (data.voxelEditMode) {
|
||||
voxelEditMode = data.voxelEditMode;
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (data.voxelSphereSize) {
|
||||
voxelSphereSize = data.voxelSphereSize;
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (data.voxelEditDynamics) {
|
||||
voxelEditDynamics = data.voxelEditDynamics;
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (data.voxelRemove) {
|
||||
voxelRemove = data.voxelRemove;
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (data.voxelPointerMode) {
|
||||
voxelPointerMode = data.voxelPointerMode;
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (data.voxelBrushLength) {
|
||||
voxelBrushLength = data.voxelBrushLength;
|
||||
needsUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
var webEventReceived = function(data) {
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
} catch (e) {
|
||||
console.log("editModes.js, EditTools.webEventReceived: Cannot parse received JSON data");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.type === "init") {
|
||||
that.emitUpdate();
|
||||
} else if (data.type === "update-edit-tools") {
|
||||
that.update(data);
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
listeners[i] && listeners[i](data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var webView = null;
|
||||
webView = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
||||
webView.webEventReceived.connect(webEventReceived);
|
||||
createToolsWindow.webEventReceived.addListener(webEventReceived);
|
||||
|
||||
that.addListener = function(callback) {
|
||||
listeners.push(callback);
|
||||
};
|
||||
|
||||
function cleanup() {
|
||||
}
|
||||
|
||||
return that;
|
||||
}
|
687
scripts/system/create/editModes/editVoxels.js
Normal file
|
@ -0,0 +1,687 @@
|
|||
//
|
||||
// editModes.js
|
||||
//
|
||||
// Created by dr Karol Suprynowicz on 2022.05.17.
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// Based on voxels.js
|
||||
// Created by Seth Alves on 2015-08-25
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Based on entitySelectionTool.js
|
||||
// Created by Brad hefta-Gaub on 10/1/14.
|
||||
// Modified by Daniela Fontes * @DanielaFifo and Tiago Andrade @TagoWill on 4/7/2017
|
||||
// Modified by David Back on 1/9/2018
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors
|
||||
//
|
||||
// This script implements voxel edit mode
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include([
|
||||
"./libraries/utils.js",
|
||||
"entitySelectionTool/entitySelectionTool.js"
|
||||
]);
|
||||
|
||||
var selectionManager = SelectionManager;
|
||||
|
||||
|
||||
EditVoxels = function() {
|
||||
var self = this;
|
||||
var that = {};
|
||||
|
||||
const NO_HAND = -1;
|
||||
|
||||
var controlHeld = false;
|
||||
var shiftHeld = false;
|
||||
var isLeftGripPressed = false;
|
||||
var isRightGripPressed = false;
|
||||
|
||||
var editEnabled = false;
|
||||
var editSingleVoxels = false;
|
||||
var editSpheres = false;
|
||||
var editCubes = false;
|
||||
var editAdd = true; // Remove voxels if false
|
||||
var inverseOperation = false; // True when middle mouse button or grip is pressed
|
||||
var brushPointer = false;
|
||||
var isActive = true;
|
||||
|
||||
var editSphereRadius = 0.15;
|
||||
var brushLength = 0.5;
|
||||
// Vector calculated from editSphereRadius for adding/remiving cubes
|
||||
var cubeSize = null;
|
||||
|
||||
// Local plane for continuous voxel editing
|
||||
// 0 - plane parallel to YZ plane
|
||||
// 1 - plane parallel to XZ plane
|
||||
// 2 - plane parallel to YZ plane
|
||||
var editPlane = 0;
|
||||
// Is true when mouse button is pressed
|
||||
var isEditing = false;
|
||||
var editedVoxelEntity = null;
|
||||
// Position of last edit in voxel space
|
||||
var oldEditPosition = null;
|
||||
// True when original operation added voxels, false otherwise
|
||||
var lastEditValue = 255;
|
||||
var isOnUpdateConnected = false;
|
||||
var isSphereResizingStarted = true;
|
||||
var sphereResizingInitialHandDistance = 0.1;
|
||||
var sphereInitialRadius = editSphereRadius;
|
||||
var sphereEntityID = null;
|
||||
|
||||
that.triggerClickMapping = Controller.newMapping(Script.resolvePath('') + '-click-voxels');
|
||||
that.triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press-voxels');
|
||||
that.gripPressMapping = Controller.newMapping(Script.resolvePath('') + '-grip-voxels');
|
||||
that.triggeredHand = NO_HAND;
|
||||
that.pressedHand = NO_HAND;
|
||||
|
||||
var soundAdd = SoundCache.getSound(Script.resourcesPath() + "sounds/Button05.wav");
|
||||
var soundDelete = SoundCache.getSound(Script.resourcesPath() + "sounds/Tab03.wav");
|
||||
|
||||
// Continuous start timer prevents activating continuous mode on short button presses
|
||||
// and adding multiple voxels when only one was intended
|
||||
|
||||
var continuousStartTimerMax = 0.200;
|
||||
var continuousStartTimer = 0.0;
|
||||
|
||||
that.setActive = function(active) {
|
||||
isActive = (active === true);
|
||||
}
|
||||
|
||||
that.updateEditSettings = function(data) {
|
||||
|
||||
if (data.createAppMode) {
|
||||
if (data.createAppMode === "voxel"){
|
||||
editEnabled = true;
|
||||
} else {
|
||||
editEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.voxelEditMode) {
|
||||
editAdd = true;
|
||||
if (data.voxelRemove) {
|
||||
editAdd = false;
|
||||
}
|
||||
if (data.voxelEditMode === "single") {
|
||||
editSpheres = false;
|
||||
editSingleVoxels = true;
|
||||
editCubes = false;
|
||||
} else if (data.voxelEditMode === "sphere") {
|
||||
editSpheres = true;
|
||||
editSingleVoxels = false;
|
||||
editCubes = false;
|
||||
} else if (data.voxelEditMode === "cube") {
|
||||
editSpheres = false;
|
||||
editSingleVoxels = false;
|
||||
editCubes = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.voxelSphereSize) {
|
||||
editSphereRadius = parseFloat(data.voxelSphereSize) / 2.0;
|
||||
}
|
||||
|
||||
if (data.voxelPointerMode) {
|
||||
if (data.voxelPointerMode === "brush") {
|
||||
brushPointer = true;
|
||||
} else {
|
||||
brushPointer = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.voxelBrushLength) {
|
||||
voxelBrushLength = parseFloat(data.voxelBrushLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function floorVector(v) {
|
||||
return {
|
||||
x: Math.floor(v.x),
|
||||
y: Math.floor(v.y),
|
||||
z: Math.floor(v.z)
|
||||
};
|
||||
}
|
||||
|
||||
function ceilVector(v) {
|
||||
return {
|
||||
x: Math.ceil(v.x),
|
||||
y: Math.ceil(v.y),
|
||||
z: Math.ceil(v.z)
|
||||
};
|
||||
}
|
||||
|
||||
function attemptVoxelChangeForEntity(entityID, pickRayDir, intersectionLocation) {
|
||||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
print("=============== eV::attemptVoxelChangeForEntity BEG =======================");
|
||||
}
|
||||
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
if (properties.type != "PolyVox") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!editEnabled || !isActive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (editSingleVoxels === false && editSpheres === false && editCubes === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var voxelOrigin = Entities.worldCoordsToVoxelCoords(entityID, Vec3.subtract(intersectionLocation, pickRayDir));
|
||||
var voxelPosition = Entities.worldCoordsToVoxelCoords(entityID, intersectionLocation);
|
||||
var pickRayDirInVoxelSpace = Vec3.subtract(voxelPosition, voxelOrigin);
|
||||
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
|
||||
|
||||
var absX = Math.abs(pickRayDirInVoxelSpace.x);
|
||||
var absY = Math.abs(pickRayDirInVoxelSpace.y);
|
||||
var absZ = Math.abs(pickRayDirInVoxelSpace.z);
|
||||
if(absX >= absY && absX >= absZ){
|
||||
editPlane = 0;
|
||||
}else if(absY >= absX && absY >= absZ){
|
||||
editPlane = 1;
|
||||
}else if(absZ >= absX && absZ >= absY){
|
||||
editPlane = 2;
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
print("voxelOrigin: " + JSON.stringify(voxelOrigin));
|
||||
print("voxelPosition: " + JSON.stringify(voxelPosition));
|
||||
print("pickRayDirInVoxelSpace: " + JSON.stringify(pickRayDirInVoxelSpace));
|
||||
}
|
||||
|
||||
lastEditValue = 0;
|
||||
if((editAdd && !inverseOperation) || (!editAdd && inverseOperation)){
|
||||
lastEditValue = 255;
|
||||
}
|
||||
|
||||
var toDrawPosition = null;
|
||||
|
||||
if(lastEditValue === 255){
|
||||
toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
|
||||
}else{
|
||||
toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, -0.1));
|
||||
}
|
||||
|
||||
if (editSingleVoxels) {
|
||||
if (wantDebug) {
|
||||
print("Calling setVoxel");
|
||||
print("entityID: " + JSON.stringify(entityID));
|
||||
print("floorVector(toDrawPosition): " + JSON.stringify(floorVector(toDrawPosition)));
|
||||
}
|
||||
oldEditPosition = floorVector(toDrawPosition);
|
||||
if (Entities.setVoxel(entityID, oldEditPosition, lastEditValue)){
|
||||
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (editSpheres) {
|
||||
if (wantDebug) {
|
||||
print("Calling setVoxelSphere");
|
||||
print("entityID: " + JSON.stringify(entityID));
|
||||
print("editSphereRadius: " + JSON.stringify(editSphereRadius));
|
||||
print("floorVector(toDrawPosition): " + JSON.stringify(floorVector(toDrawPosition)));
|
||||
}
|
||||
oldEditPosition = floorVector(toDrawPosition);
|
||||
var toDrawPositionWorld = Entities.voxelCoordsToWorldCoords(entityID, oldEditPosition);
|
||||
if (Entities.setVoxelSphere(entityID, toDrawPositionWorld, editSphereRadius, lastEditValue)){
|
||||
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (editCubes) {
|
||||
if (wantDebug) {
|
||||
print("Calling setVoxelsInCuboid");
|
||||
print("entityID: " + JSON.stringify(entityID));
|
||||
print("editSphereRadius: " + JSON.stringify(editSphereRadius));
|
||||
print("floorVector(toDrawPosition): " + JSON.stringify(floorVector(toDrawPosition)));
|
||||
}
|
||||
oldEditPosition = floorVector(toDrawPosition);
|
||||
var cubeSizeWorld = {x : editSphereRadius * 2, y : editSphereRadius * 2, z : editSphereRadius * 2};
|
||||
var zeroVecWorld = {x : 0, y: 0, z: 0};
|
||||
var zeroVecLocal = Entities.worldCoordsToVoxelCoords(entityID, zeroVecWorld);
|
||||
var cubeSizeVecLocal = Entities.worldCoordsToVoxelCoords(entityID, cubeSizeWorld);
|
||||
cubeSize = ceilVector(Vec3.subtract(cubeSizeVecLocal, zeroVecLocal));
|
||||
var lowPosition = Vec3.subtract(oldEditPosition, Vec3.multiply(cubeSize, 0.5));
|
||||
if (Entities.setVoxelsInCuboid(entityID, lowPosition, cubeSize, lastEditValue)){
|
||||
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function attemptVoxelChange(pickRayDir, intersection) {
|
||||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
print("=============== eV::attemptVoxelChange BEG =======================");
|
||||
}
|
||||
|
||||
var ids;
|
||||
|
||||
ids = Entities.findEntities(intersection.intersection, editSphereRadius + 1.0);
|
||||
if (ids.indexOf(intersection.entityID) < 0) {
|
||||
ids.push(intersection.entityID);
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
print("Entities: " + JSON.stringify(ids));
|
||||
}
|
||||
|
||||
var success = false;
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
var entityID = ids[i];
|
||||
success |= attemptVoxelChangeForEntity(entityID, pickRayDir, intersection.intersection)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
function controllerComputePickRay() {
|
||||
var hand = triggered() ? that.triggeredHand : that.pressedHand;
|
||||
var controllerPose = getControllerWorldLocation(hand, true);
|
||||
if (controllerPose.valid) {
|
||||
var controllerPosition = controllerPose.translation;
|
||||
// This gets point direction right, but if you want general quaternion it would be more complicated:
|
||||
var controllerDirection = Quat.getUp(controllerPose.rotation);
|
||||
return {origin: controllerPosition, direction: controllerDirection};
|
||||
}
|
||||
}
|
||||
|
||||
function generalComputePickRay(x, y) {
|
||||
return controllerComputePickRay() || Camera.computePickRay(x, y);
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
var wantDebug = false;
|
||||
var attemptChangeOnEmpty = false;
|
||||
if (!editEnabled || !isActive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
print("=============== eV::mousePressEvent BEG =======================");
|
||||
}
|
||||
|
||||
if (!(event.isLeftButton || event.isMiddleButton) && !triggered()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.isLeftButton || event.isMiddleButton){
|
||||
if (event.isMiddleButton){
|
||||
inverseOperation = true;
|
||||
}else{
|
||||
inverseOperation = false;
|
||||
}
|
||||
}else{
|
||||
inverseOperation = false;
|
||||
if(that.triggeredHand === Controller.Standard.RightHand && Controller.getValue(Controller.Standard.RightGrip) > 0.5){
|
||||
inverseOperation = true;
|
||||
}
|
||||
if(that.triggeredHand === Controller.Standard.LeftHand && Controller.getValue(Controller.Standard.LeftGrip) > 0.5){
|
||||
inverseOperation = true;
|
||||
}
|
||||
}
|
||||
|
||||
continuousStartTimer = 0;
|
||||
|
||||
var pickRay = generalComputePickRay(event.x, event.y);
|
||||
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
|
||||
|
||||
if (wantDebug) {
|
||||
print("Pick ray: " + JSON.stringify(pickRay));
|
||||
print("Intersection: " + JSON.stringify(intersection));
|
||||
}
|
||||
|
||||
if (intersection.intersects) {
|
||||
if (attemptVoxelChangeForEntity(intersection.entityID, pickRay.direction, intersection.intersection)) {
|
||||
Script.update.connect(onUpdateHandler);
|
||||
isOnUpdateConnected = true;
|
||||
isEditing = true;
|
||||
editedVoxelEntity = intersection.entityID;
|
||||
if (wantDebug) {
|
||||
print("onUpdateHandler connected");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if the PolyVox entity is empty, we can't pick against its "on" voxels. try picking against its
|
||||
// bounding box, instead.
|
||||
if (attemptChangeOnEmpty) {
|
||||
intersection = Entities.findRayIntersection(pickRay, false); // bounding box picking
|
||||
if (intersection.intersects) {
|
||||
if(attemptVoxelChange(pickRay.direction, intersection)){
|
||||
Script.update.connect(onUpdateHandler);
|
||||
isOnUpdateConnected = true;
|
||||
if (wantDebug) {
|
||||
print("onUpdateHandler connected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
var wantDebug = false;
|
||||
|
||||
if (wantDebug) {
|
||||
print("=============== eV::mouseReleaseEvent BEG =======================");
|
||||
}
|
||||
if(isOnUpdateConnected){
|
||||
Script.update.disconnect(onUpdateHandler);
|
||||
isOnUpdateConnected = false;
|
||||
isEditing = false;
|
||||
editedVoxelEntity = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
function keyPressEvent(event) {
|
||||
if (event.text == "CONTROL") {
|
||||
controlHeld = true;
|
||||
}
|
||||
if (event.text == "SHIFT") {
|
||||
shiftHeld = true;
|
||||
}
|
||||
}
|
||||
|
||||
function keyReleaseEvent(event) {
|
||||
if (event.text == "CONTROL") {
|
||||
controlHeld = false;
|
||||
}
|
||||
if (event.text == "SHIFT") {
|
||||
shiftHeld = false;
|
||||
}
|
||||
}
|
||||
|
||||
function triggered() {
|
||||
return that.triggeredHand !== NO_HAND;
|
||||
};
|
||||
|
||||
function pointingAtDesktopWindowOrTablet(hand) {
|
||||
var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand &&
|
||||
SelectionManager.pointingAtDesktopWindowRight) ||
|
||||
(hand === Controller.Standard.LeftHand &&
|
||||
SelectionManager.pointingAtDesktopWindowLeft);
|
||||
var pointingAtTablet = (hand === Controller.Standard.RightHand && SelectionManager.pointingAtTabletRight) ||
|
||||
(hand === Controller.Standard.LeftHand && SelectionManager.pointingAtTabletLeft);
|
||||
return pointingAtDesktopWindow || pointingAtTablet;
|
||||
}
|
||||
|
||||
function makeClickHandler(hand) {
|
||||
return function (clicked) {
|
||||
if (!editEnabled) {
|
||||
return;
|
||||
}
|
||||
// Don't allow both hands to trigger at the same time
|
||||
if (triggered() && hand !== that.triggeredHand) {
|
||||
return;
|
||||
}
|
||||
if (!triggered() && clicked && !pointingAtDesktopWindowOrTablet(hand)) {
|
||||
that.triggeredHand = hand;
|
||||
mousePressEvent({});
|
||||
} else if (triggered() && !clicked) {
|
||||
that.triggeredHand = NO_HAND;
|
||||
mouseReleaseEvent({});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function makePressHandler(hand) {
|
||||
return function (value) {
|
||||
if (!editEnabled) {
|
||||
return;
|
||||
}
|
||||
if (value >= TRIGGER_ON_VALUE && !triggered() && !pointingAtDesktopWindowOrTablet(hand)) {
|
||||
that.pressedHand = hand;
|
||||
} else {
|
||||
that.pressedHand = NO_HAND;
|
||||
if(isOnUpdateConnected){
|
||||
Script.update.disconnect(onUpdateHandler);
|
||||
isOnUpdateConnected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDistanceBetweenControllers(){
|
||||
var poseLeft = getControllerWorldLocation(Controller.Standard.LeftHand, true);
|
||||
var poseRight = getControllerWorldLocation(Controller.Standard.RightHand, true);
|
||||
return Vec3.distance(poseLeft.translation, poseRight.translation);
|
||||
}
|
||||
function getEditSpherePosition( radius ){
|
||||
var poseLeft = getControllerWorldLocation(Controller.Standard.LeftHand, true);
|
||||
var poseRight = getControllerWorldLocation(Controller.Standard.RightHand, true);
|
||||
var handsPosition = Vec3.multiply(Vec3.sum(poseLeft.translation, poseRight.translation), 0.5);
|
||||
return Vec3.sum(handsPosition, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: radius * -2.0 }));
|
||||
}
|
||||
|
||||
function updateSphereResizing(delta) {
|
||||
var wantDebug = false;
|
||||
var newDistance = getDistanceBetweenControllers();
|
||||
var newRadius = (sphereInitialRadius / sphereResizingInitialHandDistance) * newDistance;
|
||||
var newPosition = getEditSpherePosition(newRadius);
|
||||
var newDimensions = Vec3.multiply({ x: 1.0, y: 1.0, z: 1.0 }, newRadius * 2.0);
|
||||
if (wantDebug) {
|
||||
print("newDistance: " + JSON.stringify(newDistance));
|
||||
print("newRadius: " + JSON.stringify(newRadius));
|
||||
print("newPosition: " + JSON.stringify(newPosition));
|
||||
print("newDimensions: " + JSON.stringify(newDimensions));
|
||||
}
|
||||
Entities.editEntity(sphereEntityID, {
|
||||
position: newPosition,
|
||||
dimensions: newDimensions
|
||||
});
|
||||
if( that.editTools ) {
|
||||
editTools.setVoxelSphereSize(newRadius * 2);
|
||||
}
|
||||
editSphereRadius = newRadius;
|
||||
}
|
||||
|
||||
function startSphereResizing() {
|
||||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
print("=============== eV::startSphereResizing BEG =======================");
|
||||
}
|
||||
Script.update.connect(updateSphereResizing);
|
||||
sphereResizingInitialHandDistance = getDistanceBetweenControllers();
|
||||
sphereInitialRadius = editSphereRadius;
|
||||
var spherePosition = getEditSpherePosition(sphereInitialRadius);
|
||||
var sphereDimensions = Vec3.multiply({ x: 1.0, y: 1.0, z: 1.0 }, sphereInitialRadius * 2.0);
|
||||
sphereEntityID = Entities.addEntity({
|
||||
type: "Shape",
|
||||
shape: "Sphere",
|
||||
name: "voxelEditSphere",
|
||||
position: spherePosition,
|
||||
color: { r: 60, g: 100, b: 60 },
|
||||
alpha: 0.5,
|
||||
dimensions: sphereDimensions,
|
||||
collisionless: true,
|
||||
},"world");
|
||||
}
|
||||
|
||||
function stopSphereResizing() {
|
||||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
print("=============== eV::stopSphereResizing BEG =======================");
|
||||
}
|
||||
Script.update.disconnect(updateSphereResizing);
|
||||
if (sphereEntityID !== null) {
|
||||
Entities.deleteEntity(sphereEntityID);
|
||||
}
|
||||
sphereEntityID = null;
|
||||
}
|
||||
|
||||
function makeGripPressHandler(hand) {
|
||||
return function (value) {
|
||||
if (!editEnabled) {
|
||||
return;
|
||||
}
|
||||
if (value > 0.5) {
|
||||
if (hand === Controller.Standard.LeftHand) {
|
||||
isLeftGripPressed = true;
|
||||
} else if (hand === Controller.Standard.RightHand) {
|
||||
isRightGripPressed = true;
|
||||
}
|
||||
} else if (value < 0.4){
|
||||
if (hand === Controller.Standard.LeftHand) {
|
||||
isLeftGripPressed = false;
|
||||
} else if (hand === Controller.Standard.RightHand) {
|
||||
isRightGripPressed = false;
|
||||
}
|
||||
}
|
||||
if ( isLeftGripPressed && isRightGripPressed) {
|
||||
if( !isSphereResizingStarted ) {
|
||||
isSphereResizingStarted = true;
|
||||
startSphereResizing();
|
||||
}
|
||||
} else {
|
||||
if( isSphereResizingStarted ) {
|
||||
isSphereResizingStarted = false;
|
||||
stopSphereResizing();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onUpdateHandler(delta){
|
||||
var wantDebug = false;
|
||||
|
||||
if (isEditing === false || editedVoxelEntity === null){
|
||||
return;
|
||||
}
|
||||
|
||||
continuousStartTimer += delta;
|
||||
|
||||
if (continuousStartTimer < continuousStartTimerMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get pick ray origin and direction
|
||||
|
||||
var pickRay = null;
|
||||
var hand = triggered() ? that.triggeredHand : that.pressedHand;
|
||||
|
||||
if (hand === NO_HAND) {
|
||||
pickRay = Camera.computePickRay(Controller.getValue(Controller.Hardware.Keyboard.MouseX), Controller.getValue(Controller.Hardware.Keyboard.MouseY));
|
||||
}else{
|
||||
pickRay = controllerComputePickRay();
|
||||
}
|
||||
|
||||
if (pickRay === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Compute intersection of pick ray with given plane in local coordinates
|
||||
|
||||
var globalOriginInVoxelSpace = Entities.worldCoordsToVoxelCoords(editedVoxelEntity, { x: 0, y: 0, z: 0 });
|
||||
var pickRayDirInVoxelSpace = Vec3.subtract(Entities.worldCoordsToVoxelCoords(editedVoxelEntity, pickRay.direction), globalOriginInVoxelSpace);
|
||||
var voxelPickRayOrigin = Entities.worldCoordsToVoxelCoords(editedVoxelEntity, pickRay.origin);
|
||||
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
|
||||
var directionMultiplier = 1.0;
|
||||
var offsetVector = { x: 0, y: 0, z: 0 };
|
||||
switch (editPlane) {
|
||||
// 0 - plane parallel to YZ plane
|
||||
case 0:
|
||||
offsetVector.x = 0.5;
|
||||
offsetVector.y = (offsetVector.x / pickRayDirInVoxelSpace.x) * pickRayDirInVoxelSpace.y;
|
||||
offsetVector.z = (offsetVector.x / pickRayDirInVoxelSpace.x) * pickRayDirInVoxelSpace.z;
|
||||
directionMultiplier = (oldEditPosition.x - voxelPickRayOrigin.x) / pickRayDirInVoxelSpace.x;
|
||||
break;
|
||||
// 1 - plane parallel to XZ plane
|
||||
case 1:
|
||||
offsetVector.y = 0.5;
|
||||
offsetVector.x = (offsetVector.y / pickRayDirInVoxelSpace.y) * pickRayDirInVoxelSpace.x;
|
||||
offsetVector.z = (offsetVector.y / pickRayDirInVoxelSpace.y) * pickRayDirInVoxelSpace.z;
|
||||
directionMultiplier = (oldEditPosition.y - voxelPickRayOrigin.y) / pickRayDirInVoxelSpace.y;
|
||||
break;
|
||||
// 2 - plane parallel to XY plane
|
||||
case 2:
|
||||
offsetVector.z = 0.5;
|
||||
offsetVector.x = (offsetVector.z / pickRayDirInVoxelSpace.z) * pickRayDirInVoxelSpace.x;
|
||||
offsetVector.y = (offsetVector.z / pickRayDirInVoxelSpace.z) * pickRayDirInVoxelSpace.y;
|
||||
directionMultiplier = (oldEditPosition.z - voxelPickRayOrigin.z) / pickRayDirInVoxelSpace.z;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
intersectionPoint = Vec3.sum(Vec3.multiply(pickRayDirInVoxelSpace, directionMultiplier), voxelPickRayOrigin);
|
||||
newEditPosition = floorVector(Vec3.sum(intersectionPoint, offsetVector));
|
||||
|
||||
if (newEditPosition === oldEditPosition) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wantDebug) {
|
||||
print("Old edit position: " + JSON.stringify(oldEditPosition));
|
||||
print("New edit position: " + JSON.stringify(newEditPosition));
|
||||
print("directionMultiplier: " + JSON.stringify(directionMultiplier) + " pickRay.direction: " + JSON.stringify(pickRay.direction) + " pickRayDirInVoxelSpace: " + JSON.stringify(pickRayDirInVoxelSpace) + " voxelPickRayOrigin: " + JSON.stringify(voxelPickRayOrigin) + " editPlane: " + JSON.stringify(editPlane));
|
||||
}
|
||||
|
||||
if (editSingleVoxels) {
|
||||
if (Entities.setVoxel(editedVoxelEntity, newEditPosition, lastEditValue)){
|
||||
oldEditPosition = newEditPosition;
|
||||
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
|
||||
}
|
||||
} else if (editSpheres) {
|
||||
var toDrawPositionWorld = Entities.voxelCoordsToWorldCoords(editedVoxelEntity, newEditPosition);
|
||||
if (Entities.setVoxelSphere(editedVoxelEntity, toDrawPositionWorld, editSphereRadius, lastEditValue)){
|
||||
oldEditPosition = newEditPosition;
|
||||
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
|
||||
}
|
||||
} else if (editCubes) {
|
||||
var lowPosition = Vec3.subtract(newEditPosition, Vec3.multiply(cubeSize, 0.5));
|
||||
if (Entities.setVoxelsInCuboid(editedVoxelEntity, lowPosition, cubeSize, lastEditValue)){
|
||||
oldEditPosition = newEditPosition;
|
||||
Audio.playSystemSound((lastEditValue === 255) ? soundAdd : soundDelete);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
Controller.mousePressEvent.disconnect(self.mousePressEvent);
|
||||
Controller.mouseReleaseEvent.disconnect(self.mouseReleaseEvent);
|
||||
Controller.keyPressEvent.disconnect(self.keyPressEvent);
|
||||
Controller.keyReleaseEvent.disconnect(self.keyReleaseEvent);
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
that.triggerClickMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand));
|
||||
that.triggerClickMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand));
|
||||
that.triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand));
|
||||
that.triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand));
|
||||
that.gripPressMapping.from(Controller.Standard.LeftGrip).peek().to(makeGripPressHandler(Controller.Standard.LeftHand));
|
||||
that.gripPressMapping.from(Controller.Standard.RightGrip).peek().to(makeGripPressHandler(Controller.Standard.RightHand));
|
||||
that.enableTriggerMapping = function() {
|
||||
that.triggerClickMapping.enable();
|
||||
that.triggerPressMapping.enable();
|
||||
that.gripPressMapping.enable();
|
||||
};
|
||||
that.disableTriggerMapping = function() {
|
||||
that.triggerClickMapping.disable();
|
||||
that.triggerPressMapping.disable();
|
||||
that.gripPressMapping.disable();
|
||||
};
|
||||
that.enableTriggerMapping();
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Script.scriptEnding.connect(that.disableTriggerMapping);
|
||||
|
||||
return that;
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
// Created by Ryan Huffman on 13 Nov 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// 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
|
||||
|
@ -17,7 +18,8 @@
|
|||
<link rel="stylesheet" type="text/css" href="../../../html/css/edit-style.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../../html/css/colpick.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../../html/css/jsoneditor.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../../html/css/tabs.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../../html/css/tabs.css">
|
||||
<link rel="stylesheet" type="text/css" href="../../../html/css/materialAssistant.css">
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<script src="../../../html/js/jquery-2.1.4.min.js"></script>
|
||||
<script type="text/javascript" src="../../../html/js/colpick.js"></script>
|
||||
|
@ -29,7 +31,8 @@
|
|||
<script type="text/javascript" src="js/underscore-min.js"></script>
|
||||
<script type="text/javascript" src="js/createAppTooltip.js"></script>
|
||||
<script type="text/javascript" src="js/draggableNumber.js"></script>
|
||||
<script type="text/javascript" src="js/entityProperties.js"></script>
|
||||
<script type="text/javascript" src="js/entityProperties.js"></script>
|
||||
<script type="text/javascript" src="js/materialAssistant.js"></script>
|
||||
</head>
|
||||
<body onload='loaded();'>
|
||||
<div id="properties-list">
|
||||
|
@ -59,5 +62,137 @@
|
|||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id="uiMaterialAssistant" style="display: none;">
|
||||
<div id="uiMaterialAssistant-sidewalk">
|
||||
|
||||
<div id="uiMaterialAssistant-formContainer">
|
||||
<div id="uiMaterialAssistant-headerContainer">
|
||||
<div style="width: 85%; text-align: left;"><font class="uiMaterialAssistant-title">MATERIAL DATA</font></div>
|
||||
<div style="width: 15%; text-align: right;"><span id="uiMaterialAssistant-closeButton">✖</span></div>
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<font class="uiMaterialAssistant-label">Name: </font>
|
||||
<input name = "ma-name" id = "ma-name" type = "text" class="uiMaterialAssistant-input" style= "width: 90%;">
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<button class="uiMaterialAssistant-active" id="ma-albedo-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Albedo (Color): </font>
|
||||
<div id="ma-albedo-colorPicker" class="uiMaterialAssistant-color-picker"></div>
|
||||
<br><br>
|
||||
<button class="uiMaterialAssistant-active" id="ma-albedoMap-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Albedo Map (RGB) URL: </font>
|
||||
<input name = "ma-albedoMap" id = "ma-albedoMap" class="uiMaterialAssistant-input" type = "text" style= "width:100%;"><br>
|
||||
<font class="uiMaterialAssistant-Explain">The Albedo (Color) can be used to tint the texture of the Albedo Map.</font>
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<button class="uiMaterialAssistant-active" id="ma-metallic-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Metallic: </font>
|
||||
<input class="uiMaterialAssistant-input" name = "ma-metallic" id = "ma-metallic" readonly type = "text" size = "5"><br>
|
||||
<input type="range" style="width:100%;" min="1" max="1000" value="1" class="uiMaterialAssistant-slider" name = "ma-metallic-slider" id = "ma-metallic-slider"><br>
|
||||
<div style="width: 100%; display: flex;">
|
||||
<div style="width: 15%; text-align: left;"><font class = "uiMaterialAssistant-Explain">|< Nonmetal</font></div>
|
||||
<div style="width: 15%; text-align: left;"><font class = "uiMaterialAssistant-Explain">| Hair</font></div>
|
||||
<div style="width: 60%; text-align: left;"><font class = "uiMaterialAssistant-Explain">| Chitin</font></div>
|
||||
<div style="width: 10%; text-align: right;"><font class = "uiMaterialAssistant-Explain">Metal >|</font></div>
|
||||
</div><br>
|
||||
<font class="uiMaterialAssistant-label">Metallic Map (Grayscale) URL: </font>
|
||||
<input name = "ma-metallicMap" id = "ma-metallicMap" class="uiMaterialAssistant-input" type = "text" style= "width:100%;">
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<button class="uiMaterialAssistant-active" id="ma-roughness-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Roughness:</font>
|
||||
<input name = "ma-roughness" id = "ma-roughness" readonly class="uiMaterialAssistant-input" type = "text" size = "5"><br>
|
||||
<input type="range" style="width:100%;" min="0" max="1000" value="0" class="uiMaterialAssistant-slider" name = "ma-roughness-slider" id = "ma-roughness-slider"><br>
|
||||
<div style="width: 100%; display: flex;">
|
||||
<div style="width: 50%; text-align: left;"><font class = "uiMaterialAssistant-Explain">|< Glossy, polished, lustrous</font></div>
|
||||
<div style="width: 50%; text-align: right;"><font class = "uiMaterialAssistant-Explain">Unpolished, mat, rough >|</font></div>
|
||||
</div><br>
|
||||
<font class="uiMaterialAssistant-label">Roughness Map (Grayscale) URL: </font>
|
||||
<input name = "ma-roughnessMap" id = "ma-roughnessMap" class="uiMaterialAssistant-input" type = "text" style= "width:100%;">
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<button class="uiMaterialAssistant-active" id="ma-normalMap-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Normal Map URL: </font>
|
||||
<input name = "ma-normalMap" id = "ma-normalMap" class="uiMaterialAssistant-input" type = "text" style= "width:100%;">
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<button class="uiMaterialAssistant-active" id="ma-opacity-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Opacity: </font>
|
||||
<input name = "ma-opacity" id = "ma-opacity" readonly class="uiMaterialAssistant-input" type = "text" size = "5"><br>
|
||||
<input type="range" style="width:100%;" min="0" max="1000" value="0" class="uiMaterialAssistant-slider" name = "ma-opacity-slider" id = "ma-opacity-slider"><br>
|
||||
<div style="width: 100%; display: flex;">
|
||||
<div style="width: 50%; text-align: left;"><font class = "uiMaterialAssistant-Explain">|< Transparent</font></div>
|
||||
<div style="width: 50%; text-align: right;"><font class = "uiMaterialAssistant-Explain">Opaque >|</font></div>
|
||||
</div>
|
||||
<br>
|
||||
<font class="uiMaterialAssistant-label">Opacity Map Mode:</font><br><br>
|
||||
<input type="radio" class="uiMaterialAssistant-radio" checked name = "ma-opacityMapMode" id = "ma-opacityMapMode-dont" value = "OPACITY_MAP_OPAQUE"> Do not used
|
||||
<input type="radio" class="uiMaterialAssistant-radio" name = "ma-opacityMapMode" id = "ma-opacityMapMode-mask" value = "OPACITY_MAP_MASK"> Cut off mask
|
||||
<input type="radio" class="uiMaterialAssistant-radio" name = "ma-opacityMapMode" id = "ma-opacityMapMode-blend" value = "OPACITY_MAP_BLEND"> Blend<br>
|
||||
<font class="uiMaterialAssistant-Explain"><br>Note: For an opacity map, the alpha layer of the Albedo Map will be used.<br>
|
||||
'Blend' mode will used the alpha value to determine the opacity of a pixel.<br>
|
||||
'Cut off mask' mode will use the 'Cut off threshold' to determine if a pixel will be opaque or transparent, based on the alpha value from the map.</font><br><br>
|
||||
<font class="uiMaterialAssistant-label">Cut Off Threshold: </font>
|
||||
<input name = "ma-opacityCutoff" id = "ma-opacityCutoff" readonly class="uiMaterialAssistant-input" type = "text" size = "5"><br>
|
||||
<input type="range" style="width:100%;" min="0" max="1000" value="0" class="uiMaterialAssistant-slider" name = "ma-opacityCutoff-slider" id = "ma-opacityCutoff-slider"><br>
|
||||
<div style="width: 100%; display: flex;">
|
||||
<div style="width: 50%; text-align: left;"><font class = "uiMaterialAssistant-Explain">|< Transparent</font></div>
|
||||
<div style="width: 50%; text-align: right;"><font class = "uiMaterialAssistant-Explain">Opaque >|</font></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<div style="width: 100%; display: flex;">
|
||||
<div style="width: 70%; text-align: left;">
|
||||
<button class="uiMaterialAssistant-active" id="ma-emissive-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Emissive: </font>
|
||||
<div id="ma-emissive-colorPicker" class="uiMaterialAssistant-color-picker"></div>
|
||||
</div>
|
||||
<div style="width: 30%; text-align: left;">
|
||||
<input type="checkbox" class="uiMaterialAssistant-checkbox" name = "ma-unlit" id = "ma-unlit">
|
||||
<font class="uiMaterialAssistant-label">Unlit</font>
|
||||
</div>
|
||||
</div>
|
||||
<font class="uiMaterialAssistant-label">Bloom Factor:</font>
|
||||
<input name = "ma-bloom" id = "ma-bloom" readonly class="uiMaterialAssistant-input" type = "text" size = "5"><br>
|
||||
<input type="range" style="width:100%;" min="100" max="900" value="100" class="uiMaterialAssistant-slider" name = "ma-bloom-slider" id = "ma-bloom-slider"><br>
|
||||
<font class="uiMaterialAssistant-label">Emissive Map (RGB) URL:</font>
|
||||
<input name = "ma-emissiveMap" id = "ma-emissiveMap" class="uiMaterialAssistant-input" type = "text" style= "width:100%;">
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<button class="uiMaterialAssistant-active" id="ma-scattering-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Scattering: </font>
|
||||
<input name = "ma-scattering" id = "ma-scattering" readonly class="uiMaterialAssistant-input" type = "text" size = "5"><br>
|
||||
<input type="range" style="width:100%;" min="0" max="1000" value="0" class="uiMaterialAssistant-slider" name = "ma-scattering-slider" id = "ma-scattering-slider"><br>
|
||||
<font class="uiMaterialAssistant-label">Scattering Map (Grayscale) URL: </font>
|
||||
<input name = "ma-scatteringMap" id = "ma-scatteringMap" class="uiMaterialAssistant-input" type = "text" style= "width:100%;">
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<button class="uiMaterialAssistant-active" id="ma-occlusionMap-isActive"></button>
|
||||
<font class="uiMaterialAssistant-label">Occlusion Map (Grayscale) URL: </font>
|
||||
<input name = "ma-occlusionMap" id = "ma-occlusionMap" class="uiMaterialAssistant-input" type = "text" style= "width:100%;">
|
||||
</div>
|
||||
|
||||
<div class="uiMaterialAssistant-group">
|
||||
<font class="uiMaterialAssistant-label">Material displayed on surface: </font><br><br>
|
||||
<input type="radio" class="uiMaterialAssistant-radio" checked name = "ma-cullFaceMode" id = "ma-cullFaceMode-back" value = "CULL_BACK"> Outside
|
||||
<input type="radio" class="uiMaterialAssistant-radio" name = "ma-cullFaceMode" id = "ma-cullFaceMode-front" value = "CULL_FRONT"> Inside
|
||||
<input type="radio" class="uiMaterialAssistant-radio" name = "ma-cullFaceMode" id = "ma-cullFaceMode-none" value = "CULL_NONE"> Both<br>
|
||||
</div>
|
||||
<br><br><br><br><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
initiateMaUi();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Created by Ryan Huffman on 13 Nov 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// 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
|
||||
|
@ -877,9 +878,10 @@ const GROUPS = [
|
|||
{
|
||||
label: "Material Data",
|
||||
type: "textarea",
|
||||
buttons: [ { id: "clear", label: "Clear Material Data", className: "red", onClick: clearMaterialData },
|
||||
{ id: "edit", label: "Edit as JSON", className: "blue", onClick: newJSONMaterialEditor },
|
||||
{ id: "save", label: "Save Material Data", className: "black", onClick: saveMaterialData } ],
|
||||
buttons: [ { id: "materialAssistant", label: "Assistant...", className: "secondary_blue blue", onClick: openMaterialAssistant },
|
||||
{ id: "clear", label: "Clear Material", className: "secondary_red red", onClick: clearMaterialData },
|
||||
{ id: "edit", label: "Edit as JSON", className: "secondary", onClick: newJSONMaterialEditor },
|
||||
{ id: "save", label: "Save Material", className: "secondary", onClick: saveMaterialData }],
|
||||
propertyID: "materialData",
|
||||
},
|
||||
{
|
||||
|
@ -1326,6 +1328,57 @@ const GROUPS = [
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "polyvox",
|
||||
label: "POLYVOX",
|
||||
properties: [
|
||||
{
|
||||
label: "Volume Size",
|
||||
type: "vec3",
|
||||
vec3Type: "xyz",
|
||||
step: 1.0,
|
||||
decimals: 0,
|
||||
subLabels: [ "x", "y", "z" ],
|
||||
unit: "",
|
||||
propertyID: "voxelVolumeSize",
|
||||
},
|
||||
{
|
||||
label: "Texture preset",
|
||||
type: "dropdown",
|
||||
options: { 0 : "None", 1 : "Grass + ground", 2 : "Bricks", 3 : "Stone",
|
||||
4: "Concrete", 5 : "Rock"},
|
||||
propertyID: "polyVoxPreset",
|
||||
onDropdownChange: createPolyVoxPresetChangedFunction,
|
||||
skipPropertyUpdate: true,
|
||||
},
|
||||
{
|
||||
label: "Surface Style",
|
||||
type: "dropdown",
|
||||
options: { 0: "Marching cubes", 1: "Cubic",
|
||||
2: "Edged cubic", 3: "Edged marching cubes" },
|
||||
propertyID: "voxelSurfaceStyle",
|
||||
propertyName: "voxelSurfaceStyle",
|
||||
},
|
||||
{
|
||||
label: "X Texture URL",
|
||||
type: "string",
|
||||
propertyID: "xTextureURL",
|
||||
propertyName: "xTextureURL",
|
||||
},
|
||||
{
|
||||
label: "Y Texture URL",
|
||||
type: "string",
|
||||
propertyID: "yTextureURL",
|
||||
propertyName: "yTextureURL",
|
||||
},
|
||||
{
|
||||
label: "Z Texture URL",
|
||||
type: "string",
|
||||
propertyID: "zTextureURL",
|
||||
propertyName: "zTextureURL",
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
id: "spatial",
|
||||
label: "SPATIAL",
|
||||
|
@ -1705,7 +1758,7 @@ const GROUPS_PER_TYPE = {
|
|||
ParticleEffect: [ 'base', 'particles', 'particles_emit', 'particles_size', 'particles_color',
|
||||
'particles_behavior', 'particles_constraints', 'spatial', 'behavior', 'scripts', 'physics' ],
|
||||
PolyLine: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
|
||||
PolyVox: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
|
||||
PolyVox: [ 'base', 'polyvox', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
|
||||
Grid: [ 'base', 'grid', 'spatial', 'behavior', 'scripts', 'physics' ],
|
||||
Multiple: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ],
|
||||
};
|
||||
|
@ -3197,6 +3250,55 @@ function parentIDChanged() {
|
|||
}
|
||||
}
|
||||
|
||||
function createPolyVoxPresetChangedFunction(property) {
|
||||
return function() {
|
||||
property.elInput.classList.remove('multi-diff');
|
||||
var xTextureURL = "";
|
||||
var yTextureURL = "";
|
||||
var zTextureURL = "";
|
||||
switch (parseInt(this.value)) {
|
||||
// Clear texture entries
|
||||
case 0:
|
||||
xTextureURL = "";
|
||||
yTextureURL = "";
|
||||
zTextureURL = "";
|
||||
break;
|
||||
// Grass + ground
|
||||
case 1:
|
||||
xTextureURL = "qrc:///serverless/Textures/ground_5-2K/2K-ground_5-diffuse.jpg";
|
||||
yTextureURL = "qrc:///serverless/Textures/ground_grass_gen_05.png";
|
||||
zTextureURL = "qrc:///serverless/Textures/ground_5-2K/2K-ground_5-diffuse.jpg";
|
||||
break;
|
||||
// Bricks
|
||||
case 2:
|
||||
xTextureURL = "qrc:///serverless/Textures/2K-wall_stone_2-diffuse_l.jpg";
|
||||
yTextureURL = "qrc:///serverless/Textures/2K-stone_floor_3-diffuse_l.jpg";
|
||||
zTextureURL = "qrc:///serverless/Textures/2K-wall_stone_2-diffuse_l.jpg";
|
||||
break;
|
||||
// Stone
|
||||
case 3:
|
||||
xTextureURL = "qrc:///serverless/Textures/wall_l.png";
|
||||
yTextureURL = "qrc:///serverless/Textures/floor_l.png";
|
||||
zTextureURL = "qrc:///serverless/Textures/wall_l.png";
|
||||
break;
|
||||
// Concrete
|
||||
case 4:
|
||||
xTextureURL = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
|
||||
yTextureURL = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
|
||||
zTextureURL = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
|
||||
break;
|
||||
// Rock
|
||||
case 5:
|
||||
xTextureURL = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
|
||||
yTextureURL = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
|
||||
zTextureURL = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
|
||||
break;
|
||||
}
|
||||
updateProperty("xTextureURL", xTextureURL, false);
|
||||
updateProperty("yTextureURL", yTextureURL, false);
|
||||
updateProperty("zTextureURL", zTextureURL, false);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* BUTTON CALLBACKS
|
||||
|
@ -3478,6 +3580,21 @@ function saveMaterialData() {
|
|||
saveJSONMaterialData(true);
|
||||
}
|
||||
|
||||
function openMaterialAssistant() {
|
||||
if (materialEditor === null) {
|
||||
loadDataInMaUi({});
|
||||
} else {
|
||||
loadDataInMaUi(materialEditor.getText());
|
||||
}
|
||||
$('#uiMaterialAssistant').show();
|
||||
$('#properties-list').hide();
|
||||
}
|
||||
|
||||
function closeMaterialAssistant() {
|
||||
$('#uiMaterialAssistant').hide();
|
||||
$('#properties-list').show();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} noUpdate - don't update the UI, but do send a property update.
|
||||
* @param {Set.<string>} [entityIDsToUpdate] - Entity IDs to update materialData for.
|
||||
|
@ -3509,6 +3626,8 @@ function setMaterialDataFromEditor(noUpdate, entityIDsToUpdate) {
|
|||
} else {
|
||||
updateProperty('materialData', text, false);
|
||||
}
|
||||
|
||||
maGetMaterialDataAssistantAvailability(text);
|
||||
}
|
||||
|
||||
let materialEditor = null;
|
||||
|
@ -3567,6 +3686,14 @@ function hideMaterialDataSaved() {
|
|||
$('#property-materialData-saved').hide();
|
||||
}
|
||||
|
||||
function showMaterialAssistantButton() {
|
||||
$('#property-materialData-button-materialAssistant').show();
|
||||
}
|
||||
|
||||
function hideMaterialAssistantButton() {
|
||||
$('#property-materialData-button-materialAssistant').hide();
|
||||
}
|
||||
|
||||
function setMaterialEditorJSON(json) {
|
||||
materialEditor.set(json);
|
||||
if (materialEditor.hasOwnProperty('expandAll')) {
|
||||
|
@ -4043,6 +4170,7 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) {
|
|||
const multipleSelections = currentSelections.length > 1;
|
||||
const hasSelectedEntityChanged = !areSetsEqual(selectedEntityIDs, previouslySelectedEntityIDs);
|
||||
|
||||
closeMaterialAssistant();
|
||||
requestZoneList();
|
||||
|
||||
if (selections.length === 0) {
|
||||
|
@ -4344,20 +4472,20 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) {
|
|||
|
||||
let materialDataMultiValue = getMultiplePropertyValue("materialData");
|
||||
let materialDataTextArea = getPropertyInputElement("materialData");
|
||||
let materialJson = null;
|
||||
let materialJSON = null;
|
||||
if (!materialDataMultiValue.isMultiDiffValue) {
|
||||
try {
|
||||
materialJson = JSON.parse(materialDataMultiValue.value);
|
||||
materialJSON = JSON.parse(materialDataMultiValue.value);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
if (materialJson !== null && !lockedMultiValue.isMultiDiffValue && !lockedMultiValue.value) {
|
||||
if (materialJSON !== null && !lockedMultiValue.isMultiDiffValue && !lockedMultiValue.value) {
|
||||
if (materialEditor === null) {
|
||||
createJSONMaterialEditor();
|
||||
}
|
||||
materialDataTextArea.classList.remove('multi-diff');
|
||||
setMaterialEditorJSON(materialJson);
|
||||
setMaterialEditorJSON(materialJSON);
|
||||
showSaveMaterialDataButton();
|
||||
hideMaterialDataTextArea();
|
||||
hideNewJSONMaterialEditorButton();
|
||||
|
@ -4373,6 +4501,8 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) {
|
|||
hideMaterialDataSaved();
|
||||
}
|
||||
|
||||
maGetMaterialDataAssistantAvailability(materialJSON);
|
||||
|
||||
if (hasSelectedEntityChanged && selections.length === 1 && entityTypes[0] === "Material") {
|
||||
requestMaterialTarget();
|
||||
}
|
||||
|
@ -4756,7 +4886,16 @@ function loaded() {
|
|||
let propertyID = elDropdown.getAttribute("propertyID");
|
||||
let property = properties[propertyID];
|
||||
property.elInput = dt;
|
||||
dt.addEventListener('change', createEmitTextPropertyUpdateFunction(property));
|
||||
|
||||
if (property.data.
|
||||
skipPropertyUpdate !== true) {
|
||||
dt.addEventListener('change', createEmitTextPropertyUpdateFunction(property));
|
||||
}
|
||||
|
||||
if (property.data.
|
||||
onDropdownChange !== undefined) {
|
||||
dt.addEventListener('change', property.data.onDropdownChange(property));
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(ev) { closeAllDropdowns() }, true);
|
||||
|
|
|
@ -0,0 +1,924 @@
|
|||
// materialAssistant.js
|
||||
//
|
||||
// Created by Alezia Kurdis on May 19th, 2022.
|
||||
// Copyright 2022 Vircadia contributors.
|
||||
// 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
|
||||
|
||||
let maMaterialData = {};
|
||||
|
||||
let maClose,
|
||||
maName,
|
||||
maAlbedoIsActive,
|
||||
maAlbedoColorPicker,
|
||||
maAlbedoColorPickerSel,
|
||||
maAlbedoMapIsActive,
|
||||
maAlbedoMap,
|
||||
maMetallicIsActive,
|
||||
maMetallic,
|
||||
maMetallicSlider,
|
||||
maMetallicMap,
|
||||
maRoughnessIsActive,
|
||||
maRoughness,
|
||||
maRoughnessSlider,
|
||||
maRoughnessMap,
|
||||
maNormalMapIsActive,
|
||||
maNormalMap,
|
||||
maOpacityIsActive,
|
||||
maOpacity,
|
||||
maOpacitySlider,
|
||||
maOpacityMapModeDont,
|
||||
maOpacityMapModeMask,
|
||||
maOpacityMapModeBlend,
|
||||
maOpacityCutoff,
|
||||
maOpacityCutoffSlider,
|
||||
maEmissiveIsActive,
|
||||
maEmissiveColorPicker,
|
||||
maEmissiveColorPickerSel,
|
||||
maBloom,
|
||||
maBloomSlider,
|
||||
maUnlit,
|
||||
maEmissiveMap,
|
||||
maScatteringIsActive,
|
||||
maScattering,
|
||||
maScatteringSlider,
|
||||
maScatteringMap,
|
||||
maOcclusionMapIsActive,
|
||||
maOcclusionMap,
|
||||
maCullFaceModeBack,
|
||||
maCullFaceModeFront,
|
||||
maCullFaceModeNone;
|
||||
|
||||
let DEFAULT_ALBEDO = [1,1,1];
|
||||
let DEFAULT_EMISSIVE = [0,0,0];
|
||||
let DEFAULT_BLOOM_FACTOR = 1;
|
||||
let DEFAULT_ROUGHNESS = 0.9;
|
||||
let DEFAULT_METALLIC_FOR_MA_UI = 0.001;
|
||||
let DEFAULT_METALLIC = 0;
|
||||
let DEFAULT_OPACITY = 1;
|
||||
let DEFAULT_OPACITY_CUTOFF = 0.5;
|
||||
let DEFAULT_SCATTERING = 0;
|
||||
|
||||
function initiateMaUi() {
|
||||
maClose = document.getElementById("uiMaterialAssistant-closeButton");
|
||||
maName = document.getElementById("ma-name");
|
||||
maAlbedoIsActive = document.getElementById("ma-albedo-isActive");
|
||||
maAlbedoColorPicker = document.getElementById("ma-albedo-colorPicker");
|
||||
maAlbedoMapIsActive = document.getElementById("ma-albedoMap-isActive");
|
||||
maAlbedoMap = document.getElementById("ma-albedoMap");
|
||||
maMetallicIsActive = document.getElementById("ma-metallic-isActive");
|
||||
maMetallic = document.getElementById("ma-metallic");
|
||||
maMetallicSlider = document.getElementById("ma-metallic-slider");
|
||||
maMetallicMap = document.getElementById("ma-metallicMap");
|
||||
maRoughnessIsActive = document.getElementById("ma-roughness-isActive");
|
||||
maRoughness = document.getElementById("ma-roughness");
|
||||
maRoughnessSlider = document.getElementById("ma-roughness-slider");
|
||||
maRoughnessMap = document.getElementById("ma-roughnessMap");
|
||||
maNormalMapIsActive = document.getElementById("ma-normalMap-isActive");
|
||||
maNormalMap = document.getElementById("ma-normalMap");
|
||||
maOpacityIsActive = document.getElementById("ma-opacity-isActive");
|
||||
maOpacity = document.getElementById("ma-opacity");
|
||||
maOpacitySlider = document.getElementById("ma-opacity-slider");
|
||||
maOpacityMapModeDont = document.getElementById("ma-opacityMapMode-dont");
|
||||
maOpacityMapModeMask = document.getElementById("ma-opacityMapMode-mask");
|
||||
maOpacityMapModeBlend = document.getElementById("ma-opacityMapMode-blend");
|
||||
maOpacityCutoff = document.getElementById("ma-opacityCutoff");
|
||||
maOpacityCutoffSlider = document.getElementById("ma-opacityCutoff-slider");
|
||||
maEmissiveIsActive = document.getElementById("ma-emissive-isActive");
|
||||
maEmissiveColorPicker = document.getElementById("ma-emissive-colorPicker");
|
||||
maBloom = document.getElementById("ma-bloom");
|
||||
maBloomSlider = document.getElementById("ma-bloom-slider");
|
||||
maUnlit = document.getElementById("ma-unlit");
|
||||
maEmissiveMap = document.getElementById("ma-emissiveMap");
|
||||
maScatteringIsActive = document.getElementById("ma-scattering-isActive");
|
||||
maScattering = document.getElementById("ma-scattering");
|
||||
maScatteringSlider = document.getElementById("ma-scattering-slider");
|
||||
maScatteringMap = document.getElementById("ma-scatteringMap");
|
||||
maOcclusionMapIsActive = document.getElementById("ma-occlusionMap-isActive");
|
||||
maOcclusionMap = document.getElementById("ma-occlusionMap");
|
||||
maCullFaceModeBack = document.getElementById("ma-cullFaceMode-back");
|
||||
maCullFaceModeFront = document.getElementById("ma-cullFaceMode-front");
|
||||
maCullFaceModeNone = document.getElementById("ma-cullFaceMode-none");
|
||||
|
||||
maClose.onclick = function() {
|
||||
closeMaterialAssistant();
|
||||
};
|
||||
maAlbedoIsActive.onclick = function() {
|
||||
if (maMaterialData.albedoIsActive) {
|
||||
maMaterialData.albedoIsActive = false;
|
||||
maAlbedoIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maAlbedoColorPicker.style.pointerEvents = 'none';
|
||||
maAlbedoColorPicker.style.backgroundColor = "#555555";
|
||||
} else {
|
||||
maMaterialData.albedoIsActive = true;
|
||||
maAlbedoIsActive.className = "uiMaterialAssistant-active";
|
||||
maAlbedoColorPicker.style.pointerEvents = 'auto';
|
||||
maAlbedoColorPicker.style.backgroundColor = maGetRGB(maMaterialData.albedo);
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maAlbedoMapIsActive.onclick = function() {
|
||||
if (maMaterialData.albedoMapIsActive) {
|
||||
maMaterialData.albedoMapIsActive = false;
|
||||
maAlbedoMapIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maAlbedoMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.albedoMapIsActive = true;
|
||||
maAlbedoMapIsActive.className = "uiMaterialAssistant-active";
|
||||
maAlbedoMap.disabled = false;
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maMetallicIsActive.onclick = function() {
|
||||
if (maMaterialData.metallicIsActive) {
|
||||
maMaterialData.metallicIsActive = false;
|
||||
maMetallicIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maMetallic.disabled = true;
|
||||
maMetallicSlider.disabled = true;
|
||||
maMetallicMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.metallicIsActive = true;
|
||||
maMetallicIsActive.className = "uiMaterialAssistant-active";
|
||||
maMetallic.disabled = false;
|
||||
maMetallicSlider.disabled = false;
|
||||
maMetallicMap.disabled = false;
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maRoughnessIsActive.onclick = function() {
|
||||
if (maMaterialData.roughnessIsActive) {
|
||||
maMaterialData.roughnessIsActive = false;
|
||||
maRoughnessIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maRoughness.disabled = true;
|
||||
maRoughnessSlider.disabled = true;
|
||||
maRoughnessMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.roughnessIsActive = true;
|
||||
maRoughnessIsActive.className = "uiMaterialAssistant-active";
|
||||
maRoughness.disabled = false;
|
||||
maRoughnessSlider.disabled = false;
|
||||
maRoughnessMap.disabled = false;
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maNormalMapIsActive.onclick = function() {
|
||||
if (maMaterialData.normalMapIsActive) {
|
||||
maMaterialData.normalMapIsActive = false;
|
||||
maNormalMapIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maNormalMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.normalMapIsActive = true;
|
||||
maNormalMapIsActive.className = "uiMaterialAssistant-active";
|
||||
maNormalMap.disabled = false;
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maOpacityIsActive.onclick = function() {
|
||||
if (maMaterialData.opacityIsActive) {
|
||||
maMaterialData.opacityIsActive = false;
|
||||
maOpacityIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maOpacity.disabled = true;
|
||||
maOpacitySlider.disabled = true;
|
||||
maOpacityMapModeDont.disabled = true;
|
||||
maOpacityMapModeMask.disabled = true;
|
||||
maOpacityMapModeBlend.disabled = true;
|
||||
maOpacityCutoff.disabled = true;
|
||||
maOpacityCutoffSlider.disabled = true;
|
||||
} else {
|
||||
maMaterialData.opacityIsActive = true;
|
||||
maOpacityIsActive.className = "uiMaterialAssistant-active";
|
||||
maOpacity.disabled = false;
|
||||
maOpacitySlider.disabled = false;
|
||||
maOpacityMapModeDont.disabled = false;
|
||||
maOpacityMapModeMask.disabled = false;
|
||||
maOpacityMapModeBlend.disabled = false;
|
||||
maOpacityCutoff.disabled = false;
|
||||
maOpacityCutoffSlider.disabled = false;
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maEmissiveIsActive.onclick = function() {
|
||||
if (maMaterialData.emissiveIsActive) {
|
||||
maMaterialData.emissiveIsActive = false;
|
||||
maEmissiveIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maBloom.disabled = true;
|
||||
maBloomSlider.disabled = true;
|
||||
maEmissiveMap.disabled = true;
|
||||
maEmissiveColorPicker.style.pointerEvents = 'none';
|
||||
maEmissiveColorPicker.style.backgroundColor = "#555555";
|
||||
} else {
|
||||
maMaterialData.emissiveIsActive = true;
|
||||
maEmissiveIsActive.className = "uiMaterialAssistant-active";
|
||||
maBloom.disabled = false;
|
||||
maBloomSlider.disabled = false;
|
||||
maEmissiveMap.disabled = false;
|
||||
maEmissiveColorPicker.style.pointerEvents = 'auto';
|
||||
maEmissiveColorPicker.style.backgroundColor = maGetRGB(maMaterialData.emissive);
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maScatteringIsActive.onclick = function() {
|
||||
if (maMaterialData.scatteringIsActive) {
|
||||
maMaterialData.scatteringIsActive = false;
|
||||
maScatteringIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maScattering.disabled = true;
|
||||
maScatteringSlider.disabled = true;
|
||||
maScatteringMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.scatteringIsActive = true;
|
||||
maScatteringIsActive.className = "uiMaterialAssistant-active";
|
||||
maScattering.disabled = false;
|
||||
maScatteringSlider.disabled = false;
|
||||
maScatteringMap.disabled = false;
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maOcclusionMapIsActive.onclick = function() {
|
||||
if (maMaterialData.occlusionMapIsActive) {
|
||||
maMaterialData.occlusionMapIsActive = false;
|
||||
maOcclusionMapIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maOcclusionMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.occlusionMapIsActive = true;
|
||||
maOcclusionMapIsActive.className = "uiMaterialAssistant-active";
|
||||
maOcclusionMap.disabled = false;
|
||||
}
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maName.oninput = function() {
|
||||
maMaterialData.name = maName.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maAlbedoMap.oninput = function() {
|
||||
maMaterialData.albedoMap = maAlbedoMap.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maMetallicSlider.oninput = function() {
|
||||
maMetallic.value = maMetallicSlider.value/1000;
|
||||
maMaterialData.metallic = parseFloat(maMetallic.value);
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maMetallicMap.oninput = function() {
|
||||
maMaterialData.metallicMap = maMetallicMap.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maRoughnessSlider.oninput = function() {
|
||||
maRoughness.value = maRoughnessSlider.value/1000;
|
||||
maMaterialData.roughness = parseFloat(maRoughness.value);
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maRoughnessMap.oninput = function() {
|
||||
maMaterialData.roughnessMap = maRoughnessMap.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maNormalMap.oninput = function() {
|
||||
maMaterialData.normalMap = maNormalMap.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maOpacitySlider.oninput = function() {
|
||||
maOpacity.value = maOpacitySlider.value/1000;
|
||||
maMaterialData.opacity = parseFloat(maOpacity.value);
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maOpacityMapModeDont.oninput = function() {
|
||||
maMaterialData.opacityMapMode = maOpacityMapModeDont.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maOpacityMapModeMask.oninput = function() {
|
||||
maMaterialData.opacityMapMode = maOpacityMapModeMask.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maOpacityMapModeBlend.oninput = function() {
|
||||
maMaterialData.opacityMapMode = maOpacityMapModeBlend.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maOpacityCutoffSlider.oninput = function() {
|
||||
maOpacityCutoff.value = maOpacityCutoffSlider.value/1000;
|
||||
maMaterialData.opacityCutoff = parseFloat(maOpacityCutoff.value);
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maBloomSlider.oninput = function() {
|
||||
maBloom.value = maBloomSlider.value/100;
|
||||
maMaterialData.bloom = parseFloat(maBloom.value);
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maUnlit.oninput = function() {
|
||||
maMaterialData.unlit = maUnlit.checked;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maEmissiveMap.oninput = function() {
|
||||
maMaterialData.emissiveMap = maEmissiveMap.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maScatteringSlider.oninput = function() {
|
||||
maScattering.value = maScatteringSlider.value/1000;
|
||||
maMaterialData.scattering = parseFloat(maScattering.value);
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maScatteringMap.oninput = function() {
|
||||
maMaterialData.scatteringMap = maScatteringMap.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maOcclusionMap.oninput = function() {
|
||||
maMaterialData.occlusionMap = maOcclusionMap.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maCullFaceModeBack.oninput = function() {
|
||||
maMaterialData.cullFaceMode = maCullFaceModeBack.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maCullFaceModeFront.oninput = function() {
|
||||
maMaterialData.cullFaceMode = maCullFaceModeFront.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
maCullFaceModeNone.oninput = function() {
|
||||
maMaterialData.cullFaceMode = maCullFaceModeNone.value;
|
||||
maGenerateJsonAndSave();
|
||||
};
|
||||
|
||||
var maAlbedoColorPickerID = "#ma-albedo-colorPicker";
|
||||
maAlbedoColorPickerSel = $(maAlbedoColorPickerID).colpick({
|
||||
colorScheme: 'dark',
|
||||
layout: 'rgbhex',
|
||||
color: '000000',
|
||||
submit: false,
|
||||
onShow: function(colpick) {
|
||||
$(maAlbedoColorPickerID).colpickSetColor({
|
||||
"r": maMaterialData.albedo[0] * 255,
|
||||
"g": maMaterialData.albedo[1] * 255,
|
||||
"b": maMaterialData.albedo[2] * 255,
|
||||
});
|
||||
$(maAlbedoColorPickerID).attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$(maAlbedoColorPickerID).attr('active', 'false');
|
||||
},
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
if ($(maAlbedoColorPickerID).attr('active') === 'true') {
|
||||
maMaterialData.albedo = [(rgb.r/255), (rgb.g/255), (rgb.b/255)];
|
||||
maGenerateJsonAndSave();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var maEmissiveColorPickerID = "#ma-emissive-colorPicker";
|
||||
maEmissiveColorPickerSel = $(maEmissiveColorPickerID).colpick({
|
||||
colorScheme: 'dark',
|
||||
layout: 'rgbhex',
|
||||
color: '000000',
|
||||
submit: false,
|
||||
onShow: function(colpick) {
|
||||
$(maEmissiveColorPickerID).colpickSetColor({
|
||||
"r": maMaterialData.emissive[0] * 255,
|
||||
"g": maMaterialData.emissive[1] * 255,
|
||||
"b": maMaterialData.emissive[2] * 255,
|
||||
});
|
||||
$(maEmissiveColorPickerID).attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$(maEmissiveColorPickerID).attr('active', 'false');
|
||||
},
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
if ($(maEmissiveColorPickerID).attr('active') === 'true') {
|
||||
maMaterialData.emissive = [(rgb.r/255), (rgb.g/255), (rgb.b/255)];
|
||||
maGenerateJsonAndSave();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadDataInMaUi(materialDataPropertyValue) {
|
||||
var entityMaterialData, materialDefinition;
|
||||
try {
|
||||
entityMaterialData = JSON.parse(materialDataPropertyValue);
|
||||
}
|
||||
catch(e) {
|
||||
entityMaterialData = {
|
||||
"materials":{}
|
||||
};
|
||||
}
|
||||
|
||||
if (entityMaterialData.materials.length === undefined) {
|
||||
materialDefinition = entityMaterialData.materials;
|
||||
} else {
|
||||
materialDefinition = entityMaterialData.materials[0];
|
||||
}
|
||||
|
||||
//MODEL (value other than "hifi_pbr" are not supposed to get the button, so we can assume.)
|
||||
maMaterialData.model === "hifi_pbr";
|
||||
|
||||
//NAME
|
||||
if (materialDefinition.name !== undefined) {
|
||||
maMaterialData.name = materialDefinition.name;
|
||||
} else {
|
||||
maMaterialData.name = "";
|
||||
}
|
||||
maName.value = maMaterialData.name;
|
||||
|
||||
//ALBEDO
|
||||
if (materialDefinition.defaultFallthrough === true && materialDefinition.albedo === undefined) {
|
||||
maMaterialData.albedoIsActive = false;
|
||||
maAlbedoIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maAlbedoColorPicker.style.pointerEvents = 'none';
|
||||
maAlbedoColorPicker.style.backgroundColor = "#555555";
|
||||
} else {
|
||||
maMaterialData.albedoIsActive = true;
|
||||
maAlbedoIsActive.className = "uiMaterialAssistant-active";
|
||||
maAlbedoColorPicker.style.pointerEvents = 'auto';
|
||||
maAlbedoColorPicker.style.backgroundColor = maGetRGB(maMaterialData.albedo);
|
||||
}
|
||||
|
||||
if (materialDefinition.albedo !== undefined) {
|
||||
maMaterialData.albedo = materialDefinition.albedo;
|
||||
} else {
|
||||
maMaterialData.albedo = DEFAULT_ALBEDO;
|
||||
}
|
||||
maAlbedoColorPicker.style.backgroundColor = maGetRGB(maMaterialData.albedo);
|
||||
|
||||
//ALBEDO MAP
|
||||
if (materialDefinition.defaultFallthrough === true && materialDefinition.albedoMap === undefined) {
|
||||
maMaterialData.albedoMapIsActive = false;
|
||||
maAlbedoMapIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maAlbedoMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.albedoMapIsActive = true;
|
||||
maAlbedoMapIsActive.className = "uiMaterialAssistant-active";
|
||||
maAlbedoMap.disabled = false;
|
||||
}
|
||||
|
||||
if (materialDefinition.albedoMap !== undefined) {
|
||||
maMaterialData.albedoMap = materialDefinition.albedoMap;
|
||||
} else {
|
||||
maMaterialData.albedoMap = "";
|
||||
}
|
||||
maAlbedoMap.value = maMaterialData.albedoMap;
|
||||
|
||||
//METALLIC
|
||||
if (materialDefinition.defaultFallthrough === true
|
||||
&& materialDefinition.metallic === undefined
|
||||
&& materialDefinition.metallicMap === undefined) {
|
||||
maMaterialData.metallicIsActive = false;
|
||||
maMetallicIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maMetallic.disabled = true;
|
||||
maMetallicSlider.disabled = true;
|
||||
maMetallicMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.metallicIsActive = true;
|
||||
maMetallicIsActive.className = "uiMaterialAssistant-active";
|
||||
maMetallic.disabled = false;
|
||||
maMetallicSlider.disabled = false;
|
||||
maMetallicMap.disabled = false;
|
||||
}
|
||||
|
||||
if (materialDefinition.metallic !== undefined) {
|
||||
maMaterialData.metallic = materialDefinition.metallic;
|
||||
} else {
|
||||
maMaterialData.metallic = DEFAULT_METALLIC_FOR_MA_UI;
|
||||
}
|
||||
maMetallic.value = maMaterialData.metallic;
|
||||
maMetallicSlider.value = Math.floor(maMaterialData.metallic * 1000);
|
||||
|
||||
if (materialDefinition.metallicMap !== undefined) {
|
||||
maMaterialData.metallicMap = materialDefinition.metallicMap;
|
||||
} else {
|
||||
maMaterialData.metallicMap = "";
|
||||
}
|
||||
maMetallicMap.value = maMaterialData.metallicMap;
|
||||
|
||||
//ROUGHNESS
|
||||
if (materialDefinition.defaultFallthrough === true
|
||||
&& materialDefinition.roughness === undefined
|
||||
&& materialDefinition.roughnessMap === undefined) {
|
||||
maMaterialData.roughnessIsActive = false;
|
||||
maRoughnessIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maRoughness.disabled = true;
|
||||
maRoughnessSlider.disabled = true;
|
||||
maRoughnessMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.roughnessIsActive = true;
|
||||
maRoughnessIsActive.className = "uiMaterialAssistant-active";
|
||||
maRoughness.disabled = false;
|
||||
maRoughnessSlider.disabled = false;
|
||||
maRoughnessMap.disabled = false;
|
||||
}
|
||||
|
||||
if (materialDefinition.roughness !== undefined) {
|
||||
maMaterialData.roughness = materialDefinition.roughness;
|
||||
} else {
|
||||
maMaterialData.roughness = DEFAULT_ROUGHNESS;
|
||||
}
|
||||
maRoughness.value = maMaterialData.roughness;
|
||||
maRoughnessSlider.value = Math.floor(maMaterialData.roughness * 1000);
|
||||
|
||||
if (materialDefinition.roughnessMap !== undefined) {
|
||||
maMaterialData.roughnessMap = materialDefinition.roughnessMap;
|
||||
} else {
|
||||
maMaterialData.roughnessMap = "";
|
||||
}
|
||||
maRoughnessMap.value = maMaterialData.roughnessMap;
|
||||
|
||||
//NORMAL MAP
|
||||
if (materialDefinition.defaultFallthrough === true && materialDefinition.normalMap === undefined) {
|
||||
maMaterialData.normalMapIsActive = false;
|
||||
maNormalMapIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maNormalMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.normalMapIsActive = true;
|
||||
maNormalMapIsActive.className = "uiMaterialAssistant-active";
|
||||
maNormalMap.disabled = false;
|
||||
}
|
||||
|
||||
if (materialDefinition.normalMap !== undefined) {
|
||||
maMaterialData.normalMap = materialDefinition.normalMap;
|
||||
} else {
|
||||
maMaterialData.normalMap = "";
|
||||
}
|
||||
maNormalMap.value = maMaterialData.normalMap;
|
||||
|
||||
//OPACITY
|
||||
if (materialDefinition.defaultFallthrough === true
|
||||
&& materialDefinition.opacity === undefined
|
||||
&& materialDefinition.opacityMapMode === undefined) {
|
||||
maMaterialData.opacityIsActive = false;
|
||||
maOpacityIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maOpacity.disabled = true;
|
||||
maOpacitySlider.disabled = true;
|
||||
maOpacityMapModeDont.disabled = true;
|
||||
maOpacityMapModeMask.disabled = true;
|
||||
maOpacityMapModeBlend.disabled = true;
|
||||
maOpacityCutoff.disabled = true;
|
||||
maOpacityCutoffSlider.disabled = true;
|
||||
} else {
|
||||
maMaterialData.opacityIsActive = true;
|
||||
maOpacityIsActive.className = "uiMaterialAssistant-active";
|
||||
maOpacity.disabled = false;
|
||||
maOpacitySlider.disabled = false;
|
||||
maOpacityMapModeDont.disabled = false;
|
||||
maOpacityMapModeMask.disabled = false;
|
||||
maOpacityMapModeBlend.disabled = false;
|
||||
maOpacityCutoff.disabled = false;
|
||||
maOpacityCutoffSlider.disabled = false;
|
||||
}
|
||||
|
||||
if (materialDefinition.opacity !== undefined) {
|
||||
maMaterialData.opacity = materialDefinition.opacity;
|
||||
} else {
|
||||
maMaterialData.opacity = DEFAULT_OPACITY;
|
||||
}
|
||||
maOpacity.value = maMaterialData.opacity;
|
||||
maOpacitySlider.value = Math.floor(maMaterialData.opacity * 1000);
|
||||
|
||||
if (materialDefinition.opacityMapMode !== undefined) {
|
||||
maMaterialData.opacityMapMode = materialDefinition.opacityMapMode;
|
||||
} else {
|
||||
maMaterialData.opacityMapMode = "OPACITY_MAP_OPAQUE";
|
||||
}
|
||||
switch (maMaterialData.opacityMapMode) {
|
||||
case "OPACITY_MAP_OPAQUE":
|
||||
maOpacityMapModeDont.checked = true;
|
||||
break;
|
||||
case "OPACITY_MAP_MASK":
|
||||
maOpacityMapModeMask.checked = true;
|
||||
break;
|
||||
case "OPACITY_MAP_BLEND":
|
||||
maOpacityMapModeBlend.checked = true;
|
||||
break;
|
||||
default:
|
||||
alert("ERROR: opacityMapMode = '" + maMaterialData.opacityMapMode + "'. Something has been broken in the code.");
|
||||
}
|
||||
|
||||
if (materialDefinition.opacityCutoff !== undefined) {
|
||||
maMaterialData.opacityCutoff = materialDefinition.opacityCutoff;
|
||||
} else {
|
||||
maMaterialData.opacityCutoff = DEFAULT_OPACITY_CUTOFF;
|
||||
}
|
||||
maOpacityCutoff.value = maMaterialData.opacityCutoff;
|
||||
maOpacityCutoffSlider.value = Math.floor(maMaterialData.opacityCutoff * 1000);
|
||||
|
||||
//EMISSIVE
|
||||
if (materialDefinition.defaultFallthrough === true
|
||||
&& materialDefinition.emissive === undefined
|
||||
&& materialDefinition.emissiveMap === undefined) {
|
||||
maMaterialData.emissiveIsActive = false;
|
||||
maEmissiveIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maBloom.disabled = true;
|
||||
maBloomSlider.disabled = true;
|
||||
maEmissiveMap.disabled = true;
|
||||
maEmissiveColorPicker.style.pointerEvents = 'none';
|
||||
maEmissiveColorPicker.style.backgroundColor = "#555555";
|
||||
} else {
|
||||
maMaterialData.emissiveIsActive = true;
|
||||
maEmissiveIsActive.className = "uiMaterialAssistant-active";
|
||||
maBloom.disabled = false;
|
||||
maBloomSlider.disabled = false;
|
||||
maEmissiveMap.disabled = false;
|
||||
maEmissiveColorPicker.style.pointerEvents = 'auto';
|
||||
maEmissiveColorPicker.style.backgroundColor = maGetRGB(maMaterialData.emissive);
|
||||
}
|
||||
|
||||
if (materialDefinition.emissive !== undefined) {
|
||||
maMaterialData.emissive = maGetColorValueFromEmissive(materialDefinition.emissive);
|
||||
maMaterialData.bloom = maGetBloomFactorFromEmissive(materialDefinition.emissive);
|
||||
} else {
|
||||
maMaterialData.emissive = DEFAULT_EMISSIVE;
|
||||
maMaterialData.bloom = DEFAULT_BLOOM_FACTOR;
|
||||
}
|
||||
maEmissiveColorPicker.style.backgroundColor = maGetRGB(maMaterialData.emissive);
|
||||
maBloom.value = maMaterialData.bloom;
|
||||
maBloomSlider.value = Math.floor(maMaterialData.bloom * 100);
|
||||
|
||||
if (materialDefinition.emissiveMap !== undefined) {
|
||||
maMaterialData.emissiveMap = materialDefinition.emissiveMap;
|
||||
} else {
|
||||
maMaterialData.emissiveMap = "";
|
||||
}
|
||||
maEmissiveMap.value = maMaterialData.emissiveMap;
|
||||
|
||||
//UNLIT
|
||||
if (materialDefinition.unlit !== undefined) {
|
||||
maMaterialData.unlit = materialDefinition.unlit;
|
||||
} else {
|
||||
maMaterialData.unlit = false;
|
||||
}
|
||||
maUnlit.checked = maMaterialData.unlit;
|
||||
|
||||
//SCATTERING
|
||||
if (materialDefinition.defaultFallthrough === true
|
||||
&& materialDefinition.scattering === undefined
|
||||
&& materialDefinition.scatteringMap === undefined) {
|
||||
maMaterialData.scatteringIsActive = false;
|
||||
maScatteringIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maScattering.disabled = true;
|
||||
maScatteringSlider.disabled = true;
|
||||
maScatteringMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.scatteringIsActive = true;
|
||||
maScatteringIsActive.className = "uiMaterialAssistant-active";
|
||||
maScattering.disabled = false;
|
||||
maScatteringSlider.disabled = false;
|
||||
maScatteringMap.disabled = false;
|
||||
}
|
||||
|
||||
if (materialDefinition.scattering !== undefined) {
|
||||
maMaterialData.scattering = materialDefinition.scattering;
|
||||
} else {
|
||||
maMaterialData.scattering = DEFAULT_SCATTERING;
|
||||
}
|
||||
maScattering.value = maMaterialData.scattering;
|
||||
maScatteringSlider.value = Math.floor(maMaterialData.scattering * 1000);
|
||||
|
||||
if (materialDefinition.scatteringMap !== undefined) {
|
||||
maMaterialData.scatteringMap = materialDefinition.scatteringMap;
|
||||
} else {
|
||||
maMaterialData.scatteringMap = "";
|
||||
}
|
||||
maScatteringMap.value = maMaterialData.scatteringMap;
|
||||
|
||||
//OCCLUSION MAP
|
||||
if (materialDefinition.defaultFallthrough === true && materialDefinition.occlusionMap === undefined) {
|
||||
maMaterialData.occlusionMapIsActive = false;
|
||||
maOcclusionMapIsActive.className = "uiMaterialAssistant-inactive";
|
||||
maOcclusionMap.disabled = true;
|
||||
} else {
|
||||
maMaterialData.occlusionMapIsActive = true;
|
||||
maOcclusionMapIsActive.className = "uiMaterialAssistant-active";
|
||||
maOcclusionMap.disabled = false;
|
||||
}
|
||||
|
||||
if (materialDefinition.occlusionMap !== undefined) {
|
||||
maMaterialData.occlusionMap = materialDefinition.occlusionMap;
|
||||
} else {
|
||||
maMaterialData.occlusionMap = "";
|
||||
}
|
||||
maOcclusionMap.value = maMaterialData.occlusionMap;
|
||||
|
||||
//CULL FACE MODE
|
||||
if (materialDefinition.cullFaceMode !== undefined) {
|
||||
maMaterialData.cullFaceMode = materialDefinition.cullFaceMode;
|
||||
} else {
|
||||
maMaterialData.cullFaceMode = "CULL_BACK";
|
||||
}
|
||||
switch (maMaterialData.cullFaceMode) {
|
||||
case "CULL_BACK":
|
||||
maCullFaceModeBack.checked = true;
|
||||
break;
|
||||
case "CULL_FRONT":
|
||||
maCullFaceModeFront.checked = true;
|
||||
break;
|
||||
case "CULL_NONE":
|
||||
maCullFaceModeNone.checked = true;
|
||||
break;
|
||||
default:
|
||||
alert("ERROR: cullFaceMode = '" + maMaterialData.cullFaceMode + "'. Something has been broken in the code.");
|
||||
}
|
||||
}
|
||||
|
||||
function maGenerateJsonAndSave() {
|
||||
var newMaterial = {};
|
||||
var defaultFallthrough = false;
|
||||
|
||||
//NAME
|
||||
if (maMaterialData.name != "") {
|
||||
newMaterial.name = maMaterialData.name;
|
||||
}
|
||||
|
||||
//ALBEDO & ALBEDOMAP
|
||||
if (maMaterialData.albedoIsActive) {
|
||||
newMaterial.albedo = maMaterialData.albedo;
|
||||
if (maMaterialData.albedoMap !== "") {
|
||||
newMaterial.albedoMap = maMaterialData.albedoMap;
|
||||
}
|
||||
} else {
|
||||
defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//METALLIC & METALLICMAP
|
||||
if (maMaterialData.metallicIsActive) {
|
||||
if (maMaterialData.metallicMap === "") {
|
||||
newMaterial.metallic = maMaterialData.metallic;
|
||||
} else {
|
||||
newMaterial.metallicMap = maMaterialData.metallicMap;
|
||||
}
|
||||
} else {
|
||||
defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//ROUGHNESS & ROUGHNESSMAP
|
||||
if (maMaterialData.roughnessIsActive) {
|
||||
if (maMaterialData.roughnessMap === "") {
|
||||
newMaterial.roughness = maMaterialData.roughness;
|
||||
} else {
|
||||
newMaterial.roughnessMap = maMaterialData.roughnessMap;
|
||||
}
|
||||
} else {
|
||||
defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//NORMAL MAP
|
||||
if (maMaterialData.normalMapIsActive) {
|
||||
if (maMaterialData.normalMap !== "") {
|
||||
newMaterial.normalMap = maMaterialData.normalMap;
|
||||
}
|
||||
} else {
|
||||
defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//OPACITY
|
||||
if (maMaterialData.opacityIsActive) {
|
||||
switch (maMaterialData.opacityMapMode) {
|
||||
case "OPACITY_MAP_OPAQUE":
|
||||
newMaterial.opacity = maMaterialData.opacity;
|
||||
break;
|
||||
case "OPACITY_MAP_MASK":
|
||||
newMaterial.opacityMapMode = maMaterialData.opacityMapMode;
|
||||
newMaterial.opacityMap = maMaterialData.albedoMap;
|
||||
newMaterial.opacityCutoff = maMaterialData.opacityCutoff;
|
||||
break;
|
||||
case "OPACITY_MAP_BLEND":
|
||||
newMaterial.opacityMapMode = maMaterialData.opacityMapMode;
|
||||
newMaterial.opacityMap = maMaterialData.albedoMap;
|
||||
break;
|
||||
default:
|
||||
alert("ERROR: opacityMapMode = '" + maMaterialData.opacityMapMode + "'. Something has been broken in the code.");
|
||||
}
|
||||
} else {
|
||||
defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//EMISSIVE
|
||||
if (maMaterialData.emissiveIsActive) {
|
||||
if (maMaterialData.emissiveMap === "") {
|
||||
newMaterial.emissive = scaleEmissiveByBloomFactor(maMaterialData.emissive, maMaterialData.bloom);
|
||||
} else {
|
||||
newMaterial.emissiveMap = maMaterialData.emissiveMap;
|
||||
}
|
||||
} else {
|
||||
defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//UNLIT
|
||||
if (maMaterialData.unlit) {
|
||||
newMaterial.unlit = maMaterialData.unlit;
|
||||
}
|
||||
|
||||
//SCATTERING
|
||||
if (maMaterialData.scatteringIsActive) {
|
||||
if (maMaterialData.scatteringMap === "") {
|
||||
newMaterial.scattering = maMaterialData.scattering;
|
||||
} else {
|
||||
newMaterial.scatteringMap = maMaterialData.scatteringMap;
|
||||
}
|
||||
} else {
|
||||
defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//OCCLUSION MAP
|
||||
if (maMaterialData.occlusionMapIsActive) {
|
||||
if (maMaterialData.occlusionMap !== "") {
|
||||
newMaterial.occlusionMap = maMaterialData.occlusionMap;
|
||||
}
|
||||
} else {
|
||||
defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//CULL FACE MODE
|
||||
newMaterial.cullFaceMode = maMaterialData.cullFaceMode;
|
||||
|
||||
//MODEL
|
||||
newMaterial.model = maMaterialData.model;
|
||||
|
||||
//defaultFallthrough
|
||||
if (defaultFallthrough) {
|
||||
newMaterial.defaultFallthrough = true;
|
||||
}
|
||||
|
||||
//insert newMaterial to materialData
|
||||
var materialDataForUpdate = {
|
||||
"materialVersion": 1,
|
||||
"materials": []
|
||||
};
|
||||
materialDataForUpdate.materials.push(newMaterial);
|
||||
|
||||
//save to property
|
||||
EventBridge.emitWebEvent(
|
||||
JSON.stringify({
|
||||
ids: [...selectedEntityIDs],
|
||||
type: "saveMaterialData",
|
||||
properties: {
|
||||
materialData: JSON.stringify(materialDataForUpdate)
|
||||
}
|
||||
})
|
||||
);
|
||||
materialEditor.set(materialDataForUpdate);
|
||||
}
|
||||
|
||||
function maGetColorValueFromEmissive(colorArray) {
|
||||
if (Array.isArray(colorArray)) {
|
||||
var max = maGetHighestValue(colorArray);
|
||||
if (max > 1) {
|
||||
var normalizer = 1/max;
|
||||
return [colorArray[0] * normalizer, colorArray[1] * normalizer, colorArray[2] * normalizer];
|
||||
} else {
|
||||
return colorArray;
|
||||
}
|
||||
} else {
|
||||
return [0,0,0];
|
||||
}
|
||||
}
|
||||
|
||||
function maGetBloomFactorFromEmissive(colorArray) {
|
||||
if (Array.isArray(colorArray)) {
|
||||
return maGetHighestValue(colorArray);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function maGetHighestValue(colorArray) {
|
||||
var highest = colorArray[0];
|
||||
for (var i = 0; i < colorArray.length; i++) {
|
||||
if (colorArray[i] > highest) {
|
||||
highest = colorArray[i];
|
||||
}
|
||||
}
|
||||
return highest;
|
||||
}
|
||||
|
||||
function scaleEmissiveByBloomFactor(colorArray, bloomFactor) {
|
||||
return [colorArray[0] * bloomFactor, colorArray[1] * bloomFactor, colorArray[2] * bloomFactor];
|
||||
}
|
||||
|
||||
function maGetRGB(colorArray){
|
||||
if (colorArray === undefined) {
|
||||
return "#000000";
|
||||
} else {
|
||||
return "rgb(" + Math.floor(colorArray[0] * 255) + ", " + Math.floor(colorArray[1] * 255) + ", " + Math.floor(colorArray[2] * 255) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string or object} materialData - json of the materialData as a string or as an object.
|
||||
*/
|
||||
function maGetMaterialDataAssistantAvailability(materialData) {
|
||||
var materialDataJSON, materialDataString;
|
||||
if (typeof materialData === "string") {
|
||||
materialDataJSON = JSON.parse(materialData);
|
||||
materialDataString = materialData;
|
||||
} else {
|
||||
materialDataJSON = materialData;
|
||||
materialDataString = JSON.stringify(materialData);
|
||||
}
|
||||
if (getPropertyInputElement("materialURL").value === "materialData" && materialDataString.indexOf("hifi_shader_simple") === -1 &&
|
||||
materialDataString.indexOf("glossMap") === -1 && materialDataString.indexOf("specularMap") === -1 &&
|
||||
materialDataString.indexOf("bumpMap") === -1 && materialDataString.indexOf("lightMap") === -1 &&
|
||||
materialDataString.indexOf("texCoordTransform0") === -1 && materialDataString.indexOf("texCoordTransform1") === -1 &&
|
||||
(materialDataJSON.materials === undefined || materialDataJSON.materials.length <= 1 || typeof materialDataJSON.materials === "object")) {
|
||||
showMaterialAssistantButton();
|
||||
} else {
|
||||
hideMaterialAssistantButton();
|
||||
}
|
||||
}
|
BIN
scripts/system/create/entityProperties/html/tabs/polyvox.png
Normal file
After Width: | Height: | Size: 2 KiB |
|
@ -6,6 +6,7 @@
|
|||
// Modified by David Back on 1/9/2018
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors
|
||||
// Copyright 2022 Overte e.V.
|
||||
//
|
||||
// This script implements a class useful for building tools for editing entities.
|
||||
//
|
||||
|
@ -99,6 +100,9 @@ SelectionManager = (function() {
|
|||
}
|
||||
|
||||
if (messageParsed.method === "selectEntity") {
|
||||
if (!that.editEnabled) {
|
||||
return;
|
||||
}
|
||||
if (!SelectionDisplay.triggered() || SelectionDisplay.triggeredHand === messageParsed.hand) {
|
||||
if (wantDebug) {
|
||||
print("setting selection to " + messageParsed.entityID);
|
||||
|
@ -187,6 +191,21 @@ SelectionManager = (function() {
|
|||
that.pointingAtDesktopWindowRight = false;
|
||||
that.pointingAtTabletLeft = false;
|
||||
that.pointingAtTabletRight = false;
|
||||
that.editEnabled = true;
|
||||
|
||||
that.updateEditSettings = function(data) {
|
||||
|
||||
if (data.createAppMode) {
|
||||
if (data.createAppMode === "object"){
|
||||
that.editEnabled = true;
|
||||
} else {
|
||||
that.editEnabled = false;
|
||||
if(that.hasSelection()){
|
||||
that.clearSelections();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
that.saveProperties = function() {
|
||||
that.savedProperties = {};
|
||||
|
@ -1303,6 +1322,9 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
function makeClickHandler(hand) {
|
||||
return function (clicked) {
|
||||
if (!SelectionManager.editEnabled) {
|
||||
return;
|
||||
}
|
||||
// Don't allow both hands to trigger at the same time
|
||||
if (that.triggered() && hand !== that.triggeredHand) {
|
||||
return;
|
||||
|
@ -1318,6 +1340,9 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
function makePressHandler(hand) {
|
||||
return function (value) {
|
||||
if (!SelectionManager.editEnabled) {
|
||||
return;
|
||||
}
|
||||
if (value >= TRIGGER_ON_VALUE && !that.triggered() && !pointingAtDesktopWindowOrTablet(hand)) {
|
||||
that.pressedHand = hand;
|
||||
that.updateHighlight({});
|
||||
|
@ -1413,6 +1438,9 @@ SelectionDisplay = (function() {
|
|||
if (wantDebug) {
|
||||
print("=============== eST::MousePressEvent BEG =======================");
|
||||
}
|
||||
if (!SelectionManager.editEnabled) {
|
||||
return;
|
||||
}
|
||||
if (!event.isLeftButton && !that.triggered()) {
|
||||
// EARLY EXIT-(if another mouse button than left is pressed ignore it)
|
||||
return false;
|
||||
|
|
|
@ -178,6 +178,18 @@ TabBar {
|
|||
editTabView.currentIndex = 2
|
||||
}
|
||||
}
|
||||
|
||||
NewEntityButton {
|
||||
icon: "icons/voxels.svg"
|
||||
text: "VOXELS"
|
||||
onClicked: {
|
||||
editRoot.sendToScript({
|
||||
method: "newEntityButtonClicked",
|
||||
params: { buttonName: "newPolyVoxButton" }
|
||||
});
|
||||
editTabView.currentIndex = 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
|
@ -274,7 +286,7 @@ TabBar {
|
|||
}
|
||||
|
||||
EditTabButton {
|
||||
title: "GRID"
|
||||
title: "TOOLS"
|
||||
active: true
|
||||
enabled: true
|
||||
property string originalUrl: ""
|
||||
|
|
|
@ -184,6 +184,18 @@ TabBar {
|
|||
editTabView.currentIndex = tabIndex.properties
|
||||
}
|
||||
}
|
||||
|
||||
NewEntityButton {
|
||||
icon: "icons/voxels.svg"
|
||||
text: "VOXELS"
|
||||
onClicked: {
|
||||
editRoot.sendToScript({
|
||||
method: "newEntityButtonClicked",
|
||||
params: { buttonName: "newPolyVoxButton" }
|
||||
});
|
||||
editTabView.currentIndex = tabIndex.properties
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControls.Button {
|
||||
|
@ -264,7 +276,7 @@ TabBar {
|
|||
}
|
||||
|
||||
EditTabButton {
|
||||
title: "GRID"
|
||||
title: "TOOLS"
|
||||
active: true
|
||||
enabled: true
|
||||
property string originalUrl: ""
|
||||
|
|
560
scripts/system/create/qml/NewPolyVoxDialog.qml
Normal file
|
@ -0,0 +1,560 @@
|
|||
//
|
||||
// NewPolyVoxDialog.qml
|
||||
// Created by dr Karol Suprynowicz on 2022.05.17.
|
||||
// based on NewModelDialog.qml
|
||||
// qml/hifi
|
||||
//
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors
|
||||
// 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
|
||||
import stylesUit 1.0
|
||||
import controlsUit 1.0
|
||||
import hifi.dialogs 1.0
|
||||
|
||||
Rectangle {
|
||||
id: newPolyVoxDialog
|
||||
// width: parent.width
|
||||
// height: parent.height
|
||||
HifiConstants { id: hifi }
|
||||
color: hifi.colors.baseGray;
|
||||
signal sendToScript(var message);
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
property bool keyboardRasied: false
|
||||
|
||||
function errorMessageBox(message) {
|
||||
try {
|
||||
return desktop.messageBox({
|
||||
icon: hifi.icons.warning,
|
||||
defaultButton: OriginalDialogs.StandardButton.Ok,
|
||||
title: "Error",
|
||||
text: message
|
||||
});
|
||||
} catch(e) {
|
||||
Window.alert(message);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: column1
|
||||
anchors.rightMargin: 10
|
||||
anchors.leftMargin: 10
|
||||
anchors.bottomMargin: 10
|
||||
anchors.topMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: keyboard.top
|
||||
|
||||
ComboBox {
|
||||
id: texturePreset
|
||||
currentIndex: 0
|
||||
|
||||
property var texturePresetArray: ["Material presets",
|
||||
"Grass + ground",
|
||||
"Bricks",
|
||||
"Stone",
|
||||
"Concrete",
|
||||
"Rock"]
|
||||
|
||||
width: 200
|
||||
z: 100
|
||||
transformOrigin: Item.Center
|
||||
model: texturePresetArray
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
switch (currentIndex) {
|
||||
// Clear texture entries
|
||||
case 0:
|
||||
xTextureURL.text = "";
|
||||
yTextureURL.text = "";
|
||||
zTextureURL.text = "";
|
||||
break;
|
||||
// Grass + ground
|
||||
case 1:
|
||||
xTextureURL.text = "qrc:///serverless/Textures/ground_5-2K/2K-ground_5-diffuse.jpg";
|
||||
yTextureURL.text = "qrc:///serverless/Textures/ground_grass_gen_05.png";
|
||||
zTextureURL.text = "qrc:///serverless/Textures/ground_5-2K/2K-ground_5-diffuse.jpg";
|
||||
break;
|
||||
// Bricks
|
||||
case 2:
|
||||
xTextureURL.text = "qrc:///serverless/Textures/2K-wall_stone_2-diffuse_l.jpg";
|
||||
yTextureURL.text = "qrc:///serverless/Textures/2K-stone_floor_3-diffuse_l.jpg";
|
||||
zTextureURL.text = "qrc:///serverless/Textures/2K-wall_stone_2-diffuse_l.jpg";
|
||||
break;
|
||||
// Stone
|
||||
case 3:
|
||||
xTextureURL.text = "qrc:///serverless/Textures/wall_l.png";
|
||||
yTextureURL.text = "qrc:///serverless/Textures/floor_l.png";
|
||||
zTextureURL.text = "qrc:///serverless/Textures/wall_l.png";
|
||||
break;
|
||||
// Concrete
|
||||
case 4:
|
||||
xTextureURL.text = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
|
||||
yTextureURL.text = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
|
||||
zTextureURL.text = "qrc:///serverless/Textures/concrete_12-2K/2K-concrete_12-diffuse.jpg";
|
||||
break;
|
||||
// Rock
|
||||
case 5:
|
||||
xTextureURL.text = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
|
||||
yTextureURL.text = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
|
||||
zTextureURL.text = "qrc:///serverless/Textures/Rock026_2K-JPG/Rock026_2K_Color.jpg";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: text1
|
||||
anchors.top: texturePreset.bottom
|
||||
anchors.topMargin: 5
|
||||
text: qsTr("X Texture URL")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: xTextureURL
|
||||
height: 20
|
||||
text: qsTr("")
|
||||
color: "white"
|
||||
anchors.top: text1.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
font.pixelSize: 12
|
||||
|
||||
onAccepted: {
|
||||
newPolyVoxDialog.keyboardEnabled = false;
|
||||
}
|
||||
|
||||
onTextChanged : {
|
||||
if (xTextureURL.text.length === 0){
|
||||
button1.enabled = false;
|
||||
} else {
|
||||
button1.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
newPolyVoxDialog.keyboardEnabled = HMD.active
|
||||
parent.focus = true;
|
||||
parent.forceActiveFocus();
|
||||
xTextureURL.cursorPosition = xTextureURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: textInputBox1
|
||||
color: "white"
|
||||
anchors.fill: xTextureURL
|
||||
opacity: 0.1
|
||||
}
|
||||
|
||||
Text {
|
||||
id: text2
|
||||
text: qsTr("Y Texture URL")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
anchors.top: textInputBox1.bottom
|
||||
anchors.topMargin: 5
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: yTextureURL
|
||||
height: 20
|
||||
text: qsTr("")
|
||||
color: "white"
|
||||
anchors.top: text2.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
font.pixelSize: 12
|
||||
|
||||
onAccepted: {
|
||||
newPolyVoxDialog.keyboardEnabled = false;
|
||||
}
|
||||
|
||||
onTextChanged : {
|
||||
if (yTextureURL.text.length === 0){
|
||||
button1.enabled = false;
|
||||
} else {
|
||||
button1.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
newPolyVoxDialog.keyboardEnabled = HMD.active
|
||||
parent.focus = true;
|
||||
parent.forceActiveFocus();
|
||||
yTextureURL.cursorPosition = yTextureURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: textInputBox2
|
||||
color: "white"
|
||||
anchors.fill: yTextureURL
|
||||
opacity: 0.1
|
||||
}
|
||||
|
||||
Text {
|
||||
id: text3
|
||||
text: qsTr("Z Texture URL")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
anchors.top: textInputBox2.bottom
|
||||
anchors.topMargin: 5
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: zTextureURL
|
||||
height: 20
|
||||
text: qsTr("")
|
||||
color: "white"
|
||||
anchors.top: text3.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
font.pixelSize: 12
|
||||
|
||||
onAccepted: {
|
||||
newPolyVoxDialog.keyboardEnabled = false;
|
||||
}
|
||||
|
||||
onTextChanged : {
|
||||
if (zTextureURL.text.length === 0){
|
||||
button1.enabled = false;
|
||||
} else {
|
||||
button1.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
newPolyVoxDialog.keyboardEnabled = HMD.active
|
||||
parent.focus = true;
|
||||
parent.forceActiveFocus();
|
||||
zTextureURL.cursorPosition = zTextureURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: textInputBox3
|
||||
color: "white"
|
||||
anchors.fill: zTextureURL
|
||||
opacity: 0.1
|
||||
}
|
||||
|
||||
Text {
|
||||
id: textVolumeSize
|
||||
text: qsTr("Volume Size (number of voxels along the edge)")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
anchors.top: zTextureURL.bottom
|
||||
anchors.topMargin: 5
|
||||
}
|
||||
|
||||
Row {
|
||||
id: rowVolumeSize
|
||||
height: 50
|
||||
spacing: 30
|
||||
anchors.top: textVolumeSize.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
|
||||
Text {
|
||||
id: textVolumeSizeX
|
||||
text: qsTr("X")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: volumeSizeX
|
||||
height: 20
|
||||
width: 50
|
||||
anchors.left: textVolumeSizeX.right
|
||||
anchors.leftMargin: 3
|
||||
text: qsTr("16")
|
||||
color: "white"
|
||||
font.pixelSize: 12
|
||||
validator: IntValidator{bottom: 8; top: 64;}
|
||||
|
||||
onAccepted: {
|
||||
newPolyVoxDialog.keyboardEnabled = false;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
newPolyVoxDialog.keyboardEnabled = HMD.active
|
||||
parent.focus = true;
|
||||
parent.forceActiveFocus();
|
||||
volumeSizeX.cursorPosition = volumeSizeX.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: textInputBoxVolumeSizeX
|
||||
color: "white"
|
||||
anchors.fill: volumeSizeX
|
||||
opacity: 0.1
|
||||
}
|
||||
|
||||
Text {
|
||||
id: textVolumeSizeY
|
||||
text: qsTr("Y")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
anchors.left: volumeSizeX.right
|
||||
anchors.leftMargin: 5
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: volumeSizeY
|
||||
height: 20
|
||||
width: 50
|
||||
anchors.left: textVolumeSizeY.right
|
||||
anchors.leftMargin: 3
|
||||
text: qsTr("16")
|
||||
color: "white"
|
||||
font.pixelSize: 12
|
||||
validator: IntValidator{bottom: 8; top: 64;}
|
||||
|
||||
onAccepted: {
|
||||
newPolyVoxDialog.keyboardEnabled = false;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
newPolyVoxDialog.keyboardEnabled = HMD.active
|
||||
parent.focus = true;
|
||||
parent.forceActiveFocus();
|
||||
volumeSizeY.cursorPosition = volumeSizeY.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: textInputBoxVolumeSizeY
|
||||
color: "white"
|
||||
anchors.fill: volumeSizeY
|
||||
opacity: 0.1
|
||||
}
|
||||
Text {
|
||||
id: textVolumeSizeZ
|
||||
text: qsTr("X")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
anchors.left: volumeSizeY.right
|
||||
anchors.leftMargin: 5
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: volumeSizeZ
|
||||
height: 20
|
||||
width: 50
|
||||
anchors.left: textVolumeSizeZ.right
|
||||
anchors.leftMargin: 3
|
||||
text: qsTr("16")
|
||||
color: "white"
|
||||
font.pixelSize: 12
|
||||
validator: IntValidator{bottom: 8; top: 64;}
|
||||
|
||||
onAccepted: {
|
||||
newPolyVoxDialog.keyboardEnabled = false;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
newPolyVoxDialog.keyboardEnabled = HMD.active
|
||||
parent.focus = true;
|
||||
parent.forceActiveFocus();
|
||||
volumeSizeZ.cursorPosition = volumeSizeZ.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: textInputBoxVolumeSizeZ
|
||||
color: "white"
|
||||
anchors.fill: volumeSizeZ
|
||||
opacity: 0.1
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row1
|
||||
height: 400
|
||||
spacing: 30
|
||||
anchors.top: rowVolumeSize.bottom
|
||||
anchors.topMargin: 5
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
|
||||
Column {
|
||||
id: column2
|
||||
width: 200
|
||||
height: 600
|
||||
spacing: 10
|
||||
|
||||
|
||||
CheckBox {
|
||||
id: grabbable
|
||||
text: qsTr("Grabbable")
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: collisions
|
||||
text: qsTr("Collisions")
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row2
|
||||
width: 200
|
||||
height: 400
|
||||
spacing: 20
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: column3
|
||||
height: 400
|
||||
spacing: 10
|
||||
|
||||
Text {
|
||||
id: text4
|
||||
text: qsTr("Voxel type")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: surfaceStyle
|
||||
currentIndex: 3
|
||||
|
||||
property var surfaceStyleArray: ["Marching Cubes",
|
||||
"Cubic",
|
||||
"Edged Cubic",
|
||||
"Edged Marching Cubes"]
|
||||
|
||||
width: 200
|
||||
z: 100
|
||||
transformOrigin: Item.Center
|
||||
model: surfaceStyleArray
|
||||
}
|
||||
|
||||
Text {
|
||||
id: textInitialShape
|
||||
text: qsTr("Initial shape")
|
||||
color: "#ffffff"
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: initialShape
|
||||
currentIndex: 0
|
||||
|
||||
property var initialShapeArray: ["Box",
|
||||
"Plane, 1/4 full",
|
||||
"Plane, 3/4 full",
|
||||
"Single voxel",
|
||||
]
|
||||
|
||||
width: 200
|
||||
z: 100
|
||||
transformOrigin: Item.Center
|
||||
model: initialShapeArray
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row3
|
||||
width: 200
|
||||
height: 400
|
||||
spacing: 5
|
||||
|
||||
anchors.horizontalCenter: column3.horizontalCenter
|
||||
anchors.horizontalCenterOffset: -20
|
||||
|
||||
Button {
|
||||
id: button1
|
||||
text: qsTr("Create")
|
||||
z: -1
|
||||
enabled: false
|
||||
onClicked: {
|
||||
newPolyVoxDialog.sendToScript({
|
||||
method: "newPolyVoxDialogAdd",
|
||||
params: {
|
||||
xTextureURL: xTextureURL.text,
|
||||
yTextureURL: yTextureURL.text,
|
||||
zTextureURL: zTextureURL.text,
|
||||
volumeSizeX: volumeSizeX.text,
|
||||
volumeSizeY: volumeSizeY.text,
|
||||
volumeSizeZ: volumeSizeZ.text,
|
||||
surfaceStyleIndex: surfaceStyle.currentIndex,
|
||||
initialShapeIndex: initialShape.currentIndex,
|
||||
grabbable: grabbable.checked,
|
||||
collisions: collisions.checked,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: button2
|
||||
z: -1
|
||||
text: qsTr("Cancel")
|
||||
onClicked: {
|
||||
newPolyVoxDialog.sendToScript({method: "newPolyVoxDialogCancel"})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 40
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
}
|
20
scripts/system/create/qml/NewPolyVoxWindow.qml
Normal file
|
@ -0,0 +1,20 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
|
||||
StackView {
|
||||
id: stackView
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 10
|
||||
anchors.rightMargin: 10
|
||||
anchors.topMargin: 40
|
||||
|
||||
signal sendToScript(var message);
|
||||
|
||||
NewPolyVoxDialog {
|
||||
id: dialog
|
||||
anchors.fill: parent
|
||||
Component.onCompleted:{
|
||||
dialog.sendToScript.connect(stackView.sendToScript);
|
||||
}
|
||||
}
|
||||
}
|
50
scripts/system/create/qml/icons/voxels.svg
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="voxels.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs27" /><sodipodi:namedview
|
||||
id="namedview25"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="17.42"
|
||||
inkscape:cx="25.028703"
|
||||
inkscape:cy="20.407577"
|
||||
inkscape:window-width="1918"
|
||||
inkscape:window-height="1042"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="18"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{opacity:0.9;}
|
||||
.st1{fill:#1E1E1E;}
|
||||
.st2{fill:#EAEAEA;}
|
||||
</style>
|
||||
|
||||
<path
|
||||
class="st2"
|
||||
d="M 42.986179,11.33074 34.367376,6.3639716 c -0.438244,-0.2921628 -1.02257,-0.2921628 -1.460814,0 L 25.164247,10.892495 17.129769,6.2178902 c -0.438244,-0.2921628 -1.02257,-0.2921628 -1.460814,0 L 7.196233,11.184658 C 6.7579887,11.476821 6.4658259,11.915065 6.4658259,12.35331 v 9.933535 c 0,0.438244 0.2921628,1.02257 0.7304071,1.168651 l 7.888397,4.528524 v 9.057048 c 0,0.438244 0.292162,1.02257 0.730407,1.168651 l 8.618803,4.966768 c 0.292163,0.146081 0.438244,0.146081 0.730407,0.146081 0.292163,0 0.438244,0 0.730407,-0.146081 l 8.618803,-4.966768 c 0.438245,-0.292163 0.730407,-0.730407 0.730407,-1.168651 v -8.910966 l 7.888397,-4.528524 c 0.438244,-0.292163 0.730407,-0.730407 0.730407,-1.168652 V 12.499391 C 43.716586,12.061147 43.424423,11.622902 42.986179,11.33074 Z m -2.04514,8.910965 -5.989337,-3.505954 V 9.8699255 l 5.989337,3.5059535 z m -7.011907,5.551094 -7.304071,-4.236361 v -8.180559 l 5.989338,-3.5059535 v 6.8658255 l -2.921628,1.752977 c -0.584326,0.292163 -0.730407,1.02257 -0.438244,1.606896 0.292162,0.438244 0.584325,0.584326 1.022569,0.584326 0.146082,0 0.438245,0 0.584326,-0.146082 l 2.921628,-1.752977 5.989338,3.505954 z m -7.596234,5.697175 v -6.719745 l 5.989338,3.505954 v 6.719745 z M 23.703433,20.095624 17.714095,16.58967 V 9.7238441 l 5.989338,3.5059539 z M 9.2413727,13.229798 15.230711,9.7238441 V 16.58967 l -3.213791,1.899058 c -0.584326,0.292163 -0.730407,1.02257 -0.438244,1.606896 0.292163,0.438244 0.584325,0.584326 1.02257,0.584326 0.146081,0 0.438244,0 0.584325,-0.146082 l 3.213791,-1.899058 5.989338,3.505954 -5.989338,3.505954 -7.1579893,-4.09028 z m 15.9228743,27.317224 -7.157989,-4.09028 v -8.180559 l 5.989338,-3.505954 v 6.865826 l -2.921629,1.606896 c -0.584325,0.292163 -0.730407,1.02257 -0.438244,1.606895 0.292163,0.438245 0.584326,0.584326 1.02257,0.584326 0.146082,0 0.438244,0 0.584326,-0.146081 l 2.921628,-1.606896 5.989338,3.505954 z"
|
||||
id="path10"
|
||||
style="stroke-width:1.46081;fill:#000000" />
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
|
@ -4,6 +4,7 @@
|
|||
// Created by Ryan Huffman on 13 Nov 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// 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
|
||||
|
@ -495,6 +496,22 @@ input[type=button].secondary_red, button.hifi-edit-button.secondary_red {
|
|||
background: linear-gradient(#d42043 20%, #94132e 100%);
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type=button].secondary_blue, button.hifi-edit-button.secondary_blue {
|
||||
font-family: Raleway-Bold;
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
vertical-align: top;
|
||||
height: 18px;
|
||||
min-width: 60px;
|
||||
padding: 0 14px;
|
||||
margin-right: 6px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
color: #fff;
|
||||
background-color: #1080b8;
|
||||
background: linear-gradient(#00b4ef 20%, #1080b8 100%);
|
||||
cursor: pointer;
|
||||
}
|
||||
input[type=button]:enabled:hover, button.hifi-edit-button:enabled:hover {
|
||||
background: linear-gradient(#000, #000);
|
||||
border: none;
|
||||
|
@ -2062,6 +2079,42 @@ div.entity-list-menu {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.tools-select-menu {
|
||||
position: relative;
|
||||
display: none;
|
||||
width: 370px;
|
||||
height: 0px;
|
||||
top: 0px;
|
||||
left: 8px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-style: solid;
|
||||
border-color: #505050;
|
||||
border-width: 1px;
|
||||
background-color: #c0c0c0;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.tools-help-popup {
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 15px;
|
||||
position: relative;
|
||||
display: none;
|
||||
width: 690px;
|
||||
height: auto;
|
||||
top: 0px;
|
||||
left: 8px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-style: solid;
|
||||
border-color: #505050;
|
||||
border-width: 1px;
|
||||
background-color: #404040;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.menu-separator{
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
|
|
BIN
scripts/system/html/css/img/sidewalk.png
Normal file
After Width: | Height: | Size: 402 B |
223
scripts/system/html/css/materialAssistant.css
Normal file
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
// materialAssistant.css
|
||||
//
|
||||
// Created by Alezia Kurdis on May 17th, 2022.
|
||||
// Copyright 2022 Vircadia contributors.
|
||||
// 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
|
||||
*/
|
||||
|
||||
#uiMaterialAssistant {
|
||||
position: fixed;
|
||||
display: none;
|
||||
width: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
background-color: #404040;
|
||||
z-index: 2;
|
||||
border-collapse: collapse;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#uiMaterialAssistant-headerContainer {
|
||||
width: 98%;
|
||||
text-align: right;
|
||||
padding: 6px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#uiMaterialAssistant-closeButton {
|
||||
font-family: Raleway-Bold;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
border: 0px;
|
||||
padding: 6px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
#uiMaterialAssistant-sidewalk {
|
||||
width: 100%;
|
||||
background-image: url("img/sidewalk.png");
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
#uiMaterialAssistant-formContainer {
|
||||
background-color: #404040;
|
||||
width: 90%;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
div.uiMaterialAssistant-group{
|
||||
background-color: #2E2E2E;
|
||||
border: 2px solid #aaaaaa;
|
||||
padding: 5px;
|
||||
margin: 0px 0px 6px 0px;
|
||||
font-family: Raleway-SemiBold;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
font.uiMaterialAssistant-Explain{
|
||||
background-color: #2E2E2E;
|
||||
font-family: Raleway-Regular;
|
||||
text-decoration: Italic;
|
||||
font-size: 10px;
|
||||
color: #8ad5ff;
|
||||
}
|
||||
|
||||
font.uiMaterialAssistant-label{
|
||||
background-color: #2E2E2E;
|
||||
font-family: Raleway-SemiBold;
|
||||
text-decoration: none;
|
||||
font-size: 12px;
|
||||
color: #D2D2D2;
|
||||
}
|
||||
|
||||
font.uiMaterialAssistant-title{
|
||||
background-color: #404040;
|
||||
font-family: Raleway-Bold;
|
||||
font-size: 18px;
|
||||
text-decoration: none;
|
||||
color: #F2F2F2;
|
||||
}
|
||||
|
||||
input[type=range].uiMaterialAssistant-slider {
|
||||
margin: 10px 0;
|
||||
width: 100%;
|
||||
background-color: #2E2E2E;
|
||||
}
|
||||
|
||||
input[type=range].uiMaterialAssistant-slider:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type=range].uiMaterialAssistant-slider::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
cursor: pointer;
|
||||
animate: 0.2s;
|
||||
box-shadow: 0px 0px 0px #000000;
|
||||
background: #ffffff;
|
||||
border-radius: 0px;
|
||||
border: 0px solid #000000;
|
||||
}
|
||||
|
||||
input[type=range].uiMaterialAssistant-slider:disabled::-webkit-slider-runnable-track {
|
||||
background: #555555;
|
||||
border: 0px solid #333333;
|
||||
}
|
||||
|
||||
input[type=range].uiMaterialAssistant-slider::-webkit-slider-thumb {
|
||||
box-shadow: 1px 1px 1px #000000;
|
||||
border: 1px solid #000000;
|
||||
height: 22px;
|
||||
width: 12px;
|
||||
border-radius: 10px;
|
||||
background: #FFFFFF;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
margin-top: -8.5px;
|
||||
}
|
||||
|
||||
input[type=range].uiMaterialAssistant-slider:disabled::-webkit-slider-thumb {
|
||||
box-shadow: 1px 1px 1px #000000;
|
||||
border: 1px solid #333333;
|
||||
height: 22px;
|
||||
width: 12px;
|
||||
border-radius: 10px;
|
||||
background: #555555;
|
||||
}
|
||||
|
||||
input[type=range].uiMaterialAssistant-slider:focus::-webkit-slider-runnable-track {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
input[type=text].uiMaterialAssistant-input {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #000000;
|
||||
font-family: FiraSans-SemiBold;
|
||||
font-size: 14px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding: 3px;
|
||||
margin: 3px 0px 3px 0px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
input[type=text].uiMaterialAssistant-input:disabled {
|
||||
background-color: #555555;
|
||||
color: #888888;
|
||||
}
|
||||
input[type=radio].uiMaterialAssistant-radio {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 2px;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
input[type=radio].uiMaterialAssistant-radio:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type=checkbox].uiMaterialAssistant-checkbox {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 2px;
|
||||
padding: 3px;
|
||||
display: block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input[type=checkbox].uiMaterialAssistant-checkbox:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button.uiMaterialAssistant-active {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border: 1px solid #000000;
|
||||
background-color: #00FF00;
|
||||
}
|
||||
|
||||
button.uiMaterialAssistant-active:hover {
|
||||
background-color: #33FF33;
|
||||
border: 1px solid #ffffff;
|
||||
}
|
||||
|
||||
button.uiMaterialAssistant-active:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button.uiMaterialAssistant-inactive {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border: 1px solid #000000;
|
||||
background-color: #555555;
|
||||
}
|
||||
|
||||
button.uiMaterialAssistant-inactive:hover {
|
||||
background-color: #777777;
|
||||
border: 1px solid #ffffff;
|
||||
}
|
||||
|
||||
button.uiMaterialAssistant-inactive:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.uiMaterialAssistant-color-picker {
|
||||
background-color: #000000;
|
||||
border: 1px solid #AAAAAA;
|
||||
width: 120px;
|
||||
height: 30px;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 6 Nov 2014
|
||||
// Copyright 2014 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
|
||||
|
@ -20,7 +21,80 @@
|
|||
<script type="text/javascript" src="js/gridControls.js"></script>
|
||||
</head>
|
||||
<body onload='loaded();'>
|
||||
<div id="mode-section" class="section">
|
||||
<div class="property container">
|
||||
<label for="create-app-mode">Create app mode </label>
|
||||
<div class="property container">
|
||||
<input name="create-app-mode" type="button" class="entity-list-menutitle" id="create-app-mode" value="Create app mode▾" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="tools-select-menu" id="edit-mode-menu" >
|
||||
<button class="menu-button" id="edit-mode-object" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Object mode</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="edit-mode-voxel" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Voxel edit mode</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="voxels-section" class="section">
|
||||
<h2>Voxel edit settings</h2>
|
||||
<div class="property container">
|
||||
<label for="voxel-edit-mode">Voxel edit mode </label>
|
||||
<div class="property container">
|
||||
<input name="voxel-edit-mode" type="button" class="entity-list-menutitle" id="voxel-edit-mode" value="Voxel edit mode▾" />
|
||||
</div>
|
||||
<label for="voxel-sphere-size"> Sphere/cube size <span class="unit">m</span></label>
|
||||
<div class="number">
|
||||
<input type="number" id="voxel-sphere-size" min="0.01" step="0.2" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="tools-select-menu" id="voxel-edit-mode-menu" >
|
||||
<button class="menu-button" id="voxel-edit-mode-single" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Single voxels</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="voxel-edit-mode-sphere" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Spheres</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="menu-button" id="voxel-edit-mode-cube" >
|
||||
<div class = "menu-item">
|
||||
<div class = "menu-item-caption">Cubes</div>
|
||||
<div class = "menu-item-shortcut"></div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="property container">
|
||||
<label for="voxel-remove"> Remove voxels</label>
|
||||
<div style="width: 100%">
|
||||
<input type='checkbox' id="voxel-remove" style="width: 100%">
|
||||
<label for="voxel-remove"> </label>
|
||||
</div>
|
||||
<div class="property container">
|
||||
<input name="voxel-help-button" type="button" class="entity-list-menutitle" id="voxel-help-button" value="Voxel edit help▾" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="tools-help-popup" id="voxel-help-popup" >
|
||||
<p>To edit voxels, Voxel Edit Mode needs to be selected.</p>
|
||||
<p>Desktop mode:</p>
|
||||
<p>Click the left mouse button to add a voxel. Click the middle mouse button to remove a voxel. Hold the mouse button and move the mouse to add or remove voxels in a single plane. The plane is determined by the direction in which you are looking when first voxel is added or removed (for example, look downwards to draw in horizontal plane).</p>
|
||||
<p>VR mode:</p>
|
||||
<p>Press the trigger to add a voxel. Press the trigger while holding the grip to remove a voxel. Hold the trigger and move the controller to add or remove voxels in a single plane. The plane is determined by the direction in which the controller's ray points when the first voxel is added or removed (for example point downwards to draw in the horizontal plane). Hold both grips and move your hands together or apart to change the size of the edit sphere.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="grid-section" class="section">
|
||||
<h2>Grid settings</h2>
|
||||
<div class="property container">
|
||||
<label for="horiz-grid-visible">Visible</label>
|
||||
<div style="width: 100%">
|
||||
|
@ -67,5 +141,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="menuBackgroundOverlay" ></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,12 +2,30 @@
|
|||
//
|
||||
// Created by Ryan Huffman on 6 Nov 2014
|
||||
// Copyright 2014 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
|
||||
|
||||
var createAppModeValue = "";
|
||||
var voxelEditModeValue = "";
|
||||
|
||||
function loaded() {
|
||||
openEventBridge(function() {
|
||||
elCreateAppModeMenu = document.getElementById("create-app-mode");
|
||||
elEditModeObject = document.getElementById("edit-mode-object");
|
||||
elEditModeVoxel = document.getElementById("edit-mode-voxel");
|
||||
elVoxelEditModeMenu = document.getElementById("voxel-edit-mode");
|
||||
elVoxelEditModeSingle = document.getElementById("voxel-edit-mode-single");
|
||||
elVoxelEditModeSphere = document.getElementById("voxel-edit-mode-sphere");
|
||||
elVoxelEditModeCube = document.getElementById("voxel-edit-mode-cube");
|
||||
elMenuBackgroundOverlay = document.getElementById("menuBackgroundOverlay");
|
||||
elVoxelHelpButton = document.getElementById("voxel-help-button");
|
||||
elVoxelHelpPopup = document.getElementById("voxel-help-popup");
|
||||
|
||||
elVoxelSphereSize = document.getElementById("voxel-sphere-size");
|
||||
elVoxelRemove = document.getElementById("voxel-remove");
|
||||
|
||||
elPosY = document.getElementById("horiz-y");
|
||||
elMinorSpacing = document.getElementById("minor-spacing");
|
||||
elMajorSpacing = document.getElementById("major-spacing");
|
||||
|
@ -16,10 +34,102 @@ function loaded() {
|
|||
elMoveToSelection = document.getElementById("move-to-selection");
|
||||
elMoveToAvatar = document.getElementById("move-to-avatar");
|
||||
|
||||
elCreateAppModeMenu.onclick = function() {
|
||||
document.getElementById("menuBackgroundOverlay").style.display = "block";
|
||||
document.getElementById("edit-mode-menu").style.display = "block";
|
||||
};
|
||||
|
||||
elVoxelEditModeMenu.onclick = function() {
|
||||
document.getElementById("menuBackgroundOverlay").style.display = "block";
|
||||
document.getElementById("voxel-edit-mode-menu").style.display = "block";
|
||||
};
|
||||
|
||||
elVoxelHelpButton.onclick = function() {
|
||||
document.getElementById("menuBackgroundOverlay").style.display = "block";
|
||||
document.getElementById("voxel-help-popup").style.display = "block";
|
||||
};
|
||||
|
||||
elMenuBackgroundOverlay.onclick = function() {
|
||||
closeAllEntityListMenu();
|
||||
};
|
||||
|
||||
elEditModeObject.onclick = function() {
|
||||
createAppModeValue = "object";
|
||||
elCreateAppModeMenu.value = "Object mode\u25BE";
|
||||
emitUpdateEditTools();
|
||||
closeAllEntityListMenu();
|
||||
};
|
||||
|
||||
elEditModeVoxel.onclick = function() {
|
||||
createAppModeValue = "voxel";
|
||||
elCreateAppModeMenu.value = "Voxel edit mode\u25BE";
|
||||
emitUpdateEditTools();
|
||||
closeAllEntityListMenu();
|
||||
};
|
||||
|
||||
elVoxelEditModeSingle.onclick = function() {
|
||||
voxelEditModeValue = "single";
|
||||
elVoxelEditModeMenu.value = "Single voxels\u25BE";
|
||||
emitUpdateEditTools();
|
||||
closeAllEntityListMenu();
|
||||
};
|
||||
|
||||
elVoxelEditModeSphere.onclick = function() {
|
||||
voxelEditModeValue = "sphere";
|
||||
elVoxelEditModeMenu.value = "Spheres\u25BE";
|
||||
emitUpdateEditTools();
|
||||
closeAllEntityListMenu();
|
||||
};
|
||||
|
||||
elVoxelEditModeCube.onclick = function() {
|
||||
voxelEditModeValue = "cube";
|
||||
elVoxelEditModeMenu.value = "Cubes\u25BE";
|
||||
emitUpdateEditTools();
|
||||
closeAllEntityListMenu();
|
||||
};
|
||||
|
||||
elVoxelHelpPopup.onclick = function() {
|
||||
closeAllEntityListMenu();
|
||||
};
|
||||
|
||||
if (window.EventBridge !== undefined) {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
|
||||
if (data.createAppMode !== undefined) {
|
||||
if (data.createAppMode === "object") {
|
||||
createAppModeValue = data.createAppMode;
|
||||
elCreateAppModeMenu.value = "Object mode\u25BE";
|
||||
}
|
||||
if (data.createAppMode === "voxel") {
|
||||
createAppModeValue = data.createAppMode;
|
||||
elCreateAppModeMenu.value = "Voxel edit mode\u25BE";
|
||||
}
|
||||
}
|
||||
|
||||
if (data.voxelEditMode !== undefined) {
|
||||
if (data.voxelEditMode === "single") {
|
||||
voxelEditModeValue = data.voxelEditMode;
|
||||
elVoxelEditModeMenu.value = "Single voxels\u25BE";
|
||||
}
|
||||
if (data.voxelEditMode === "sphere") {
|
||||
voxelEditModeValue = data.voxelEditMode;
|
||||
elVoxelEditModeMenu.value = "Spheres\u25BE";
|
||||
}
|
||||
if (data.voxelEditMode === "cube") {
|
||||
voxelEditModeValue = data.voxelEditMode;
|
||||
elVoxelEditModeMenu.value = "Cubes\u25BE";
|
||||
}
|
||||
}
|
||||
|
||||
if (data.voxelSphereSize !== undefined) {
|
||||
elVoxelSphereSize.value = data.voxelSphereSize;
|
||||
}
|
||||
|
||||
if (data.voxelRemove !== undefined) {
|
||||
elVoxelRemove.checked = data.voxelRemove == true;
|
||||
}
|
||||
|
||||
if (data.origin) {
|
||||
var origin = data.origin;
|
||||
elPosY.value = origin.y;
|
||||
|
@ -60,8 +170,20 @@ function loaded() {
|
|||
}));
|
||||
}
|
||||
|
||||
function emitUpdateEditTools() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "update-edit-tools",
|
||||
createAppMode: createAppModeValue,
|
||||
voxelEditMode: voxelEditModeValue,
|
||||
voxelSphereSize: elVoxelSphereSize.value,
|
||||
voxelRemove: elVoxelRemove.checked,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
elVoxelSphereSize.addEventListener("change", emitUpdateEditTools);
|
||||
elVoxelRemove.addEventListener("change", emitUpdateEditTools);
|
||||
|
||||
elPosY.addEventListener("change", emitUpdate);
|
||||
elMinorSpacing.addEventListener("change", emitUpdate);
|
||||
elMajorSpacing.addEventListener("change", emitUpdate);
|
||||
|
@ -154,8 +276,16 @@ function loaded() {
|
|||
}));
|
||||
}, false);
|
||||
|
||||
function closeAllEntityListMenu() {
|
||||
document.getElementById("menuBackgroundOverlay").style.display = "none";
|
||||
document.getElementById("edit-mode-menu").style.display = "none";
|
||||
document.getElementById("voxel-edit-mode-menu").style.display = "none";
|
||||
document.getElementById("voxel-help-popup").style.display = "none";
|
||||
}
|
||||
|
||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||
document.addEventListener("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
}, false);
|
||||
|
||||
}
|
||||
|
|
|
@ -508,4 +508,4 @@
|
|||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
20
scripts/system/inventory/.gitignore
vendored
|
@ -1,20 +0,0 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
|
@ -1,24 +0,0 @@
|
|||
# inventory
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
|
@ -1,5 +0,0 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
.draggable-card{background-color:#272727;margin:5px 0}.draggable-card .handle{width:40px!important}.top-level-folder{background-color:#272727}.top-level-folder .v-list-group__header__prepend-icon{background-color:rgba(0,0,0,.3);width:50px;height:50px;margin:5px 5px 7px 0!important;padding:5px 18px 5px 8px}.top-level-folder .handle{width:40px!important}.top-level-folder .folder-icon{margin-right:10px}.top-level-folder .folder-button{font-size:.795rem!important}.v-list-group .column-item{max-width:100%!important;margin-top:5px;margin-bottom:5px}.v-list-group .draggable-card{background-color:rgba(0,0,0,.3);padding-right:16px;padding-left:0!important}.v-list-group .draggable-card .handle{margin-right:16px}.app-version{text-align:center;color:hsla(0,0%,100%,.6);font-weight:lighter}.handle{background-color:rgba(0,0,0,.3)}.inventoryApp::-webkit-scrollbar{width:0!important}
|
BIN
scripts/system/inventory/dist/favicon.ico
vendored
Before Width: | Height: | Size: 4.2 KiB |
1
scripts/system/inventory/dist/index.html
vendored
|
@ -1 +0,0 @@
|
|||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=favicon.ico><title>Inventory</title><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900"><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css><link href=css/app.a93e8b1f.css rel=preload as=style><link href=css/chunk-vendors.8540aa41.css rel=preload as=style><link href=js/app.a3555a80.js rel=preload as=script><link href=js/chunk-vendors.a0f21a27.js rel=preload as=script><link href=css/chunk-vendors.8540aa41.css rel=stylesheet><link href=css/app.a93e8b1f.css rel=stylesheet></head><body><noscript><strong>We're sorry but Inventory doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=js/chunk-vendors.a0f21a27.js></script><script src=js/app.a3555a80.js></script></body></html>
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="#0c0" d="M17,14H19V17H22V19H19V22H17V19H14V17H17V14M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V13.53C20.94,12.58 19.54,12 18,12A6,6 0 0,0 12,18C12,19.09 12.29,20.12 12.8,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" /></svg>
|
Before Width: | Height: | Size: 552 B |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16.5,12C19,12 21,14 21,16.5C21,17.38 20.75,18.21 20.31,18.9L23.39,22L22,23.39L18.88,20.32C18.19,20.75 17.37,21 16.5,21C14,21 12,19 12,16.5C12,14 14,12 16.5,12M16.5,14A2.5,2.5 0 0,0 14,16.5A2.5,2.5 0 0,0 16.5,19A2.5,2.5 0 0,0 19,16.5A2.5,2.5 0 0,0 16.5,14M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V13.03C20.85,11.21 18.82,10 16.5,10A6.5,6.5 0 0,0 10,16.5C10,18.25 10.69,19.83 11.81,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" /></svg>
|
Before Width: | Height: | Size: 761 B |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="#0f0" d="M17,14H19V17H22V19H19V22H17V19H14V17H17V14M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V13.53C20.94,12.58 19.54,12 18,12A6,6 0 0,0 12,18C12,19.09 12.29,20.12 12.8,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" /></svg>
|
Before Width: | Height: | Size: 552 B |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="white" d="M16.5,12C19,12 21,14 21,16.5C21,17.38 20.75,18.21 20.31,18.9L23.39,22L22,23.39L18.88,20.32C18.19,20.75 17.37,21 16.5,21C14,21 12,19 12,16.5C12,14 14,12 16.5,12M16.5,14A2.5,2.5 0 0,0 14,16.5A2.5,2.5 0 0,0 16.5,19A2.5,2.5 0 0,0 19,16.5A2.5,2.5 0 0,0 16.5,14M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V13.03C20.85,11.21 18.82,10 16.5,10A6.5,6.5 0 0,0 10,16.5C10,18.25 10.69,19.83 11.81,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" /></svg>
|
Before Width: | Height: | Size: 775 B |
299
scripts/system/inventory/dist/inventory.js
vendored
|
@ -1,299 +0,0 @@
|
|||
//
|
||||
// inventory.js
|
||||
//
|
||||
// Created by kasenvr@gmail.com on 2 Apr 2020
|
||||
// Copyright 2020 Vircadia and contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* global AvatarList Clipboard console Controller Entities location Messages MyAvatar Script ScriptDiscoveryService Settings
|
||||
Tablet Vec3 Window */
|
||||
|
||||
(function () { // BEGIN LOCAL_SCOPE
|
||||
"use strict";
|
||||
var AppUi = Script.require('appUi');
|
||||
var ui;
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
||||
// VARIABLES
|
||||
var inventoryDataSettingString = "inventoryApp.data";
|
||||
var inventoryData;
|
||||
|
||||
var inventorySettingsString = "inventoryApp.settings";
|
||||
var inventorySettings;
|
||||
|
||||
var RECEIVING_ITEM_QUEUE_LIMIT = 5;
|
||||
var receivingItemQueue = [];
|
||||
|
||||
var NEARBY_USERS_SEARCH_RADIUS = 25;
|
||||
|
||||
|
||||
// APP EVENT AND MESSAGING ROUTING
|
||||
|
||||
function onWebAppEventReceived(event) {
|
||||
var eventJSON = JSON.parse(event);
|
||||
if (eventJSON.app === "inventory") { // This is our web app!
|
||||
// print("inventory.js received a web event: " + event);
|
||||
|
||||
if (eventJSON.command === "ready") {
|
||||
initializeInventoryApp();
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-inventory") {
|
||||
receiveInventory(eventJSON.data);
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-settings") {
|
||||
receiveSettings(eventJSON.data);
|
||||
}
|
||||
|
||||
if (eventJSON.command === "use-item") {
|
||||
useItem(eventJSON.data);
|
||||
}
|
||||
|
||||
if (eventJSON.command === "share-item") {
|
||||
shareItem(eventJSON.data);
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-request-nearby-users") {
|
||||
sendNearbyUsers();
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-request-receiving-item-queue") {
|
||||
sendReceivingItemQueue();
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-update-receiving-item-queue") {
|
||||
updateReceivingItemQueue(eventJSON.data);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tablet.webEventReceived.connect(onWebAppEventReceived);
|
||||
|
||||
function sendToWeb(command, data) {
|
||||
var dataToSend = {
|
||||
"app": "inventory",
|
||||
"command": command,
|
||||
"data": data
|
||||
};
|
||||
|
||||
tablet.emitScriptEvent(JSON.stringify(dataToSend));
|
||||
}
|
||||
|
||||
var inventoryMessagesChannel = "com.vircadia.inventory";
|
||||
|
||||
function onMessageReceived(channel, message, sender, localOnly) {
|
||||
if (channel === inventoryMessagesChannel) {
|
||||
var messageJSON = JSON.parse(message);
|
||||
// Window.alert("Passed 0 " + messageJSON.recipient + " vs " + MyAvatar.sessionUUID);
|
||||
if (messageJSON.command === "share-item"
|
||||
&& messageJSON.recipient === MyAvatar.sessionUUID) { // We are receiving an item.
|
||||
// Window.alert("Passed 1 " + messageJSON.recipient + " vs " + MyAvatar.sessionUUID);
|
||||
pushReceivedItemToQueue(sender, messageJSON.type, messageJSON.name, messageJSON.url);
|
||||
}
|
||||
}
|
||||
// print("Message received:");
|
||||
// print("- channel: " + channel);
|
||||
// print("- message: " + message);
|
||||
// print("- sender: " + sender);
|
||||
// print("- localOnly: " + localOnly);
|
||||
}
|
||||
|
||||
function sendMessage(dataToSend) {
|
||||
Messages.sendMessage(inventoryMessagesChannel, JSON.stringify(dataToSend));
|
||||
}
|
||||
|
||||
// END APP EVENT AND MESSAGING ROUTING
|
||||
|
||||
// SEND AND RECEIVE INVENTORY STATE
|
||||
|
||||
function receiveInventory(receivedInventoryData) {
|
||||
inventoryData = receivedInventoryData;
|
||||
saveInventory();
|
||||
}
|
||||
|
||||
function sendInventory() {
|
||||
sendToWeb("script-to-web-inventory", inventoryData);
|
||||
}
|
||||
|
||||
// END SEND AND RECEIVE INVENTORY STATE
|
||||
|
||||
// SEND AND RECEIVE SETTINGS STATE
|
||||
|
||||
function receiveSettings(receivedSettingsData) {
|
||||
inventorySettings = receivedSettingsData;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function sendSettings() {
|
||||
sendToWeb("script-to-web-settings", inventorySettings);
|
||||
}
|
||||
|
||||
// END SEND AND RECEIVE SETTINGS STATE
|
||||
|
||||
function saveInventory() {
|
||||
Settings.setValue(inventoryDataSettingString, inventoryData);
|
||||
}
|
||||
|
||||
function loadInventory() {
|
||||
inventoryData = Settings.getValue(inventoryDataSettingString);
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
Settings.setValue(inventorySettingsString, inventorySettings);
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
inventorySettings = Settings.getValue(inventorySettingsString);
|
||||
}
|
||||
|
||||
function pushReceivedItemToQueue(senderUUID, type, name, url) {
|
||||
console.info("Receiving an item:", name, "from:", senderUUID);
|
||||
var getAvatarData = AvatarList.getAvatar(senderUUID);
|
||||
var senderName = getAvatarData.sessionDisplayName;
|
||||
var senderDistance = Vec3.distance(MyAvatar.position, getAvatarData.position);
|
||||
|
||||
var packageRequest = {
|
||||
"senderUUID": senderUUID,
|
||||
"senderName": senderName,
|
||||
"senderDistance": senderDistance,
|
||||
"data": {
|
||||
"type": type,
|
||||
"name": name,
|
||||
"url": url
|
||||
}
|
||||
};
|
||||
|
||||
if (receivingItemQueue.length === RECEIVING_ITEM_QUEUE_LIMIT) {
|
||||
receivingItemQueue = receivingItemQueue.slice(1, RECEIVING_ITEM_QUEUE_LIMIT);
|
||||
}
|
||||
|
||||
receivingItemQueue.push(packageRequest);
|
||||
ui.messagesWaiting(receivingItemQueue.length > 0);
|
||||
}
|
||||
|
||||
function sendReceivingItemQueue() {
|
||||
sendToWeb("script-to-web-receiving-item-queue", receivingItemQueue);
|
||||
}
|
||||
|
||||
function updateReceivingItemQueue(data) {
|
||||
receivingItemQueue = data;
|
||||
ui.messagesWaiting(receivingItemQueue.length > 0);
|
||||
}
|
||||
|
||||
function sendNearbyUsers() {
|
||||
var nearbyUsers = AvatarList.getAvatarsInRange(MyAvatar.position, NEARBY_USERS_SEARCH_RADIUS);
|
||||
var nearbyUsersToSend = [];
|
||||
|
||||
nearbyUsers.forEach(function(user) {
|
||||
var objectToWrite;
|
||||
var aviDetails = AvatarList.getAvatar(user);
|
||||
var aviName = aviDetails.displayName;
|
||||
var aviDistance = Vec3.distance(MyAvatar.position, aviDetails.position);
|
||||
// Window.alert("aviName" + aviName + "user" + user + "MyAvatar.sessionUUID" + MyAvatar.sessionUUID);
|
||||
if (user !== MyAvatar.sessionUUID
|
||||
|| Controller.getValue(Controller.Hardware.Keyboard.Shift)) { // Don't add ourselves to the list!
|
||||
objectToWrite = { "name": aviName, "distance": aviDistance, "uuid": user };
|
||||
nearbyUsersToSend.push(objectToWrite);
|
||||
}
|
||||
});
|
||||
|
||||
sendToWeb("script-to-web-nearby-users", nearbyUsersToSend);
|
||||
}
|
||||
|
||||
function useItem(item) {
|
||||
|
||||
//TODO: Add animation support for avatars...?
|
||||
|
||||
// Convert the item.type before checking it...
|
||||
item.type = item.type.toUpperCase();
|
||||
|
||||
// Depending on the type, we decide how to load this item.
|
||||
if (item.type === "SCRIPT") {
|
||||
ScriptDiscoveryService.loadScript(item.url, true, false, false, true, false);
|
||||
}
|
||||
|
||||
if (item.type === "MODEL") {
|
||||
Entities.addEntity({
|
||||
type: "Model",
|
||||
position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1.5 })),
|
||||
rotation: MyAvatar.orientation,
|
||||
modelURL: item.url,
|
||||
collisionless: true
|
||||
});
|
||||
}
|
||||
|
||||
if (item.type === "AVATAR") {
|
||||
MyAvatar.useFullAvatarURL(item.url);
|
||||
}
|
||||
|
||||
if (item.type === "PLACE") {
|
||||
location.handleLookupString(item.url, true);
|
||||
}
|
||||
|
||||
if (item.type === "JSON") {
|
||||
var jsonToLoad = item.url;
|
||||
if (jsonToLoad) {
|
||||
if (Clipboard.importEntities(jsonToLoad)) {
|
||||
Clipboard.pasteEntities(
|
||||
Vec3.sum(
|
||||
MyAvatar.position,
|
||||
Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1.5 })
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item.type === "UNKNOWN") {
|
||||
// We don't know how to handle this yet.
|
||||
Window.alert("Unknown item type, unable to use.");
|
||||
}
|
||||
}
|
||||
|
||||
function shareItem(data) {
|
||||
data.command = "share-item";
|
||||
sendMessage(data);
|
||||
}
|
||||
|
||||
function initializeInventoryApp() {
|
||||
sendSettings();
|
||||
sendInventory();
|
||||
sendReceivingItemQueue();
|
||||
}
|
||||
|
||||
function onOpened() {
|
||||
}
|
||||
|
||||
function onClosed() {
|
||||
}
|
||||
|
||||
function startup() {
|
||||
|
||||
loadInventory();
|
||||
loadSettings();
|
||||
|
||||
Messages.messageReceived.connect(onMessageReceived);
|
||||
Messages.subscribe(inventoryMessagesChannel);
|
||||
|
||||
ui = new AppUi({
|
||||
buttonName: "INVENTORY",
|
||||
home: Script.resolvePath("index.html"),
|
||||
graphicsDirectory: Script.resolvePath("./"), // Where your button icons are located
|
||||
onOpened: onOpened,
|
||||
onClosed: onClosed
|
||||
});
|
||||
}
|
||||
|
||||
startup();
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
Messages.messageReceived.disconnect(onMessageReceived);
|
||||
Messages.unsubscribe(inventoryMessagesChannel);
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
12932
scripts/system/inventory/package-lock.json
generated
|
@ -1,52 +0,0 @@
|
|||
{
|
||||
"name": "Inventory",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdi/font": "^4.9.95",
|
||||
"core-js": "^3.6.5",
|
||||
"vue": "^2.6.11",
|
||||
"vuedraggable": "^2.24.0",
|
||||
"vuetify": "^2.3.4",
|
||||
"vuex": "^3.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.3.1",
|
||||
"@vue/cli-plugin-eslint": "^4.3.1",
|
||||
"@vue/cli-service": "^4.3.1",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"sass": "^1.26.10",
|
||||
"sass-loader": "^8.0.0",
|
||||
"vue-cli-plugin-vuetify": "^2.0.7",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vuetify-loader": "^1.6.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
},
|
||||
"rules": {}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not dead",
|
||||
"ChromeAndroid > 55",
|
||||
"Chrome > 55"
|
||||
]
|
||||
}
|
Before Width: | Height: | Size: 4.2 KiB |
|
@ -1,30 +0,0 @@
|
|||
<!--
|
||||
//
|
||||
// index.html
|
||||
//
|
||||
// Created by kasenvr@gmail.com on 7 Apr 2020
|
||||
// Copyright 2020 Vircadia and contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="#0c0" d="M17,14H19V17H22V19H19V22H17V19H14V17H17V14M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V13.53C20.94,12.58 19.54,12 18,12A6,6 0 0,0 12,18C12,19.09 12.29,20.12 12.8,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" /></svg>
|
Before Width: | Height: | Size: 552 B |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16.5,12C19,12 21,14 21,16.5C21,17.38 20.75,18.21 20.31,18.9L23.39,22L22,23.39L18.88,20.32C18.19,20.75 17.37,21 16.5,21C14,21 12,19 12,16.5C12,14 14,12 16.5,12M16.5,14A2.5,2.5 0 0,0 14,16.5A2.5,2.5 0 0,0 16.5,19A2.5,2.5 0 0,0 19,16.5A2.5,2.5 0 0,0 16.5,14M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V13.03C20.85,11.21 18.82,10 16.5,10A6.5,6.5 0 0,0 10,16.5C10,18.25 10.69,19.83 11.81,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" /></svg>
|
Before Width: | Height: | Size: 761 B |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="#0f0" d="M17,14H19V17H22V19H19V22H17V19H14V17H17V14M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V13.53C20.94,12.58 19.54,12 18,12A6,6 0 0,0 12,18C12,19.09 12.29,20.12 12.8,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" /></svg>
|
Before Width: | Height: | Size: 552 B |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path fill="white" d="M16.5,12C19,12 21,14 21,16.5C21,17.38 20.75,18.21 20.31,18.9L23.39,22L22,23.39L18.88,20.32C18.19,20.75 17.37,21 16.5,21C14,21 12,19 12,16.5C12,14 14,12 16.5,12M16.5,14A2.5,2.5 0 0,0 14,16.5A2.5,2.5 0 0,0 16.5,19A2.5,2.5 0 0,0 19,16.5A2.5,2.5 0 0,0 16.5,14M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V13.03C20.85,11.21 18.82,10 16.5,10A6.5,6.5 0 0,0 10,16.5C10,18.25 10.69,19.83 11.81,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" /></svg>
|
Before Width: | Height: | Size: 775 B |
|
@ -1,299 +0,0 @@
|
|||
//
|
||||
// inventory.js
|
||||
//
|
||||
// Created by kasenvr@gmail.com on 2 Apr 2020
|
||||
// Copyright 2020 Vircadia and contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* global AvatarList Clipboard console Controller Entities location Messages MyAvatar Script ScriptDiscoveryService Settings
|
||||
Tablet Vec3 Window */
|
||||
|
||||
(function () { // BEGIN LOCAL_SCOPE
|
||||
"use strict";
|
||||
var AppUi = Script.require('appUi');
|
||||
var ui;
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
||||
// VARIABLES
|
||||
var inventoryDataSettingString = "inventoryApp.data";
|
||||
var inventoryData;
|
||||
|
||||
var inventorySettingsString = "inventoryApp.settings";
|
||||
var inventorySettings;
|
||||
|
||||
var RECEIVING_ITEM_QUEUE_LIMIT = 5;
|
||||
var receivingItemQueue = [];
|
||||
|
||||
var NEARBY_USERS_SEARCH_RADIUS = 25;
|
||||
|
||||
|
||||
// APP EVENT AND MESSAGING ROUTING
|
||||
|
||||
function onWebAppEventReceived(event) {
|
||||
var eventJSON = JSON.parse(event);
|
||||
if (eventJSON.app === "inventory") { // This is our web app!
|
||||
// print("inventory.js received a web event: " + event);
|
||||
|
||||
if (eventJSON.command === "ready") {
|
||||
initializeInventoryApp();
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-inventory") {
|
||||
receiveInventory(eventJSON.data);
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-settings") {
|
||||
receiveSettings(eventJSON.data);
|
||||
}
|
||||
|
||||
if (eventJSON.command === "use-item") {
|
||||
useItem(eventJSON.data);
|
||||
}
|
||||
|
||||
if (eventJSON.command === "share-item") {
|
||||
shareItem(eventJSON.data);
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-request-nearby-users") {
|
||||
sendNearbyUsers();
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-request-receiving-item-queue") {
|
||||
sendReceivingItemQueue();
|
||||
}
|
||||
|
||||
if (eventJSON.command === "web-to-script-update-receiving-item-queue") {
|
||||
updateReceivingItemQueue(eventJSON.data);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
tablet.webEventReceived.connect(onWebAppEventReceived);
|
||||
|
||||
function sendToWeb(command, data) {
|
||||
var dataToSend = {
|
||||
"app": "inventory",
|
||||
"command": command,
|
||||
"data": data
|
||||
};
|
||||
|
||||
tablet.emitScriptEvent(JSON.stringify(dataToSend));
|
||||
}
|
||||
|
||||
var inventoryMessagesChannel = "com.vircadia.inventory";
|
||||
|
||||
function onMessageReceived(channel, message, sender, localOnly) {
|
||||
if (channel === inventoryMessagesChannel) {
|
||||
var messageJSON = JSON.parse(message);
|
||||
// Window.alert("Passed 0 " + messageJSON.recipient + " vs " + MyAvatar.sessionUUID);
|
||||
if (messageJSON.command === "share-item"
|
||||
&& messageJSON.recipient === MyAvatar.sessionUUID) { // We are receiving an item.
|
||||
// Window.alert("Passed 1 " + messageJSON.recipient + " vs " + MyAvatar.sessionUUID);
|
||||
pushReceivedItemToQueue(sender, messageJSON.type, messageJSON.name, messageJSON.url);
|
||||
}
|
||||
}
|
||||
// print("Message received:");
|
||||
// print("- channel: " + channel);
|
||||
// print("- message: " + message);
|
||||
// print("- sender: " + sender);
|
||||
// print("- localOnly: " + localOnly);
|
||||
}
|
||||
|
||||
function sendMessage(dataToSend) {
|
||||
Messages.sendMessage(inventoryMessagesChannel, JSON.stringify(dataToSend));
|
||||
}
|
||||
|
||||
// END APP EVENT AND MESSAGING ROUTING
|
||||
|
||||
// SEND AND RECEIVE INVENTORY STATE
|
||||
|
||||
function receiveInventory(receivedInventoryData) {
|
||||
inventoryData = receivedInventoryData;
|
||||
saveInventory();
|
||||
}
|
||||
|
||||
function sendInventory() {
|
||||
sendToWeb("script-to-web-inventory", inventoryData);
|
||||
}
|
||||
|
||||
// END SEND AND RECEIVE INVENTORY STATE
|
||||
|
||||
// SEND AND RECEIVE SETTINGS STATE
|
||||
|
||||
function receiveSettings(receivedSettingsData) {
|
||||
inventorySettings = receivedSettingsData;
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
function sendSettings() {
|
||||
sendToWeb("script-to-web-settings", inventorySettings);
|
||||
}
|
||||
|
||||
// END SEND AND RECEIVE SETTINGS STATE
|
||||
|
||||
function saveInventory() {
|
||||
Settings.setValue(inventoryDataSettingString, inventoryData);
|
||||
}
|
||||
|
||||
function loadInventory() {
|
||||
inventoryData = Settings.getValue(inventoryDataSettingString);
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
Settings.setValue(inventorySettingsString, inventorySettings);
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
inventorySettings = Settings.getValue(inventorySettingsString);
|
||||
}
|
||||
|
||||
function pushReceivedItemToQueue(senderUUID, type, name, url) {
|
||||
console.info("Receiving an item:", name, "from:", senderUUID);
|
||||
var getAvatarData = AvatarList.getAvatar(senderUUID);
|
||||
var senderName = getAvatarData.sessionDisplayName;
|
||||
var senderDistance = Vec3.distance(MyAvatar.position, getAvatarData.position);
|
||||
|
||||
var packageRequest = {
|
||||
"senderUUID": senderUUID,
|
||||
"senderName": senderName,
|
||||
"senderDistance": senderDistance,
|
||||
"data": {
|
||||
"type": type,
|
||||
"name": name,
|
||||
"url": url
|
||||
}
|
||||
};
|
||||
|
||||
if (receivingItemQueue.length === RECEIVING_ITEM_QUEUE_LIMIT) {
|
||||
receivingItemQueue = receivingItemQueue.slice(1, RECEIVING_ITEM_QUEUE_LIMIT);
|
||||
}
|
||||
|
||||
receivingItemQueue.push(packageRequest);
|
||||
ui.messagesWaiting(receivingItemQueue.length > 0);
|
||||
}
|
||||
|
||||
function sendReceivingItemQueue() {
|
||||
sendToWeb("script-to-web-receiving-item-queue", receivingItemQueue);
|
||||
}
|
||||
|
||||
function updateReceivingItemQueue(data) {
|
||||
receivingItemQueue = data;
|
||||
ui.messagesWaiting(receivingItemQueue.length > 0);
|
||||
}
|
||||
|
||||
function sendNearbyUsers() {
|
||||
var nearbyUsers = AvatarList.getAvatarsInRange(MyAvatar.position, NEARBY_USERS_SEARCH_RADIUS);
|
||||
var nearbyUsersToSend = [];
|
||||
|
||||
nearbyUsers.forEach(function(user) {
|
||||
var objectToWrite;
|
||||
var aviDetails = AvatarList.getAvatar(user);
|
||||
var aviName = aviDetails.displayName;
|
||||
var aviDistance = Vec3.distance(MyAvatar.position, aviDetails.position);
|
||||
// Window.alert("aviName" + aviName + "user" + user + "MyAvatar.sessionUUID" + MyAvatar.sessionUUID);
|
||||
if (user !== MyAvatar.sessionUUID
|
||||
|| Controller.getValue(Controller.Hardware.Keyboard.Shift)) { // Don't add ourselves to the list!
|
||||
objectToWrite = { "name": aviName, "distance": aviDistance, "uuid": user };
|
||||
nearbyUsersToSend.push(objectToWrite);
|
||||
}
|
||||
});
|
||||
|
||||
sendToWeb("script-to-web-nearby-users", nearbyUsersToSend);
|
||||
}
|
||||
|
||||
function useItem(item) {
|
||||
|
||||
//TODO: Add animation support for avatars...?
|
||||
|
||||
// Convert the item.type before checking it...
|
||||
item.type = item.type.toUpperCase();
|
||||
|
||||
// Depending on the type, we decide how to load this item.
|
||||
if (item.type === "SCRIPT") {
|
||||
ScriptDiscoveryService.loadScript(item.url, true, false, false, true, false);
|
||||
}
|
||||
|
||||
if (item.type === "MODEL") {
|
||||
Entities.addEntity({
|
||||
type: "Model",
|
||||
position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1.5 })),
|
||||
rotation: MyAvatar.orientation,
|
||||
modelURL: item.url,
|
||||
collisionless: true
|
||||
});
|
||||
}
|
||||
|
||||
if (item.type === "AVATAR") {
|
||||
MyAvatar.useFullAvatarURL(item.url);
|
||||
}
|
||||
|
||||
if (item.type === "PLACE") {
|
||||
location.handleLookupString(item.url, true);
|
||||
}
|
||||
|
||||
if (item.type === "JSON") {
|
||||
var jsonToLoad = item.url;
|
||||
if (jsonToLoad) {
|
||||
if (Clipboard.importEntities(jsonToLoad)) {
|
||||
Clipboard.pasteEntities(
|
||||
Vec3.sum(
|
||||
MyAvatar.position,
|
||||
Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1.5 })
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item.type === "UNKNOWN") {
|
||||
// We don't know how to handle this yet.
|
||||
Window.alert("Unknown item type, unable to use.");
|
||||
}
|
||||
}
|
||||
|
||||
function shareItem(data) {
|
||||
data.command = "share-item";
|
||||
sendMessage(data);
|
||||
}
|
||||
|
||||
function initializeInventoryApp() {
|
||||
sendSettings();
|
||||
sendInventory();
|
||||
sendReceivingItemQueue();
|
||||
}
|
||||
|
||||
function onOpened() {
|
||||
}
|
||||
|
||||
function onClosed() {
|
||||
}
|
||||
|
||||
function startup() {
|
||||
|
||||
loadInventory();
|
||||
loadSettings();
|
||||
|
||||
Messages.messageReceived.connect(onMessageReceived);
|
||||
Messages.subscribe(inventoryMessagesChannel);
|
||||
|
||||
ui = new AppUi({
|
||||
buttonName: "INVENTORY",
|
||||
home: Script.resolvePath("index.html"),
|
||||
graphicsDirectory: Script.resolvePath("./"), // Where your button icons are located
|
||||
onOpened: onOpened,
|
||||
onClosed: onClosed
|
||||
});
|
||||
}
|
||||
|
||||
startup();
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
Messages.messageReceived.disconnect(onMessageReceived);
|
||||
Messages.unsubscribe(inventoryMessagesChannel);
|
||||
});
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
Before Width: | Height: | Size: 6.7 KiB |
|
@ -1 +0,0 @@
|
|||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>
|
Before Width: | Height: | Size: 539 B |
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
styles.css
|
||||
|
||||
Created by Kalila L. on 7 Apr 2020
|
||||
Copyright 2020 Vircadia and contributors.
|
||||
|
||||
Distributed under the Apache License, Version 2.0.
|
||||
See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
|
||||
/* Top Level */
|
||||
|
||||
.draggable-card {
|
||||
background-color: rgba(39, 39, 39, 1.0);
|
||||
margin: 5px 0px;
|
||||
}
|
||||
|
||||
.draggable-card .handle {
|
||||
width: 40px !important;
|
||||
}
|
||||
|
||||
.top-level-folder {
|
||||
background-color: rgba(39, 39, 39, 1.0);
|
||||
}
|
||||
|
||||
.top-level-folder .v-list-group__header__prepend-icon {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 5px 5px 7px 0px !important;
|
||||
padding: 5px 18px 5px 8px;
|
||||
}
|
||||
|
||||
.top-level-folder .handle {
|
||||
width: 40px !important;
|
||||
}
|
||||
|
||||
.top-level-folder .folder-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.top-level-folder .folder-button {
|
||||
font-size: 0.795rem !important;
|
||||
}
|
||||
|
||||
/* Second Level */
|
||||
|
||||
.v-list-group .column-item {
|
||||
max-width: 100% !important;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.v-list-group .draggable-card {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
padding-right: 16px;
|
||||
padding-left: 0px !important;
|
||||
}
|
||||
|
||||
.v-list-group .draggable-card .handle {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
/* Menu Slideout */
|
||||
|
||||
.app-version {
|
||||
text-align: center;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
/* Universal */
|
||||
|
||||
.handle {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.inventoryApp::-webkit-scrollbar { width: 0 !important }
|
|
@ -1,391 +0,0 @@
|
|||
<!--
|
||||
// ItemIterator.vue
|
||||
//
|
||||
// Created by Kalila L. on 13 April 2020.
|
||||
// Copyright 2020 Vircadia and contributors..
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<template>
|
||||
<draggable :group="options" :list="itemsForIterator" handle=".handle">
|
||||
<v-item-group
|
||||
v-for="item in itemsForIterator"
|
||||
v-bind:key="item.uuid"
|
||||
>
|
||||
<v-list-item
|
||||
one-line
|
||||
v-if="!item.items"
|
||||
class="mx-auto draggable-card"
|
||||
max-width="344"
|
||||
outlined
|
||||
>
|
||||
<div class="handle pa-2">
|
||||
<!-- <v-icon color="orange darken-2">mdi-blur-linear</v-icon> -->
|
||||
<!-- <v-icon color="orange darken-2">mdi-package-variant</v-icon> -->
|
||||
<v-icon color="orange darken-2">mdi-square-medium-outline</v-icon>
|
||||
</div>
|
||||
<v-list-item-content
|
||||
class="pb-1 pt-2 pl-4"
|
||||
>
|
||||
<div v-show="settings.displayDensity.size > 0" class="overline" style="font-size: 0.825rem !important;">{{item.type}}</div>
|
||||
<v-list-item-title class="subtitle-1 mb-1">{{item.name}}</v-list-item-title>
|
||||
<v-list-item-subtitle v-show="settings.displayDensity.size == 2">{{item.url}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-menu bottom left>
|
||||
<template v-slot:activator="{ on }">
|
||||
<!-- settings.displayDensity.size >= 1 -->
|
||||
<v-btn
|
||||
:style="{backgroundColor: (getIconColor(item.type)) }"
|
||||
v-show="settings.displayDensity.size >= 1"
|
||||
medium
|
||||
fab
|
||||
dark
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>{{getIcon(item.type)}}</v-icon>
|
||||
</v-btn>
|
||||
<!-- settings.displayDensity.size < 1 -->
|
||||
<v-btn
|
||||
:style="{backgroundColor: (getIconColor(item.type)) }"
|
||||
v-show="settings.displayDensity.size < 1"
|
||||
small
|
||||
fab
|
||||
dark
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>{{getIcon(item.type)}}</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list color="grey darken-3">
|
||||
<v-list-item
|
||||
@click="sendEvent('use-item', { 'type': item.type, 'url': item.url })"
|
||||
>
|
||||
<v-list-item-title>Use</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-play</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
@click="
|
||||
editDialogStore.show = true;
|
||||
editDialogStore.uuid = item.uuid;
|
||||
editDialogStore.data.type = item.type.toUpperCase();
|
||||
editDialogStore.data.folder = null;
|
||||
editDialogStore.data.name = item.name;
|
||||
editDialogStore.data.url = item.url;
|
||||
"
|
||||
>
|
||||
<v-list-item-title>Edit</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
@click="
|
||||
shareDialogStore.show = true;
|
||||
shareDialogStore.data.url = item.url;
|
||||
shareDialogStore.data.uuid = item.uuid;
|
||||
"
|
||||
>
|
||||
<v-list-item-title>Share</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-share</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
@click="
|
||||
removeDialogStore.show = true;
|
||||
removeDialogStore.uuid = item.uuid;
|
||||
"
|
||||
color="red darken-1"
|
||||
>
|
||||
<v-list-item-title>Remove</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-minus</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
</v-list-item>
|
||||
|
||||
|
||||
<!-- The Folder List Item -->
|
||||
<v-list-group
|
||||
v-else
|
||||
class="top-level-folder"
|
||||
>
|
||||
<!-- prepend-icon="mdi-blur-linear" put this in the list group, no idea how to make it a handle yet though... -->
|
||||
<template v-slot:activator>
|
||||
<v-list-item
|
||||
one-line
|
||||
class="mx-auto"
|
||||
max-width="344"
|
||||
outlined
|
||||
>
|
||||
<v-icon class="folder-icon" color="teal">mdi-folder-settings</v-icon>
|
||||
{{item.name}}
|
||||
</v-list-item>
|
||||
</template>
|
||||
<div class="text-center my-2">
|
||||
<v-btn medium tile color="purple" class="mx-1 folder-button"
|
||||
@click="
|
||||
editFolderDialogStore.data.uuid = item.uuid;
|
||||
editFolderDialogStore.data.name = item.name;
|
||||
editFolderDialogStore.show = true;
|
||||
"
|
||||
>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
<v-btn medium tile color="red" class="mx-1 folder-button"
|
||||
@click="
|
||||
removeFolderDialogStore.show = true;
|
||||
removeFolderDialogStore.uuid = item.uuid;
|
||||
"
|
||||
>
|
||||
<v-icon>mdi-minus</v-icon>
|
||||
</v-btn>
|
||||
|
||||
<v-menu bottom left>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-btn
|
||||
medium tile
|
||||
color="blue"
|
||||
class="mx-1 folder-button"
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>mdi-sort</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list color="grey darken-3">
|
||||
<v-list-item
|
||||
@click="sortFolder(item.uuid, 'az');"
|
||||
>
|
||||
<v-list-item-title>A-Z</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon large>mdi-sort-alphabetical-ascending</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
@click="sortFolder(item.uuid, 'za');"
|
||||
>
|
||||
<v-list-item-title>Z-A</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon large>mdi-sort-alphabetical-descending</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</div>
|
||||
|
||||
<v-container fluid>
|
||||
<itemiterator v-bind:key="item.uuid" :itemsForIterator="item.items"></itemiterator>
|
||||
</v-container>
|
||||
|
||||
</v-list-group>
|
||||
</v-item-group>
|
||||
</draggable>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
import { EventBus } from '../plugins/event-bus.js';
|
||||
import draggable from 'vuedraggable';
|
||||
|
||||
export default {
|
||||
name: 'itemiterator',
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
props: ['itemsForIterator'],
|
||||
data: () => ({
|
||||
settings: {}
|
||||
}),
|
||||
created: function () {
|
||||
this.settings = this.$store.state.settings;
|
||||
},
|
||||
computed: {
|
||||
options : function (){
|
||||
return {
|
||||
name: 'column-item',
|
||||
pull: true,
|
||||
put: true
|
||||
}
|
||||
},
|
||||
settingsChanged() {
|
||||
return this.$store.state.settings;
|
||||
},
|
||||
addDialogStore: {
|
||||
get() {
|
||||
return this.$store.state.addDialog;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('mutate', {
|
||||
property: 'addDialog',
|
||||
with: value
|
||||
});
|
||||
}
|
||||
},
|
||||
editDialogStore: {
|
||||
get() {
|
||||
return this.$store.state.editDialog;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('mutate', {
|
||||
property: 'editDialog',
|
||||
with: value
|
||||
});
|
||||
}
|
||||
},
|
||||
editFolderDialogStore: {
|
||||
get() {
|
||||
return this.$store.state.editFolderDialog;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('mutate', {
|
||||
property: 'editFolderDialog',
|
||||
with: value
|
||||
});
|
||||
}
|
||||
},
|
||||
shareDialogStore: {
|
||||
get() {
|
||||
return this.$store.state.shareDialog;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('mutate', {
|
||||
property: 'shareDialog',
|
||||
with: value
|
||||
});
|
||||
}
|
||||
},
|
||||
removeFolderDialogStore: {
|
||||
get() {
|
||||
return this.$store.state.removeFolderDialog;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('mutate', {
|
||||
property: 'removeFolderDialog',
|
||||
with: value
|
||||
});
|
||||
}
|
||||
},
|
||||
removeDialogStore: {
|
||||
get() {
|
||||
return this.$store.state.removeDialog;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit('mutate', {
|
||||
property: 'removeDialog',
|
||||
with: value
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
settingsChanged (newVal, oldVal) {
|
||||
console.info ("Settings previous value:", oldVal);
|
||||
if (newVal) {
|
||||
this.settings = newVal;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
sendEvent: function(command, data) {
|
||||
EventBus.$emit(command, data);
|
||||
},
|
||||
getIcon: function(itemType) {
|
||||
itemType = itemType.toUpperCase();
|
||||
var returnedItemIcon;
|
||||
|
||||
if (this.$store.state.iconType[itemType]) {
|
||||
returnedItemIcon = this.$store.state.iconType[itemType].icon;
|
||||
} else {
|
||||
returnedItemIcon = this.$store.state.iconType.UNKNOWN.icon;
|
||||
}
|
||||
|
||||
return returnedItemIcon;
|
||||
},
|
||||
getIconColor: function(itemType) {
|
||||
itemType = itemType.toUpperCase();
|
||||
var returnedItemIconColor;
|
||||
|
||||
if (this.$store.state.iconType[itemType]) {
|
||||
returnedItemIconColor = this.$store.state.iconType[itemType].color;
|
||||
} else {
|
||||
returnedItemIconColor = this.$store.state.iconType.UNKNOWN.color;
|
||||
}
|
||||
|
||||
return returnedItemIconColor;
|
||||
},
|
||||
sortFolder: function(uuid, sort) {
|
||||
var findFolder = this.searchForItem(uuid);
|
||||
|
||||
if (findFolder) {
|
||||
if (sort === "az") {
|
||||
findFolder.returnedItem.items.sort(function(a, b) {
|
||||
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
|
||||
if (nameA < nameB) {
|
||||
return -1;
|
||||
}
|
||||
if (nameA > nameB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// names must be equal
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
if (sort === "za") {
|
||||
findFolder.returnedItem.items.sort(function(a, b) {
|
||||
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
|
||||
if (nameA > nameB) {
|
||||
return -1;
|
||||
}
|
||||
if (nameA < nameB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// names must be equal
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
searchForItem: function(uuid) {
|
||||
var foundItem = this.recursiveSingularSearch(uuid, this.itemsForIterator);
|
||||
|
||||
if (foundItem) {
|
||||
return {
|
||||
"returnedItem": foundItem.returnedItem,
|
||||
"iteration": foundItem.iteration,
|
||||
"parentArray": foundItem.parentArray,
|
||||
"itemUUID": uuid,
|
||||
}
|
||||
}
|
||||
},
|
||||
recursiveSingularSearch: function(uuid, indexToSearch) {
|
||||
for (var i = 0; i < indexToSearch.length; i++) {
|
||||
if (indexToSearch[i].uuid == uuid) {
|
||||
var foundItem = {
|
||||
"returnedItem": indexToSearch[i],
|
||||
"iteration": i,
|
||||
"parentArray": indexToSearch,
|
||||
}
|
||||
return foundItem;
|
||||
} else if (Object.prototype.hasOwnProperty.call(indexToSearch[i], "items") && indexToSearch[i].items.length > 0) {
|
||||
return this.recursiveSingularSearch(uuid, indexToSearch[i].items);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -1,272 +0,0 @@
|
|||
<!--
|
||||
NotUsing.vue
|
||||
|
||||
Created by Kalila L. on 7 Apr 2020
|
||||
Copyright 2020 Vircadia and contributors.
|
||||
|
||||
Distributed under the Apache License, Version 2.0.
|
||||
See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
-->
|
||||
|
||||
<template v-if="!disabledProp">
|
||||
<v-data-iterator
|
||||
:items="items"
|
||||
hide-default-footer
|
||||
>
|
||||
<template>
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
md="4"
|
||||
lg="3"
|
||||
class="py-1 column-item"
|
||||
>
|
||||
<draggable :group="options" :list="items" handle=".handle">
|
||||
<v-item-group
|
||||
v-for="item in items"
|
||||
v-bind:key="item.uuid"
|
||||
>
|
||||
<v-list-item
|
||||
one-line
|
||||
v-if="!item.hasChildren"
|
||||
class="mx-auto draggable-card"
|
||||
max-width="344"
|
||||
outlined
|
||||
>
|
||||
<div class="handle pa-2">
|
||||
<v-icon color="orange darken-2">mdi-blur-linear</v-icon>
|
||||
</div>
|
||||
<v-list-item-content
|
||||
class="pb-1 pt-2 pl-4"
|
||||
>
|
||||
<div v-show="settings.displayDensity.size > 0" class="overline" style="font-size: 0.825rem !important;">{{item.type}}</div>
|
||||
<v-list-item-title class="subtitle-1 mb-1">{{item.name}}</v-list-item-title>
|
||||
<v-list-item-subtitle v-show="settings.displayDensity.size == 2">{{item.url}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-menu bottom left>
|
||||
<template v-slot:activator="{ on }">
|
||||
<!-- settings.displayDensity.size >= 1 -->
|
||||
<v-btn
|
||||
:style="{backgroundColor: (getIconColor(item.type)) }"
|
||||
v-show="settings.displayDensity.size >= 1"
|
||||
medium
|
||||
fab
|
||||
dark
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>{{getIcon(item.type)}}</v-icon>
|
||||
</v-btn>
|
||||
<!-- settings.displayDensity.size < 1 -->
|
||||
<v-btn
|
||||
:style="{backgroundColor: (getIconColor(item.type)) }"
|
||||
v-show="settings.displayDensity.size < 1"
|
||||
small
|
||||
fab
|
||||
dark
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>{{getIcon(item.type)}}</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list color="grey darken-3">
|
||||
<v-list-item
|
||||
@click="useItem(item.type, item.url)"
|
||||
>
|
||||
<v-list-item-title>Use</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-play</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
@click="
|
||||
editDialog.show = true;
|
||||
editDialog.uuid = item.uuid;
|
||||
editDialog.data.type = item.type.toUpperCase();
|
||||
editDialog.data.folder = null;
|
||||
editDialog.data.name = item.name;
|
||||
editDialog.data.url = item.url;
|
||||
getFolderList('edit');
|
||||
"
|
||||
>
|
||||
<v-list-item-title>Edit</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
@click="shareDialog.show = true; shareDialog.data.url = item.url; shareDialog.data.uuid = item.uuid; sendAppMessage('web-to-script-request-nearby-users', '')"
|
||||
>
|
||||
<v-list-item-title>Share</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-share</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
@click="removeDialog.show = true; removeDialog.uuid = item.uuid;"
|
||||
color="red darken-1"
|
||||
>
|
||||
<v-list-item-title>Remove</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-minus</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
</v-list-item>
|
||||
|
||||
|
||||
<!-- The Folder List Item -->
|
||||
<v-list-group
|
||||
v-if="item.hasChildren"
|
||||
class="top-level-folder"
|
||||
>
|
||||
<!-- prepend-icon="mdi-blur-linear" put this in the list group, no idea how to make it a handle yet though... -->
|
||||
<template v-slot:activator>
|
||||
<v-list-item
|
||||
one-line
|
||||
class="mx-auto"
|
||||
max-width="344"
|
||||
outlined
|
||||
>
|
||||
<v-icon class="folder-icon" color="teal">mdi-folder-settings</v-icon>
|
||||
{{item.name}}
|
||||
</v-list-item>
|
||||
</template>
|
||||
<div class="text-center my-2">
|
||||
<v-btn medium tile color="purple" class="mx-1 folder-button"
|
||||
@click="
|
||||
editFolderDialog.show = true;
|
||||
editFolderDialog.uuid = item.uuid;
|
||||
editFolderDialog.data.name = item.name;
|
||||
"
|
||||
>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
<v-btn medium tile color="red" class="mx-1 folder-button"
|
||||
@click="removeFolderDialog.show = true; removeFolderDialog.uuid = item.uuid;"
|
||||
>
|
||||
<v-icon>mdi-minus</v-icon>
|
||||
</v-btn>
|
||||
<v-btn medium tile color="blue" class="mx-1 folder-button"
|
||||
@click="sortFolder(item.uuid);"
|
||||
>
|
||||
<v-icon>mdi-ab-testing</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
md="4"
|
||||
lg="3"
|
||||
class="py-1 column-item"
|
||||
>
|
||||
<draggable
|
||||
:list="item.items"
|
||||
:group="options"
|
||||
>
|
||||
<v-item-group
|
||||
v-for="item in item.items"
|
||||
v-bind:key="item.uuid"
|
||||
>
|
||||
<v-list-item
|
||||
one-line
|
||||
class="mx-auto draggable-card"
|
||||
outlined
|
||||
>
|
||||
<div class="handle pa-2">
|
||||
<v-icon color="orange darken-2">mdi-blur-linear</v-icon>
|
||||
</div>
|
||||
<v-list-item-content class="pb-1 pt-2">
|
||||
<div v-show="settings.displayDensity.size > 0" class="overline" style="font-size: 0.825rem !important;">{{item.type}}</div>
|
||||
<v-list-item-title class="subtitle-1 mb-1">{{item.name}}</v-list-item-title>
|
||||
<v-list-item-subtitle v-show="settings.displayDensity.size == 2">{{item.url}}</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
|
||||
<v-menu bottom left>
|
||||
<template v-slot:activator="{ on }">
|
||||
<!-- settings.displayDensity.size >= 1 -->
|
||||
<v-btn
|
||||
:style="{backgroundColor: (getIconColor(item.type)) }"
|
||||
v-show="settings.displayDensity.size >= 1"
|
||||
medium
|
||||
fab
|
||||
dark
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>{{getIcon(item.type)}}</v-icon>
|
||||
</v-btn>
|
||||
<!-- settings.displayDensity.size < 1 -->
|
||||
<v-btn
|
||||
:style="{backgroundColor: (getIconColor(item.type)) }"
|
||||
v-show="settings.displayDensity.size < 1"
|
||||
small
|
||||
fab
|
||||
dark
|
||||
v-on="on"
|
||||
>
|
||||
<v-icon>{{getIcon(item.type)}}</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list color="grey darken-3">
|
||||
|
||||
<v-list-item
|
||||
@click="useItem(item.type, item.url)"
|
||||
>
|
||||
<v-list-item-title>Use</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-play</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
@click="
|
||||
editDialog.show = true;
|
||||
editDialog.uuid = item.uuid;
|
||||
editDialog.data.type = item.type.toUpperCase();
|
||||
editDialog.data.folder = null;
|
||||
editDialog.data.name = item.name;
|
||||
editDialog.data.url = item.url;
|
||||
getFolderList('edit');
|
||||
"
|
||||
>
|
||||
<v-list-item-title>Edit</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
@click="shareDialog.show = true; shareDialog.data.url = item.url; shareDialog.data.uuid = item.uuid; sendAppMessage('web-to-script-request-nearby-users', '')"
|
||||
>
|
||||
<v-list-item-title>Share</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-share</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
@click="removeDialog.show = true; removeDialog.uuid = item.uuid;"
|
||||
color="red darken-1"
|
||||
>
|
||||
<v-list-item-title>Remove</v-list-item-title>
|
||||
<v-list-item-action>
|
||||
<v-icon>mdi-minus</v-icon>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-list-item>
|
||||
</v-item-group>
|
||||
</draggable>
|
||||
</v-col>
|
||||
</v-list-group>
|
||||
</v-item-group>
|
||||
</draggable>
|
||||
</v-col>
|
||||
</template>
|
||||
</v-data-iterator>
|
||||
</template>
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
main.js
|
||||
|
||||
Created by Kalila L. on 7 Apr 2020
|
||||
Copyright 2020 Vircadia and contributors.
|
||||
|
||||
Distributed under the Apache License, Version 2.0.
|
||||
See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import vuetify from './plugins/vuetify';
|
||||
import { store } from './plugins/store';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
window.vm = new Vue({
|
||||
vuetify,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app');
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
event-bus.js
|
||||
|
||||
Created by Kalila L. on 21 May 2020.
|
||||
Copyright 2020 Vircadia and contributors.
|
||||
|
||||
Distributed under the Apache License, Version 2.0.
|
||||
See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
|
||||
import Vue from 'vue';
|
||||
export const EventBus = new Vue();
|
|
@ -1,321 +0,0 @@
|
|||
/*
|
||||
store.js
|
||||
|
||||
Created by Kalila L. on 16 Apr 2020.
|
||||
Copyright 2020 Vircadia and contributors.
|
||||
|
||||
Distributed under the Apache License, Version 2.0.
|
||||
See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export const store = new Vuex.Store({
|
||||
devtools: true,
|
||||
state: {
|
||||
items: [
|
||||
// This is test data and is primarily used for in browser development.
|
||||
{
|
||||
"type": "script",
|
||||
"name": "VRGrabScale",
|
||||
"url": "https://gooawefaweawfgle.com/vr.js",
|
||||
"folder": "No Folder",
|
||||
"uuid": "54254354353"
|
||||
},
|
||||
{
|
||||
"name": "Test Folder",
|
||||
"folder": "No Folder",
|
||||
"items": [
|
||||
{
|
||||
"name": "inception1",
|
||||
"folder": "Test Folder",
|
||||
"items": [
|
||||
{
|
||||
"name": "inception2",
|
||||
"folder": "Test Folder",
|
||||
"items": [
|
||||
{
|
||||
"type": "script",
|
||||
"name": "itemincepted",
|
||||
"url": "https://googfdafsgaergale.com/vr.js",
|
||||
"folder": "FolderWithinAFolder",
|
||||
"uuid": "hkjkjhkjk",
|
||||
},
|
||||
],
|
||||
"uuid": "adsfa32"
|
||||
},
|
||||
],
|
||||
"uuid": "s4g4sg"
|
||||
},
|
||||
],
|
||||
"uuid": "sdfsdf",
|
||||
},
|
||||
{
|
||||
"type": "script",
|
||||
"name": "VRGrabScale",
|
||||
"url": "https://googfdafsgaergale.com/vr.js",
|
||||
"folder": "No Folder",
|
||||
"uuid": "54hgfhgf254354353",
|
||||
},
|
||||
{
|
||||
"type": "script",
|
||||
"name": "TEST",
|
||||
"url": "https://gooadfdagle.com/vr.js",
|
||||
"folder": "No Folder",
|
||||
"uuid": "542rfwat4t5fsddf4354353",
|
||||
},
|
||||
{
|
||||
"type": "json",
|
||||
"name": "TESTJSON",
|
||||
"url": "https://gooadfdagle.com/vr.json",
|
||||
"folder": "No Folder",
|
||||
"uuid": "542rfwat4t54354353",
|
||||
},
|
||||
{
|
||||
"type": "script",
|
||||
"name": "TESTLONGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",
|
||||
"url": "https://googfdaffle.com/vrLONGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.js",
|
||||
"folder": "No Folder",
|
||||
"uuid": "5425ggsrg45354353",
|
||||
},
|
||||
{
|
||||
"type": "whatttype",
|
||||
"name": "BrokenIcon",
|
||||
"url": "https://googfdaffle.com/vrLONGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.js",
|
||||
"folder": "No Folder",
|
||||
"uuid": "5425ggsrg4fdaffdff535asdasd4353",
|
||||
},
|
||||
{
|
||||
"type": "avatar",
|
||||
"name": "AVI",
|
||||
"url": "https://googlfadfe.com/vr.fst",
|
||||
"folder": "No Folder",
|
||||
"uuid": "542gregg45s3g4354353",
|
||||
},
|
||||
{
|
||||
"type": "avatar",
|
||||
"name": "AVI",
|
||||
"url": "https://googlefdaf.com/vr.fst",
|
||||
"folder": "No Folder",
|
||||
"uuid": "5420798-087-54354353",
|
||||
},
|
||||
{
|
||||
"type": "model",
|
||||
"name": "3D MODEL",
|
||||
"url": "https://googlee.com/vr.fbx",
|
||||
"folder": "No Folder",
|
||||
"uuid": "54254354980-7667jt353",
|
||||
},
|
||||
{
|
||||
"type": "place",
|
||||
"name": "PLACE DOMAIN",
|
||||
"url": "https://googleee.com/vr.fbx",
|
||||
"folder": "No Folder",
|
||||
"uuid": "542543sg45s4gg54353",
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
"displayDensity": {
|
||||
"size": 1,
|
||||
"labels": [
|
||||
"List",
|
||||
"Compact",
|
||||
"Large",
|
||||
],
|
||||
},
|
||||
},
|
||||
iconType: {
|
||||
"SCRIPT": {
|
||||
"icon": "mdi-code-tags",
|
||||
"color": "red",
|
||||
},
|
||||
"MODEL": {
|
||||
"icon": "mdi-video-3d",
|
||||
"color": "green",
|
||||
},
|
||||
"AVATAR": {
|
||||
"icon": "mdi-account-convert",
|
||||
"color": "purple",
|
||||
},
|
||||
"PLACE": {
|
||||
"icon": "mdi-earth",
|
||||
"color": "#0097A7", // cyan darken-2
|
||||
},
|
||||
"JSON": {
|
||||
"icon": "mdi-inbox-multiple",
|
||||
"color": "#37474F", // blue-grey darken-3
|
||||
},
|
||||
"UNKNOWN": {
|
||||
"icon": "mdi-help",
|
||||
"color": "grey",
|
||||
}
|
||||
},
|
||||
supportedItemTypes: [
|
||||
"SCRIPT",
|
||||
"MODEL",
|
||||
"AVATAR",
|
||||
"PLACE",
|
||||
"JSON",
|
||||
"UNKNOWN",
|
||||
],
|
||||
removeDialog: {
|
||||
show: false,
|
||||
uuid: null,
|
||||
},
|
||||
removeFolderDialog: {
|
||||
show: false,
|
||||
uuid: null,
|
||||
},
|
||||
createFolderDialog: {
|
||||
show: false,
|
||||
valid: false,
|
||||
data: {
|
||||
"name": null,
|
||||
},
|
||||
},
|
||||
addDialog: {
|
||||
show: false,
|
||||
valid: false,
|
||||
data: {
|
||||
"name": null,
|
||||
"folder": null,
|
||||
"url": null,
|
||||
},
|
||||
},
|
||||
editDialog: {
|
||||
show: false,
|
||||
valid: false,
|
||||
uuid: null, //
|
||||
data: {
|
||||
"type": null,
|
||||
"name": null,
|
||||
"url": null,
|
||||
"folder": null,
|
||||
},
|
||||
},
|
||||
editFolderDialog: {
|
||||
show: false,
|
||||
valid: false,
|
||||
uuid: null, //
|
||||
data: {
|
||||
"name": null,
|
||||
"folder": null,
|
||||
},
|
||||
},
|
||||
receiveDialog: {
|
||||
show: false,
|
||||
valid: false,
|
||||
data: {
|
||||
"userUUID": null,
|
||||
"userDisplayName": null,
|
||||
"name": null,
|
||||
"folder": null,
|
||||
"type": null,
|
||||
"url": null,
|
||||
},
|
||||
},
|
||||
shareDialog: {
|
||||
show: false,
|
||||
valid: false,
|
||||
data: {
|
||||
"uuid": null, // UUID of the item you want to share. THIS IS THE KEY.
|
||||
"url": null, // The item you want to share.
|
||||
"recipient": null,
|
||||
}
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
mutate (state, payload) {
|
||||
state[payload.property] = payload.with;
|
||||
// console.info("Payload:", payload.property, "with:", payload.with, "state is now:", this.state);
|
||||
},
|
||||
sortTopInventory (state, payload) {
|
||||
let { items } = state;
|
||||
|
||||
if (payload.sort === "az") {
|
||||
state.items.sort(function(a, b) {
|
||||
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
|
||||
if (nameA < nameB) {
|
||||
return -1;
|
||||
}
|
||||
if (nameA > nameB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// names must be equal
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (payload.sort === "za") {
|
||||
state.items.sort(function(a, b) {
|
||||
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
|
||||
if (nameA > nameB) {
|
||||
return -1;
|
||||
}
|
||||
if (nameA < nameB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// names must be equal
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
Vue.set(state,'items', items);
|
||||
},
|
||||
pushToItems (state, payload) {
|
||||
let { items } = state;
|
||||
items.push(payload);
|
||||
|
||||
Vue.set(state,'items', items);
|
||||
},
|
||||
moveFolder (state, payload) {
|
||||
let { items } = state;
|
||||
|
||||
if (payload.parentFolderUUID === "top") {
|
||||
payload.findFolder.returnedItem.folder = "No Folder";
|
||||
// console.info("Going to push...", payload.findFolder.returnedItem);
|
||||
// console.info("Containing these items...", payload.findFolder.returnedItem.items);
|
||||
|
||||
items.push(payload.findFolder.returnedItem);
|
||||
Vue.set(state, 'items', items);
|
||||
|
||||
} else if (payload.findParentFolder) {
|
||||
// console.info("Going to push...", payload.findFolder.returnedItem);
|
||||
// console.info("Containing these items...", payload.findFolder.returnedItem.items);
|
||||
// console.info("Into...", payload.findParentFolder.returnedItem);
|
||||
|
||||
payload.findFolder.returnedItem.folder = payload.findParentFolder.name;
|
||||
payload.findParentFolder.returnedItem.items.push(payload.findFolder.returnedItem);
|
||||
Vue.set(state,'items', items);
|
||||
}
|
||||
},
|
||||
moveItem (state, payload) {
|
||||
let { items } = state;
|
||||
|
||||
if (payload.parentFolderUUID === "top") {
|
||||
payload.findItem.returnedItem.folder = "No Folder";
|
||||
// console.info("Going to push...", payload.findFolder.returnedItem);
|
||||
// console.info("Containing these items...", payload.findFolder.returnedItem.items);
|
||||
|
||||
items.push(payload.findItem.returnedItem);
|
||||
Vue.set(state,'items', items);
|
||||
|
||||
} else if (payload.findParentFolder) {
|
||||
// console.info("Going to push...", payload.findFolder.returnedItem);
|
||||
// console.info("Containing these items...", payload.findFolder.returnedItem.items);
|
||||
// console.info("Into...", payload.findParentFolder.returnedItem);
|
||||
|
||||
payload.findItem.returnedItem.folder = payload.findParentFolder.name;
|
||||
payload.findParentFolder.returnedItem.items.push(payload.findItem.returnedItem);
|
||||
Vue.set(state,'items', items);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
vuetify.js
|
||||
|
||||
Created by Kalila L. on 7 Apr 2020
|
||||
Copyright 2020 Vircadia and contributors.
|
||||
|
||||
Distributed under the Apache License, Version 2.0.
|
||||
See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
|
||||
import Vue from 'vue';
|
||||
import Vuetify from 'vuetify/lib';
|
||||
|
||||
Vue.use(Vuetify);
|
||||
|
||||
export default new Vuetify({
|
||||
});
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
vue.config.js
|
||||
|
||||
Created by Kalila L. on 7 Apr 2020
|
||||
Copyright 2020 Vircadia and contributors.
|
||||
|
||||
Distributed under the Apache License, Version 2.0.
|
||||
See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
publicPath: "./",
|
||||
assetsDir: "./",
|
||||
"transpileDependencies": [
|
||||
"vuetify"
|
||||
]
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
// Created by Ryan Huffman on 6 Nov 2014
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// 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
|
||||
|
@ -196,8 +197,11 @@ Grid = function() {
|
|||
};
|
||||
|
||||
that.update = function(data) {
|
||||
var gridNeedsUpdate = false;
|
||||
|
||||
if (data.snapToGrid !== undefined) {
|
||||
snapToGrid = data.snapToGrid;
|
||||
var gridNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (data.origin) {
|
||||
|
@ -206,29 +210,37 @@ Grid = function() {
|
|||
pos.y = pos.y === undefined ? origin.y : parseFloat(pos.y);
|
||||
pos.z = pos.z === undefined ? origin.z : parseFloat(pos.z);
|
||||
that.setPosition(pos, true);
|
||||
var gridNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (data.minorGridEvery) {
|
||||
minorGridEvery = data.minorGridEvery;
|
||||
var gridNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (data.majorGridEvery) {
|
||||
majorGridEvery = data.majorGridEvery;
|
||||
var gridNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (data.gridColor) {
|
||||
gridColor = data.gridColor;
|
||||
var gridNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (data.gridSize) {
|
||||
halfSize = data.gridSize;
|
||||
var gridNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (data.visible !== undefined) {
|
||||
that.setVisible(data.visible, true);
|
||||
var gridNeedsUpdate = true;
|
||||
}
|
||||
|
||||
updateGrid(true);
|
||||
if (gridNeedsUpdate) {
|
||||
updateGrid(true);
|
||||
}
|
||||
};
|
||||
|
||||
function updateGrid(noUpdate) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[
|
||||
{"node": "https://metaverse.vircadia.com/live"},
|
||||
{"node": "https://mv.overte.org/server"}
|
||||
]
|
||||
{"node": "https://mv.overte.org/server"}
|
||||
]
|
||||
|
|
|
@ -487,6 +487,41 @@ div.placeEntry {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
div.addMsEntry {
|
||||
width: 85%;
|
||||
height: 38px;
|
||||
background: #292929;
|
||||
border: 0px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 3px 3px 5px rgba(0,0,0,0.8);
|
||||
margin: 6px 0px 9px 6px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#addMS {
|
||||
margin: 8px;
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
#addMsBtn {
|
||||
background: #bababa;
|
||||
background-image: linear-gradient(to bottom, #bababa, #424242);
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
font-size: 18px;
|
||||
padding: 1px 5px 1px 5px;
|
||||
border: 0px;
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#addMsBtn:hover {
|
||||
background: #e0e0e0;
|
||||
background-image: linear-gradient(to bottom, #e0e0e0, #737373);
|
||||
text-decoration: none;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
div.placeEntryHighlighter {
|
||||
width: 85%;
|
||||
height: 80px;
|
||||
|
@ -847,7 +882,7 @@ td.warningTitle {
|
|||
font-size: 10px;
|
||||
font-style: none;
|
||||
color: #ffffff;
|
||||
text-align: left;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.region-LOCAL {
|
||||
|
@ -913,3 +948,10 @@ button.federationFilterOn:hover {
|
|||
button.externalFilterOn:hover {
|
||||
border: solid #00e2ff 1px;
|
||||
}
|
||||
|
||||
#reloading {
|
||||
width: 80%;
|
||||
color: #ffffff;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
|
|