// // avatarScannerZoneClient.js // // created by Rebecca Stankus on 03/1/19 // Copyright 2019 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // (function() { var _this; /* TEXT ENTITIES WILL BE IN THIS ORDER: 0-OVERALL SCORE 1-NUMBER OF MATERIALS 2-SIZE OF MATERIALS TEXTURES IN PIXELS 3-NUMBER OF MATERIALS TEXTURES 4-NUMBER OF TRIANGLES 5-MATERIAL ENTITIES 6-WEARABLES 7-NUMBER OF PARTS 8-FLOW JOINTS 9-BLENDSHAPES 10-SKINNING JOINTS */ var TEXT_NUMBER_INDEX = 24; var AVATAR_COPY_Y_OFFSET_M = 0.7; var SEARCH_RADIUS_M = 20; var MIN_COPY_HEIGHT_M = 0.7; var NINETY_PERCENT = 0.9; var WAIT_TO_GET_DATA_MS = 200; var WAIT_TO_DISPLAY_SCORES_MS = 1000; var scannerZoneMarker; var textEntityIDs = []; var textToShow = []; var avatarCopy; var avatarCopyShelf; var wearables = []; var materialEntities = []; var graphicsModel; var flowJointNames = []; var numberSkinningJoints = []; var AvatarScannerZone = function() { _this = this; }; AvatarScannerZone.prototype = { /* ON PRELOAD: Save a reference to this */ preload: function(entityID) { _this.entityID = entityID; scannerZoneMarker = Entities.getEntityProperties(_this.entityID, 'parentID').parentID; }, /* ENTER ENTITY: Upon entering this zone */ enterEntity: function() { Entities.getChildrenIDs(scannerZoneMarker).forEach(function(childOfZoneMarker) { var name = Entities.getEntityProperties(childOfZoneMarker, 'name').name; if (name.indexOf("FeedBack") !== -1) { var indexNumber = +name.substr(TEXT_NUMBER_INDEX); textEntityIDs[indexNumber] = childOfZoneMarker; } else if (name.indexOf("Shelf") !== -1) { avatarCopyShelf = childOfZoneMarker; } }); MyAvatar.useFlow(true,true); _this.showAvatarData(); // play sound // light on }, /* LEAVE ENTITY: Upon leaving this zone */ leaveEntity: function() { for ( var i = 0; i < textEntityIDs.length; i++) { Entities.editEntity(textEntityIDs[i], { visible: false, text: "" }); } var scannerPosition = Entities.getEntityProperties(_this.entityID, 'position').position; Entities.findEntities(scannerPosition, SEARCH_RADIUS_M).forEach(function(entity) { var name = Entities.getEntityProperties(entity, 'name').name; if (name === "Avatar Scanner Copy") { Entities.deleteEntity(entity); } }); // light off }, /* Get all avatar entities and separate wearables from materials */ separateAvatarEntities: function() { wearables = []; materialEntities = []; var entityAttachments = MyAvatar.getAvatarEntitiesVariant(); entityAttachments.forEach(function(avatarEntity) { if (avatarEntity.properties.type === "Material") { materialEntities.push(avatarEntity); } else { wearables.push(avatarEntity); } }); }, /* Get number of avtar parts */ getPartsCount: function() { var partsCount = 0; graphicsModel.meshes.forEach(function(mesh) { partsCount += mesh.numParts; }); return partsCount; }, /* Return number of triangles */ getNumberTriangles: function() { var trianglesCount = 0; graphicsModel.meshes.forEach(function(mesh) { var parts = mesh.parts; parts.forEach(function(part) { trianglesCount += part.numFaces; }); }); return trianglesCount; }, /* Create miniature copy of avatar and a graphics model copy. */ showAvatarData: function() { var avatarScore, avatarMaterialsScore, avatarMaterialsSize, avatarMaterialsSizeScore, textures, texturesScore, wearablesScore, materialEntitiesScore, parts, partsScore, triangles, trianglesScore, numberflowJoints, flowJointsScore, blendShapesScore, skinningJointsScore; var blendShapes = []; var avatarMaterials = []; var renderInfo; // Entities.findEntities(MyAvatar.position, 1000).forEach(function(entity) { // var parentID = // }); var spawnPosition = Entities.getEntityProperties(avatarCopyShelf, 'position').position; spawnPosition.y += AVATAR_COPY_Y_OFFSET_M; var numberAvatarMaterials; avatarCopy = Entities.addEntity({ type: 'Model', name: "Avatar Scanner Copy", modelURL: MyAvatar.skeletonModelURL, position: spawnPosition, lifetime: 300, // backup just in case grab: { grabbable: false }, parentID: scannerZoneMarker, visible: false }, 'avatarEntity'); Script.setTimeout(function() { // Natural dimensions are not available immediately var dimensions = Entities.getEntityProperties(avatarCopy, 'naturalDimensions').naturalDimensions; while (dimensions.y > MIN_COPY_HEIGHT_M) { dimensions = Vec3.multiply(dimensions, NINETY_PERCENT); Entities.editEntity(avatarCopy, { visible: true, dimensions: dimensions }); renderInfo = Entities.getEntityProperties(avatarCopy, 'renderInfo').renderInfo; } graphicsModel = Graphics.getModel(MyAvatar.sessionUUID); parts = _this.getPartsCount(); avatarMaterials = graphicsModel.materialLayers["mat::Bodymat"]; triangles = _this.getNumberTriangles(); numberAvatarMaterials = avatarMaterials ? avatarMaterials.length : 0; _this.separateAvatarEntities(); flowJointNames = Object.keys(MyAvatar.getFlowData().threads); print(Object.keys(MyAvatar.getFlowData().threads)); numberflowJoints = flowJointNames ? flowJointNames.length : 0; var skinningJoints = MyAvatar.getJointNames(); if (skinningJoints) { flowJointNames.forEach(function(flowJointName) { var flowJointIndex = skinningJoints.indexOf(flowJointName); if (flowJointIndex > -1) { skinningJoints.splice(flowJointIndex, 1); } }); } numberSkinningJoints = skinningJoints ? skinningJoints.length : 0; }, WAIT_TO_GET_DATA_MS); // render info and natural dimensions are not immediately available Script.setTimeout(function() { textToShow[0] = JSON.stringify("Hello " + MyAvatar.displayName + " Your overall avatar score is " + avatarScore); textToShow[1] = JSON.stringify("Your avatar has " + numberAvatarMaterials + " avatar materials. Your avatar materials score is " + avatarMaterialsScore); // textToShow[2] = JSON.stringify("The size of all of your avatar materials is " + avatarMaterialsSize + // " pixels. Your avatar materials size score is " + avatarMaterialsSizeScore); textToShow[3] = JSON.stringify("Your avatar has " + renderInfo.texturesCount + " textures. Your textures score is " + texturesScore); textToShow[4] = JSON.stringify("Your avatar has " + triangles + " triangles. Your triangles score is " + trianglesScore); textToShow[5] = JSON.stringify("Your avatar has " + materialEntities.length + " material entities. Your " + "total material entities score is " + materialEntitiesScore); textToShow[6] = JSON.stringify("Your avatar has " + wearables.length + " wearables. Your total wearables " + "score is " + wearablesScore); textToShow[7] = JSON.stringify("Your avatar has " + parts + " parts. Your parts score is " + partsScore); textToShow[8] = JSON.stringify("Your avatar has " + numberflowJoints + " flow joints. Your flow joints score is " + flowJointsScore); // textToShow[9] = JSON.stringify("Your avatar has " + blendShapes.length + " blend shapes. Your blend " + // "shapes score is " + blendShapesScore); textToShow[10] = JSON.stringify("Your avatar has " + numberSkinningJoints + " skinning joints. Your " + "skinning joints score is " + skinningJointsScore); for ( var i = 0; i < textEntityIDs.length; i++) { Entities.editEntity(textEntityIDs[i], { text:textToShow[i], visible: true }); } }, WAIT_TO_DISPLAY_SCORES_MS); // allows time for all values to be calculated }, /* ON UNLOADING THE SCRIPT: Make sure the avatar leaves the zone so extra entities are deleted and intervals ended */ unload: function(){ _this.leaveEntity(); } }; return new AvatarScannerZone(); });