diff --git a/demos/data/packageServer/3tzContent/README.md b/demos/data/packageServer/3tzContent/README.md new file mode 100644 index 00000000..7393a1aa --- /dev/null +++ b/demos/data/packageServer/3tzContent/README.md @@ -0,0 +1,4 @@ + +This example is the same as `./specs/data/combineTilesets/nestedExternal`, +but with the tilesets in `sub0` and `sub1` directories being converted +into 3TZ archives. diff --git a/demos/data/packageServer/3tzContent/externalA.json b/demos/data/packageServer/3tzContent/externalA.json new file mode 100644 index 00000000..d4f878fb --- /dev/null +++ b/demos/data/packageServer/3tzContent/externalA.json @@ -0,0 +1,31 @@ +{ + "asset" : { + "version" : "1.1" + }, + "geometricError" : 4.0, + "root" : { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 2.0, + "children": [ + { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 1.0, + "content": { + "uri": "tileB.glb" + } + }, { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 1.0, + "content": { + "uri": "sub1/externalC.3tz" + } + } + ] + } +} \ No newline at end of file diff --git a/demos/data/packageServer/3tzContent/sub0/externalB.3tz b/demos/data/packageServer/3tzContent/sub0/externalB.3tz new file mode 100644 index 00000000..dae52c6e Binary files /dev/null and b/demos/data/packageServer/3tzContent/sub0/externalB.3tz differ diff --git a/demos/data/packageServer/3tzContent/sub1/externalC.3tz b/demos/data/packageServer/3tzContent/sub1/externalC.3tz new file mode 100644 index 00000000..76d88141 Binary files /dev/null and b/demos/data/packageServer/3tzContent/sub1/externalC.3tz differ diff --git a/demos/data/packageServer/3tzContent/tileA.glb b/demos/data/packageServer/3tzContent/tileA.glb new file mode 100644 index 00000000..2602e2e2 Binary files /dev/null and b/demos/data/packageServer/3tzContent/tileA.glb differ diff --git a/demos/data/packageServer/3tzContent/tileB.glb b/demos/data/packageServer/3tzContent/tileB.glb new file mode 100644 index 00000000..2602e2e2 Binary files /dev/null and b/demos/data/packageServer/3tzContent/tileB.glb differ diff --git a/demos/data/packageServer/3tzContent/tileset.json b/demos/data/packageServer/3tzContent/tileset.json new file mode 100644 index 00000000..7e657b19 --- /dev/null +++ b/demos/data/packageServer/3tzContent/tileset.json @@ -0,0 +1,39 @@ +{ + "asset" : { + "version" : "1.1" + }, + "geometricError" : 4.0, + "root" : { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 2.0, + "children": [ + { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 1.0, + "content": { + "uri": "tileA.glb" + } + }, { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 1.0, + "content": { + "uri": "externalA.json" + } + }, { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 1.0, + "content": { + "uri": "sub0/externalB.3tz" + } + } + ] + } +} \ No newline at end of file diff --git a/demos/packageServer/ContentDataTypeUtilities.ts b/demos/packageServer/ContentDataTypeUtilities.ts new file mode 100644 index 00000000..ee36b854 --- /dev/null +++ b/demos/packageServer/ContentDataTypeUtilities.ts @@ -0,0 +1,111 @@ +import { ContentDataTypes } from "../../src/contentTypes/ContentDataTypes"; + +/** + * Utility methods for determining default file extensions and MIME + * types for a `ContentDataType`. + * + * These are only used in the package server demo. The functionality + * could later become part of the `contentTypes` package, maybe as + * part of the `ContentDataTypeRegistry`. + * + * @internal + */ +export class ContentDataTypeUtilities { + /** + * A mapping from `ContentDataType` strings to "default" file + * extensions (without the `.` dot) + */ + private static extensions: { [key: string]: string }; + + /** + * A mapping from `ContentDataType` strings to MIME types + */ + private static mimeTypes: { [key: string]: string }; + + /** + * Initialize the `extensions` dictionary if it was not + * initialized yet. + */ + private static initializeExtensions() { + if (ContentDataTypeUtilities.extensions !== undefined) { + return; + } + const d: { [key: string]: string } = {}; + d[ContentDataTypes.CONTENT_TYPE_GLB] = "glb"; + d[ContentDataTypes.CONTENT_TYPE_B3DM] = "b3dm"; + d[ContentDataTypes.CONTENT_TYPE_I3DM] = "i3dm"; + d[ContentDataTypes.CONTENT_TYPE_CMPT] = "cmpt"; + d[ContentDataTypes.CONTENT_TYPE_PNTS] = "pnts"; + d[ContentDataTypes.CONTENT_TYPE_GEOM] = "geom"; + d[ContentDataTypes.CONTENT_TYPE_VCTR] = "vctr"; + d[ContentDataTypes.CONTENT_TYPE_SUBT] = "subtree"; + d[ContentDataTypes.CONTENT_TYPE_PNG] = "png"; + d[ContentDataTypes.CONTENT_TYPE_JPEG] = "jpg"; + d[ContentDataTypes.CONTENT_TYPE_GIF] = "gif"; + d[ContentDataTypes.CONTENT_TYPE_GEOJSON] = "geojson"; + d[ContentDataTypes.CONTENT_TYPE_3TZ] = "3tz"; + d[ContentDataTypes.CONTENT_TYPE_GLTF] = "gltf"; + d[ContentDataTypes.CONTENT_TYPE_TILESET] = "json"; + ContentDataTypeUtilities.extensions = d; + } + + /** + * Initialize the `mimeTypes` dictionary if it was not + * initialized yet. + */ + private static initializeMimeTypes() { + if (ContentDataTypeUtilities.mimeTypes !== undefined) { + return; + } + const d: { [key: string]: string } = {}; + d[ContentDataTypes.CONTENT_TYPE_GLB] = "model/gltf-binary"; + d[ContentDataTypes.CONTENT_TYPE_B3DM] = "application/octet-stream"; + d[ContentDataTypes.CONTENT_TYPE_I3DM] = "application/octet-stream"; + d[ContentDataTypes.CONTENT_TYPE_CMPT] = "application/octet-stream"; + d[ContentDataTypes.CONTENT_TYPE_PNTS] = "application/octet-stream"; + d[ContentDataTypes.CONTENT_TYPE_GEOM] = "text/plain"; // ??? + d[ContentDataTypes.CONTENT_TYPE_VCTR] = "application/json"; // ??? + d[ContentDataTypes.CONTENT_TYPE_SUBT] = "application/octet-stream"; + d[ContentDataTypes.CONTENT_TYPE_PNG] = "image/png"; + d[ContentDataTypes.CONTENT_TYPE_JPEG] = "image/jpeg"; + d[ContentDataTypes.CONTENT_TYPE_GIF] = "image/gif"; + d[ContentDataTypes.CONTENT_TYPE_GEOJSON] = "application/json"; // ??? + d[ContentDataTypes.CONTENT_TYPE_3TZ] = "application/octet-stream"; // ??? + d[ContentDataTypes.CONTENT_TYPE_GLTF] = "model/gltf+json"; + d[ContentDataTypes.CONTENT_TYPE_TILESET] = "application/json"; + ContentDataTypeUtilities.mimeTypes = d; + } + + /** + * Returns the "default" file extension (without `.` dot) for the + * given content data type, or `undefined` if the given type is + * `undefined` or not known. + * + * @param contentDataType The `ContentDataType` string + * @returns The file extension, without `.` dot + */ + static getFileExtension( + contentDataType: string | undefined + ): string | undefined { + if (contentDataType === undefined) { + return undefined; + } + ContentDataTypeUtilities.initializeExtensions(); + return ContentDataTypeUtilities.extensions[contentDataType]; + } + + /** + * Returns the MIME type for the given content data type, or + * `undefined` if the given type is `undefined` or not known. + * + * @param contentDataType The `ContentDataType` string + * @returns The file extension, without `.` dot + */ + static getMimeType(contentDataType: string | undefined): string | undefined { + if (contentDataType === undefined) { + return undefined; + } + ContentDataTypeUtilities.initializeMimeTypes(); + return ContentDataTypeUtilities.mimeTypes[contentDataType]; + } +} diff --git a/demos/packageServer/PackageServer.ts b/demos/packageServer/PackageServer.ts new file mode 100644 index 00000000..97aca84f --- /dev/null +++ b/demos/packageServer/PackageServer.ts @@ -0,0 +1,266 @@ +import path from "path"; +import http from "http"; + +import { Buffers } from "../../src/base/Buffers"; +import { Paths } from "../../src/base/Paths"; + +import { TilesetSource } from "../../src/tilesetData/TilesetSource"; +import { TilesetSources } from "../../src/tilesetData/TilesetSources"; + +import { ContentDataTypes } from "../../src/contentTypes/ContentDataTypes"; +import { ContentDataTypeRegistry } from "../../src/contentTypes/ContentDataTypeRegistry"; + +import { ContentDataTypeUtilities } from "./ContentDataTypeUtilities"; + +import { Loggers } from "../../src/logging/Loggers"; +import { PackageServerOptions } from "./PackageServerOptions"; + +const logger = Loggers.get("packageServer"); + +export class PackageServer { + /** + * The base directory from which the server is serving. + * + * This is used for resolving the content from the + * root tileset source (if it was a tileset JSON file) + */ + private readonly baseDirectory: string; + + /** + * The tileset sources that the server is serving from. + * + * The key of each entry is the name of the tileset source + * relative to the base directory. The key for the "root" + * tileset source is `""` (the empty string). + * + * For example, when a tileset refers to `data/external.3tz`, + * then the entry with the key `data/external.3tz` will + * contain the data of the external 3TZ package. + */ + private tilesetSources: { [key: string]: TilesetSource } = {}; + + /** + * Creates a new instance + * + * @param baseDirectory - The base directory + */ + constructor(baseDirectory: string) { + this.baseDirectory = baseDirectory; + } + + /** + * Start the server based on the given options + * + * @param options The options + */ + start(options: PackageServerOptions) { + const hostName = options.hostName; + const port = options.port; + const sourceName = options.sourceName; + + const tilesetSource = TilesetSources.createAndOpen(sourceName); + if (!tilesetSource) { + logger.error("Could not create source for " + sourceName); + return; + } + this.tilesetSources[""] = tilesetSource; + + const server = http.createServer((req, res) => + this.handleRequest(req, res) + ); + server.listen(port, hostName, () => { + logger.info(`Server running at http://${hostName}:${port}/`); + }); + } + + /** + * Set overly permissive CORS header options for local tests + * + * @param res - The server response + */ + private static setCorsHeader(res: http.ServerResponse) { + res.setHeader("Access-Control-Allow-Origin", "*"); + res.setHeader("Access-Control-Request-Method", "*"); + res.setHeader("Access-Control-Allow-Methods", "OPTIONS, GET"); + res.setHeader( + "Access-Control-Allow-Headers", + "Origin, X-Requested-With, Content-Type, Accept" + ); + } + + /** + * The request handler for the node http server + * + * @param req The request + * @param res The response + */ + private async handleRequest( + req: http.IncomingMessage, + res: http.ServerResponse + ): Promise { + if (!req.url) { + logger.warn("Return 404 for undefined URL"); + res.statusCode = 404; + res.end(); + return; + } + + PackageServer.setCorsHeader(res); + if (req.method === "OPTIONS") { + res.setHeader("Allow", "OPTIONS, GET"); + res.writeHead(204); + res.end(); + return; + } + + // TODO Anything to be done for HTTPS here? + // (We only use the `pathname` anyhow, so probably not...) + const url = new URL(`http://${req.headers.host}${req.url}`); + //console.log("url ", url); + await this.handleResponseForUrlPathname(res, url.pathname); + } + + /** + * Resolve the content data for the given key. + * + * The key is just the URL pathname, without a leading slash, + * used for looking up entries in packages. + * + * This will try to look up the key in all known tileset sources, + * and return the first content that is found for this key. + * + * @param key - The key + * @returns - The content data + */ + private resolveContentData(key: string): Buffer | undefined { + logger.info(`Resolve content data for key ${key}`); + + for (const name of Object.keys(this.tilesetSources)) { + const tilesetSource = this.tilesetSources[name]; + + const dirName = path.dirname(name); + const relatviveKey = Paths.relativize(dirName, key); + + logger.info(` Looking up ${relatviveKey} in source "${name}"`); + const content = tilesetSource.getValue(relatviveKey); + if (content) { + logger.info( + ` Looking up ${relatviveKey} in source "${name}" succeeded` + ); + return content; + } + logger.info(` Looking up ${relatviveKey} in source "${name}" failed`); + } + + logger.info(`Resolve content data for key ${key} FAILED!`); + return undefined; + } + + /** + * Returns the data of the top-level tileset JSON from the package + * that is identified with the given key. + * + * If the respective package has not been opened yet, then it + * will be opened and stored as one of the `this.tilesetSources`. + * + * @param key - The key + * @returns The tileset JSON data + */ + private resolvePackageTilesetData(key: string): Buffer | undefined { + logger.info(`Resolve tileset data for package key ${key}`); + + let tilesetSource = this.tilesetSources[key]; + if (!tilesetSource) { + const fullSourceName = path.resolve(this.baseDirectory, key); + try { + tilesetSource = TilesetSources.createAndOpen(fullSourceName); + } catch (error) { + logger.error( + `Could not open tileset source for key ${key} with full source name ${fullSourceName}` + ); + return undefined; + } + this.tilesetSources[key] = tilesetSource; + } + const content = tilesetSource.getValue("tileset.json"); + if (content) { + logger.info(`Resolve tileset data for package key ${key} succeeded`); + return content; + } + logger.info(`Resolve tileset data for package key ${key} failed`); + return undefined; + } + + /** + * Handle the response for the given URL pathname. + * + * This will try to look up the data that is identified with the + * given path name, and send it out via the given response. + * + * If the given path name refers to a package (3TZ file), then + * this package will be opened internally and used for serving + * subsequent requests, with the first response being the + * top-level "tileset.json" data from this package. + * + * @param res - The response + * @param urlPathname - The URL pathname + */ + private async handleResponseForUrlPathname( + res: http.ServerResponse, + urlPathname: string + ): Promise { + logger.info(`Handle response for URL pathname ${urlPathname}`); + + const key = urlPathname.startsWith("/") + ? urlPathname.substring(1) + : urlPathname; + + // Try to resolve the content data + let content = this.resolveContentData(key); + if (!content) { + logger.info(`Return 404 for URL pathname ${urlPathname}`); + res.statusCode = 404; + res.end(); + return; + } + + // If the content is a 3TZ package, then the content data + // will be its top-level tileset JSON + let contentDataType = await ContentDataTypeRegistry.findType(key, content); + if (contentDataType === ContentDataTypes.CONTENT_TYPE_3TZ) { + logger.info(`Found 3TZ content for key ${key}`); + content = this.resolvePackageTilesetData(key); + if (!content) { + logger.info(`Return 404 for URL pathname ${urlPathname}`); + res.statusCode = 404; + res.end(); + return; + } + // Assuming that the "tileset.json" is actually a tileset JSON: + contentDataType = ContentDataTypes.CONTENT_TYPE_TILESET; + } + + // Prepare the headers for the response + let mimeType = ContentDataTypeUtilities.getMimeType(contentDataType); + if (mimeType === undefined) { + mimeType = "application/octet-stream"; + } + const headers: http.OutgoingHttpHeaders = { + "Content-Type": mimeType, + "Content-Length": content.length, + }; + if (Buffers.isGzipped(content)) { + headers["Content-Encoding"] = "gzip"; + } + + // Send out the actual resonse + logger.info(`Handle response for URL pathname ${urlPathname} succeeded:`); + logger.info(` key: ${key}`); + logger.info(` mimeType: ${mimeType}`); + logger.info(` content.length: ${content.length}`); + + res.writeHead(200, headers); + res.end(content); + return; + } +} diff --git a/demos/packageServer/PackageServerOptions.ts b/demos/packageServer/PackageServerOptions.ts new file mode 100644 index 00000000..67e45d1e --- /dev/null +++ b/demos/packageServer/PackageServerOptions.ts @@ -0,0 +1,20 @@ +/** + * Options for starting the package server + */ +export type PackageServerOptions = { + /** + * The host name + */ + hostName: string; + + /** + * The port + */ + port: number; + + /** + * The full name of the (root) tileset source that + * should be served. + */ + sourceName: string; +}; diff --git a/demos/packageServer/packageServerMain.ts b/demos/packageServer/packageServerMain.ts new file mode 100644 index 00000000..cefeacf6 --- /dev/null +++ b/demos/packageServer/packageServerMain.ts @@ -0,0 +1,90 @@ +import path from "path"; +import minimist from "minimist"; + +import { Paths } from "../../src/base/Paths"; +import { defined } from "../../src/base/defined"; +import { defaultValue } from "../../src/base/defaultValue"; + +import { PackageServer } from "./PackageServer"; + +import { Loggers } from "../../src/logging/Loggers"; +import { PackageServerOptions } from "./PackageServerOptions"; + +const logger = Loggers.get("packageServer"); + +/** + * Print the help message showing the command line options + */ +function printHelp() { + const help = + "Usage: PackageServer [OPTIONS]\n" + + " -n, --hostName Host name. Default: '127.0.0.1' (localhost).\n" + + " -p, --port Port number. Default: '8003'.\n" + + " -s, --sourceName Package file or directory name.\n" + + " -h --help Print help. Not more than what you're currently seeing.\n"; + console.log(help); +} + +/** + * Parses the options from the command line arguments. + * + * If the 'help' should be printed, or the arguments cannot be parsed, + * then the help is printed and `undefined` is returned. + * + * @param {minimist.ParsedArgs} args The arguments + * @returns The options + */ +function parseOptions(args: any) { + if (defined(args.h) || defined(args.help)) { + printHelp(); + return undefined; + } + + const hostName = defaultValue( + defaultValue(args.n, args.hostName), + "127.0.0.1" + ); + const port = defaultValue(defaultValue(args.p, args.port), "8003"); + let sourceName = ""; + sourceName = defaultValue(args.s, args.sourceName); + + if (!defined(sourceName)) { + logger.warn("No source name was given"); + printHelp(); + return undefined; + } + + const options = { + hostName: hostName, + port: port, + sourceName: sourceName, + }; + return options; +} + +/** + * Run the package server + */ +async function run() { + const parsedArguments = minimist(process.argv.slice(2)); + const options = parseOptions(parsedArguments); + if (!defined(options)) { + return; + } + + const sourceName = options.sourceName; + let baseDirectory = sourceName; + if (!Paths.isDirectory(sourceName)) { + baseDirectory = path.dirname(sourceName); + } + + const packageServer = new PackageServer(baseDirectory); + const serverOptions: PackageServerOptions = { + hostName: options.hostName, + port: options.port, + sourceName: options.sourceName, + }; + packageServer.start(serverOptions); +} + +run(); diff --git a/specs/data/combineTilesets/nestedExternal/README.md b/specs/data/combineTilesets/nestedExternal/README.md index 32a949f2..b864dc6d 100644 --- a/specs/data/combineTilesets/nestedExternal/README.md +++ b/specs/data/combineTilesets/nestedExternal/README.md @@ -1,20 +1,20 @@ ``` tileset.json refers to - tileA.b3dm + tileA.glb externalA.json sub0/externalB.json externalA.json refers to - tileB.b3dm + tileB.glb sub1/externalC.json sub0/externalB.json refers to - tileC.b3dm - sub01/tileD.b3dm + tileC.glb + sub01/tileD.glb sub1/externalC.json refers to - tileE.b3dm - sub10/tileF.b3dm + tileE.glb + sub10/tileF.glb ``` diff --git a/specs/data/combineTilesets/nestedExternal/externalA.json b/specs/data/combineTilesets/nestedExternal/externalA.json index 98ff8810..a3f4c346 100644 --- a/specs/data/combineTilesets/nestedExternal/externalA.json +++ b/specs/data/combineTilesets/nestedExternal/externalA.json @@ -1,31 +1,31 @@ { - "asset" : { - "version" : "1.1" + "asset" : { + "version" : "1.1" + }, + "geometricError" : 4.0, + "root" : { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, - "geometricError" : 4.0, - "root" : { - "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] - }, - "geometricError" : 2.0, - "children": [ - { - "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] - }, - "geometricError" : 1.0, - "content": { - "uri": "tileB.b3dm" - } - }, { - "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] - }, - "geometricError" : 1.0, - "content": { - "uri": "sub1/externalC.json" - } - } - ] - } - } \ No newline at end of file + "geometricError" : 2.0, + "children": [ + { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 1.0, + "content": { + "uri": "tileB.glb" + } + }, { + "boundingVolume" : { + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + }, + "geometricError" : 1.0, + "content": { + "uri": "sub1/externalC.json" + } + } + ] + } +} \ No newline at end of file diff --git a/specs/data/combineTilesets/nestedExternal/sub0/externalB.json b/specs/data/combineTilesets/nestedExternal/sub0/externalB.json index ea1939b9..54f4d0bc 100644 --- a/specs/data/combineTilesets/nestedExternal/sub0/externalB.json +++ b/specs/data/combineTilesets/nestedExternal/sub0/externalB.json @@ -5,25 +5,25 @@ "geometricError" : 4.0, "root" : { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 2.0, "children": [ { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 1.0, "content": { - "uri": "tileC.b3dm" + "uri": "tileC.glb" } }, { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 1.0, "content": { - "uri": "sub01/tileD.b3dm" + "uri": "sub01/tileD.glb" } } ] diff --git a/specs/data/combineTilesets/nestedExternal/sub0/sub01/tileD.b3dm b/specs/data/combineTilesets/nestedExternal/sub0/sub01/tileD.b3dm deleted file mode 100644 index e69de29b..00000000 diff --git a/specs/data/combineTilesets/nestedExternal/sub0/sub01/tileD.glb b/specs/data/combineTilesets/nestedExternal/sub0/sub01/tileD.glb new file mode 100644 index 00000000..2602e2e2 Binary files /dev/null and b/specs/data/combineTilesets/nestedExternal/sub0/sub01/tileD.glb differ diff --git a/specs/data/combineTilesets/nestedExternal/sub0/tileC.b3dm b/specs/data/combineTilesets/nestedExternal/sub0/tileC.b3dm deleted file mode 100644 index e69de29b..00000000 diff --git a/specs/data/combineTilesets/nestedExternal/sub0/tileC.glb b/specs/data/combineTilesets/nestedExternal/sub0/tileC.glb new file mode 100644 index 00000000..2602e2e2 Binary files /dev/null and b/specs/data/combineTilesets/nestedExternal/sub0/tileC.glb differ diff --git a/specs/data/combineTilesets/nestedExternal/sub1/externalC.json b/specs/data/combineTilesets/nestedExternal/sub1/externalC.json index 02c71b20..7139d1f0 100644 --- a/specs/data/combineTilesets/nestedExternal/sub1/externalC.json +++ b/specs/data/combineTilesets/nestedExternal/sub1/externalC.json @@ -5,25 +5,25 @@ "geometricError" : 4.0, "root" : { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 2.0, "children": [ { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 1.0, "content": { - "uri": "tileE.b3dm" + "uri": "tileE.glb" } }, { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 1.0, "content": { - "uri": "sub10/tileF.b3dm" + "uri": "sub10/tileF.glb" } } ] diff --git a/specs/data/combineTilesets/nestedExternal/sub1/sub10/tileF.b3dm b/specs/data/combineTilesets/nestedExternal/sub1/sub10/tileF.b3dm deleted file mode 100644 index e69de29b..00000000 diff --git a/specs/data/combineTilesets/nestedExternal/sub1/sub10/tileF.glb b/specs/data/combineTilesets/nestedExternal/sub1/sub10/tileF.glb new file mode 100644 index 00000000..2602e2e2 Binary files /dev/null and b/specs/data/combineTilesets/nestedExternal/sub1/sub10/tileF.glb differ diff --git a/specs/data/combineTilesets/nestedExternal/sub1/tileE.b3dm b/specs/data/combineTilesets/nestedExternal/sub1/tileE.b3dm deleted file mode 100644 index e69de29b..00000000 diff --git a/specs/data/combineTilesets/nestedExternal/sub1/tileE.glb b/specs/data/combineTilesets/nestedExternal/sub1/tileE.glb new file mode 100644 index 00000000..2602e2e2 Binary files /dev/null and b/specs/data/combineTilesets/nestedExternal/sub1/tileE.glb differ diff --git a/specs/data/combineTilesets/nestedExternal/tileA.b3dm b/specs/data/combineTilesets/nestedExternal/tileA.b3dm deleted file mode 100644 index e69de29b..00000000 diff --git a/specs/data/combineTilesets/nestedExternal/tileA.glb b/specs/data/combineTilesets/nestedExternal/tileA.glb new file mode 100644 index 00000000..2602e2e2 Binary files /dev/null and b/specs/data/combineTilesets/nestedExternal/tileA.glb differ diff --git a/specs/data/combineTilesets/nestedExternal/tileB.b3dm b/specs/data/combineTilesets/nestedExternal/tileB.b3dm deleted file mode 100644 index e69de29b..00000000 diff --git a/specs/data/combineTilesets/nestedExternal/tileB.glb b/specs/data/combineTilesets/nestedExternal/tileB.glb new file mode 100644 index 00000000..2602e2e2 Binary files /dev/null and b/specs/data/combineTilesets/nestedExternal/tileB.glb differ diff --git a/specs/data/combineTilesets/nestedExternal/tileset.json b/specs/data/combineTilesets/nestedExternal/tileset.json index 078c879d..b1e1c92c 100644 --- a/specs/data/combineTilesets/nestedExternal/tileset.json +++ b/specs/data/combineTilesets/nestedExternal/tileset.json @@ -5,21 +5,21 @@ "geometricError" : 4.0, "root" : { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 2.0, "children": [ { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 1.0, "content": { - "uri": "tileA.b3dm" + "uri": "tileA.glb" } }, { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 1.0, "content": { @@ -27,7 +27,7 @@ } }, { "boundingVolume" : { - "box" : [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] + "box" : [ 0.5, -0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] }, "geometricError" : 1.0, "content": {