Skip to content

Commit

Permalink
Merge pull request #1132 from mozilla/qa-test
Browse files Browse the repository at this point in the history
April 2021 Hubs Cloud Release
  • Loading branch information
johnshaughnessy authored Apr 20, 2021
2 parents 4a17cb0 + ffff4f8 commit a2a2970
Show file tree
Hide file tree
Showing 37 changed files with 1,958 additions and 314 deletions.
2 changes: 1 addition & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ HUBS_SERVER="dev.reticulum.io"
RETICULUM_SERVER="dev.reticulum.io"
FARSPARK_SERVER="farspark-dev.reticulum.io"
NON_CORS_PROXY_DOMAINS="hubs.local,localhost"
CORS_PROXY_SERVER="hubs-proxy.com"
CORS_PROXY_SERVER="cors-proxy-dev.reticulum.io"
HOST_PORT="9090"
IS_MOZ="false"
71 changes: 68 additions & 3 deletions src/api/Api.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,25 @@ export default class Project extends EventEmitter {
return json;
}

async getProjectlessScenes() {
const token = this.getToken();

const headers = {
"content-type": "application/json",
authorization: `Bearer ${token}`
};

const response = await this.fetch(`https://${RETICULUM_SERVER}/api/v1/scenes/projectless`, { headers });

const json = await response.json();

if (!Array.isArray(json.scenes)) {
throw new Error(`Error fetching scenes: ${json.error || "Unknown error."}`);
}

return json.scenes;
}

async resolveUrl(url, index) {
if (!shouldCorsProxy(url)) {
return { origin: url };
Expand Down Expand Up @@ -287,11 +306,12 @@ export default class Project extends EventEmitter {
if (resolveMediaCache.has(cacheKey)) return resolveMediaCache.get(cacheKey);

const request = (async () => {
let contentType, canonicalUrl, accessibleUrl;
let contentType, canonicalUrl, accessibleUrl, meta;

try {
const result = await this.resolveUrl(absoluteUrl);
canonicalUrl = result.origin;
meta = result.meta;
accessibleUrl = proxiedUrlFor(canonicalUrl, index);

contentType =
Expand All @@ -315,7 +335,7 @@ export default class Project extends EventEmitter {
throw new RethrownError(`Error loading Sketchfab model "${accessibleUrl}"`, error);
}

return { canonicalUrl, accessibleUrl, contentType };
return { canonicalUrl, accessibleUrl, contentType, meta };
})();

resolveMediaCache.set(cacheKey, request);
Expand Down Expand Up @@ -890,7 +910,7 @@ export default class Project extends EventEmitter {
allow_promotion: publishParams.allowPromotion,
name: publishParams.name,
attributions: {
creator: publishParams.creatorAttribution,
creator: publishParams.creatorAttribution && publishParams.creatorAttribution.trim(),
content: publishParams.contentAttributions
}
};
Expand Down Expand Up @@ -954,6 +974,51 @@ export default class Project extends EventEmitter {
return project;
}

async publishGLBScene(screenshotFile, glbFile, params, signal, sceneId) {
let screenshotId, screenshotToken;
if (screenshotFile) {
const {
file_id,
meta: { access_token }
} = await this.upload(screenshotFile, null, signal);
screenshotId = file_id;
screenshotToken = access_token;
}

let glbId, glbToken;
if (glbFile) {
const {
file_id,
meta: { access_token }
} = await this.upload(glbFile, null, signal);
glbId = file_id;
glbToken = access_token;
}

const headers = {
"content-type": "application/json",
authorization: `Bearer ${this.getToken()}`
};

const sceneParams = {
screenshot_file_id: screenshotId,
screenshot_file_token: screenshotToken,
model_file_id: glbId,
model_file_token: glbToken,
...params
};

const body = JSON.stringify({ scene: sceneParams });

const resp = await this.fetch(`https://${RETICULUM_SERVER}/api/v1/scenes${sceneId ? "/" + sceneId : ""}`, {
method: sceneId ? "PUT" : "POST",
headers,
body
});

return resp.json();
}

async upload(blob, onUploadProgress, signal) {
// Use direct upload API, see: https://github.com/mozilla/reticulum/pull/319
const { phx_host: uploadHost } = await (await this.fetch(`https://${RETICULUM_SERVER}/api/v1/meta`)).json();
Expand Down
13 changes: 12 additions & 1 deletion src/api/PublishDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,18 @@ export default class PublishDialog extends Component {
{contentAttributions && (
<FormField>
<label>Model Attribution:</label>
<p>{contentAttributions.map(a => `${a.name} by ${a.author}\n`)}</p>
<ul>
{contentAttributions.map(
(a, i) =>
a.author &&
a.title && (
<li key={i}>
<b>{`${a.title}`}</b>
{(a.author && ` (by ${a.author})`) || ` (by Unknown)`}
</li>
)
)}
</ul>
</FormField>
)}
</PreviewDialog>
Expand Down
2 changes: 1 addition & 1 deletion src/editor/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export default class Editor extends EventEmitter {

const scene = this.scene;

const floorPlanNode = scene.findNodeByType(FloorPlanNode);
const floorPlanNode = scene.findNodeByType(FloorPlanNode, false);

if (floorPlanNode) {
await floorPlanNode.generate(signal);
Expand Down
13 changes: 5 additions & 8 deletions src/editor/gltf/GLTFExporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -837,14 +837,11 @@ class GLTFExporter {
}

// alphaMode
if (material.transparent || material.alphaTest > 0.0) {
// Write alphaCutoff if it's non-zero and different from the default (0.5).
if (material.alphaTest > 0.0 && material.alphaTest !== 0.5) {
gltfMaterial.alphaMode = "MASK";
gltfMaterial.alphaCutoff = material.alphaTest;
} else {
gltfMaterial.alphaMode = "BLEND";
}
if (material.transparent) {
gltfMaterial.alphaMode = "BLEND";
} else if (material.alphaTest > 0.0) {
gltfMaterial.alphaMode = "MASK";
gltfMaterial.alphaCutoff = material.alphaTest;
}

// doubleSided
Expand Down
122 changes: 96 additions & 26 deletions src/editor/nodes/EditorNodeMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Color, Object3D } from "three";
import serializeColor from "../utils/serializeColor";
import LoadingCube from "../objects/LoadingCube";
import ErrorIcon from "../objects/ErrorIcon";
import traverseFilteredSubtrees from "../utils/traverseFilteredSubtrees";

export default function EditorNodeMixin(Object3DClass) {
return class extends Object3DClass {
Expand Down Expand Up @@ -56,7 +57,13 @@ export default function EditorNodeMixin(Object3DClass) {
const visibleComponent = json.components.find(c => c.name === "visible");

if (visibleComponent) {
node.visible = visibleComponent.props.visible;
node._visible = visibleComponent.props.visible;
}

const editorSettingsComponent = json.components.find(c => c.name === "editor-settings");

if (editorSettingsComponent) {
node.enabled = editorSettingsComponent.props.enabled;
}
}

Expand All @@ -70,13 +77,14 @@ export default function EditorNodeMixin(Object3DClass) {
this.nodeName = this.constructor.nodeName;
this.name = this.constructor.nodeName;
this.isNode = true;
this.isCollapsed = false;
this.disableTransform = this.constructor.disableTransform;
this.useMultiplePlacementMode = this.constructor.useMultiplePlacementMode;
this.ignoreRaycast = this.constructor.ignoreRaycast;

this.staticMode = StaticModes.Inherits;
this.originalStaticMode = null;
this.enabled = true;
this._visible = true;
this.saveParent = false;
this.loadingCube = null;
this.errorIcon = null;
Expand Down Expand Up @@ -110,10 +118,20 @@ export default function EditorNodeMixin(Object3DClass) {
}

this.issues = source.issues.slice();
this._visible = source._visible;
this.enabled = source.enabled;

return this;
}

get visible() {
return this.enabled && this._visible;
}

set visible(value) {
this._visible = value;
}

onPlay() {}

onUpdate(dt) {
Expand Down Expand Up @@ -163,7 +181,13 @@ export default function EditorNodeMixin(Object3DClass) {
{
name: "visible",
props: {
visible: this.visible
visible: this._visible
}
},
{
name: "editor-settings",
props: {
enabled: this.enabled
}
}
]
Expand Down Expand Up @@ -345,40 +369,46 @@ export default function EditorNodeMixin(Object3DClass) {
return isDynamic(this);
}

findNodeByType(nodeType) {
if (this.constructor === nodeType) {
return this;
}
findNodeByType(nodeType, includeDisabled = true) {
let node = null;

for (const child of this.children) {
if (child.isNode) {
const result = child.findNodeByType(nodeType);
traverseFilteredSubtrees(this, child => {
if (node) {
return false;
}

if (result) {
return result;
}
if (!child.isNode) {
return;
}
}

return null;
if (!child.enabled && !includeDisabled) {
return false;
}

if (child.constructor === nodeType) {
node = child;
}
});

return node;
}

getNodesByType(nodeType) {
getNodesByType(nodeType, includeDisabled = true) {
const nodes = [];

if (this.constructor === nodeType) {
nodes.push(this);
}
traverseFilteredSubtrees(this, child => {
if (!child.isNode) {
return;
}

for (const child of this.children) {
if (child.isNode) {
const results = child.getNodesByType(nodeType);
if (!child.enabled && !includeDisabled) {
return false;
}

for (const result of results) {
nodes.push(result);
}
if (child.constructor === nodeType) {
nodes.push(this);
}
}
});

return nodes;
}
Expand All @@ -387,5 +417,45 @@ export default function EditorNodeMixin(Object3DClass) {
getRuntimeResourcesForStats() {
// return { textures: [], materials: [], meshes: [], lights: [] };
}

// Returns the node's attribution information by default just the name
// This should be overriding by nodes that can provide a more specific info (ie. models based on GLTF)
getAttribution() {
return {
title: this.name.replace(/\.[^/.]+$/, "")
};
}

// Updates attribution information. The meta information from the API is consider the most authoritative source
// That info then would be updated with node's source information if exists.
updateAttribution() {
const attribution = this.getAttribution();
this.attribution = this.attribution || {};
if (this.meta) {
Object.assign(
this.attribution,
this.meta.author ? { author: this.meta.author ? this.meta.author.replace(/ \(http.+\)/, "") : "" } : null,
this.meta.name ? { title: this.meta.name } : this.name ? { title: this.name.replace(/\.[^/.]+$/, "") } : null,
this.meta.author && this.meta.name && this._canonicalUrl ? { url: this._canonicalUrl } : null
);
}
// Replace the attribute keys only if they don't exist otherwise
// we give preference to the info coming from the API source over the GLTF asset
Object.keys(this.attribution).forEach(key => {
if (!this.attribution[key] || this.attribution[key] == null) {
this.attribution[key] = attribution[key];
}
});
// If the GLTF attribution info has keys that are missing form the API source, we add them
for (const key in attribution) {
if (!Object.prototype.hasOwnProperty.call(this.attribution, key)) {
if (key === "author") {
this.attribution[key] = attribution[key] ? attribution[key].replace(/ \(http.+\)/, "") : "";
} else {
this.attribution[key] = attribution[key];
}
}
}
}
};
}
Loading

0 comments on commit a2a2970

Please sign in to comment.