buildMeshes(styles, progress) {
        if (this.error) {
            return;
        }

        this.build_id = build_id++; // record order in which tile was built

        // Debug
        if (progress.start) {
            this.debug.geometry_count = 0;
            this.debug.buffer_size = 0;
        }

        // Create VBOs
        let meshes = {}; // new data to be added to tile
        let mesh_data = this.mesh_data;
        if (mesh_data) {
            for (let s in mesh_data) {
                for (let variant in mesh_data[s].meshes) {
                    let mesh_variant = mesh_data[s].meshes[variant];
                    if (mesh_variant.vertex_data) {
                        if (!styles[s]) {
                            log('warn', `Could not create mesh because style '${s}' not found, for tile ${this.key}, aborting tile`);
                            break;
                        }

                        // first add style-level uniforms, then add any mesh-specific ones
                        let mesh_options = Object.assign({}, mesh_data[s]);
                        mesh_options.uniforms = Object.assign({}, mesh_options.uniforms, mesh_variant.uniforms);
                        mesh_options.variant = mesh_variant.variant;

                        // for labels, keep buffer data on CPU so they can be modified later
                        if (mesh_variant.labels) {
                            mesh_options.retain = true;
                        }

                        let mesh = styles[s].makeMesh(mesh_variant.vertex_data, mesh_variant.vertex_elements, mesh_options);
                        mesh.variant = mesh_options.variant;
                        mesh.labels = mesh_variant.labels;
                        meshes[s] = meshes[s] || [];
                        meshes[s].push(mesh);
                        if (mesh.variant.mesh_order == null) {
                            mesh.variant.mesh_order = meshes[s].length - 1; // assign default variant render order
                        }

                        this.debug.buffer_size += mesh.buffer_size;
                        this.debug.geometry_count += mesh.geometry_count;
                    }
                }

                // Sort mesh variants by explicit render order (if present)
                if (meshes[s]) {
                    meshes[s].sort((a, b) => {
                        // Sort variant order ascending if present, then all null values (where order is unspecified)
                        let ao = a.variant.mesh_order, bo = b.variant.mesh_order;
                        return (ao == null ? 1 : (bo == null ? -1 : (ao < bo ? -1 : 1)));
                    });
                }
            }
        }
        delete this.mesh_data;

        // New meshes
        for (let m in meshes) {
            // swap in non-collision meshes right away
            if (!styles[m].collision) {
                if (this.meshes[m]) {
                    this.meshes[m].forEach(m => m.destroy()); // free old meshes
                }

                this.meshes[m] = meshes[m]; // set new mesh
                this.new_mesh_styles.push(m);
            }
            // keep label meshes out of view until collision is complete
            else {
                this.pending_label_meshes = this.pending_label_meshes || {};
                this.pending_label_meshes[m] = meshes[m];
            }
        }

        if (progress.done) {
            // Release un-replaced meshes (existing in previous generation, but weren't built for this one)
            for (let m in this.meshes) {
                if (this.new_mesh_styles.indexOf(m) === -1 && (!this.pending_label_meshes || this.pending_label_meshes[m] == null)) {
                    this.meshes[m].forEach(m => m.destroy());
                    delete this.meshes[m];
                }
            }
            this.new_mesh_styles = [];

            this.debug.geometry_ratio = (this.debug.geometry_count / this.debug.feature_count).toFixed(1);
        }
        this.printDebug(progress);
    }
Called on main thread when a web worker completes processing
       for a single tile.