Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add gltf.openGlbFile #222

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"onCommand:gltf.previewModel",
"onCommand:gltf.validateFile",
"onCommand:gltf.exportGlbFile",
"onCommand:gltf.importGlbFile"
"onCommand:gltf.importGlbFile",
"onCommand:gltf.openGlbFile"
],
"main": "./out/src/extension",
"contributes": {
Expand Down Expand Up @@ -177,6 +178,10 @@
"command": "gltf.importGlbFile",
"title": "glTF: Import from GLB"
},
{
"command": "gltf.openGlbFile",
"title": "glTF: Open GLB"
},
{
"command": "gltf.importAnimation",
"title": "glTF: Import animation"
Expand Down Expand Up @@ -232,6 +237,10 @@
"command": "gltf.importGlbFile",
"group": "glTF"
},
{
"command": "gltf.openGlbFile",
"group": "glTF"
},
{
"command": "gltf.validateFile",
"group": "glTF"
Expand Down
60 changes: 46 additions & 14 deletions src/dataUriTextDocumentContentProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { getFromJsonPointer, btoa, atob, getAccessorData, AccessorTypeToNumCompo
import { GLTF2 } from './GLTF2';

let decoderModule;
draco3dgltf.createDecoderModule({}).then(function(module) {
draco3dgltf.createDecoderModule({}).then(function (module) {
decoderModule = module;
});

Expand Down Expand Up @@ -57,12 +57,54 @@ export class DataUriTextDocumentContentProvider implements vscode.TextDocumentCo
return !!jsonPointer.match(/^\/meshes\/\d+\/primitives\//);
}

getDocument(fileName: string): vscode.TextDocument {
let document = vscode.workspace.textDocuments.find(e => e.uri.scheme === 'file' && e.fileName === fileName);
if (document) {
return document;
}

// get json document from glbProvider
return vscode.workspace.textDocuments.find(e => e.uri.scheme === 'glb' && e.fileName === fileName);
}

getTitleAndData(data: any, gltf: GLTF2.GLTF, jsonPointer: string, fileName: string): [string, string] {
if (data.hasOwnProperty('uri')) {
// from external uri
let dataUri: string = data.uri;
let previewTitle = dataUri;
if (!dataUri.startsWith('data:')) {
// Not a DataURI: Look up external reference.
const name = decodeURI(Url.resolve(fileName, dataUri));
const contents = fs.readFileSync(name);
dataUri = 'data:image;base64,' + btoa(contents);
previewTitle = decodeURI(previewTitle);
} else {
previewTitle = jsonPointer;
}

return [previewTitle, dataUri];
}

if (data.hasOwnProperty('bufferView')) {
// from internal bufferView
const bufferView = gltf.bufferViews[data.bufferView];
const buffer = gltf.buffers[bufferView.buffer];
const name = decodeURI(Url.resolve(fileName, buffer.uri));
const contents = fs.readFileSync(name).slice(bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength);
const dataUri = 'data:image;base64,' + btoa(contents);
const previewTitle = `${buffer.uri}:${jsonPointer}`;
return [previewTitle, dataUri];
}

return [null, null]
}

public async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
const fileName = decodeURIComponent(uri.fragment);
const query = querystring.parse(uri.query);
query.viewColumn = query.viewColumn || vscode.ViewColumn.Active.toString();
let glTFContent: string;
const document = vscode.workspace.textDocuments.find(e => e.uri.scheme === 'file' && e.fileName === fileName);
const document = this.getDocument(fileName);
if (document) {
glTFContent = document.getText();
} else {
Expand All @@ -76,18 +118,8 @@ export class DataUriTextDocumentContentProvider implements vscode.TextDocumentCo
const data = getFromJsonPointer(glTF, jsonPointer);

if (data && (typeof data === 'object')) {
if (data.hasOwnProperty('uri')) {
let dataUri: string = data.uri;
let previewTitle = dataUri;
if (!dataUri.startsWith('data:')) {
// Not a DataURI: Look up external reference.
const name = decodeURI(Url.resolve(fileName, dataUri));
const contents = fs.readFileSync(name);
dataUri = 'data:image;base64,' + btoa(contents);
previewTitle = decodeURI(previewTitle);
} else {
previewTitle = jsonPointer;
}
let [previewTitle, dataUri] = this.getTitleAndData(data, glTF, jsonPointer, fileName);
if (previewTitle && dataUri) {

if (this.isImage(jsonPointer)) {
// Peek Definition requests have a document that matches the current document
Expand Down
19 changes: 19 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as fs from 'fs';
import { getFromJsonPointer, guessMimeType, btoa, guessFileExtension, getAccessorData, AccessorTypeToNumComponents, parseJsonMap, truncateJsonPointer } from './utilities';
import { GLTF2 } from './GLTF2';
import { GltfWindow } from './gltfWindow';
import { GlbTextDocumentContentProvider } from './glbTextDocumentContentProvider';

function checkValidEditor(): boolean {
if (vscode.window.activeTextEditor === undefined) {
Expand Down Expand Up @@ -457,6 +458,24 @@ export function activate(context: vscode.ExtensionContext): void {
}
}));

//
// Virtual TextDocumentContentProvider for glb json chunk.
//
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider('glb', new GlbTextDocumentContentProvider()));

//
// Open GLB with 'glb:' schema, and send GlbProvider.
//
context.subscriptions.push(vscode.commands.registerCommand('gltf.openGlbFile', async (fileUri) => {

const virtualTextPath = `glb:${fileUri.fsPath}.json`;
const uri = vscode.Uri.parse(virtualTextPath);
const doc = await vscode.workspace.openTextDocument(uri); // calls back into the provider
vscode.languages.setTextDocumentLanguage(doc, "json");
await vscode.window.showTextDocument(doc, { preview: false });

}));

//
// Run the validator on an external file.
//
Expand Down
82 changes: 82 additions & 0 deletions src/glbTextDocumentContentProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';

//
// GlbTextDocumentContentProvider provide json chunk of glb.
//
export class GlbTextDocumentContentProvider implements vscode.TextDocumentContentProvider {

// emitter and its event
onDidChangeEmitter = new vscode.EventEmitter<vscode.Uri>();
onDidChange = this.onDidChangeEmitter.event;

provideTextDocumentContent(uri: vscode.Uri): string {

if (!uri.fsPath.endsWith(".json")) {
return "fsPath must endsWith .json";
}
let fsPath = uri.fsPath.substr(0, uri.fsPath.length - 5);

let data = fs.readFileSync(fsPath);
let offset = 0;
if (data.readInt32LE(offset) != 0x46546C67) {
return `not glb`;
}
offset += 4;

let version = data.readInt32LE(offset)
if (version != 2) {
return `gltf version ${version} not support`;
}
offset += 4;

let length = data.readInt32LE(offset);
offset += 4;

let json = null;
let binOffset = null;
while (offset < length) {

let chunkLength = data.readInt32LE(offset);
offset += 4;

let chunkType = data.readInt32LE(offset);
offset += 4;

let chunkData = data.toString('utf8', offset, offset + chunkLength);

if (chunkType == 0x4E4F534A) {

json = JSON.parse(chunkData);

}
else if (chunkType == 0x004E4942) {

binOffset = offset;

}
else {
// unknown
}

offset += chunkLength;
}

if (binOffset && json) {

// buffer access hack
json.buffers[0]['uri'] = path.basename(fsPath);
for (let bufferView of json.bufferViews) {
bufferView.byteOffset += binOffset;
}

return JSON.stringify(json, null, ' ');
}
else {

return `invalid glb`;

}
}
};
10 changes: 9 additions & 1 deletion src/gltfWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ import { GltfInspectData } from './gltfInspectData';
import { GltfOutline } from './gltfOutline';

function isGltfFile(editor: vscode.TextEditor | undefined): boolean {
return editor && editor.document.fileName.toLowerCase().endsWith('.gltf');
if (editor) {
if (editor.document.fileName.toLowerCase().endsWith('.gltf')) {
return true;
}
if (editor.document.uri.scheme == 'glb') {
return true;
}
}
return false;
}

export class GltfWindow {
Expand Down