avatar selection & wearables adjustments work-on-progress

This commit is contained in:
Alexander Ivash 2018-05-08 21:43:07 +03:00
parent 57568d120e
commit b6769f9678
8 changed files with 192 additions and 45 deletions

View file

@ -25,12 +25,34 @@ Rectangle {
property var jointNames;
function setCurrentAvatar(currentAvatar) {
currentAvatarModel.clear();
root.currentAvatar = {
'name' : '',
'url' : allAvatars.makeThumbnailUrl(currentAvatar.avatarUrl),
'wearables' : currentAvatar.avatarEntites ? currentAvatar.avatarEntites : [],
'entry' : currentAvatar,
'getMoreAvatars' : false
};
console.debug('AvatarApp.qml: currentAvatar: ', JSON.stringify(root.currentAvatar, null, '\t'))
currentAvatarModel.append(root.currentAvatar);
root.currentAvatar = currentAvatarModel.get(currentAvatarModel.count - 1);
}
function fromScript(message) {
console.debug('AvatarApp.qml: fromScript: ', JSON.stringify(message, null, '\t'))
if(message.method === 'initialize') {
jointNames = message.reply.jointNames;
emitSendToScript({'method' : getAvatarsMethod});
} else if(message.method === 'bookmarkLoaded') {
setCurrentAvatar(message.reply.currentAvatar);
selectedAvatarId = message.reply.name;
var avatarIndex = allAvatars.findAvatarIndex(selectedAvatarId);
allAvatars.move(avatarIndex, 0, 1);
view.setPage(0);
} else if(message.method === getAvatarsMethod) {
var getAvatarsReply = message.reply;
allAvatars.populate(getAvatarsReply.bookmarks);
@ -70,20 +92,10 @@ Rectangle {
console.debug('selectedAvatarIndex = -1, avatar is not favorite')
setCurrentAvatar(currentAvatar);
if(selectedAvatarIndex === -1) {
var currentAvatarEntry = {
'name' : '',
'url' : Qt.resolvedUrl(allAvatars.urls[i++ % allAvatars.urls.length]),
'wearables' : currentAvatar.avatarEntites ? currentAvatar.avatarEntites : [],
'entry' : currentAvatar,
'getMoreAvatars' : false
};
currentAvatarModel.append(currentAvatarEntry);
currentAvatarEntry = allAvatars.get(allAvatars.count - 1);
selectedAvatar = currentAvatarEntry;
selectedAvatar = root.currentAvatar;
view.setPage(0);
console.debug('selectedAvatar = ', JSON.stringify(selectedAvatar, null, '\t'))
@ -93,6 +105,8 @@ Rectangle {
}
}
property var currentAvatar;
property string selectedAvatarId: ''
onSelectedAvatarIdChanged: {
console.debug('selectedAvatarId: ', selectedAvatarId)
@ -174,6 +188,9 @@ Rectangle {
anchors.top: header.bottom
anchors.bottom: parent.bottom
jointNames: root.jointNames
onWearableChanged: {
emitSendToScript({'method' : 'adjustWearable', 'id' : id, 'properties' : properties})
}
z: 3
}
@ -365,7 +382,7 @@ Rectangle {
anchors.fill: parent
onClicked: {
console.debug('adjustWearables.open');
adjustWearables.open(selectedAvatar);
adjustWearables.open(currentAvatar);
}
}
}
@ -488,11 +505,7 @@ Rectangle {
property int verticalSpacing: 36
function selectAvatar(avatar) {
AvatarBookmarks.loadBookmark(avatar.name);
selectedAvatarId = avatar.name;
var avatarIndex = allAvatars.findAvatarIndex(selectedAvatarId);
allAvatars.move(avatarIndex, 0, 1);
view.setPage(0);
emitSendToScript({'method' : 'selectAvatar', 'name' : avatar.name})
}
AvatarsModel {
@ -630,7 +643,10 @@ Rectangle {
imageUrl: url
border.color: container.highlighted ? style.colors.blueHighlight : 'transparent'
border.width: container.highlighted ? 2 : 0
wearablesCount: !getMoreAvatars ? wearables.count : 0
wearablesCount: {
console.debug('getMoreAvatars: ', getMoreAvatars, 'name: ', name);
return !getMoreAvatars ? wearables.count : 0
}
onWearablesCountChanged: {
console.debug('delegate: AvatarThumbnail.wearablesCount: ', wearablesCount)
}

View file

@ -11,6 +11,8 @@ Rectangle {
height: 706
color: 'white'
signal wearableChanged(var id, var properties);
property bool modified: false;
Component.onCompleted: {
modified = false;
@ -24,11 +26,13 @@ Rectangle {
property var onButton1Clicked;
property var jointNames;
property var wearables: ({})
function open(avatar) {
console.debug('AdjustWearables.qml: open');
console.debug('AdjustWearables.qml: open: ', JSON.stringify(avatar, null, '\t'));
visible = true;
wearablesCombobox.model.clear();
wearables = {};
console.debug('AdjustWearables.qml: avatar.wearables.count: ', avatar.wearables.count);
for(var i = 0; i < avatar.wearables.count; ++i) {
@ -38,6 +42,12 @@ Rectangle {
for(var j = (wearable.modelURL.length - 1); j >= 0; --j) {
if(wearable.modelURL[j] === '/') {
wearable.text = wearable.modelURL.substring(j + 1) + ' [%jointIndex%]'.replace('%jointIndex%', jointNames[wearable.parentJointIndex]);
wearables[wearable.id] = {
position: wearable.localPosition,
rotation: wearable.localRotation,
dimensions: wearable.dimensions
};
console.debug('wearable.text = ', wearable.text);
break;
}
@ -79,6 +89,25 @@ Rectangle {
model: ListModel {
}
comboBox.onCurrentIndexChanged: {
console.debug('wearable index changed: ', currentIndex);
var currentWearable = wearablesCombobox.model.get(currentIndex)
if(currentWearable) {
position.notify = false;
position.xvalue = currentWearable.localPosition.x
position.yvalue = currentWearable.localPosition.y
position.zvalue = currentWearable.localPosition.z
position.notify = true;
rotation.notify = false;
rotation.xvalue = currentWearable.localRotationAngles.x
rotation.yvalue = currentWearable.localRotationAngles.y
rotation.zvalue = currentWearable.localRotationAngles.z
rotation.notify = true;
}
}
}
Column {
@ -101,9 +130,25 @@ Rectangle {
id: position
backgroundColor: "lightgray"
onXvalueChanged: modified = true;
onYvalueChanged: modified = true;
onZvalueChanged: modified = true;
function notifyPositionChanged() {
modified = true;
var properties = {};
properties.localPosition = { 'x' : xvalue, 'y' : yvalue, 'z' : zvalue }
var currentWearable = wearablesCombobox.model.get(wearablesCombobox.currentIndex)
wearableChanged(currentWearable.id, properties);
}
property bool notify: false;
onXvalueChanged: if(notify) notifyPositionChanged();
onYvalueChanged: if(notify) notifyPositionChanged();
onZvalueChanged: if(notify) notifyPositionChanged();
decimals: 4
realFrom: -100
realTo: 100
realStepSize: 0.0001
}
}
@ -127,9 +172,25 @@ Rectangle {
id: rotation
backgroundColor: "lightgray"
onXvalueChanged: modified = true;
onYvalueChanged: modified = true;
onZvalueChanged: modified = true;
function notifyRotationChanged() {
modified = true;
var properties = {};
properties.localRotationAngles = { 'x' : xvalue, 'y' : yvalue, 'z' : zvalue }
var currentWearable = wearablesCombobox.model.get(wearablesCombobox.currentIndex)
wearableChanged(currentWearable.id, properties);
}
property bool notify: false;
onXvalueChanged: if(notify) notifyRotationChanged();
onYvalueChanged: if(notify) notifyRotationChanged();
onZvalueChanged: if(notify) notifyRotationChanged();
decimals: 4
realFrom: -100
realTo: 100
realStepSize: 0.0001
}
}

View file

@ -3,16 +3,22 @@ import QtQuick 2.9
ListModel {
id: model
function makeThumbnailUrl(avatarUrl) {
var splittedUrl = avatarUrl.split('/');
var marketId = splittedUrl[splittedUrl.length - 2];
var indexOfVSuffix = marketId.indexOf('-v');
if(indexOfVSuffix !== -1) {
marketId = marketId.substring(0, indexOfVSuffix);
}
var avatarThumbnailUrl = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/%marketId%/large/hifi-mp-%marketId%.jpg"
.split('%marketId%').join(marketId);
return avatarThumbnailUrl;
}
function populate(bookmarks) {
for(var avatarName in bookmarks) {
var splittedUrl = bookmarks[avatarName].avatarUrl.split('/');
var marketId = splittedUrl[splittedUrl.length - 2];
var indexOfVSuffix = marketId.indexOf('-v');
if(indexOfVSuffix !== -1) {
marketId = marketId.substring(0, indexOfVSuffix);
}
var avatarThumbnailUrl = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/%marketId%/medium/hifi-mp-%marketId%.jpg"
.split('%marketId%').join(marketId);
var avatarThumbnailUrl = makeThumbnailUrl(bookmarks[avatarName].avatarUrl);
var avatarEntry = {
'name' : avatarName,

View file

@ -5,6 +5,7 @@ import "../../controls-uit" as HifiControlsUit
import "../../controls" as HifiControls
Row {
id: root
width: parent.width
height: xspinner.controlHeight
@ -12,11 +13,16 @@ Row {
property int spinboxWidth: (parent.width - 2 * spinboxSpace) / 3
property color backgroundColor: "darkgray"
property int decimals: 4
property real realFrom: 0
property real realTo: 100
property real realStepSize: 0.0001
spacing: spinboxSpace
property real xvalue: xspinner.value
property real yvalue: yspinner.value
property real zvalue: zspinner.value
property alias xvalue: xspinner.realValue
property alias yvalue: yspinner.realValue
property alias zvalue: zspinner.realValue
HifiControlsUit.SpinBox {
id: xspinner
@ -25,6 +31,10 @@ Row {
backgroundColor: parent.backgroundColor
colorLabelInside: hifi.colors.redHighlight
colorScheme: hifi.colorSchemes.light
decimals: root.decimals;
realFrom: root.realFrom
realTo: root.realTo
realStepSize: root.realStepSize
}
HifiControlsUit.SpinBox {
@ -34,6 +44,10 @@ Row {
backgroundColor: parent.backgroundColor
colorLabelInside: hifi.colors.greenHighlight
colorScheme: hifi.colorSchemes.light
decimals: root.decimals;
realFrom: root.realFrom
realTo: root.realTo
realStepSize: root.realStepSize
}
HifiControlsUit.SpinBox {
@ -43,5 +57,9 @@ Row {
backgroundColor: parent.backgroundColor
colorLabelInside: hifi.colors.primaryHighlight
colorScheme: hifi.colorSchemes.light
decimals: root.decimals;
realFrom: root.realFrom
realTo: root.realTo
realStepSize: root.realStepSize
}
}

View file

@ -162,6 +162,8 @@ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) {
const QVariantList& avatarEntities = bookmark.value(ENTRY_AVATAR_ENTITIES, QVariantList()).toList();
addAvatarEntities(avatarEntities);
emit bookmarkLoaded(bookmarkName);
}
}
}
@ -234,6 +236,7 @@ void AvatarBookmarks::changeToBookmarkedAvatar() {
const QVariantList& avatarEntities = bookmark.value(ENTRY_AVATAR_ENTITIES, QVariantList()).toList();
addAvatarEntities(avatarEntities);
emit bookmarkLoaded(action->text());
} else {
qCDebug(interfaceapp) << " Bookmark entry does not match client version, make sure client has a handler for the new AvatarBookmark";
}

View file

@ -45,6 +45,9 @@ public slots:
void removeBookmark(const QString& bookmarkName);
QVariantMap getBookmarks() { return _bookmarks; }
signals:
void bookmarkLoaded(const QString& bookmarkName);
protected:
void addBookmarkToMenu(Menu* menubar, const QString& name, const QVariant& bookmark) override;
void readFromFile() override;

View file

@ -1596,7 +1596,11 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() {
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(child);
if (modelEntity) {
QVariantMap avatarEntityData;
EntityItemProperties entityProperties = modelEntity->getProperties();
EncodeBitstreamParams params;
auto desiredProperties = modelEntity->getEntityProperties(params);
desiredProperties += PROP_LOCAL_POSITION;
desiredProperties += PROP_LOCAL_ROTATION;
EntityItemProperties entityProperties = modelEntity->getProperties(desiredProperties);
QScriptValue scriptProperties = EntityItemPropertiesToScriptValue(&scriptEngine, entityProperties);
avatarEntityData["properties"] = scriptProperties.toVariant();
avatarEntitiesData.append(QVariant(avatarEntityData));

View file

@ -25,24 +25,51 @@ var ENTRY_AVATAR_ENTITIES = "avatarEntites";
var ENTRY_AVATAR_SCALE = "avatarScale";
var ENTRY_VERSION = "version";
function getCurrentAvatar() {
var currentAvatar = {}
currentAvatar[ENTRY_AVATAR_URL] = MyAvatar.skeletonModelURL;
currentAvatar[ENTRY_AVATAR_SCALE] = MyAvatar.getAvatarScale();
currentAvatar[ENTRY_AVATAR_ATTACHMENTS] = MyAvatar.getAttachmentsVariant();
currentAvatar[ENTRY_AVATAR_ENTITIES] = MyAvatar.getAvatarEntitiesVariant();
for(var i = 0; i < currentAvatar[ENTRY_AVATAR_ENTITIES].length; ++i) {
var wearable = currentAvatar[ENTRY_AVATAR_ENTITIES][i];
console.debug('updating localRotationAngles for wearable: ', JSON.stringify(wearable, null, '\t'));
var localRotation = wearable.properties.localRotation;
wearable.properties.localRotationAngles = Quat.safeEulerAngles(localRotation)
}
return currentAvatar;
}
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
console.debug('fromQml: message = ', JSON.stringify(message, null, '\t'))
switch (message.method) {
case 'getAvatars':
var currentAvatar = {}
currentAvatar[ENTRY_AVATAR_URL] = MyAvatar.skeletonModelURL;
currentAvatar[ENTRY_AVATAR_SCALE] = MyAvatar.getAvatarScale();
currentAvatar[ENTRY_AVATAR_ATTACHMENTS] = MyAvatar.getAttachmentsVariant();
currentAvatar[ENTRY_AVATAR_ENTITIES] = MyAvatar.getAvatarEntitiesVariant();
message.reply = {
'bookmarks' : AvatarBookmarks.getBookmarks(),
'currentAvatar' : currentAvatar
'currentAvatar' : getCurrentAvatar()
};
console.debug('avatarapp.js: currentAvatar: ', JSON.stringify(message.reply.currentAvatar, null, '\t'))
sendToQml(message)
break;
case 'adjustWearable':
if(message.properties.localRotationAngles) {
message.properties.localRotation = Quat.fromVec3Degrees(message.properties.localRotationAngles)
delete message.properties.localRotationAngles;
}
console.debug('Entities.editEntity(message.id, message.properties)'.replace('message.id', message.id).replace('message.properties', JSON.stringify(message.properties)));
Entities.editEntity(message.id, message.properties);
break;
case 'selectAvatar':
console.debug('avatarapp.js: selecting avatar: ', message.name);
AvatarBookmarks.loadBookmark(message.name);
break;
default:
print('Unrecognized message from AvatarApp.qml:', JSON.stringify(message));
}
@ -52,6 +79,12 @@ function sendToQml(message) {
tablet.sendToQml(message);
}
function onBookmarkLoaded(bookmarkName) {
var currentAvatar = getCurrentAvatar();
console.debug('avatarapp.js: onBookmarkLoaded: ', JSON.stringify(currentAvatar, 0, 4));
sendToQml({'method' : 'bookmarkLoaded', 'reply' : {'name' : bookmarkName, 'currentAvatar' : getCurrentAvatar()} });
}
//
// Manage the connection between the button and the window.
//
@ -69,6 +102,7 @@ function startup() {
});
button.clicked.connect(onTabletButtonClicked);
tablet.screenChanged.connect(onTabletScreenChanged);
AvatarBookmarks.bookmarkLoaded.connect(onBookmarkLoaded);
// Window.domainChanged.connect(clearLocalQMLDataAndClosePAL);
// Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL);
// Users.avatarDisconnected.connect(avatarDisconnected);
@ -160,6 +194,8 @@ function shutdown() {
button.clicked.disconnect(onTabletButtonClicked);
tablet.removeButton(button);
tablet.screenChanged.disconnect(onTabletScreenChanged);
AvatarBookmarks.bookmarkLoaded.disconnect(onBookmarkLoaded);
// Window.domainChanged.disconnect(clearLocalQMLDataAndClosePAL);
// Window.domainConnectionRefused.disconnect(clearLocalQMLDataAndClosePAL);
// AvatarList.avatarAddedEvent.disconnect(avatarAdded);